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