/* quirc -- QR-code recognition library * Copyright (C) 2010-2012 Daniel Beer * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include #include "dbgutil.h" void dump_data(const struct quirc_data *data) { printf(" Version: %d\n", data->version); printf(" ECC level: %c\n", "MLHQ"[data->ecc_level]); printf(" Mask: %d\n", data->mask); printf(" Data type: %d\n", data->data_type); printf(" Length: %d\n", data->payload_len); printf(" Payload: %s\n", data->payload); } void dump_cells(const struct quirc_code *code) { int u, v; printf(" %d cells, corners:", code->size); for (u = 0; u < 4; u++) printf(" (%d,%d)", code->corners[u].x, code->corners[u].y); printf("\n"); for (v = 0; v < code->size; v++) { printf(" "); for (u = 0; u < code->size; u++) { int p = v * code->size + u; if (code->cell_bitmap[p >> 3] & (1 << (p & 7))) printf("[]"); else printf(" "); } printf("\n"); } } struct my_jpeg_error { struct jpeg_error_mgr base; jmp_buf env; }; static void my_output_message(struct jpeg_common_struct *com) { struct my_jpeg_error *err = (struct my_jpeg_error *)com->err; char buf[JMSG_LENGTH_MAX]; err->base.format_message(com, buf); fprintf(stderr, "JPEG error: %s", buf); } static void my_error_exit(struct jpeg_common_struct *com) { struct my_jpeg_error *err = (struct my_jpeg_error *)com->err; my_output_message(com); longjmp(err->env, 0); } static struct jpeg_error_mgr *my_error_mgr(struct my_jpeg_error *err) { jpeg_std_error(&err->base); err->base.error_exit = my_error_exit; err->base.output_message = my_output_message; return &err->base; } int load_jpeg(struct quirc *q, const char *filename) { FILE *infile = fopen(filename, "rb"); struct jpeg_decompress_struct dinfo; struct my_jpeg_error err; uint8_t *image; int y; if (!infile) { perror("can't open input file"); return -1; } memset(&dinfo, 0, sizeof(dinfo)); dinfo.err = my_error_mgr(&err); if (setjmp(err.env)) goto fail; jpeg_create_decompress(&dinfo); jpeg_stdio_src(&dinfo, infile); jpeg_read_header(&dinfo, TRUE); dinfo.output_components = 1; dinfo.out_color_space = JCS_GRAYSCALE; jpeg_start_decompress(&dinfo); if (dinfo.output_components != 1) { fprintf(stderr, "Unexpected number of output components: %d", dinfo.output_components); goto fail; } if (quirc_resize(q, dinfo.output_width, dinfo.output_height) < 0) goto fail; image = quirc_begin(q, NULL, NULL); for (y = 0; y < dinfo.output_height; y++) { JSAMPROW row_pointer = image + y * dinfo.output_width; jpeg_read_scanlines(&dinfo, &row_pointer, 1); } fclose(infile); jpeg_finish_decompress(&dinfo); jpeg_destroy_decompress(&dinfo); return 0; fail: fclose(infile); jpeg_destroy_decompress(&dinfo); return -1; } /* hacked from https://dev.w3.org/Amaya/libpng/example.c * * Check if a file is a PNG image using png_sig_cmp(). Returns 1 if the given * file is a PNG and 0 otherwise. */ #define PNG_BYTES_TO_CHECK 4 int check_if_png(const char *filename) { int ret = 0; FILE *infile = NULL; unsigned char buf[PNG_BYTES_TO_CHECK]; /* Open the prospective PNG file. */ if ((infile = fopen(filename, "rb")) == NULL) goto out; /* Read in some of the signature bytes */ if (fread(buf, 1, PNG_BYTES_TO_CHECK, infile) != PNG_BYTES_TO_CHECK) goto out; /* * Compare the first PNG_BYTES_TO_CHECK bytes of the signature. * png_sig_cmp() returns zero if the image is a PNG and nonzero if it * isn't a PNG. */ if (png_sig_cmp(buf, (png_size_t)0, PNG_BYTES_TO_CHECK) == 0) ret = 1; /* FALLTHROUGH */ out: if (infile) fclose(infile); return (ret); } int load_png(struct quirc *q, const char *filename) { int width, height, rowbytes, interlace_type, number_passes = 1; png_byte color_type, bit_depth; png_structp png_ptr = NULL; png_infop info_ptr = NULL; FILE *infile = NULL; uint8_t *image; int ret = -1; int pass; if ((infile = fopen(filename, "rb")) == NULL) goto out; png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) goto out; info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) goto out; if (setjmp(png_jmpbuf(png_ptr))) goto out; png_init_io(png_ptr, infile); png_read_info(png_ptr, info_ptr); color_type = png_get_color_type(png_ptr, info_ptr); bit_depth = png_get_bit_depth(png_ptr, info_ptr); interlace_type = png_get_interlace_type(png_ptr, info_ptr); // Read any color_type into 8bit depth, Grayscale format. // See http://www.libpng.org/pub/png/libpng-manual.txt // PNG_COLOR_TYPE_GRAY_ALPHA is always 8 or 16bit depth. if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) png_set_expand_gray_1_2_4_to_8(png_ptr); if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png_ptr); if (bit_depth == 16) png_set_strip_16(png_ptr); if (color_type & PNG_COLOR_MASK_ALPHA) png_set_strip_alpha(png_ptr); if (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_RGB_ALPHA) { png_set_rgb_to_gray_fixed(png_ptr, 1, -1, -1); } if (interlace_type != PNG_INTERLACE_NONE) number_passes = png_set_interlace_handling(png_ptr); png_read_update_info(png_ptr, info_ptr); width = png_get_image_width(png_ptr, info_ptr); height = png_get_image_height(png_ptr, info_ptr); rowbytes = png_get_rowbytes(png_ptr, info_ptr); if (rowbytes != width) { fprintf(stderr, "load_png: expected rowbytes to be %u but got %u\n", width, rowbytes); goto out; } if (quirc_resize(q, width, height) < 0) goto out; image = quirc_begin(q, NULL, NULL); for (pass = 0; pass < number_passes; pass++) { int y; for (y = 0; y < height; y++) { png_bytep row_pointer = image + y * width; png_read_rows(png_ptr, &row_pointer, NULL, 1); } } png_read_end(png_ptr, info_ptr); ret = 0; /* FALLTHROUGH */ out: /* cleanup */ if (png_ptr) { if (info_ptr) png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); else png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL); } if (infile) fclose(infile); return (ret); }