2 * png2pnm.c --- conversion from PNG-file to PGM/PPM-file
3 * copyright (C) 1999 by Willem van Schaik <willem@schaik.com>
5 * version 1.0 - 1999.10.15 - First version.
7 * Permission to use, copy, modify, and distribute this software and
8 * its documentation for any purpose and without fee is hereby granted,
9 * provided that the above copyright notice appear in all copies and
10 * that both that copyright notice and this permission notice appear in
11 * supporting documentation. This software is provided "as is" without
12 * express or implied warranty.
24 #define BOOL unsigned char
30 #define FALSE (BOOL) 0
39 /* to make png2pnm verbose so we can find problems (needs to be before png.h) */
46 /* Define png_jmpbuf() in case we are using a pre-1.0.6 version of libpng */
48 # define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf)
51 /* function prototypes */
53 int main (int argc
, char *argv
[]);
55 BOOL
png2pnm (FILE *png_file
, FILE *pnm_file
, FILE *alpha_file
, BOOL raw
, BOOL alpha
);
61 int main(int argc
, char *argv
[])
70 for (argi
= 1; argi
< argc
; argi
++)
72 if (argv
[argi
][0] == '-')
74 switch (argv
[argi
][1])
85 if ((fp_al
= fopen (argv
[argi
], "wb")) == NULL
)
87 fprintf (stderr
, "PNM2PNG\n");
88 fprintf (stderr
, "Error: can not create alpha-channel file %s\n", argv
[argi
]);
98 fprintf (stderr
, "PNG2PNM\n");
99 fprintf (stderr
, "Error: unknown option %s\n", argv
[argi
]);
105 else if (fp_rd
== stdin
)
107 if ((fp_rd
= fopen (argv
[argi
], "rb")) == NULL
)
109 fprintf (stderr
, "PNG2PNM\n");
110 fprintf (stderr
, "Error: file %s does not exist\n", argv
[argi
]);
114 else if (fp_wr
== stdout
)
116 if ((fp_wr
= fopen (argv
[argi
], "wb")) == NULL
)
118 fprintf (stderr
, "PNG2PNM\n");
119 fprintf (stderr
, "Error: can not create file %s\n", argv
[argi
]);
125 fprintf (stderr
, "PNG2PNM\n");
126 fprintf (stderr
, "Error: too many parameters\n");
133 /* set stdin/stdout if required to binary */
136 setmode (STDIN
, O_BINARY
);
138 if ((raw
) && (fp_wr
== stdout
))
140 setmode (STDOUT
, O_BINARY
);
144 /* call the conversion program itself */
145 if (png2pnm (fp_rd
, fp_wr
, fp_al
, raw
, alpha
) == FALSE
)
147 fprintf (stderr
, "PNG2PNM\n");
148 fprintf (stderr
, "Error: unsuccessful conversion of PNG-image\n");
152 /* close input file */
154 /* close output file */
156 /* close alpha file */
169 fprintf (stderr
, "PNG2PNM\n");
170 fprintf (stderr
, " by Willem van Schaik, 1999\n");
172 fprintf (stderr
, " for Turbo-C and Borland-C compilers\n");
174 fprintf (stderr
, " for Linux (and Unix) compilers\n");
176 fprintf (stderr
, "Usage: png2pnm [options] <file>.png [<file>.pnm]\n");
177 fprintf (stderr
, " or: ... | png2pnm [options]\n");
178 fprintf (stderr
, "Options:\n");
179 fprintf (stderr
, " -r[aw] write pnm-file in binary format (P4/P5/P6) (default)\n");
180 fprintf (stderr
, " -n[oraw] write pnm-file in ascii format (P1/P2/P3)\n");
181 fprintf (stderr
, " -a[lpha] <file>.pgm write PNG alpha channel as pgm-file\n");
182 fprintf (stderr
, " -h | -? print this help-information\n");
189 BOOL
png2pnm (FILE *png_file
, FILE *pnm_file
, FILE *alpha_file
, BOOL raw
, BOOL alpha
)
191 png_struct
*png_ptr
= NULL
;
192 png_info
*info_ptr
= NULL
;
194 png_byte
*png_pixels
= NULL
;
195 png_byte
**row_pointers
= NULL
;
196 png_byte
*pix_ptr
= NULL
;
197 png_uint_32 row_bytes
;
210 /* read and check signature in PNG file */
211 ret
= fread (buf
, 1, 8, png_file
);
215 ret
= png_sig_cmp (buf
, 0, 8);
219 /* create png and info structures */
221 png_ptr
= png_create_read_struct (PNG_LIBPNG_VER_STRING
,
224 return FALSE
; /* out of memory */
226 info_ptr
= png_create_info_struct (png_ptr
);
229 png_destroy_read_struct (&png_ptr
, NULL
, NULL
);
230 return FALSE
; /* out of memory */
233 if (setjmp (png_jmpbuf(png_ptr
)))
235 png_destroy_read_struct (&png_ptr
, &info_ptr
, NULL
);
239 /* set up the input control for C streams */
240 png_init_io (png_ptr
, png_file
);
241 png_set_sig_bytes (png_ptr
, 8); /* we already read the 8 signature bytes */
243 /* read the file information */
244 png_read_info (png_ptr
, info_ptr
);
246 /* get size and bit-depth of the PNG-image */
247 png_get_IHDR (png_ptr
, info_ptr
,
248 &width
, &height
, &bit_depth
, &color_type
,
251 /* set-up the transformations */
253 /* transform paletted images into full-color rgb */
254 if (color_type
== PNG_COLOR_TYPE_PALETTE
)
255 png_set_expand (png_ptr
);
256 /* expand images to bit-depth 8 (only applicable for grayscale images) */
257 if (color_type
== PNG_COLOR_TYPE_GRAY
&& bit_depth
< 8)
258 png_set_expand (png_ptr
);
259 /* transform transparency maps into full alpha-channel */
260 if (png_get_valid (png_ptr
, info_ptr
, PNG_INFO_tRNS
))
261 png_set_expand (png_ptr
);
264 /* downgrade 16-bit images to 8 bit */
266 png_set_strip_16 (png_ptr
);
267 /* transform grayscale images into full-color */
268 if (color_type
== PNG_COLOR_TYPE_GRAY
||
269 color_type
== PNG_COLOR_TYPE_GRAY_ALPHA
)
270 png_set_gray_to_rgb (png_ptr
);
271 /* only if file has a file gamma, we do a correction */
272 if (png_get_gAMA (png_ptr
, info_ptr
, &file_gamma
))
273 png_set_gamma (png_ptr
, (double) 2.2, file_gamma
);
276 /* all transformations have been registered; now update info_ptr data,
277 * get rowbytes and channels, and allocate image memory */
279 png_read_update_info (png_ptr
, info_ptr
);
281 /* get the new color-type and bit-depth (after expansion/stripping) */
282 png_get_IHDR (png_ptr
, info_ptr
, &width
, &height
, &bit_depth
, &color_type
,
285 /* check for 16-bit files */
290 pnm_file
->flags
&= ~((unsigned) _F_BIN
);
294 /* calculate new number of channels and store alpha-presence */
295 if (color_type
== PNG_COLOR_TYPE_GRAY
)
297 else if (color_type
== PNG_COLOR_TYPE_GRAY_ALPHA
)
299 else if (color_type
== PNG_COLOR_TYPE_RGB
)
301 else if (color_type
== PNG_COLOR_TYPE_RGB_ALPHA
)
304 channels
= 0; /* should never happen */
305 alpha_present
= (channels
- 1) % 2;
307 /* check if alpha is expected to be present in file */
308 if (alpha
&& !alpha_present
)
310 fprintf (stderr
, "PNG2PNM\n");
311 fprintf (stderr
, "Error: PNG-file doesn't contain alpha channel\n");
315 /* row_bytes is the width x number of channels x (bit-depth / 8) */
316 row_bytes
= png_get_rowbytes (png_ptr
, info_ptr
);
318 if ((png_pixels
= (png_byte
*) malloc (row_bytes
* height
* sizeof (png_byte
))) == NULL
) {
319 png_destroy_read_struct (&png_ptr
, &info_ptr
, NULL
);
323 if ((row_pointers
= (png_byte
**) malloc (height
* sizeof (png_bytep
))) == NULL
)
325 png_destroy_read_struct (&png_ptr
, &info_ptr
, NULL
);
331 /* set the individual row_pointers to point at the correct offsets */
332 for (i
= 0; i
< (height
); i
++)
333 row_pointers
[i
] = png_pixels
+ i
* row_bytes
;
335 /* now we can go ahead and just read the whole image */
336 png_read_image (png_ptr
, row_pointers
);
338 /* read rest of file, and get additional chunks in info_ptr - REQUIRED */
339 png_read_end (png_ptr
, info_ptr
);
341 /* clean up after the read, and free any memory allocated - REQUIRED */
342 png_destroy_read_struct (&png_ptr
, &info_ptr
, (png_infopp
) NULL
);
344 /* write header of PNM file */
346 if ((color_type
== PNG_COLOR_TYPE_GRAY
) ||
347 (color_type
== PNG_COLOR_TYPE_GRAY_ALPHA
))
349 fprintf (pnm_file
, "%s\n", (raw
) ? "P5" : "P2");
350 fprintf (pnm_file
, "%d %d\n", (int) width
, (int) height
);
351 fprintf (pnm_file
, "%ld\n", ((1L << (int) bit_depth
) - 1L));
353 else if ((color_type
== PNG_COLOR_TYPE_RGB
) ||
354 (color_type
== PNG_COLOR_TYPE_RGB_ALPHA
))
356 fprintf (pnm_file
, "%s\n", (raw
) ? "P6" : "P3");
357 fprintf (pnm_file
, "%d %d\n", (int) width
, (int) height
);
358 fprintf (pnm_file
, "%ld\n", ((1L << (int) bit_depth
) - 1L));
361 /* write header of PGM file with alpha channel */
364 ((color_type
== PNG_COLOR_TYPE_GRAY_ALPHA
) ||
365 (color_type
== PNG_COLOR_TYPE_RGB_ALPHA
)))
367 fprintf (alpha_file
, "%s\n", (raw
) ? "P5" : "P2");
368 fprintf (alpha_file
, "%d %d\n", (int) width
, (int) height
);
369 fprintf (alpha_file
, "%ld\n", ((1L << (int) bit_depth
) - 1L));
372 /* write data to PNM file */
373 pix_ptr
= png_pixels
;
375 for (row
= 0; row
< height
; row
++)
377 for (col
= 0; col
< width
; col
++)
379 for (i
= 0; i
< (channels
- alpha_present
); i
++)
382 fputc ((int) *pix_ptr
++ , pnm_file
);
384 if (bit_depth
== 16){
385 dep_16
= (long) *pix_ptr
++;
386 fprintf (pnm_file
, "%ld ", (dep_16
<< 8) + ((long) *pix_ptr
++));
389 fprintf (pnm_file
, "%ld ", (long) *pix_ptr
++);
395 pix_ptr
++; /* alpha */
399 else /* output alpha-channel as pgm file */
402 fputc ((int) *pix_ptr
++ , alpha_file
);
404 if (bit_depth
== 16){
405 dep_16
= (long) *pix_ptr
++;
406 fprintf (alpha_file
, "%ld ", (dep_16
<< 8) + (long) *pix_ptr
++);
409 fprintf (alpha_file
, "%ld ", (long) *pix_ptr
++);
411 } /* if alpha_present */
415 fprintf (pnm_file
, "\n");
420 fprintf (pnm_file
, "\n");
423 if (row_pointers
!= (unsigned char**) NULL
)
425 if (png_pixels
!= (unsigned char*) NULL
)
430 } /* end of source */