]> git.imager.perl.org - imager.git/blob - png.c
Fixed an overflow bug in png.c where reading images with a palette or
[imager.git] / png.c
1 #include "image.h"
2 #include "png.h"
3
4 /* Check to see if a file is a PNG file using png_sig_cmp().  png_sig_cmp()
5  * returns zero if the image is a PNG and nonzero if it isn't a PNG.
6  *
7  * The function check_if_png() shown here, but not used, returns nonzero (true)
8  * if the file can be opened and is a PNG, 0 (false) otherwise.
9  *
10  * If this call is successful, and you are going to keep the file open,
11  * you should call png_set_sig_bytes(png_ptr, PNG_BYTES_TO_CHECK); once
12  * you have created the png_ptr, so that libpng knows your application
13  * has read that many bytes from the start of the file.  Make sure you
14  * don't call png_set_sig_bytes() with more than 8 bytes read or give it
15  * an incorrect number of bytes read, or you will either have read too
16  * many bytes (your fault), or you are telling libpng to read the wrong
17  * number of magic bytes (also your fault).
18  *
19  * Many applications already read the first 2 or 4 bytes from the start
20  * of the image to determine the file type, so it would be easiest just
21  * to pass the bytes to png_sig_cmp() or even skip that if you know
22  * you have a PNG file, and call png_set_sig_bytes().
23  */
24
25 /* this is a way to get number of channels from color space 
26  * Color code to channel number */
27
28 int CC2C[PNG_COLOR_MASK_PALETTE|PNG_COLOR_MASK_COLOR|PNG_COLOR_MASK_ALPHA];
29
30 #define PNG_BYTES_TO_CHECK 4
31  
32
33
34
35
36
37
38
39
40 /*
41 png_set_read_fn(png_structp read_ptr, voidp read_io_ptr, png_rw_ptr read_data_fn)
42 png_set_write_fn(png_structp write_ptr, voidp write_io_ptr, png_rw_ptr write_data_fn,
43 png_flush_ptr output_flush_fn);
44 voidp read_io_ptr = png_get_io_ptr(read_ptr);
45 voidp write_io_ptr = png_get_io_ptr(write_ptr);
46 */
47
48 struct png_scalar_info {
49   char *data;
50   int length;
51   int cpos;
52 };
53
54
55 struct png_wiol_info {
56   io_glue *cp;
57   int length;
58   int cpos;
59 };
60
61 static void
62 user_read_data(png_structp png_ptr,png_bytep data, png_size_t length) {
63   struct png_scalar_info *sci=(struct png_scalar_info *)png_ptr->io_ptr;
64   
65   /*   fprintf(stderr,"user_read_data: cpos %d/%d (%d)\n",sci->cpos,sci->length,length); */
66   
67   if (sci->cpos+(ssize_t)length > sci->length ) { png_error(png_ptr, "Read overflow error on a scalar."); }
68   
69   memcpy(data, sci->data+sci->cpos , length);
70   sci->cpos+=length;
71 }
72
73 /*
74 static void
75 user_write_data(png_structp png_ptr, png_bytep data, png_uint_32 length) {
76    FIXME: implement these 
77 }
78
79 static void
80 user_flush_data(png_structp png_ptr) {
81   FIXME: implement these 
82 }
83 */
84
85
86 void
87 scalar_png_init_io(png_structp png_ptr,struct png_scalar_info *sci) {
88   png_ptr->io_ptr = (png_voidp)sci;
89 }
90
91
92
93
94
95
96 int
97 check_if_png(char *file_name, FILE **fp) {
98    char buf[PNG_BYTES_TO_CHECK];
99    
100    /* Open the prospective PNG file. */
101    if ((*fp = fopen(file_name, "rb")) != NULL) return 0;
102    
103    /* Read in some of the signature bytes */
104    if (fread(buf, 1, PNG_BYTES_TO_CHECK, *fp) != PNG_BYTES_TO_CHECK) return 0;
105
106    /* Compare the first PNG_BYTES_TO_CHECK bytes of the signature.
107       Return nonzero (true) if they match */
108
109    return(!png_sig_cmp((png_bytep)buf, (png_size_t)0, PNG_BYTES_TO_CHECK));
110 }
111
112 /* Read a PNG file.  You may want to return an error code if the read
113  * fails (depending upon the failure).  There are two "prototypes" given
114  * here - one where we are given the filename, and we need to open the
115  * file, and the other where we are given an open file (possibly with
116  * some or all of the magic bytes read - see comments above).
117  */
118
119 i_img *
120 i_readpng(int fd) {
121   i_img *im;
122   png_structp png_ptr;
123   png_infop info_ptr;
124   png_uint_32 width, height, y;
125   int bit_depth, color_type, interlace_type;
126   int number_passes;
127   int channels, pass;
128   
129   FILE *fp;
130   unsigned int sig_read;
131
132   sig_read = 0;
133
134   if ((fp = fdopen(fd,"r")) == NULL) {
135     mm_log((1,"can't fdopen.\n"));
136     exit(1);
137   }
138
139   mm_log((1,"i_readpng(fd %d)\n",fd));
140
141   png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,NULL,NULL,NULL);
142   
143   if (png_ptr == NULL) {
144     fclose(fp);
145     return 0;
146   }
147   
148   /* Allocate/initialize the memory for image information.  REQUIRED. */
149   info_ptr = png_create_info_struct(png_ptr);
150   if (info_ptr == NULL) {
151     fclose(fp);
152     png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
153     return 0;
154   }
155   
156   /* Set error handling if you are using the setjmp/longjmp method (this is
157    * the normal method of doing things with libpng).  REQUIRED unless you
158    * set up your own error handlers in the png_create_read_struct() earlier.
159    */
160   
161   if (setjmp(png_ptr->jmpbuf)) {
162     /* Free all of the memory associated with the png_ptr and info_ptr */
163     png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
164     fclose(fp);
165     /* If we get here, we had a problem reading the file */
166     return NULL;
167   }
168   
169   /* Set up the input control if you are using standard C streams */
170   png_init_io(png_ptr, fp);
171   /* If we have already read some of the signature */
172   png_set_sig_bytes(png_ptr, sig_read);
173   
174   /* The call to png_read_info() gives us all of the information from the
175    * PNG file before the first IDAT (image data chunk).  REQUIRED
176    */
177   
178   png_read_info(png_ptr, info_ptr);
179   png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
180                &interlace_type, NULL, NULL);
181   
182   mm_log((1,
183           "png_get_IHDR results: width %d, height %d, bit_depth %d,color_type %d,interlace_type %d\n",
184           width, height, bit_depth, color_type, interlace_type));
185
186   CC2C[PNG_COLOR_TYPE_GRAY]=1;
187   CC2C[PNG_COLOR_TYPE_PALETTE]=3;
188   CC2C[PNG_COLOR_TYPE_RGB]=3;
189   CC2C[PNG_COLOR_TYPE_RGB_ALPHA]=4;
190   CC2C[PNG_COLOR_TYPE_GRAY_ALPHA]=2;
191
192   channels=CC2C[color_type];
193   
194   mm_log((1,"channels %d\n", channels));
195   
196   im = i_img_empty_ch(NULL, width, height, channels);
197
198   /**** Set up the data transformations you want.  Note that these are all
199    **** optional.  Only call them if you want/need them.  Many of the
200    **** transformations only work on specific types of images, and many
201    **** are mutually exclusive.
202    ****/
203
204   /* tell libpng to strip 16 bit/color files down to 8 bits/color */
205   png_set_strip_16(png_ptr);
206   
207  
208   /* Extract multiple pixels with bit depths of 1, 2, and 4 from a single
209    * byte into separate bytes (useful for paletted and grayscale images).
210    */
211
212   png_set_packing(png_ptr);
213
214   /* Expand paletted colors into true RGB triplets */
215   if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_expand(png_ptr);
216   
217   /* Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel */
218   if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) png_set_expand(png_ptr);
219
220   /* Expand paletted or RGB images with transparency to full alpha channels
221    * so the data will be available as RGBA quartets.
222    *
223    * if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_expand(png_ptr);
224    * 
225    */
226   
227   /* Strip alpha bytes from the input data without combining with the
228    * background (not recommended).
229    */
230   if (color_type != PNG_COLOR_TYPE_RGB_ALPHA || color_type != PNG_COLOR_TYPE_GRAY_ALPHA) 
231     png_set_strip_alpha(png_ptr);
232
233
234   number_passes = png_set_interlace_handling(png_ptr);
235
236   mm_log((1,"number of passes=%d\n",number_passes));
237   
238   png_read_update_info(png_ptr, info_ptr);
239
240   for (pass = 0; pass < number_passes; pass++)
241     for (y = 0; y < height; y++) {
242       png_read_row(png_ptr,(png_bytep) &(im->data[channels*width*y]), NULL);
243       mm_log((1, "pass = %d, row %d\n", pass, y));
244     }
245   /* read rest of file, and get additional chunks in info_ptr - REQUIRED */
246
247   mm_log((1,"FOO!\n"));
248
249   png_read_end(png_ptr, info_ptr); 
250   /* clean up after the read, and free any memory allocated - REQUIRED */
251   png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
252
253   fclose(fp);
254   return im;
255 }
256
257   
258
259
260 undef_int
261 i_writepng(i_img *im,int fd) {
262   FILE *fp;
263   png_structp png_ptr;
264   png_infop info_ptr;
265   int width,height,y;
266   volatile int cspace,channels;
267
268   mm_log((1,"i_writepng(0x%x,fd %d)\n",im,fd));
269   
270   if ((fp = fdopen(fd,"w")) == NULL) {
271     mm_log((1,"can't fdopen.\n"));
272     exit(1);
273   }
274
275   height=im->ysize;
276   width=im->xsize;
277
278   channels=im->channels;
279
280   if (channels>2) { cspace=PNG_COLOR_TYPE_RGB; channels-=3; }
281   else { cspace=PNG_COLOR_TYPE_GRAY; channels--; }
282   
283   if (channels) cspace|=PNG_COLOR_MASK_ALPHA;
284   mm_log((1,"cspace=%d\n",cspace));
285
286   channels=im->channels;
287
288   /* Create and initialize the png_struct with the desired error handler
289    * functions.  If you want to use the default stderr and longjump method,
290    * you can supply NULL for the last three parameters.  We also check that
291    * the library version is compatible with the one used at compile time,
292    * in case we are using dynamically linked libraries.  REQUIRED.
293    */
294   
295   png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,NULL,NULL,NULL);
296   
297   if (png_ptr == NULL) {
298     fclose(fp);
299     return 0;
300   }
301   
302   /* Allocate/initialize the image information data.  REQUIRED */
303   info_ptr = png_create_info_struct(png_ptr);
304
305   if (info_ptr == NULL) {
306     fclose(fp);
307     png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
308     return(0);
309   }
310   
311   /* Set error handling.  REQUIRED if you aren't supplying your own
312    * error hadnling functions in the png_create_write_struct() call.
313    */
314   if (setjmp(png_ptr->jmpbuf)) {
315     /* If we get here, we had a problem reading the file */
316     fclose(fp);
317     png_destroy_write_struct(&png_ptr,  (png_infopp)NULL);
318     return(0);
319   }
320   
321   png_init_io(png_ptr, fp);
322
323   /* Set the image information here.  Width and height are up to 2^31,
324    * bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on
325    * the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY,
326    * PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB,
327    * or PNG_COLOR_TYPE_RGB_ALPHA.  interlace is either PNG_INTERLACE_NONE or
328    * PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST
329    * currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED
330    */
331
332   png_set_IHDR(png_ptr, info_ptr, width, height, 8, cspace,
333                PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
334
335   png_write_info(png_ptr, info_ptr);
336   for (y = 0; y < height; y++) png_write_row(png_ptr, (png_bytep) &(im->data[channels*width*y]));
337   png_write_end(png_ptr, info_ptr);
338   png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
339
340   fclose(fp);
341   return(1);
342 }
343
344
345
346
347 i_img*
348 i_readpng_scalar(char *data, int length) {
349   i_img *im;
350   png_structp png_ptr;
351   png_infop info_ptr;
352   png_uint_32 width, height, y;
353   int bit_depth, color_type, interlace_type;
354   int number_passes;
355   int channels, pass;
356   unsigned int sig_read;
357
358   struct png_scalar_info sci;
359
360   sci.data=data;
361   sci.length=length;
362   sci.cpos=0;
363
364   sig_read=0;
365   mm_log((1,"i_readpng_scalar(char 0x%08X, length %d)\n",data,length));
366
367   png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,NULL,NULL,NULL);
368   png_set_read_fn(png_ptr, (void*) (&sci), user_read_data);
369   
370   info_ptr = png_create_info_struct(png_ptr);
371   if (info_ptr == NULL) {
372     png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
373     return NULL;
374   }
375   
376   if (setjmp(png_ptr->jmpbuf)) {
377     mm_log((1,"i_readpng_scalar: error.\n"));
378     png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
379     return NULL;
380   }
381   
382   scalar_png_init_io(png_ptr, &sci);
383   png_set_sig_bytes(png_ptr, sig_read);
384   png_read_info(png_ptr, info_ptr);
385   png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL);
386   
387   mm_log((1,
388           "png_get_IHDR results: width %d, height %d, bit_depth %d,color_type %d,interlace_type %d\n",
389           width,height,bit_depth,color_type,interlace_type));
390   
391   CC2C[PNG_COLOR_TYPE_GRAY]=1;
392   CC2C[PNG_COLOR_TYPE_PALETTE]=3;
393   CC2C[PNG_COLOR_TYPE_RGB]=3;
394   CC2C[PNG_COLOR_TYPE_RGB_ALPHA]=4;
395   CC2C[PNG_COLOR_TYPE_GRAY_ALPHA]=2;
396   channels=CC2C[color_type];
397   mm_log((1,"channels %d\n",channels));
398   im=i_img_empty_ch(NULL,width,height,channels);
399   png_set_strip_16(png_ptr);
400   png_set_packing(png_ptr);
401   if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_expand(png_ptr);
402   if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) png_set_expand(png_ptr);
403   if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_expand(png_ptr);
404   number_passes = png_set_interlace_handling(png_ptr);
405   mm_log((1,"number of passes=%d\n",number_passes));
406   png_read_update_info(png_ptr, info_ptr);
407   mm_log((1,"made it to here 1\n"));
408   for (pass = 0; pass < number_passes; pass++)
409     for (y = 0; y < height; y++) { png_read_row(png_ptr,(png_bytep) &(im->data[channels*width*y]), NULL); }
410   mm_log((1,"made it to here 2\n"));
411   png_read_end(png_ptr, info_ptr); 
412   mm_log((1,"made it to here 3\n"));
413   png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
414   mm_log((1,"made it to here 4\n"));
415   mm_log((1,"(0x%08X) <- i_readpng_scalar\n",im));  
416   return im;
417 }
418
419
420
421
422 /* i_img* */
423 /* i_readpng_wiol(io_glue *ig, int length) { */
424 /*   i_img *im; */
425 /*   png_structp png_ptr; */
426 /*   png_infop info_ptr; */
427 /*   png_uint_32 width, height; */
428 /*   int bit_depth, color_type, interlace_type; */
429 /*   int number_passes,y; */
430 /*   int channels,pass; */
431 /*   unsigned int sig_read; */
432
433 /*   struct png_wiol_info wi; */
434
435 /*   wi.data   = ig; */
436 /*   wi.length = length; */
437 /*   wi.cpos   = 0; */
438     
439 /*   sig_read=0; */
440 /*   mm_log((1,"i_readpng_wiol(char 0x%p, length %d)\n", data, length)); */
441
442 /*   png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,NULL,NULL,NULL); */
443 /*   png_set_read_fn(png_ptr, (void*) (&wi), user_read_data); */
444   
445 /*   info_ptr = png_create_info_struct(png_ptr); */
446 /*   if (info_ptr == NULL) { */
447 /*     png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); */
448 /*     return NULL; */
449 /*   } */
450   
451 /*   if (setjmp(png_ptr->jmpbuf)) { */
452 /*     mm_log((1,"i_readpng_wiol: error.\n")); */
453 /*     png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); */
454 /*     return NULL; */
455 /*   } */
456   
457 /*   scalar_png_init_io(png_ptr, &sci); */
458 /*   png_set_sig_bytes(png_ptr, sig_read); */
459 /*   png_read_info(png_ptr, info_ptr); */
460 /*   png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL); */
461   
462 /*   mm_log((1, */
463 /*        "png_get_IHDR results: width %d, height %d, bit_depth %d,color_type %d,interlace_type %d\n", */
464 /*        width,height,bit_depth,color_type,interlace_type)); */
465   
466 /*   CC2C[PNG_COLOR_TYPE_GRAY]=1; */
467 /*   CC2C[PNG_COLOR_TYPE_PALETTE]=3; */
468 /*   CC2C[PNG_COLOR_TYPE_RGB]=3; */
469 /*   CC2C[PNG_COLOR_TYPE_RGB_ALPHA]=4; */
470 /*   CC2C[PNG_COLOR_TYPE_GRAY_ALPHA]=2; */
471 /*   channels = CC2C[color_type]; */
472
473 /*   mm_log((1,"i_readpng_wiol: channels %d\n",channels)); */
474
475 /*   im = i_img_empty_ch(NULL,width,height,channels); */
476 /*   png_set_strip_16(png_ptr); */
477 /*   png_set_packing(png_ptr); */
478 /*   if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_expand(png_ptr); */
479 /*   if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) png_set_expand(png_ptr); */
480 /*   if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_expand(png_ptr); */
481 /*   number_passes = png_set_interlace_handling(png_ptr); */
482 /*   mm_log((1,"number of passes=%d\n",number_passes)); */
483 /*   png_read_update_info(png_ptr, info_ptr); */
484 /*   mm_log((1,"made it to here 1\n")); */
485 /*   for (pass = 0; pass < number_passes; pass++) */
486 /*     for (y = 0; y < height; y++) { png_read_row(png_ptr,(png_bytep) &(im->data[channels*width*y]), NULL); } */
487 /*   mm_log((1,"made it to here 2\n")); */
488 /*   png_read_end(png_ptr, info_ptr);  */
489 /*   mm_log((1,"made it to here 3\n")); */
490 /*   png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); */
491 /*   mm_log((1,"made it to here 4\n")); */
492 /*   mm_log((1,"(0x%08X) <- i_readpng_scalar\n",im));   */
493
494 /*   return im; */
495 /* } */