VirtualBox

source: vbox/trunk/src/libs/libpng-1.6.42/contrib/pngminus/pnm2png.c@ 103585

最後變更 在這個檔案從103585是 103316,由 vboxsync 提交於 12 月 前

libpng-1.6.42: Applied and adjusted our libpng changes to 1.6.42. bugref:8515

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette