|
14 | 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
15 | 15 | */ |
16 | 16 |
|
17 | | -#include <string.h> |
18 | 17 | #include <stdio.h> |
19 | | -#include <setjmp.h> |
| 18 | +#include <stdlib.h> |
| 19 | +#include <string.h> |
| 20 | + |
20 | 21 | #include <jpeglib.h> |
| 22 | +#include <png.h> |
| 23 | + |
21 | 24 | #include "dbgutil.h" |
22 | 25 |
|
23 | 26 | void dump_data(const struct quirc_data *data) |
@@ -140,3 +143,131 @@ int load_jpeg(struct quirc *q, const char *filename) |
140 | 143 | jpeg_destroy_decompress(&dinfo); |
141 | 144 | return -1; |
142 | 145 | } |
| 146 | + |
| 147 | +/* hacked from https://dev.w3.org/Amaya/libpng/example.c |
| 148 | + * |
| 149 | + * Check to see if a file is a PNG file using png_sig_cmp(). png_sig_cmp() |
| 150 | + * returns zero if the image is a PNG and nonzero if it isn't a PNG. |
| 151 | + */ |
| 152 | +#define PNG_BYTES_TO_CHECK 4 |
| 153 | +int check_if_png(const char *filename) |
| 154 | +{ |
| 155 | + int ret = 0; |
| 156 | + FILE *infile = NULL; |
| 157 | + unsigned char buf[PNG_BYTES_TO_CHECK]; |
| 158 | + |
| 159 | + /* Open the prospective PNG file. */ |
| 160 | + if ((infile = fopen(filename, "rb")) == NULL) |
| 161 | + goto out; |
| 162 | + |
| 163 | + /* Read in some of the signature bytes */ |
| 164 | + if (fread(buf, 1, PNG_BYTES_TO_CHECK, infile) != PNG_BYTES_TO_CHECK) |
| 165 | + goto out; |
| 166 | + |
| 167 | + /* Compare the first PNG_BYTES_TO_CHECK bytes of the signature. */ |
| 168 | + if (png_sig_cmp(buf, (png_size_t)0, PNG_BYTES_TO_CHECK) == 0) |
| 169 | + ret = 1; |
| 170 | + |
| 171 | + /* FALLTHROUGH */ |
| 172 | +out: |
| 173 | + if (infile) |
| 174 | + fclose(infile); |
| 175 | + return (ret); |
| 176 | +} |
| 177 | + |
| 178 | +int load_png(struct quirc *q, const char *filename) |
| 179 | +{ |
| 180 | + int width, height, rowbytes, interlace_type, number_passes = 1; |
| 181 | + png_byte color_type, bit_depth; |
| 182 | + png_structp png_ptr = NULL; |
| 183 | + png_infop info_ptr = NULL; |
| 184 | + FILE *infile = NULL; |
| 185 | + uint8_t *image; |
| 186 | + int ret = -1; |
| 187 | + |
| 188 | + if ((infile = fopen(filename, "rb")) == NULL) |
| 189 | + goto out; |
| 190 | + |
| 191 | + png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); |
| 192 | + if (!png_ptr) |
| 193 | + goto out; |
| 194 | + |
| 195 | + info_ptr = png_create_info_struct(png_ptr); |
| 196 | + if (!info_ptr) |
| 197 | + goto out; |
| 198 | + |
| 199 | + if (setjmp(png_jmpbuf(png_ptr))) |
| 200 | + goto out; |
| 201 | + |
| 202 | + png_init_io(png_ptr, infile); |
| 203 | + |
| 204 | + png_read_info(png_ptr, info_ptr); |
| 205 | + |
| 206 | + color_type = png_get_color_type(png_ptr, info_ptr); |
| 207 | + bit_depth = png_get_bit_depth(png_ptr, info_ptr); |
| 208 | + interlace_type = png_get_interlace_type(png_ptr, info_ptr); |
| 209 | + |
| 210 | + // Read any color_type into 8bit depth, Grayscale format. |
| 211 | + // See http://www.libpng.org/pub/png/libpng-manual.txt |
| 212 | + |
| 213 | + // PNG_COLOR_TYPE_GRAY_ALPHA is always 8 or 16bit depth. |
| 214 | + if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) |
| 215 | + png_set_expand_gray_1_2_4_to_8(png_ptr); |
| 216 | + |
| 217 | + if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) |
| 218 | + png_set_tRNS_to_alpha(png_ptr); |
| 219 | + |
| 220 | + if (bit_depth == 16) |
| 221 | + png_set_strip_16(png_ptr); |
| 222 | + |
| 223 | + if (color_type & PNG_COLOR_MASK_ALPHA) |
| 224 | + png_set_strip_alpha(png_ptr); |
| 225 | + |
| 226 | + if (color_type == PNG_COLOR_TYPE_RGB || |
| 227 | + color_type == PNG_COLOR_TYPE_RGB_ALPHA) { |
| 228 | + png_set_rgb_to_gray_fixed(png_ptr, 1, -1, -1); |
| 229 | + } |
| 230 | + |
| 231 | + if (interlace_type != PNG_INTERLACE_NONE) |
| 232 | + number_passes = png_set_interlace_handling(png_ptr); |
| 233 | + |
| 234 | + png_read_update_info(png_ptr, info_ptr); |
| 235 | + |
| 236 | + width = png_get_image_width(png_ptr, info_ptr); |
| 237 | + height = png_get_image_height(png_ptr, info_ptr); |
| 238 | + rowbytes = png_get_rowbytes(png_ptr, info_ptr); |
| 239 | + if (rowbytes != width) { |
| 240 | + fprintf(stderr, |
| 241 | + "load_png: expected rowbytes to be %u but got %u\n", |
| 242 | + width, rowbytes); |
| 243 | + goto out; |
| 244 | + } |
| 245 | + |
| 246 | + if (quirc_resize(q, width, height) < 0) |
| 247 | + goto out; |
| 248 | + |
| 249 | + image = quirc_begin(q, NULL, NULL); |
| 250 | + |
| 251 | + for (int pass = 0; pass < number_passes; pass++) { |
| 252 | + for (int y = 0; y < height; y++) { |
| 253 | + png_bytep row_pointer = image + y * width; |
| 254 | + png_read_rows(png_ptr, &row_pointer, NULL, 1); |
| 255 | + } |
| 256 | + } |
| 257 | + |
| 258 | + png_read_end(png_ptr, info_ptr); |
| 259 | + |
| 260 | + ret = 0; |
| 261 | + /* FALLTHROUGH */ |
| 262 | +out: |
| 263 | + /* cleanup */ |
| 264 | + if (png_ptr) { |
| 265 | + if (info_ptr) |
| 266 | + png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); |
| 267 | + else |
| 268 | + png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL); |
| 269 | + } |
| 270 | + if (infile) |
| 271 | + fclose(infile); |
| 272 | + return (ret); |
| 273 | +} |
0 commit comments