xref: /aosp_15_r20/external/libpng/contrib/pngminus/pnm2png.c (revision a67afe4df73cf47866eedc69947994b8ff839aba)
1*a67afe4dSAndroid Build Coastguard Worker /*
2*a67afe4dSAndroid Build Coastguard Worker  *  pnm2png.c --- conversion from PBM/PGM/PPM-file to PNG-file
3*a67afe4dSAndroid Build Coastguard Worker  *  copyright (C) 1999-2019 by Willem van Schaik <willem at schaik dot com>
4*a67afe4dSAndroid Build Coastguard Worker  *
5*a67afe4dSAndroid Build Coastguard Worker  *  This software is released under the MIT license. For conditions of
6*a67afe4dSAndroid Build Coastguard Worker  *  distribution and use, see the LICENSE file part of this package.
7*a67afe4dSAndroid Build Coastguard Worker  */
8*a67afe4dSAndroid Build Coastguard Worker 
9*a67afe4dSAndroid Build Coastguard Worker #include <limits.h>
10*a67afe4dSAndroid Build Coastguard Worker #include <stdio.h>
11*a67afe4dSAndroid Build Coastguard Worker #include <stdlib.h>
12*a67afe4dSAndroid Build Coastguard Worker #include <fcntl.h>
13*a67afe4dSAndroid Build Coastguard Worker 
14*a67afe4dSAndroid Build Coastguard Worker #ifndef BOOL
15*a67afe4dSAndroid Build Coastguard Worker #define BOOL unsigned char
16*a67afe4dSAndroid Build Coastguard Worker #endif
17*a67afe4dSAndroid Build Coastguard Worker #ifndef TRUE
18*a67afe4dSAndroid Build Coastguard Worker #define TRUE ((BOOL) 1)
19*a67afe4dSAndroid Build Coastguard Worker #endif
20*a67afe4dSAndroid Build Coastguard Worker #ifndef FALSE
21*a67afe4dSAndroid Build Coastguard Worker #define FALSE ((BOOL) 0)
22*a67afe4dSAndroid Build Coastguard Worker #endif
23*a67afe4dSAndroid Build Coastguard Worker 
24*a67afe4dSAndroid Build Coastguard Worker #include "png.h"
25*a67afe4dSAndroid Build Coastguard Worker 
26*a67afe4dSAndroid Build Coastguard Worker /* function prototypes */
27*a67afe4dSAndroid Build Coastguard Worker 
28*a67afe4dSAndroid Build Coastguard Worker int main (int argc, char *argv[]);
29*a67afe4dSAndroid Build Coastguard Worker void usage ();
30*a67afe4dSAndroid Build Coastguard Worker BOOL pnm2png (FILE *pnm_file, FILE *png_file, FILE *alpha_file,
31*a67afe4dSAndroid Build Coastguard Worker               BOOL interlace, BOOL alpha);
32*a67afe4dSAndroid Build Coastguard Worker BOOL do_pnm2png (png_struct *png_ptr, png_info *info_ptr,
33*a67afe4dSAndroid Build Coastguard Worker                  FILE *pnm_file, FILE *alpha_file,
34*a67afe4dSAndroid Build Coastguard Worker                  BOOL interlace, BOOL alpha);
35*a67afe4dSAndroid Build Coastguard Worker int fscan_pnm_magic (FILE *pnm_file, char *magic_buf, size_t magic_buf_size);
36*a67afe4dSAndroid Build Coastguard Worker int fscan_pnm_token (FILE *pnm_file, char *token_buf, size_t token_buf_size);
37*a67afe4dSAndroid Build Coastguard Worker int fscan_pnm_uint_32 (FILE *pnm_file, png_uint_32 *num_ptr);
38*a67afe4dSAndroid Build Coastguard Worker png_uint_32 get_pnm_data (FILE *pnm_file, int depth);
39*a67afe4dSAndroid Build Coastguard Worker png_uint_32 get_pnm_value (FILE *pnm_file, int depth);
40*a67afe4dSAndroid Build Coastguard Worker 
41*a67afe4dSAndroid Build Coastguard Worker /*
42*a67afe4dSAndroid Build Coastguard Worker  *  main
43*a67afe4dSAndroid Build Coastguard Worker  */
44*a67afe4dSAndroid Build Coastguard Worker 
main(int argc,char * argv[])45*a67afe4dSAndroid Build Coastguard Worker int main (int argc, char *argv[])
46*a67afe4dSAndroid Build Coastguard Worker {
47*a67afe4dSAndroid Build Coastguard Worker   FILE *fp_rd = stdin;
48*a67afe4dSAndroid Build Coastguard Worker   FILE *fp_al = NULL;
49*a67afe4dSAndroid Build Coastguard Worker   FILE *fp_wr = stdout;
50*a67afe4dSAndroid Build Coastguard Worker   const char *fname_wr = NULL;
51*a67afe4dSAndroid Build Coastguard Worker   BOOL interlace = FALSE;
52*a67afe4dSAndroid Build Coastguard Worker   BOOL alpha = FALSE;
53*a67afe4dSAndroid Build Coastguard Worker   int argi;
54*a67afe4dSAndroid Build Coastguard Worker   int ret;
55*a67afe4dSAndroid Build Coastguard Worker 
56*a67afe4dSAndroid Build Coastguard Worker   for (argi = 1; argi < argc; argi++)
57*a67afe4dSAndroid Build Coastguard Worker   {
58*a67afe4dSAndroid Build Coastguard Worker     if (argv[argi][0] == '-')
59*a67afe4dSAndroid Build Coastguard Worker     {
60*a67afe4dSAndroid Build Coastguard Worker       switch (argv[argi][1])
61*a67afe4dSAndroid Build Coastguard Worker       {
62*a67afe4dSAndroid Build Coastguard Worker         case 'i':
63*a67afe4dSAndroid Build Coastguard Worker           interlace = TRUE;
64*a67afe4dSAndroid Build Coastguard Worker           break;
65*a67afe4dSAndroid Build Coastguard Worker         case 'a':
66*a67afe4dSAndroid Build Coastguard Worker           alpha = TRUE;
67*a67afe4dSAndroid Build Coastguard Worker           argi++;
68*a67afe4dSAndroid Build Coastguard Worker           if ((fp_al = fopen (argv[argi], "rb")) == NULL)
69*a67afe4dSAndroid Build Coastguard Worker           {
70*a67afe4dSAndroid Build Coastguard Worker             fprintf (stderr, "PNM2PNG\n");
71*a67afe4dSAndroid Build Coastguard Worker             fprintf (stderr, "Error:  alpha-channel file %s does not exist\n",
72*a67afe4dSAndroid Build Coastguard Worker                      argv[argi]);
73*a67afe4dSAndroid Build Coastguard Worker             exit (1);
74*a67afe4dSAndroid Build Coastguard Worker           }
75*a67afe4dSAndroid Build Coastguard Worker           break;
76*a67afe4dSAndroid Build Coastguard Worker         case 'h':
77*a67afe4dSAndroid Build Coastguard Worker         case '?':
78*a67afe4dSAndroid Build Coastguard Worker           usage ();
79*a67afe4dSAndroid Build Coastguard Worker           exit (0);
80*a67afe4dSAndroid Build Coastguard Worker           break;
81*a67afe4dSAndroid Build Coastguard Worker         default:
82*a67afe4dSAndroid Build Coastguard Worker           fprintf (stderr, "PNM2PNG\n");
83*a67afe4dSAndroid Build Coastguard Worker           fprintf (stderr, "Error:  unknown option %s\n", argv[argi]);
84*a67afe4dSAndroid Build Coastguard Worker           usage ();
85*a67afe4dSAndroid Build Coastguard Worker           exit (1);
86*a67afe4dSAndroid Build Coastguard Worker           break;
87*a67afe4dSAndroid Build Coastguard Worker       } /* end switch */
88*a67afe4dSAndroid Build Coastguard Worker     }
89*a67afe4dSAndroid Build Coastguard Worker     else if (fp_rd == stdin)
90*a67afe4dSAndroid Build Coastguard Worker     {
91*a67afe4dSAndroid Build Coastguard Worker       if ((fp_rd = fopen (argv[argi], "rb")) == NULL)
92*a67afe4dSAndroid Build Coastguard Worker       {
93*a67afe4dSAndroid Build Coastguard Worker         fprintf (stderr, "PNM2PNG\n");
94*a67afe4dSAndroid Build Coastguard Worker         fprintf (stderr, "Error:  file %s does not exist\n", argv[argi]);
95*a67afe4dSAndroid Build Coastguard Worker         exit (1);
96*a67afe4dSAndroid Build Coastguard Worker       }
97*a67afe4dSAndroid Build Coastguard Worker     }
98*a67afe4dSAndroid Build Coastguard Worker     else if (fp_wr == stdout)
99*a67afe4dSAndroid Build Coastguard Worker     {
100*a67afe4dSAndroid Build Coastguard Worker       fname_wr = argv[argi];
101*a67afe4dSAndroid Build Coastguard Worker       if ((fp_wr = fopen (argv[argi], "wb")) == NULL)
102*a67afe4dSAndroid Build Coastguard Worker       {
103*a67afe4dSAndroid Build Coastguard Worker         fprintf (stderr, "PNM2PNG\n");
104*a67afe4dSAndroid Build Coastguard Worker         fprintf (stderr, "Error:  cannot create PNG-file %s\n", argv[argi]);
105*a67afe4dSAndroid Build Coastguard Worker         exit (1);
106*a67afe4dSAndroid Build Coastguard Worker       }
107*a67afe4dSAndroid Build Coastguard Worker     }
108*a67afe4dSAndroid Build Coastguard Worker     else
109*a67afe4dSAndroid Build Coastguard Worker     {
110*a67afe4dSAndroid Build Coastguard Worker       fprintf (stderr, "PNM2PNG\n");
111*a67afe4dSAndroid Build Coastguard Worker       fprintf (stderr, "Error:  too many parameters\n");
112*a67afe4dSAndroid Build Coastguard Worker       usage ();
113*a67afe4dSAndroid Build Coastguard Worker       exit (1);
114*a67afe4dSAndroid Build Coastguard Worker     }
115*a67afe4dSAndroid Build Coastguard Worker   } /* end for */
116*a67afe4dSAndroid Build Coastguard Worker 
117*a67afe4dSAndroid Build Coastguard Worker #if defined(O_BINARY) && (O_BINARY != 0)
118*a67afe4dSAndroid Build Coastguard Worker   /* set stdin/stdout to binary,
119*a67afe4dSAndroid Build Coastguard Worker    * we're reading the PNM always! in binary format
120*a67afe4dSAndroid Build Coastguard Worker    */
121*a67afe4dSAndroid Build Coastguard Worker   if (fp_rd == stdin)
122*a67afe4dSAndroid Build Coastguard Worker     setmode (fileno (stdin), O_BINARY);
123*a67afe4dSAndroid Build Coastguard Worker   if (fp_wr == stdout)
124*a67afe4dSAndroid Build Coastguard Worker     setmode (fileno (stdout), O_BINARY);
125*a67afe4dSAndroid Build Coastguard Worker #endif
126*a67afe4dSAndroid Build Coastguard Worker 
127*a67afe4dSAndroid Build Coastguard Worker   /* call the conversion program itself */
128*a67afe4dSAndroid Build Coastguard Worker   ret = pnm2png (fp_rd, fp_wr, fp_al, interlace, alpha);
129*a67afe4dSAndroid Build Coastguard Worker 
130*a67afe4dSAndroid Build Coastguard Worker   /* close input file */
131*a67afe4dSAndroid Build Coastguard Worker   fclose (fp_rd);
132*a67afe4dSAndroid Build Coastguard Worker   /* close output file */
133*a67afe4dSAndroid Build Coastguard Worker   fclose (fp_wr);
134*a67afe4dSAndroid Build Coastguard Worker   /* close alpha file */
135*a67afe4dSAndroid Build Coastguard Worker   if (alpha)
136*a67afe4dSAndroid Build Coastguard Worker     fclose (fp_al);
137*a67afe4dSAndroid Build Coastguard Worker 
138*a67afe4dSAndroid Build Coastguard Worker   if (!ret)
139*a67afe4dSAndroid Build Coastguard Worker   {
140*a67afe4dSAndroid Build Coastguard Worker     fprintf (stderr, "PNM2PNG\n");
141*a67afe4dSAndroid Build Coastguard Worker     fprintf (stderr, "Error:  unsuccessful converting to PNG-image\n");
142*a67afe4dSAndroid Build Coastguard Worker     if (fname_wr)
143*a67afe4dSAndroid Build Coastguard Worker       remove (fname_wr); /* no broken output file shall remain behind */
144*a67afe4dSAndroid Build Coastguard Worker     exit (1);
145*a67afe4dSAndroid Build Coastguard Worker   }
146*a67afe4dSAndroid Build Coastguard Worker 
147*a67afe4dSAndroid Build Coastguard Worker   return 0;
148*a67afe4dSAndroid Build Coastguard Worker }
149*a67afe4dSAndroid Build Coastguard Worker 
150*a67afe4dSAndroid Build Coastguard Worker /*
151*a67afe4dSAndroid Build Coastguard Worker  *  usage
152*a67afe4dSAndroid Build Coastguard Worker  */
153*a67afe4dSAndroid Build Coastguard Worker 
usage()154*a67afe4dSAndroid Build Coastguard Worker void usage ()
155*a67afe4dSAndroid Build Coastguard Worker {
156*a67afe4dSAndroid Build Coastguard Worker   fprintf (stderr, "PNM2PNG\n");
157*a67afe4dSAndroid Build Coastguard Worker   fprintf (stderr, "   by Willem van Schaik, 1999\n");
158*a67afe4dSAndroid Build Coastguard Worker   fprintf (stderr, "Usage:  pnm2png [options] <file>.<pnm> [<file>.png]\n");
159*a67afe4dSAndroid Build Coastguard Worker   fprintf (stderr, "   or:  ... | pnm2png [options]\n");
160*a67afe4dSAndroid Build Coastguard Worker   fprintf (stderr, "Options:\n");
161*a67afe4dSAndroid Build Coastguard Worker   fprintf (stderr, "   -i[nterlace]   write png-file with interlacing on\n");
162*a67afe4dSAndroid Build Coastguard Worker   fprintf (stderr,
163*a67afe4dSAndroid Build Coastguard Worker       "   -a[lpha] <file>.pgm read PNG alpha channel as pgm-file\n");
164*a67afe4dSAndroid Build Coastguard Worker   fprintf (stderr, "   -h | -?  print this help-information\n");
165*a67afe4dSAndroid Build Coastguard Worker }
166*a67afe4dSAndroid Build Coastguard Worker 
167*a67afe4dSAndroid Build Coastguard Worker /*
168*a67afe4dSAndroid Build Coastguard Worker  *  pnm2png
169*a67afe4dSAndroid Build Coastguard Worker  */
170*a67afe4dSAndroid Build Coastguard Worker 
pnm2png(FILE * pnm_file,FILE * png_file,FILE * alpha_file,BOOL interlace,BOOL alpha)171*a67afe4dSAndroid Build Coastguard Worker BOOL pnm2png (FILE *pnm_file, FILE *png_file, FILE *alpha_file,
172*a67afe4dSAndroid Build Coastguard Worker               BOOL interlace, BOOL alpha)
173*a67afe4dSAndroid Build Coastguard Worker {
174*a67afe4dSAndroid Build Coastguard Worker   png_struct    *png_ptr;
175*a67afe4dSAndroid Build Coastguard Worker   png_info      *info_ptr;
176*a67afe4dSAndroid Build Coastguard Worker   BOOL          ret;
177*a67afe4dSAndroid Build Coastguard Worker 
178*a67afe4dSAndroid Build Coastguard Worker   /* initialize the libpng context for writing to png_file */
179*a67afe4dSAndroid Build Coastguard Worker 
180*a67afe4dSAndroid Build Coastguard Worker   png_ptr = png_create_write_struct (png_get_libpng_ver(NULL),
181*a67afe4dSAndroid Build Coastguard Worker                                      NULL, NULL, NULL);
182*a67afe4dSAndroid Build Coastguard Worker   if (!png_ptr)
183*a67afe4dSAndroid Build Coastguard Worker     return FALSE; /* out of memory */
184*a67afe4dSAndroid Build Coastguard Worker 
185*a67afe4dSAndroid Build Coastguard Worker   info_ptr = png_create_info_struct (png_ptr);
186*a67afe4dSAndroid Build Coastguard Worker   if (!info_ptr)
187*a67afe4dSAndroid Build Coastguard Worker   {
188*a67afe4dSAndroid Build Coastguard Worker     png_destroy_write_struct (&png_ptr, NULL);
189*a67afe4dSAndroid Build Coastguard Worker     return FALSE; /* out of memory */
190*a67afe4dSAndroid Build Coastguard Worker   }
191*a67afe4dSAndroid Build Coastguard Worker 
192*a67afe4dSAndroid Build Coastguard Worker   if (setjmp (png_jmpbuf (png_ptr)))
193*a67afe4dSAndroid Build Coastguard Worker   {
194*a67afe4dSAndroid Build Coastguard Worker     png_destroy_write_struct (&png_ptr, &info_ptr);
195*a67afe4dSAndroid Build Coastguard Worker     return FALSE; /* generic libpng error */
196*a67afe4dSAndroid Build Coastguard Worker   }
197*a67afe4dSAndroid Build Coastguard Worker 
198*a67afe4dSAndroid Build Coastguard Worker   png_init_io (png_ptr, png_file);
199*a67afe4dSAndroid Build Coastguard Worker 
200*a67afe4dSAndroid Build Coastguard Worker   /* do the actual conversion */
201*a67afe4dSAndroid Build Coastguard Worker   ret = do_pnm2png (png_ptr, info_ptr, pnm_file, alpha_file, interlace, alpha);
202*a67afe4dSAndroid Build Coastguard Worker 
203*a67afe4dSAndroid Build Coastguard Worker   /* clean up the libpng structures and their internally-managed data */
204*a67afe4dSAndroid Build Coastguard Worker   png_destroy_write_struct (&png_ptr, &info_ptr);
205*a67afe4dSAndroid Build Coastguard Worker 
206*a67afe4dSAndroid Build Coastguard Worker   return ret;
207*a67afe4dSAndroid Build Coastguard Worker }
208*a67afe4dSAndroid Build Coastguard Worker 
209*a67afe4dSAndroid Build Coastguard Worker /*
210*a67afe4dSAndroid Build Coastguard Worker  *  do_pnm2png - does the conversion in a fully-initialized libpng context
211*a67afe4dSAndroid Build Coastguard Worker  */
212*a67afe4dSAndroid Build Coastguard Worker 
do_pnm2png(png_struct * png_ptr,png_info * info_ptr,FILE * pnm_file,FILE * alpha_file,BOOL interlace,BOOL alpha)213*a67afe4dSAndroid Build Coastguard Worker BOOL do_pnm2png (png_struct *png_ptr, png_info *info_ptr,
214*a67afe4dSAndroid Build Coastguard Worker                  FILE *pnm_file, FILE *alpha_file,
215*a67afe4dSAndroid Build Coastguard Worker                  BOOL interlace, BOOL alpha)
216*a67afe4dSAndroid Build Coastguard Worker {
217*a67afe4dSAndroid Build Coastguard Worker   png_byte      **row_pointers;
218*a67afe4dSAndroid Build Coastguard Worker   png_byte      *pix_ptr;
219*a67afe4dSAndroid Build Coastguard Worker   int           bit_depth;
220*a67afe4dSAndroid Build Coastguard Worker   int           color_type;
221*a67afe4dSAndroid Build Coastguard Worker   int           channels;
222*a67afe4dSAndroid Build Coastguard Worker   char          magic_token[4];
223*a67afe4dSAndroid Build Coastguard Worker   BOOL          raw;
224*a67afe4dSAndroid Build Coastguard Worker   png_uint_32   width, height, maxval;
225*a67afe4dSAndroid Build Coastguard Worker   png_uint_32   row_bytes;
226*a67afe4dSAndroid Build Coastguard Worker   png_uint_32   row, col;
227*a67afe4dSAndroid Build Coastguard Worker   png_uint_32   val16, i;
228*a67afe4dSAndroid Build Coastguard Worker   png_uint_32   alpha_width = 0, alpha_height = 0;
229*a67afe4dSAndroid Build Coastguard Worker   int           alpha_depth = 0, alpha_present = 0;
230*a67afe4dSAndroid Build Coastguard Worker   BOOL          alpha_raw = FALSE;
231*a67afe4dSAndroid Build Coastguard Worker   BOOL          packed_bitmap = FALSE;
232*a67afe4dSAndroid Build Coastguard Worker 
233*a67afe4dSAndroid Build Coastguard Worker   /* read header of PNM file */
234*a67afe4dSAndroid Build Coastguard Worker 
235*a67afe4dSAndroid Build Coastguard Worker   if (fscan_pnm_magic (pnm_file, magic_token, sizeof (magic_token)) != 1)
236*a67afe4dSAndroid Build Coastguard Worker     return FALSE; /* not a PNM file */
237*a67afe4dSAndroid Build Coastguard Worker 
238*a67afe4dSAndroid Build Coastguard Worker   if ((magic_token[1] == '1') || (magic_token[1] == '4'))
239*a67afe4dSAndroid Build Coastguard Worker   {
240*a67afe4dSAndroid Build Coastguard Worker     if ((fscan_pnm_uint_32 (pnm_file, &width) != 1) ||
241*a67afe4dSAndroid Build Coastguard Worker         (fscan_pnm_uint_32 (pnm_file, &height) != 1))
242*a67afe4dSAndroid Build Coastguard Worker       return FALSE; /* bad PBM file header */
243*a67afe4dSAndroid Build Coastguard Worker   } else if ((magic_token[1] == '2') || (magic_token[1] == '5') ||
244*a67afe4dSAndroid Build Coastguard Worker              (magic_token[1] == '3') || (magic_token[1] == '6'))
245*a67afe4dSAndroid Build Coastguard Worker   {
246*a67afe4dSAndroid Build Coastguard Worker     if ((fscan_pnm_uint_32 (pnm_file, &width) != 1) ||
247*a67afe4dSAndroid Build Coastguard Worker         (fscan_pnm_uint_32 (pnm_file, &height) != 1) ||
248*a67afe4dSAndroid Build Coastguard Worker         (fscan_pnm_uint_32 (pnm_file, &maxval) != 1))
249*a67afe4dSAndroid Build Coastguard Worker       return FALSE; /* bad PGM/PPM file header */
250*a67afe4dSAndroid Build Coastguard Worker   }
251*a67afe4dSAndroid Build Coastguard Worker 
252*a67afe4dSAndroid Build Coastguard Worker   if ((magic_token[1] == '1') || (magic_token[1] == '4'))
253*a67afe4dSAndroid Build Coastguard Worker   {
254*a67afe4dSAndroid Build Coastguard Worker     raw = (magic_token[1] == '4');
255*a67afe4dSAndroid Build Coastguard Worker     bit_depth = 1;
256*a67afe4dSAndroid Build Coastguard Worker     color_type = PNG_COLOR_TYPE_GRAY;
257*a67afe4dSAndroid Build Coastguard Worker     packed_bitmap = TRUE;
258*a67afe4dSAndroid Build Coastguard Worker   }
259*a67afe4dSAndroid Build Coastguard Worker   else if ((magic_token[1] == '2') || (magic_token[1] == '5'))
260*a67afe4dSAndroid Build Coastguard Worker   {
261*a67afe4dSAndroid Build Coastguard Worker     raw = (magic_token[1] == '5');
262*a67afe4dSAndroid Build Coastguard Worker     color_type = PNG_COLOR_TYPE_GRAY;
263*a67afe4dSAndroid Build Coastguard Worker     if (maxval == 0)
264*a67afe4dSAndroid Build Coastguard Worker       return FALSE;
265*a67afe4dSAndroid Build Coastguard Worker     else if (maxval == 1)
266*a67afe4dSAndroid Build Coastguard Worker       bit_depth = 1;
267*a67afe4dSAndroid Build Coastguard Worker     else if (maxval <= 3)
268*a67afe4dSAndroid Build Coastguard Worker       bit_depth = 2;
269*a67afe4dSAndroid Build Coastguard Worker     else if (maxval <= 15)
270*a67afe4dSAndroid Build Coastguard Worker       bit_depth = 4;
271*a67afe4dSAndroid Build Coastguard Worker     else if (maxval <= 255)
272*a67afe4dSAndroid Build Coastguard Worker       bit_depth = 8;
273*a67afe4dSAndroid Build Coastguard Worker     else if (maxval <= 65535U)
274*a67afe4dSAndroid Build Coastguard Worker       bit_depth = 16;
275*a67afe4dSAndroid Build Coastguard Worker     else /* maxval > 65535U */
276*a67afe4dSAndroid Build Coastguard Worker       return FALSE;
277*a67afe4dSAndroid Build Coastguard Worker   }
278*a67afe4dSAndroid Build Coastguard Worker   else if ((magic_token[1] == '3') || (magic_token[1] == '6'))
279*a67afe4dSAndroid Build Coastguard Worker   {
280*a67afe4dSAndroid Build Coastguard Worker     raw = (magic_token[1] == '6');
281*a67afe4dSAndroid Build Coastguard Worker     color_type = PNG_COLOR_TYPE_RGB;
282*a67afe4dSAndroid Build Coastguard Worker     if (maxval == 0)
283*a67afe4dSAndroid Build Coastguard Worker       return FALSE;
284*a67afe4dSAndroid Build Coastguard Worker     else if (maxval == 1)
285*a67afe4dSAndroid Build Coastguard Worker       bit_depth = 1;
286*a67afe4dSAndroid Build Coastguard Worker     else if (maxval <= 3)
287*a67afe4dSAndroid Build Coastguard Worker       bit_depth = 2;
288*a67afe4dSAndroid Build Coastguard Worker     else if (maxval <= 15)
289*a67afe4dSAndroid Build Coastguard Worker       bit_depth = 4;
290*a67afe4dSAndroid Build Coastguard Worker     else if (maxval <= 255)
291*a67afe4dSAndroid Build Coastguard Worker       bit_depth = 8;
292*a67afe4dSAndroid Build Coastguard Worker     else if (maxval <= 65535U)
293*a67afe4dSAndroid Build Coastguard Worker       bit_depth = 16;
294*a67afe4dSAndroid Build Coastguard Worker     else /* maxval > 65535U */
295*a67afe4dSAndroid Build Coastguard Worker       return FALSE;
296*a67afe4dSAndroid Build Coastguard Worker   }
297*a67afe4dSAndroid Build Coastguard Worker   else if (magic_token[1] == '7')
298*a67afe4dSAndroid Build Coastguard Worker   {
299*a67afe4dSAndroid Build Coastguard Worker     fprintf (stderr, "PNM2PNG can't read PAM (P7) files\n");
300*a67afe4dSAndroid Build Coastguard Worker     return FALSE;
301*a67afe4dSAndroid Build Coastguard Worker   }
302*a67afe4dSAndroid Build Coastguard Worker   else
303*a67afe4dSAndroid Build Coastguard Worker   {
304*a67afe4dSAndroid Build Coastguard Worker     return FALSE;
305*a67afe4dSAndroid Build Coastguard Worker   }
306*a67afe4dSAndroid Build Coastguard Worker 
307*a67afe4dSAndroid Build Coastguard Worker   /* read header of PGM file with alpha channel */
308*a67afe4dSAndroid Build Coastguard Worker 
309*a67afe4dSAndroid Build Coastguard Worker   if (alpha)
310*a67afe4dSAndroid Build Coastguard Worker   {
311*a67afe4dSAndroid Build Coastguard Worker     if ((fscan_pnm_magic (alpha_file, magic_token, sizeof (magic_token)) != 1)
312*a67afe4dSAndroid Build Coastguard Worker         || ((magic_token[1] != '2') && (magic_token[1] != '5')))
313*a67afe4dSAndroid Build Coastguard Worker       return FALSE; /* not a PGM file */
314*a67afe4dSAndroid Build Coastguard Worker 
315*a67afe4dSAndroid Build Coastguard Worker     if ((fscan_pnm_uint_32 (alpha_file, &alpha_width) != 1) ||
316*a67afe4dSAndroid Build Coastguard Worker         (fscan_pnm_uint_32 (alpha_file, &alpha_height) != 1) ||
317*a67afe4dSAndroid Build Coastguard Worker         (fscan_pnm_uint_32 (alpha_file, &maxval) != 1))
318*a67afe4dSAndroid Build Coastguard Worker       return FALSE; /* bad PGM file header */
319*a67afe4dSAndroid Build Coastguard Worker 
320*a67afe4dSAndroid Build Coastguard Worker     if ((alpha_width != width) || (alpha_height != height))
321*a67afe4dSAndroid Build Coastguard Worker       return FALSE; /* mismatched PGM dimensions */
322*a67afe4dSAndroid Build Coastguard Worker 
323*a67afe4dSAndroid Build Coastguard Worker     alpha_raw = (magic_token[1] == '5');
324*a67afe4dSAndroid Build Coastguard Worker     color_type |= PNG_COLOR_MASK_ALPHA;
325*a67afe4dSAndroid Build Coastguard Worker     if (maxval == 0)
326*a67afe4dSAndroid Build Coastguard Worker       return FALSE;
327*a67afe4dSAndroid Build Coastguard Worker     else if (maxval == 1)
328*a67afe4dSAndroid Build Coastguard Worker       alpha_depth = 1;
329*a67afe4dSAndroid Build Coastguard Worker     else if (maxval <= 3)
330*a67afe4dSAndroid Build Coastguard Worker       alpha_depth = 2;
331*a67afe4dSAndroid Build Coastguard Worker     else if (maxval <= 15)
332*a67afe4dSAndroid Build Coastguard Worker       alpha_depth = 4;
333*a67afe4dSAndroid Build Coastguard Worker     else if (maxval <= 255)
334*a67afe4dSAndroid Build Coastguard Worker       alpha_depth = 8;
335*a67afe4dSAndroid Build Coastguard Worker     else if (maxval <= 65535U)
336*a67afe4dSAndroid Build Coastguard Worker       alpha_depth = 16;
337*a67afe4dSAndroid Build Coastguard Worker     else /* maxval > 65535U */
338*a67afe4dSAndroid Build Coastguard Worker       return FALSE;
339*a67afe4dSAndroid Build Coastguard Worker     if (alpha_depth != bit_depth)
340*a67afe4dSAndroid Build Coastguard Worker       return FALSE;
341*a67afe4dSAndroid Build Coastguard Worker   } /* end if alpha */
342*a67afe4dSAndroid Build Coastguard Worker 
343*a67afe4dSAndroid Build Coastguard Worker   /* calculate the number of channels and store alpha-presence */
344*a67afe4dSAndroid Build Coastguard Worker   if (color_type == PNG_COLOR_TYPE_GRAY)
345*a67afe4dSAndroid Build Coastguard Worker     channels = 1;
346*a67afe4dSAndroid Build Coastguard Worker   else if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
347*a67afe4dSAndroid Build Coastguard Worker     channels = 2;
348*a67afe4dSAndroid Build Coastguard Worker   else if (color_type == PNG_COLOR_TYPE_RGB)
349*a67afe4dSAndroid Build Coastguard Worker     channels = 3;
350*a67afe4dSAndroid Build Coastguard Worker   else if (color_type == PNG_COLOR_TYPE_RGB_ALPHA)
351*a67afe4dSAndroid Build Coastguard Worker     channels = 4;
352*a67afe4dSAndroid Build Coastguard Worker   else
353*a67afe4dSAndroid Build Coastguard Worker     return FALSE; /* NOTREACHED */
354*a67afe4dSAndroid Build Coastguard Worker 
355*a67afe4dSAndroid Build Coastguard Worker   alpha_present = (channels - 1) % 2;
356*a67afe4dSAndroid Build Coastguard Worker 
357*a67afe4dSAndroid Build Coastguard Worker   if (packed_bitmap)
358*a67afe4dSAndroid Build Coastguard Worker   {
359*a67afe4dSAndroid Build Coastguard Worker     /* row data is as many bytes as can fit width x channels x bit_depth */
360*a67afe4dSAndroid Build Coastguard Worker     row_bytes = (width * channels * bit_depth + 7) / 8;
361*a67afe4dSAndroid Build Coastguard Worker   }
362*a67afe4dSAndroid Build Coastguard Worker   else
363*a67afe4dSAndroid Build Coastguard Worker   {
364*a67afe4dSAndroid Build Coastguard Worker     /* row_bytes is the width x number of channels x (bit-depth / 8) */
365*a67afe4dSAndroid Build Coastguard Worker     row_bytes = width * channels * ((bit_depth <= 8) ? 1 : 2);
366*a67afe4dSAndroid Build Coastguard Worker   }
367*a67afe4dSAndroid Build Coastguard Worker 
368*a67afe4dSAndroid Build Coastguard Worker   if ((row_bytes == 0) ||
369*a67afe4dSAndroid Build Coastguard Worker       ((size_t) height > (size_t) (-1) / (size_t) row_bytes))
370*a67afe4dSAndroid Build Coastguard Worker   {
371*a67afe4dSAndroid Build Coastguard Worker     /* too big */
372*a67afe4dSAndroid Build Coastguard Worker     return FALSE;
373*a67afe4dSAndroid Build Coastguard Worker   }
374*a67afe4dSAndroid Build Coastguard Worker 
375*a67afe4dSAndroid Build Coastguard Worker   /* allocate the rows using the same memory layout as libpng, and transfer
376*a67afe4dSAndroid Build Coastguard Worker    * their ownership to libpng, with the responsibility to clean everything up;
377*a67afe4dSAndroid Build Coastguard Worker    * please note the use of png_calloc instead of png_malloc */
378*a67afe4dSAndroid Build Coastguard Worker   row_pointers = (png_byte **)
379*a67afe4dSAndroid Build Coastguard Worker                  png_calloc (png_ptr, height * sizeof (png_byte *));
380*a67afe4dSAndroid Build Coastguard Worker   png_set_rows (png_ptr, info_ptr, row_pointers);
381*a67afe4dSAndroid Build Coastguard Worker   png_data_freer (png_ptr, info_ptr, PNG_DESTROY_WILL_FREE_DATA, PNG_FREE_ALL);
382*a67afe4dSAndroid Build Coastguard Worker   for (row = 0; row < height; row++)
383*a67afe4dSAndroid Build Coastguard Worker   {
384*a67afe4dSAndroid Build Coastguard Worker     /* the individual rows should only be allocated after all the previous
385*a67afe4dSAndroid Build Coastguard Worker      * steps completed successfully, because libpng must handle correctly
386*a67afe4dSAndroid Build Coastguard Worker      * any image allocation left incomplete after an out-of-memory error */
387*a67afe4dSAndroid Build Coastguard Worker     row_pointers[row] = (png_byte *) png_malloc (png_ptr, row_bytes);
388*a67afe4dSAndroid Build Coastguard Worker   }
389*a67afe4dSAndroid Build Coastguard Worker 
390*a67afe4dSAndroid Build Coastguard Worker   /* read the data from PNM file */
391*a67afe4dSAndroid Build Coastguard Worker 
392*a67afe4dSAndroid Build Coastguard Worker   for (row = 0; row < height; row++)
393*a67afe4dSAndroid Build Coastguard Worker   {
394*a67afe4dSAndroid Build Coastguard Worker     pix_ptr = row_pointers[row];
395*a67afe4dSAndroid Build Coastguard Worker     if (packed_bitmap)
396*a67afe4dSAndroid Build Coastguard Worker     {
397*a67afe4dSAndroid Build Coastguard Worker       for (i = 0; i < row_bytes; i++)
398*a67afe4dSAndroid Build Coastguard Worker       {
399*a67afe4dSAndroid Build Coastguard Worker         /* png supports this format natively so no conversion is needed */
400*a67afe4dSAndroid Build Coastguard Worker         *pix_ptr++ = get_pnm_data (pnm_file, 8);
401*a67afe4dSAndroid Build Coastguard Worker       }
402*a67afe4dSAndroid Build Coastguard Worker     }
403*a67afe4dSAndroid Build Coastguard Worker     else
404*a67afe4dSAndroid Build Coastguard Worker     {
405*a67afe4dSAndroid Build Coastguard Worker       for (col = 0; col < width; col++)
406*a67afe4dSAndroid Build Coastguard Worker       {
407*a67afe4dSAndroid Build Coastguard Worker         for (i = 0; i < (png_uint_32) (channels - alpha_present); i++)
408*a67afe4dSAndroid Build Coastguard Worker         {
409*a67afe4dSAndroid Build Coastguard Worker           if (raw)
410*a67afe4dSAndroid Build Coastguard Worker           {
411*a67afe4dSAndroid Build Coastguard Worker             *pix_ptr++ = get_pnm_data (pnm_file, bit_depth);
412*a67afe4dSAndroid Build Coastguard Worker             if (bit_depth == 16)
413*a67afe4dSAndroid Build Coastguard Worker               *pix_ptr++ = get_pnm_data (pnm_file, bit_depth);
414*a67afe4dSAndroid Build Coastguard Worker           }
415*a67afe4dSAndroid Build Coastguard Worker           else
416*a67afe4dSAndroid Build Coastguard Worker           {
417*a67afe4dSAndroid Build Coastguard Worker             if (bit_depth <= 8)
418*a67afe4dSAndroid Build Coastguard Worker             {
419*a67afe4dSAndroid Build Coastguard Worker               *pix_ptr++ = get_pnm_value (pnm_file, bit_depth);
420*a67afe4dSAndroid Build Coastguard Worker             }
421*a67afe4dSAndroid Build Coastguard Worker             else
422*a67afe4dSAndroid Build Coastguard Worker             {
423*a67afe4dSAndroid Build Coastguard Worker               val16 = get_pnm_value (pnm_file, bit_depth);
424*a67afe4dSAndroid Build Coastguard Worker               *pix_ptr = (png_byte) ((val16 >> 8) & 0xFF);
425*a67afe4dSAndroid Build Coastguard Worker               pix_ptr++;
426*a67afe4dSAndroid Build Coastguard Worker               *pix_ptr = (png_byte) (val16 & 0xFF);
427*a67afe4dSAndroid Build Coastguard Worker               pix_ptr++;
428*a67afe4dSAndroid Build Coastguard Worker             }
429*a67afe4dSAndroid Build Coastguard Worker           }
430*a67afe4dSAndroid Build Coastguard Worker         }
431*a67afe4dSAndroid Build Coastguard Worker 
432*a67afe4dSAndroid Build Coastguard Worker         if (alpha) /* read alpha-channel from pgm file */
433*a67afe4dSAndroid Build Coastguard Worker         {
434*a67afe4dSAndroid Build Coastguard Worker           if (alpha_raw)
435*a67afe4dSAndroid Build Coastguard Worker           {
436*a67afe4dSAndroid Build Coastguard Worker             *pix_ptr++ = get_pnm_data (alpha_file, alpha_depth);
437*a67afe4dSAndroid Build Coastguard Worker             if (alpha_depth == 16)
438*a67afe4dSAndroid Build Coastguard Worker               *pix_ptr++ = get_pnm_data (alpha_file, alpha_depth);
439*a67afe4dSAndroid Build Coastguard Worker           }
440*a67afe4dSAndroid Build Coastguard Worker           else
441*a67afe4dSAndroid Build Coastguard Worker           {
442*a67afe4dSAndroid Build Coastguard Worker             if (alpha_depth <= 8)
443*a67afe4dSAndroid Build Coastguard Worker             {
444*a67afe4dSAndroid Build Coastguard Worker               *pix_ptr++ = get_pnm_value (alpha_file, bit_depth);
445*a67afe4dSAndroid Build Coastguard Worker             }
446*a67afe4dSAndroid Build Coastguard Worker             else
447*a67afe4dSAndroid Build Coastguard Worker             {
448*a67afe4dSAndroid Build Coastguard Worker               val16 = get_pnm_value (alpha_file, bit_depth);
449*a67afe4dSAndroid Build Coastguard Worker               *pix_ptr++ = (png_byte) ((val16 >> 8) & 0xFF);
450*a67afe4dSAndroid Build Coastguard Worker               *pix_ptr++ = (png_byte) (val16 & 0xFF);
451*a67afe4dSAndroid Build Coastguard Worker             }
452*a67afe4dSAndroid Build Coastguard Worker           }
453*a67afe4dSAndroid Build Coastguard Worker         } /* end if alpha */
454*a67afe4dSAndroid Build Coastguard Worker       } /* end if packed_bitmap */
455*a67afe4dSAndroid Build Coastguard Worker     } /* end for col */
456*a67afe4dSAndroid Build Coastguard Worker   } /* end for row */
457*a67afe4dSAndroid Build Coastguard Worker 
458*a67afe4dSAndroid Build Coastguard Worker   /* we're going to write more or less the same PNG as the input file */
459*a67afe4dSAndroid Build Coastguard Worker   png_set_IHDR (png_ptr, info_ptr, width, height, bit_depth, color_type,
460*a67afe4dSAndroid Build Coastguard Worker                 (!interlace) ? PNG_INTERLACE_NONE : PNG_INTERLACE_ADAM7,
461*a67afe4dSAndroid Build Coastguard Worker                 PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
462*a67afe4dSAndroid Build Coastguard Worker 
463*a67afe4dSAndroid Build Coastguard Worker   if (packed_bitmap == TRUE)
464*a67afe4dSAndroid Build Coastguard Worker   {
465*a67afe4dSAndroid Build Coastguard Worker     png_set_packing (png_ptr);
466*a67afe4dSAndroid Build Coastguard Worker     png_set_invert_mono (png_ptr);
467*a67afe4dSAndroid Build Coastguard Worker   }
468*a67afe4dSAndroid Build Coastguard Worker 
469*a67afe4dSAndroid Build Coastguard Worker   /* write the file header information */
470*a67afe4dSAndroid Build Coastguard Worker   png_write_info (png_ptr, info_ptr);
471*a67afe4dSAndroid Build Coastguard Worker 
472*a67afe4dSAndroid Build Coastguard Worker   /* write out the entire image data in one call */
473*a67afe4dSAndroid Build Coastguard Worker   png_write_image (png_ptr, row_pointers);
474*a67afe4dSAndroid Build Coastguard Worker 
475*a67afe4dSAndroid Build Coastguard Worker   /* write the additional chunks to the PNG file (not really needed) */
476*a67afe4dSAndroid Build Coastguard Worker   png_write_end (png_ptr, info_ptr);
477*a67afe4dSAndroid Build Coastguard Worker 
478*a67afe4dSAndroid Build Coastguard Worker   return TRUE;
479*a67afe4dSAndroid Build Coastguard Worker } /* end of pnm2png */
480*a67afe4dSAndroid Build Coastguard Worker 
481*a67afe4dSAndroid Build Coastguard Worker /*
482*a67afe4dSAndroid Build Coastguard Worker  * fscan_pnm_magic - like fscan_pnm_token below, but expects the magic string
483*a67afe4dSAndroid Build Coastguard Worker  *                   to start immediately, without any comment or whitespace,
484*a67afe4dSAndroid Build Coastguard Worker  *                   and to match the regex /^P[1-9]$/
485*a67afe4dSAndroid Build Coastguard Worker  */
486*a67afe4dSAndroid Build Coastguard Worker 
fscan_pnm_magic(FILE * pnm_file,char * magic_buf,size_t magic_buf_size)487*a67afe4dSAndroid Build Coastguard Worker int fscan_pnm_magic (FILE *pnm_file, char *magic_buf, size_t magic_buf_size)
488*a67afe4dSAndroid Build Coastguard Worker {
489*a67afe4dSAndroid Build Coastguard Worker   int ret;
490*a67afe4dSAndroid Build Coastguard Worker 
491*a67afe4dSAndroid Build Coastguard Worker   ret = fgetc (pnm_file);
492*a67afe4dSAndroid Build Coastguard Worker   if (ret == EOF) return 0;
493*a67afe4dSAndroid Build Coastguard Worker   ungetc (ret, pnm_file);
494*a67afe4dSAndroid Build Coastguard Worker   if (ret != 'P') return 0;
495*a67afe4dSAndroid Build Coastguard Worker 
496*a67afe4dSAndroid Build Coastguard Worker   /* the string buffer must be at least four bytes long, i.e., the capacity
497*a67afe4dSAndroid Build Coastguard Worker    * required for strings of at least three characters long, i.e., the minimum
498*a67afe4dSAndroid Build Coastguard Worker    * required for ensuring that our magic string is exactly two characters long
499*a67afe4dSAndroid Build Coastguard Worker    */
500*a67afe4dSAndroid Build Coastguard Worker   if (magic_buf_size < 4) return -1;
501*a67afe4dSAndroid Build Coastguard Worker 
502*a67afe4dSAndroid Build Coastguard Worker   ret = fscan_pnm_token (pnm_file, magic_buf, magic_buf_size);
503*a67afe4dSAndroid Build Coastguard Worker   if (ret < 1) return ret;
504*a67afe4dSAndroid Build Coastguard Worker 
505*a67afe4dSAndroid Build Coastguard Worker   if ((magic_buf[1] < '1') || (magic_buf[1] > '9')) return 0;
506*a67afe4dSAndroid Build Coastguard Worker   if (magic_buf[2] != '\0') return 0;
507*a67afe4dSAndroid Build Coastguard Worker 
508*a67afe4dSAndroid Build Coastguard Worker   return 1;
509*a67afe4dSAndroid Build Coastguard Worker }
510*a67afe4dSAndroid Build Coastguard Worker 
511*a67afe4dSAndroid Build Coastguard Worker /*
512*a67afe4dSAndroid Build Coastguard Worker  * fscan_pnm_token - extracts the first string token after whitespace,
513*a67afe4dSAndroid Build Coastguard Worker  *                   and (like fscanf) returns the number of successful
514*a67afe4dSAndroid Build Coastguard Worker  *                   extractions, which can be either 0 or 1
515*a67afe4dSAndroid Build Coastguard Worker  */
516*a67afe4dSAndroid Build Coastguard Worker 
fscan_pnm_token(FILE * pnm_file,char * token_buf,size_t token_buf_size)517*a67afe4dSAndroid Build Coastguard Worker int fscan_pnm_token (FILE *pnm_file, char *token_buf, size_t token_buf_size)
518*a67afe4dSAndroid Build Coastguard Worker {
519*a67afe4dSAndroid Build Coastguard Worker   size_t i = 0;
520*a67afe4dSAndroid Build Coastguard Worker   int ret;
521*a67afe4dSAndroid Build Coastguard Worker 
522*a67afe4dSAndroid Build Coastguard Worker   /* remove white-space and comment lines */
523*a67afe4dSAndroid Build Coastguard Worker   do
524*a67afe4dSAndroid Build Coastguard Worker   {
525*a67afe4dSAndroid Build Coastguard Worker     ret = fgetc (pnm_file);
526*a67afe4dSAndroid Build Coastguard Worker     if (ret == '#')
527*a67afe4dSAndroid Build Coastguard Worker     {
528*a67afe4dSAndroid Build Coastguard Worker       /* the rest of this line is a comment */
529*a67afe4dSAndroid Build Coastguard Worker       do
530*a67afe4dSAndroid Build Coastguard Worker       {
531*a67afe4dSAndroid Build Coastguard Worker         ret = fgetc (pnm_file);
532*a67afe4dSAndroid Build Coastguard Worker       }
533*a67afe4dSAndroid Build Coastguard Worker       while ((ret != '\n') && (ret != '\r') && (ret != EOF));
534*a67afe4dSAndroid Build Coastguard Worker     }
535*a67afe4dSAndroid Build Coastguard Worker     if (ret == EOF) break;
536*a67afe4dSAndroid Build Coastguard Worker     token_buf[i] = (char) ret;
537*a67afe4dSAndroid Build Coastguard Worker   }
538*a67afe4dSAndroid Build Coastguard Worker   while ((ret == '\n') || (ret == '\r') || (ret == ' '));
539*a67afe4dSAndroid Build Coastguard Worker 
540*a67afe4dSAndroid Build Coastguard Worker   /* read string */
541*a67afe4dSAndroid Build Coastguard Worker   do
542*a67afe4dSAndroid Build Coastguard Worker   {
543*a67afe4dSAndroid Build Coastguard Worker     ret = fgetc (pnm_file);
544*a67afe4dSAndroid Build Coastguard Worker     if (ret == EOF) break;
545*a67afe4dSAndroid Build Coastguard Worker     if (ret == '0')
546*a67afe4dSAndroid Build Coastguard Worker     {
547*a67afe4dSAndroid Build Coastguard Worker       /* avoid storing more than one leading '0' in the token buffer,
548*a67afe4dSAndroid Build Coastguard Worker        * to ensure that all valid (in-range) numeric inputs can fit in. */
549*a67afe4dSAndroid Build Coastguard Worker       if ((i == 0) && (token_buf[i] == '0')) continue;
550*a67afe4dSAndroid Build Coastguard Worker     }
551*a67afe4dSAndroid Build Coastguard Worker     if (++i == token_buf_size - 1) break;
552*a67afe4dSAndroid Build Coastguard Worker     token_buf[i] = (char) ret;
553*a67afe4dSAndroid Build Coastguard Worker   }
554*a67afe4dSAndroid Build Coastguard Worker   while ((ret != '\n') && (ret != '\r') && (ret != ' '));
555*a67afe4dSAndroid Build Coastguard Worker 
556*a67afe4dSAndroid Build Coastguard Worker   token_buf[i] = '\0';
557*a67afe4dSAndroid Build Coastguard Worker   return (i > 0) ? 1 : 0;
558*a67afe4dSAndroid Build Coastguard Worker }
559*a67afe4dSAndroid Build Coastguard Worker 
560*a67afe4dSAndroid Build Coastguard Worker /*
561*a67afe4dSAndroid Build Coastguard Worker  * fscan_pnm_uint_32 - like fscan_token above, but expects the extracted token
562*a67afe4dSAndroid Build Coastguard Worker  *                     to be numeric, and converts it to an unsigned 32-bit int
563*a67afe4dSAndroid Build Coastguard Worker  */
564*a67afe4dSAndroid Build Coastguard Worker 
fscan_pnm_uint_32(FILE * pnm_file,png_uint_32 * num_ptr)565*a67afe4dSAndroid Build Coastguard Worker int fscan_pnm_uint_32 (FILE *pnm_file, png_uint_32 *num_ptr)
566*a67afe4dSAndroid Build Coastguard Worker {
567*a67afe4dSAndroid Build Coastguard Worker   char token[16];
568*a67afe4dSAndroid Build Coastguard Worker   unsigned long token_value;
569*a67afe4dSAndroid Build Coastguard Worker   int ret;
570*a67afe4dSAndroid Build Coastguard Worker 
571*a67afe4dSAndroid Build Coastguard Worker   ret = fscan_pnm_token (pnm_file, token, sizeof (token));
572*a67afe4dSAndroid Build Coastguard Worker   if (ret < 1) return ret;
573*a67afe4dSAndroid Build Coastguard Worker 
574*a67afe4dSAndroid Build Coastguard Worker   if ((token[0] < '0') && (token[0] > '9'))
575*a67afe4dSAndroid Build Coastguard Worker     return 0; /* the token starts with junk, or a +/- sign, which is invalid */
576*a67afe4dSAndroid Build Coastguard Worker 
577*a67afe4dSAndroid Build Coastguard Worker   ret = sscanf (token, "%lu%*c", &token_value);
578*a67afe4dSAndroid Build Coastguard Worker   if (ret != 1)
579*a67afe4dSAndroid Build Coastguard Worker     return 0; /* the token ends with junk */
580*a67afe4dSAndroid Build Coastguard Worker 
581*a67afe4dSAndroid Build Coastguard Worker   *num_ptr = (png_uint_32) token_value;
582*a67afe4dSAndroid Build Coastguard Worker 
583*a67afe4dSAndroid Build Coastguard Worker #if ULONG_MAX > 0xFFFFFFFFUL
584*a67afe4dSAndroid Build Coastguard Worker   /* saturate the converted number, following the fscanf convention */
585*a67afe4dSAndroid Build Coastguard Worker   if (token_value > 0xFFFFFFFFUL)
586*a67afe4dSAndroid Build Coastguard Worker     *num_ptr = 0xFFFFFFFFUL;
587*a67afe4dSAndroid Build Coastguard Worker #endif
588*a67afe4dSAndroid Build Coastguard Worker 
589*a67afe4dSAndroid Build Coastguard Worker   return 1;
590*a67afe4dSAndroid Build Coastguard Worker }
591*a67afe4dSAndroid Build Coastguard Worker 
592*a67afe4dSAndroid Build Coastguard Worker /*
593*a67afe4dSAndroid Build Coastguard Worker  *  get_pnm_data - takes first byte and converts into next pixel value,
594*a67afe4dSAndroid Build Coastguard Worker  *                 taking as many bits as defined by bit-depth and
595*a67afe4dSAndroid Build Coastguard Worker  *                 using the bit-depth to fill up a byte (0x0A -> 0xAA)
596*a67afe4dSAndroid Build Coastguard Worker  */
597*a67afe4dSAndroid Build Coastguard Worker 
get_pnm_data(FILE * pnm_file,int depth)598*a67afe4dSAndroid Build Coastguard Worker png_uint_32 get_pnm_data (FILE *pnm_file, int depth)
599*a67afe4dSAndroid Build Coastguard Worker {
600*a67afe4dSAndroid Build Coastguard Worker   static int bits_left = 0;
601*a67afe4dSAndroid Build Coastguard Worker   static int old_value = 0;
602*a67afe4dSAndroid Build Coastguard Worker   static int mask = 0;
603*a67afe4dSAndroid Build Coastguard Worker   png_uint_32 ret_value;
604*a67afe4dSAndroid Build Coastguard Worker   int i;
605*a67afe4dSAndroid Build Coastguard Worker 
606*a67afe4dSAndroid Build Coastguard Worker   if (mask == 0)
607*a67afe4dSAndroid Build Coastguard Worker     for (i = 0; i < depth; i++)
608*a67afe4dSAndroid Build Coastguard Worker       mask = (mask >> 1) | 0x80;
609*a67afe4dSAndroid Build Coastguard Worker 
610*a67afe4dSAndroid Build Coastguard Worker   if (bits_left <= 0)
611*a67afe4dSAndroid Build Coastguard Worker   {
612*a67afe4dSAndroid Build Coastguard Worker     /* FIXME:
613*a67afe4dSAndroid Build Coastguard Worker      * signal the premature end of file, instead of pretending to read zeroes
614*a67afe4dSAndroid Build Coastguard Worker      */
615*a67afe4dSAndroid Build Coastguard Worker     old_value = fgetc (pnm_file);
616*a67afe4dSAndroid Build Coastguard Worker     if (old_value == EOF) return 0;
617*a67afe4dSAndroid Build Coastguard Worker     bits_left = 8;
618*a67afe4dSAndroid Build Coastguard Worker   }
619*a67afe4dSAndroid Build Coastguard Worker 
620*a67afe4dSAndroid Build Coastguard Worker   ret_value = old_value & mask;
621*a67afe4dSAndroid Build Coastguard Worker   for (i = 1; i < (8 / depth); i++)
622*a67afe4dSAndroid Build Coastguard Worker     ret_value = ret_value || (ret_value >> depth);
623*a67afe4dSAndroid Build Coastguard Worker 
624*a67afe4dSAndroid Build Coastguard Worker   old_value = (old_value << depth) & 0xFF;
625*a67afe4dSAndroid Build Coastguard Worker   bits_left -= depth;
626*a67afe4dSAndroid Build Coastguard Worker 
627*a67afe4dSAndroid Build Coastguard Worker   return ret_value;
628*a67afe4dSAndroid Build Coastguard Worker }
629*a67afe4dSAndroid Build Coastguard Worker 
630*a67afe4dSAndroid Build Coastguard Worker /*
631*a67afe4dSAndroid Build Coastguard Worker  *  get_pnm_value - takes first (numeric) string and converts into number,
632*a67afe4dSAndroid Build Coastguard Worker  *                  using the bit-depth to fill up a byte (0x0A -> 0xAA)
633*a67afe4dSAndroid Build Coastguard Worker  */
634*a67afe4dSAndroid Build Coastguard Worker 
get_pnm_value(FILE * pnm_file,int depth)635*a67afe4dSAndroid Build Coastguard Worker png_uint_32 get_pnm_value (FILE *pnm_file, int depth)
636*a67afe4dSAndroid Build Coastguard Worker {
637*a67afe4dSAndroid Build Coastguard Worker   static png_uint_32 mask = 0;
638*a67afe4dSAndroid Build Coastguard Worker   png_uint_32 ret_value;
639*a67afe4dSAndroid Build Coastguard Worker   int i;
640*a67afe4dSAndroid Build Coastguard Worker 
641*a67afe4dSAndroid Build Coastguard Worker   if (mask == 0)
642*a67afe4dSAndroid Build Coastguard Worker     for (i = 0; i < depth; i++)
643*a67afe4dSAndroid Build Coastguard Worker       mask = (mask << 1) | 0x01;
644*a67afe4dSAndroid Build Coastguard Worker 
645*a67afe4dSAndroid Build Coastguard Worker   if (fscan_pnm_uint_32 (pnm_file, &ret_value) != 1)
646*a67afe4dSAndroid Build Coastguard Worker   {
647*a67afe4dSAndroid Build Coastguard Worker     /* FIXME:
648*a67afe4dSAndroid Build Coastguard Worker      * signal the invalid numeric tokens or the premature end of file,
649*a67afe4dSAndroid Build Coastguard Worker      * instead of pretending to read zeroes
650*a67afe4dSAndroid Build Coastguard Worker      */
651*a67afe4dSAndroid Build Coastguard Worker     return 0;
652*a67afe4dSAndroid Build Coastguard Worker   }
653*a67afe4dSAndroid Build Coastguard Worker 
654*a67afe4dSAndroid Build Coastguard Worker   ret_value &= mask;
655*a67afe4dSAndroid Build Coastguard Worker 
656*a67afe4dSAndroid Build Coastguard Worker   if (depth < 8)
657*a67afe4dSAndroid Build Coastguard Worker     for (i = 0; i < (8 / depth); i++)
658*a67afe4dSAndroid Build Coastguard Worker       ret_value = (ret_value << depth) || ret_value;
659*a67afe4dSAndroid Build Coastguard Worker 
660*a67afe4dSAndroid Build Coastguard Worker   return ret_value;
661*a67afe4dSAndroid Build Coastguard Worker }
662*a67afe4dSAndroid Build Coastguard Worker 
663*a67afe4dSAndroid Build Coastguard Worker /* end of source */
664