xref: /aosp_15_r20/external/libpng/contrib/pngminus/png2pnm.c (revision a67afe4df73cf47866eedc69947994b8ff839aba)
1 /*
2  *  png2pnm.c --- conversion from PNG-file to PGM/PPM-file
3  *  copyright (C) 1999-2019 by Willem van Schaik <willem at schaik dot com>
4  *
5  *  This software is released under the MIT license. For conditions of
6  *  distribution and use, see the LICENSE file part of this package.
7  */
8 
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <fcntl.h>
12 
13 #ifndef BOOL
14 #define BOOL unsigned char
15 #endif
16 #ifndef TRUE
17 #define TRUE ((BOOL) 1)
18 #endif
19 #ifndef FALSE
20 #define FALSE ((BOOL) 0)
21 #endif
22 
23 #include "png.h"
24 
25 /* function prototypes */
26 
27 int main (int argc, char *argv[]);
28 void usage ();
29 BOOL png2pnm (FILE *png_file, FILE *pnm_file, FILE *alpha_file,
30               BOOL raw, BOOL alpha);
31 BOOL do_png2pnm (png_struct *png_ptr, png_info *info_ptr,
32                  FILE *pnm_file, FILE *alpha_file,
33                  BOOL raw, BOOL alpha);
34 
35 /*
36  *  main
37  */
38 
main(int argc,char * argv[])39 int main (int argc, char *argv[])
40 {
41   FILE *fp_rd = stdin;
42   FILE *fp_wr = stdout;
43   FILE *fp_al = NULL;
44   const char *fname_wr = NULL;
45   const char *fname_al = NULL;
46   BOOL raw = TRUE;
47   BOOL alpha = FALSE;
48   int argi;
49   int ret;
50 
51   for (argi = 1; argi < argc; argi++)
52   {
53     if (argv[argi][0] == '-')
54     {
55       switch (argv[argi][1])
56       {
57         case 'n':
58           raw = FALSE;
59           break;
60         case 'r':
61           raw = TRUE;
62           break;
63         case 'a':
64           alpha = TRUE;
65           argi++;
66           if ((fp_al = fopen (argv[argi], "wb")) == NULL)
67           {
68             fname_al = argv[argi];
69             fprintf (stderr, "PNM2PNG\n");
70             fprintf (stderr, "Error:  cannot create alpha-channel file %s\n",
71                      argv[argi]);
72             exit (1);
73           }
74           break;
75         case 'h':
76         case '?':
77           usage ();
78           exit (0);
79           break;
80         default:
81           fprintf (stderr, "PNG2PNM\n");
82           fprintf (stderr, "Error:  unknown option %s\n", argv[argi]);
83           usage ();
84           exit (1);
85           break;
86       } /* end switch */
87     }
88     else if (fp_rd == stdin)
89     {
90       if ((fp_rd = fopen (argv[argi], "rb")) == NULL)
91       {
92         fprintf (stderr, "PNG2PNM\n");
93         fprintf (stderr, "Error:  file %s does not exist\n", argv[argi]);
94         exit (1);
95       }
96     }
97     else if (fp_wr == stdout)
98     {
99       fname_wr = argv[argi];
100       if ((fp_wr = fopen (argv[argi], "wb")) == NULL)
101       {
102         fprintf (stderr, "PNG2PNM\n");
103         fprintf (stderr, "Error:  cannot create file %s\n", argv[argi]);
104         exit (1);
105       }
106     }
107     else
108     {
109       fprintf (stderr, "PNG2PNM\n");
110       fprintf (stderr, "Error:  too many parameters\n");
111       usage ();
112       exit (1);
113     }
114   } /* end for */
115 
116 #if defined(O_BINARY) && (O_BINARY != 0)
117   /* set stdin/stdout if required to binary */
118   if (fp_rd == stdin)
119     setmode (fileno (stdin), O_BINARY);
120   if ((raw) && (fp_wr == stdout))
121     setmode (fileno (stdout), O_BINARY);
122 #endif
123 
124   /* call the conversion program itself */
125   ret = png2pnm (fp_rd, fp_wr, fp_al, raw, alpha);
126 
127   /* close input file */
128   fclose (fp_rd);
129   /* close output file */
130   fclose (fp_wr);
131   /* close alpha file */
132   if (alpha)
133     fclose (fp_al);
134 
135   if (!ret)
136   {
137     fprintf (stderr, "PNG2PNM\n");
138     fprintf (stderr, "Error:  unsuccessful conversion of PNG-image\n");
139     if (fname_wr)
140       remove (fname_wr); /* no broken output file shall remain behind */
141     if (fname_al)
142       remove (fname_al); /* ditto */
143     exit (1);
144   }
145 
146   return 0;
147 }
148 
149 /*
150  *  usage
151  */
152 
usage()153 void usage ()
154 {
155   fprintf (stderr, "PNG2PNM\n");
156   fprintf (stderr, "   by Willem van Schaik, 1999\n");
157   fprintf (stderr, "Usage:  png2pnm [options] <file>.png [<file>.pnm]\n");
158   fprintf (stderr, "   or:  ... | png2pnm [options]\n");
159   fprintf (stderr, "Options:\n");
160   fprintf (stderr,
161       "   -r[aw]   write pnm-file in binary format (P4/P5/P6) (default)\n");
162   fprintf (stderr, "   -n[oraw] write pnm-file in ascii format (P1/P2/P3)\n");
163   fprintf (stderr,
164       "   -a[lpha] <file>.pgm write PNG alpha channel as pgm-file\n");
165   fprintf (stderr, "   -h | -?  print this help-information\n");
166 }
167 
168 /*
169  *  png2pnm
170  */
171 
png2pnm(FILE * png_file,FILE * pnm_file,FILE * alpha_file,BOOL raw,BOOL alpha)172 BOOL png2pnm (FILE *png_file, FILE *pnm_file, FILE *alpha_file,
173               BOOL raw, BOOL alpha)
174 {
175   png_struct    *png_ptr;
176   png_info      *info_ptr;
177   BOOL          ret;
178 
179   /* initialize the libpng context for reading from png_file */
180 
181   png_ptr = png_create_read_struct (png_get_libpng_ver(NULL),
182                                     NULL, NULL, NULL);
183   if (!png_ptr)
184     return FALSE; /* out of memory */
185 
186   info_ptr = png_create_info_struct (png_ptr);
187   if (!info_ptr)
188   {
189     png_destroy_read_struct (&png_ptr, NULL, NULL);
190     return FALSE; /* out of memory */
191   }
192 
193   if (setjmp (png_jmpbuf (png_ptr)))
194   {
195     png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
196     return FALSE; /* generic libpng error */
197   }
198 
199   png_init_io (png_ptr, png_file);
200 
201   /* do the actual conversion */
202   ret = do_png2pnm (png_ptr, info_ptr, pnm_file, alpha_file, raw, alpha);
203 
204   /* clean up the libpng structures and their internally-managed data */
205   png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
206 
207   return ret;
208 }
209 
210 /*
211  *  do_png2pnm - does the conversion in a fully-initialized libpng context
212  */
213 
do_png2pnm(png_struct * png_ptr,png_info * info_ptr,FILE * pnm_file,FILE * alpha_file,BOOL raw,BOOL alpha)214 BOOL do_png2pnm (png_struct *png_ptr, png_info *info_ptr,
215                  FILE *pnm_file, FILE *alpha_file,
216                  BOOL raw, BOOL alpha)
217 {
218   png_byte      **row_pointers;
219   png_byte      *pix_ptr;
220   png_uint_32   width;
221   png_uint_32   height;
222   int           bit_depth;
223   int           channels;
224   int           color_type;
225   int           alpha_present;
226   png_uint_32   row, col, i;
227   long          dep_16;
228 
229   /* set up the image transformations that are necessary for the PNM format */
230 
231   /* set up (if applicable) the expansion of paletted images to full-color rgb,
232    * and the expansion of transparency maps to full alpha-channel */
233   png_set_expand (png_ptr);
234 
235   /* set up (if applicable) the expansion of grayscale images to bit-depth 8 */
236   png_set_expand_gray_1_2_4_to_8 (png_ptr);
237 
238 #ifdef NJET
239   /* downgrade 16-bit images to 8-bit */
240   if (bit_depth == 16)
241     png_set_strip_16 (png_ptr);
242   /* transform grayscale images into full-color */
243   if (color_type == PNG_COLOR_TYPE_GRAY ||
244       color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
245     png_set_gray_to_rgb (png_ptr);
246   /* if the PNG image has a gAMA chunk then gamma-correct the output image */
247   {
248     double file_gamma;
249     if (png_get_gAMA (png_ptr, info_ptr, &file_gamma))
250       png_set_gamma (png_ptr, (double) 2.2, file_gamma);
251   }
252 #endif
253 
254   /* read the image file, with all of the above image transforms applied */
255   png_read_png (png_ptr, info_ptr, 0, NULL);
256 
257   /* get the image size, bit-depth and color-type */
258   png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
259                 NULL, NULL, NULL);
260 
261   /* calculate the number of channels and store alpha-presence */
262   if (color_type == PNG_COLOR_TYPE_GRAY)
263     channels = 1;
264   else if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
265     channels = 2;
266   else if (color_type == PNG_COLOR_TYPE_RGB)
267     channels = 3;
268   else if (color_type == PNG_COLOR_TYPE_RGB_ALPHA)
269     channels = 4;
270   else
271     channels = 0; /* should never happen */
272   alpha_present = (channels - 1) % 2;
273 
274   /* check if alpha is expected to be present in file */
275   if (alpha && !alpha_present)
276   {
277     fprintf (stderr, "PNG2PNM\n");
278     fprintf (stderr, "Warning:  no alpha channel in PNG file\n");
279     return FALSE;
280   }
281 
282   /* get address of internally-allocated image data */
283   row_pointers = png_get_rows (png_ptr, info_ptr);
284 
285   /* write header of PNM file */
286 
287   if ((color_type == PNG_COLOR_TYPE_GRAY) ||
288       (color_type == PNG_COLOR_TYPE_GRAY_ALPHA))
289   {
290     fprintf (pnm_file, "%s\n", (raw) ? "P5" : "P2");
291     fprintf (pnm_file, "%d %d\n", (int) width, (int) height);
292     fprintf (pnm_file, "%ld\n", ((1L << (int) bit_depth) - 1L));
293   }
294   else if ((color_type == PNG_COLOR_TYPE_RGB) ||
295            (color_type == PNG_COLOR_TYPE_RGB_ALPHA))
296   {
297     fprintf (pnm_file, "%s\n", (raw) ? "P6" : "P3");
298     fprintf (pnm_file, "%d %d\n", (int) width, (int) height);
299     fprintf (pnm_file, "%ld\n", ((1L << (int) bit_depth) - 1L));
300   }
301 
302   /* write header of PGM file with alpha channel */
303 
304   if ((alpha) &&
305       ((color_type == PNG_COLOR_TYPE_GRAY_ALPHA) ||
306        (color_type == PNG_COLOR_TYPE_RGB_ALPHA)))
307   {
308     fprintf (alpha_file, "%s\n", (raw) ? "P5" : "P2");
309     fprintf (alpha_file, "%d %d\n", (int) width, (int) height);
310     fprintf (alpha_file, "%ld\n", ((1L << (int) bit_depth) - 1L));
311   }
312 
313   /* write data to PNM file */
314 
315   for (row = 0; row < height; row++)
316   {
317     pix_ptr = row_pointers[row];
318     for (col = 0; col < width; col++)
319     {
320       for (i = 0; i < (png_uint_32) (channels - alpha_present); i++)
321       {
322         if (raw)
323         {
324           fputc ((int) *pix_ptr++, pnm_file);
325           if (bit_depth == 16)
326             fputc ((int) *pix_ptr++, pnm_file);
327         }
328         else
329         {
330           if (bit_depth == 16)
331           {
332             dep_16 = ((long) *pix_ptr++) << 8;
333             dep_16 += ((long) *pix_ptr++);
334             fprintf (pnm_file, "%ld ", dep_16);
335           }
336           else
337           {
338             fprintf (pnm_file, "%ld ", (long) *pix_ptr++);
339           }
340         }
341       }
342       if (alpha_present)
343       {
344         if (!alpha)
345         {
346           /* skip the alpha-channel */
347           pix_ptr++;
348           if (bit_depth == 16)
349             pix_ptr++;
350         }
351         else
352         {
353           /* output the alpha-channel as pgm file */
354           if (raw)
355           {
356             fputc ((int) *pix_ptr++, alpha_file);
357             if (bit_depth == 16)
358               fputc ((int) *pix_ptr++, alpha_file);
359           }
360           else
361           {
362             if (bit_depth == 16)
363             {
364               dep_16 = ((long) *pix_ptr++) << 8;
365               dep_16 += ((long) *pix_ptr++);
366               fprintf (alpha_file, "%ld ", dep_16);
367             }
368             else
369             {
370               fprintf (alpha_file, "%ld ", (long) *pix_ptr++);
371             }
372           }
373         }
374       } /* end if alpha_present */
375 
376       if (!raw)
377         if (col % 4 == 3)
378           fprintf (pnm_file, "\n");
379     } /* end for col */
380 
381     if (!raw)
382       if (col % 4 != 0)
383         fprintf (pnm_file, "\n");
384   } /* end for row */
385 
386   return TRUE;
387 } /* end of source */
388