• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  png2pnm.c --- conversion from PNG-file to PGM/PPM-file
3  *  copyright (C) 1999,2017 by Willem van Schaik <willem at schaik.com>
4  *
5  *  version 1.0 - 1999.10.15 - First version.
6  *          1.1 - 2017.04.22 - Add buffer-size check (Glenn Randers-Pehrson)
7  *          1.2 - 2017.08.24 - Fix potential overflow in buffer-size check
8  *                             (Glenn Randers-Pehrson)
9  *          1.3 - 2017.08.28 - Add PNGMINUS_UNUSED (Christian Hesse)
10  *
11  *  Permission to use, copy, modify, and distribute this software and
12  *  its documentation for any purpose and without fee is hereby granted,
13  *  provided that the above copyright notice appear in all copies and
14  *  that both that copyright notice and this permission notice appear in
15  *  supporting documentation. This software is provided "as is" without
16  *  express or implied warranty.
17  */
18 
19 #include <stdio.h>
20 #include <stdlib.h>
21 #ifdef __TURBOC__
22 #include <mem.h>
23 #include <fcntl.h>
24 #endif
25 #include <zlib.h>
26 
27 #ifndef BOOL
28 #define BOOL unsigned char
29 #endif
30 #ifndef TRUE
31 #define TRUE (BOOL) 1
32 #endif
33 #ifndef FALSE
34 #define FALSE (BOOL) 0
35 #endif
36 
37 #ifdef __TURBOC__
38 #define STDIN  0
39 #define STDOUT 1
40 #define STDERR 2
41 #endif
42 
43 /* to make png2pnm verbose so we can find problems (needs to be before png.h) */
44 #ifndef PNG_DEBUG
45 #define PNG_DEBUG 0
46 #endif
47 
48 
49 #include "png.h"
50 
51 /* Define png_jmpbuf() in case we are using a pre-1.0.6 version of libpng */
52 #ifndef png_jmpbuf
53 #  define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf)
54 #endif
55 
56 #ifndef PNGMINUS_UNUSED
57 /* Unused formal parameter warnings are silenced using the following macro
58  * which is expected to have no bad effects on performance (optimizing
59  * compilers will probably remove it entirely).
60  */
61 #  define PNGMINUS_UNUSED(param) (void)param
62 #endif
63 
64 /* function prototypes */
65 
66 int  main (int argc, char *argv[]);
67 void usage ();
68 BOOL png2pnm (FILE *png_file, FILE *pnm_file, FILE *alpha_file, BOOL raw,
69    BOOL alpha);
70 
71 /*
72  *  main
73  */
74 
main(int argc,char * argv[])75 int main(int argc, char *argv[])
76 {
77   FILE *fp_rd = stdin;
78   FILE *fp_wr = stdout;
79   FILE *fp_al = NULL;
80   BOOL raw = TRUE;
81   BOOL alpha = FALSE;
82   int argi;
83 
84   for (argi = 1; argi < argc; argi++)
85   {
86     if (argv[argi][0] == '-')
87     {
88       switch (argv[argi][1])
89       {
90         case 'n':
91           raw = FALSE;
92           break;
93         case 'r':
94           raw = TRUE;
95           break;
96         case 'a':
97           alpha = TRUE;
98           argi++;
99           if ((fp_al = fopen (argv[argi], "wb")) == NULL)
100           {
101             fprintf (stderr, "PNM2PNG\n");
102             fprintf (stderr, "Error:  can not create alpha-channel file %s\n",
103                argv[argi]);
104             exit (1);
105           }
106           break;
107         case 'h':
108         case '?':
109           usage();
110           exit(0);
111           break;
112         default:
113           fprintf (stderr, "PNG2PNM\n");
114           fprintf (stderr, "Error:  unknown option %s\n", argv[argi]);
115           usage();
116           exit(1);
117           break;
118       } /* end switch */
119     }
120     else if (fp_rd == stdin)
121     {
122       if ((fp_rd = fopen (argv[argi], "rb")) == NULL)
123       {
124              fprintf (stderr, "PNG2PNM\n");
125             fprintf (stderr, "Error:  file %s does not exist\n", argv[argi]);
126             exit (1);
127       }
128     }
129     else if (fp_wr == stdout)
130     {
131       if ((fp_wr = fopen (argv[argi], "wb")) == NULL)
132       {
133         fprintf (stderr, "PNG2PNM\n");
134         fprintf (stderr, "Error:  can not create file %s\n", argv[argi]);
135         exit (1);
136       }
137     }
138     else
139     {
140       fprintf (stderr, "PNG2PNM\n");
141       fprintf (stderr, "Error:  too many parameters\n");
142       usage();
143       exit(1);
144     }
145   } /* end for */
146 
147 #ifdef __TURBOC__
148   /* set stdin/stdout if required to binary */
149   if (fp_rd == stdin)
150   {
151     setmode (STDIN, O_BINARY);
152   }
153   if ((raw) && (fp_wr == stdout))
154   {
155     setmode (STDOUT, O_BINARY);
156   }
157 #endif
158 
159   /* call the conversion program itself */
160   if (png2pnm (fp_rd, fp_wr, fp_al, raw, alpha) == FALSE)
161   {
162     fprintf (stderr, "PNG2PNM\n");
163     fprintf (stderr, "Error:  unsuccessful conversion of PNG-image\n");
164     exit(1);
165   }
166 
167   /* close input file */
168   fclose (fp_rd);
169   /* close output file */
170   fclose (fp_wr);
171   /* close alpha file */
172   if (alpha)
173     fclose (fp_al);
174 
175   return 0;
176 }
177 
178 /*
179  *  usage
180  */
181 
usage()182 void usage()
183 {
184   fprintf (stderr, "PNG2PNM\n");
185   fprintf (stderr, "   by Willem van Schaik, 1999\n");
186 #ifdef __TURBOC__
187   fprintf (stderr, "   for Turbo-C and Borland-C compilers\n");
188 #else
189   fprintf (stderr, "   for Linux (and Unix) compilers\n");
190 #endif
191   fprintf (stderr, "Usage:  png2pnm [options] <file>.png [<file>.pnm]\n");
192   fprintf (stderr, "   or:  ... | png2pnm [options]\n");
193   fprintf (stderr, "Options:\n");
194   fprintf (stderr,
195      "   -r[aw]   write pnm-file in binary format (P4/P5/P6) (default)\n");
196   fprintf (stderr, "   -n[oraw] write pnm-file in ascii format (P1/P2/P3)\n");
197   fprintf (stderr,
198      "   -a[lpha] <file>.pgm write PNG alpha channel as pgm-file\n");
199   fprintf (stderr, "   -h | -?  print this help-information\n");
200 }
201 
202 /*
203  *  png2pnm
204  */
205 
png2pnm(FILE * png_file,FILE * pnm_file,FILE * alpha_file,volatile BOOL raw,BOOL alpha)206 BOOL png2pnm (FILE *png_file, FILE *pnm_file, FILE *alpha_file,
207     volatile BOOL raw, BOOL alpha)
208 {
209   png_struct    *png_ptr = NULL;
210   png_info        *info_ptr = NULL;
211   png_byte      buf[8];
212   png_byte      *png_pixels = NULL;
213   png_byte      **row_pointers = NULL;
214   png_byte      *pix_ptr = NULL;
215   png_uint_32   row_bytes;
216 
217   png_uint_32   width;
218   png_uint_32   height;
219   int           bit_depth;
220   int           channels;
221   int           color_type;
222   int           alpha_present;
223   int           row, col;
224   int           ret;
225   int           i;
226   long          dep_16;
227 
228   /* read and check signature in PNG file */
229   ret = fread (buf, 1, 8, png_file);
230   if (ret != 8)
231     return FALSE;
232 
233   ret = png_sig_cmp (buf, 0, 8);
234   if (ret)
235     return FALSE;
236 
237   /* create png and info structures */
238 
239   png_ptr = png_create_read_struct (png_get_libpng_ver(NULL),
240     NULL, NULL, NULL);
241   if (!png_ptr)
242     return FALSE;   /* out of memory */
243 
244   info_ptr = png_create_info_struct (png_ptr);
245   if (!info_ptr)
246   {
247     png_destroy_read_struct (&png_ptr, NULL, NULL);
248     return FALSE;   /* out of memory */
249   }
250 
251   if (setjmp (png_jmpbuf(png_ptr)))
252   {
253     png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
254     return FALSE;
255   }
256 
257   /* set up the input control for C streams */
258   png_init_io (png_ptr, png_file);
259   png_set_sig_bytes (png_ptr, 8);  /* we already read the 8 signature bytes */
260 
261   /* read the file information */
262   png_read_info (png_ptr, info_ptr);
263 
264   /* get size and bit-depth of the PNG-image */
265   png_get_IHDR (png_ptr, info_ptr,
266     &width, &height, &bit_depth, &color_type,
267     NULL, NULL, NULL);
268 
269   /* set-up the transformations */
270 
271   /* transform paletted images into full-color rgb */
272   if (color_type == PNG_COLOR_TYPE_PALETTE)
273     png_set_expand (png_ptr);
274   /* expand images to bit-depth 8 (only applicable for grayscale images) */
275   if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
276     png_set_expand (png_ptr);
277   /* transform transparency maps into full alpha-channel */
278   if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS))
279     png_set_expand (png_ptr);
280 
281 #ifdef NJET
282   /* downgrade 16-bit images to 8-bit */
283   if (bit_depth == 16)
284     png_set_strip_16 (png_ptr);
285   /* transform grayscale images into full-color */
286   if (color_type == PNG_COLOR_TYPE_GRAY ||
287     color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
288     png_set_gray_to_rgb (png_ptr);
289   /* only if file has a file gamma, we do a correction */
290   if (png_get_gAMA (png_ptr, info_ptr, &file_gamma))
291     png_set_gamma (png_ptr, (double) 2.2, file_gamma);
292 #endif
293 
294   /* all transformations have been registered; now update info_ptr data,
295    * get rowbytes and channels, and allocate image memory */
296 
297   png_read_update_info (png_ptr, info_ptr);
298 
299   /* get the new color-type and bit-depth (after expansion/stripping) */
300   png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
301     NULL, NULL, NULL);
302 
303   /* check for 16-bit files */
304   if (bit_depth == 16)
305   {
306     raw = FALSE;
307 #ifdef __TURBOC__
308     pnm_file->flags &= ~((unsigned) _F_BIN);
309 #endif
310   }
311 
312   /* calculate new number of channels and store alpha-presence */
313   if (color_type == PNG_COLOR_TYPE_GRAY)
314     channels = 1;
315   else if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
316     channels = 2;
317   else if (color_type == PNG_COLOR_TYPE_RGB)
318     channels = 3;
319   else if (color_type == PNG_COLOR_TYPE_RGB_ALPHA)
320     channels = 4;
321   else
322     channels = 0; /* should never happen */
323   alpha_present = (channels - 1) % 2;
324 
325   /* check if alpha is expected to be present in file */
326   if (alpha && !alpha_present)
327   {
328     fprintf (stderr, "PNG2PNM\n");
329     fprintf (stderr, "Error:  PNG-file doesn't contain alpha channel\n");
330     exit (1);
331   }
332 
333   /* row_bytes is the width x number of channels x (bit-depth / 8) */
334   row_bytes = png_get_rowbytes (png_ptr, info_ptr);
335 
336   if ((row_bytes == 0 || (size_t)height > ((size_t)(-1))/(size_t)row_bytes))
337   {
338     /* too big */
339     png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
340     return FALSE;
341   }
342   if ((png_pixels = (png_byte *)
343      malloc ((size_t)row_bytes * (size_t)height * sizeof (png_byte))) == NULL)
344   {
345     png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
346     return FALSE;
347   }
348 
349   if ((row_pointers = (png_byte **)
350      malloc ((size_t)height * sizeof (png_bytep))) == NULL)
351   {
352     png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
353     free (png_pixels);
354     png_pixels = NULL;
355     return FALSE;
356   }
357 
358   /* set the individual row_pointers to point at the correct offsets */
359   for (i = 0; i < ((int) height); i++)
360     row_pointers[i] = png_pixels + i * row_bytes;
361 
362   /* now we can go ahead and just read the whole image */
363   png_read_image (png_ptr, row_pointers);
364 
365   /* read rest of file, and get additional chunks in info_ptr - REQUIRED */
366   png_read_end (png_ptr, info_ptr);
367 
368   /* clean up after the read, and free any memory allocated - REQUIRED */
369   png_destroy_read_struct (&png_ptr, &info_ptr, (png_infopp) NULL);
370 
371   /* write header of PNM file */
372 
373   if ((color_type == PNG_COLOR_TYPE_GRAY) ||
374       (color_type == PNG_COLOR_TYPE_GRAY_ALPHA))
375   {
376     fprintf (pnm_file, "%s\n", (raw) ? "P5" : "P2");
377     fprintf (pnm_file, "%d %d\n", (int) width, (int) height);
378     fprintf (pnm_file, "%ld\n", ((1L << (int) bit_depth) - 1L));
379   }
380   else if ((color_type == PNG_COLOR_TYPE_RGB) ||
381            (color_type == PNG_COLOR_TYPE_RGB_ALPHA))
382   {
383     fprintf (pnm_file, "%s\n", (raw) ? "P6" : "P3");
384     fprintf (pnm_file, "%d %d\n", (int) width, (int) height);
385     fprintf (pnm_file, "%ld\n", ((1L << (int) bit_depth) - 1L));
386   }
387 
388   /* write header of PGM file with alpha channel */
389 
390   if ((alpha) &&
391       ((color_type == PNG_COLOR_TYPE_GRAY_ALPHA) ||
392        (color_type == PNG_COLOR_TYPE_RGB_ALPHA)))
393   {
394     fprintf (alpha_file, "%s\n", (raw) ? "P5" : "P2");
395     fprintf (alpha_file, "%d %d\n", (int) width, (int) height);
396     fprintf (alpha_file, "%ld\n", ((1L << (int) bit_depth) - 1L));
397   }
398 
399   /* write data to PNM file */
400   pix_ptr = png_pixels;
401 
402   for (row = 0; row < (int) height; row++)
403   {
404     for (col = 0; col < (int) width; col++)
405     {
406       for (i = 0; i < (channels - alpha_present); i++)
407       {
408         if (raw)
409           fputc ((int) *pix_ptr++ , pnm_file);
410         else
411           if (bit_depth == 16){
412             dep_16 = (long) *pix_ptr++;
413             fprintf (pnm_file, "%ld ", (dep_16 << 8) + ((long) *pix_ptr++));
414           }
415           else
416             fprintf (pnm_file, "%ld ", (long) *pix_ptr++);
417       }
418       if (alpha_present)
419       {
420         if (!alpha)
421         {
422           pix_ptr++; /* alpha */
423           if (bit_depth == 16)
424             pix_ptr++;
425         }
426         else /* output alpha-channel as pgm file */
427         {
428           if (raw)
429             fputc ((int) *pix_ptr++ , alpha_file);
430           else
431             if (bit_depth == 16)
432             {
433               dep_16 = (long) *pix_ptr++;
434               fprintf (alpha_file, "%ld ", (dep_16 << 8) + (long) *pix_ptr++);
435             }
436             else
437               fprintf (alpha_file, "%ld ", (long) *pix_ptr++);
438         }
439       } /* if alpha_present */
440 
441       if (!raw)
442         if (col % 4 == 3)
443           fprintf (pnm_file, "\n");
444     } /* end for col */
445 
446     if (!raw)
447       if (col % 4 != 0)
448         fprintf (pnm_file, "\n");
449   } /* end for row */
450 
451   if (row_pointers != (unsigned char**) NULL)
452     free (row_pointers);
453   if (png_pixels != (unsigned char*) NULL)
454     free (png_pixels);
455 
456   PNGMINUS_UNUSED(raw); /* to quiet a Coverity defect */
457   return TRUE;
458 
459 } /* end of source */
460 
461