Imported Upstream version 1.6.13
[platform/upstream/libpng.git] / contrib / pngminus / pnm2png.c
1 /*
2  *  pnm2png.c --- conversion from PBM/PGM/PPM-file to PNG-file
3  *  copyright (C) 1999 by Willem van Schaik <willem@schaik.com>
4  *
5  *  version 1.0 - 1999.10.15 - First version.
6  *
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.
13  */
14
15 #include <stdio.h>
16 #include <stdlib.h>
17 #ifdef __TURBOC__
18 #include <mem.h>
19 #include <fcntl.h>
20 #endif
21 #include <zlib.h>
22
23 #ifndef BOOL
24 #define BOOL unsigned char
25 #endif
26 #ifndef TRUE
27 #define TRUE (BOOL) 1
28 #endif
29 #ifndef FALSE
30 #define FALSE (BOOL) 0
31 #endif
32
33 #define STDIN  0
34 #define STDOUT 1
35 #define STDERR 2
36
37 /* to make pnm2png verbose so we can find problems (needs to be before png.h) */
38 #ifndef PNG_DEBUG
39 #define PNG_DEBUG 0
40 #endif
41
42 #include "png.h"
43
44 /* Define png_jmpbuf() in case we are using a pre-1.0.6 version of libpng */
45 #ifndef png_jmpbuf
46 #  define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf)
47 #endif
48
49 /* function prototypes */
50
51 int  main (int argc, char *argv[]);
52 void usage ();
53 BOOL pnm2png (FILE *pnm_file, FILE *png_file, FILE *alpha_file, BOOL interlace,
54     BOOL alpha);
55 void get_token(FILE *pnm_file, char *token);
56 png_uint_32 get_data (FILE *pnm_file, int depth);
57 png_uint_32 get_value (FILE *pnm_file, int depth);
58
59 /*
60  *  main
61  */
62
63 int main(int argc, char *argv[])
64 {
65   FILE *fp_rd = stdin;
66   FILE *fp_al = NULL;
67   FILE *fp_wr = stdout;
68   BOOL interlace = FALSE;
69   BOOL alpha = FALSE;
70   int argi;
71
72   for (argi = 1; argi < argc; argi++)
73   {
74     if (argv[argi][0] == '-')
75     {
76       switch (argv[argi][1])
77       {
78         case 'i':
79           interlace = TRUE;
80           break;
81         case 'a':
82           alpha = TRUE;
83           argi++;
84           if ((fp_al = fopen (argv[argi], "rb")) == NULL)
85           {
86             fprintf (stderr, "PNM2PNG\n");
87             fprintf (stderr, "Error:  alpha-channel file %s does not exist\n",
88                argv[argi]);
89             exit (1);
90           }
91           break;
92         case 'h':
93         case '?':
94           usage();
95           exit(0);
96           break;
97         default:
98           fprintf (stderr, "PNM2PNG\n");
99           fprintf (stderr, "Error:  unknown option %s\n", argv[argi]);
100           usage();
101           exit(1);
102           break;
103       } /* end switch */
104     }
105     else if (fp_rd == stdin)
106     {
107       if ((fp_rd = fopen (argv[argi], "rb")) == NULL)
108       {
109         fprintf (stderr, "PNM2PNG\n");
110         fprintf (stderr, "Error:  file %s does not exist\n", argv[argi]);
111         exit (1);
112       }
113     }
114     else if (fp_wr == stdout)
115     {
116       if ((fp_wr = fopen (argv[argi], "wb")) == NULL)
117       {
118         fprintf (stderr, "PNM2PNG\n");
119         fprintf (stderr, "Error:  can not create PNG-file %s\n", argv[argi]);
120         exit (1);
121       }
122     }
123     else
124     {
125       fprintf (stderr, "PNM2PNG\n");
126       fprintf (stderr, "Error:  too many parameters\n");
127       usage();
128       exit (1);
129     }
130   } /* end for */
131
132 #ifdef __TURBOC__
133   /* set stdin/stdout to binary, we're reading the PNM always! in binary format */
134   if (fp_rd == stdin)
135   {
136     setmode (STDIN, O_BINARY);
137   }
138   if (fp_wr == stdout)
139   {
140     setmode (STDOUT, O_BINARY);
141   }
142 #endif
143
144   /* call the conversion program itself */
145   if (pnm2png (fp_rd, fp_wr, fp_al, interlace, alpha) == FALSE)
146   {
147     fprintf (stderr, "PNM2PNG\n");
148     fprintf (stderr, "Error:  unsuccessful converting to PNG-image\n");
149     exit (1);
150   }
151
152   /* close input file */
153   fclose (fp_rd);
154   /* close output file */
155   fclose (fp_wr);
156   /* close alpha file */
157   if (alpha)
158     fclose (fp_al);
159
160   return 0;
161 }
162
163 /*
164  *  usage
165  */
166
167 void usage()
168 {
169   fprintf (stderr, "PNM2PNG\n");
170   fprintf (stderr, "   by Willem van Schaik, 1999\n");
171 #ifdef __TURBOC__
172   fprintf (stderr, "   for Turbo-C and Borland-C compilers\n");
173 #else
174   fprintf (stderr, "   for Linux (and Unix) compilers\n");
175 #endif
176   fprintf (stderr, "Usage:  pnm2png [options] <file>.<pnm> [<file>.png]\n");
177   fprintf (stderr, "   or:  ... | pnm2png [options]\n");
178   fprintf (stderr, "Options:\n");
179   fprintf (stderr, "   -i[nterlace]   write png-file with interlacing on\n");
180   fprintf (stderr,
181       "   -a[lpha] <file>.pgm read PNG alpha channel as pgm-file\n");
182   fprintf (stderr, "   -h | -?  print this help-information\n");
183 }
184
185 /*
186  *  pnm2png
187  */
188
189 BOOL pnm2png (FILE *pnm_file, FILE *png_file, FILE *alpha_file, BOOL interlace,
190      BOOL alpha)
191 {
192   png_struct    *png_ptr = NULL;
193   png_info      *info_ptr = NULL;
194   png_byte      *png_pixels = NULL;
195   png_byte      **row_pointers = NULL;
196   png_byte      *pix_ptr = NULL;
197   volatile png_uint_32   row_bytes;
198
199   char          type_token[16];
200   char          width_token[16];
201   char          height_token[16];
202   char          maxval_token[16];
203   volatile int           color_type;
204   unsigned long   ul_width=0, ul_alpha_width=0;
205   unsigned long   ul_height=0, ul_alpha_height=0;
206   unsigned long   ul_maxval=0;
207   volatile png_uint_32   width, height;
208   volatile png_uint_32   alpha_width, alpha_height;
209   png_uint_32   maxval;
210   volatile int           bit_depth = 0;
211   int           channels;
212   int           alpha_depth = 0;
213   int           alpha_present;
214   int           row, col;
215   BOOL          raw, alpha_raw = FALSE;
216 #if defined(PNG_WRITE_INVERT_SUPPORTED) || defined(PNG_WRITE_PACK_SUPPORTED)
217   BOOL          packed_bitmap = FALSE;
218 #endif
219   png_uint_32   tmp16;
220   int           i;
221
222   /* read header of PNM file */
223
224   get_token(pnm_file, type_token);
225   if (type_token[0] != 'P')
226   {
227     return FALSE;
228   }
229   else if ((type_token[1] == '1') || (type_token[1] == '4'))
230   {
231 #if defined(PNG_WRITE_INVERT_SUPPORTED) || defined(PNG_WRITE_PACK_SUPPORTED)
232     raw = (type_token[1] == '4');
233     color_type = PNG_COLOR_TYPE_GRAY;
234     get_token(pnm_file, width_token);
235     sscanf (width_token, "%lu", &ul_width);
236     width = (png_uint_32) ul_width;
237     get_token(pnm_file, height_token);
238     sscanf (height_token, "%lu", &ul_height);
239     height = (png_uint_32) ul_height;
240     bit_depth = 1;
241     packed_bitmap = TRUE;
242 #else
243     fprintf (stderr, "PNM2PNG built without PNG_WRITE_INVERT_SUPPORTED and \n");
244     fprintf (stderr, "PNG_WRITE_PACK_SUPPORTED can't read PBM (P1,P4) files\n");
245 #endif
246   }
247   else if ((type_token[1] == '2') || (type_token[1] == '5'))
248   {
249     raw = (type_token[1] == '5');
250     color_type = PNG_COLOR_TYPE_GRAY;
251     get_token(pnm_file, width_token);
252     sscanf (width_token, "%lu", &ul_width);
253     width = (png_uint_32) ul_width;
254     get_token(pnm_file, height_token);
255     sscanf (height_token, "%lu", &ul_height);
256     height = (png_uint_32) ul_height;
257     get_token(pnm_file, maxval_token);
258     sscanf (maxval_token, "%lu", &ul_maxval);
259     maxval = (png_uint_32) ul_maxval;
260
261     if (maxval <= 1)
262       bit_depth = 1;
263     else if (maxval <= 3)
264       bit_depth = 2;
265     else if (maxval <= 15)
266       bit_depth = 4;
267     else if (maxval <= 255)
268       bit_depth = 8;
269     else /* if (maxval <= 65535) */
270       bit_depth = 16;
271   }
272   else if ((type_token[1] == '3') || (type_token[1] == '6'))
273   {
274     raw = (type_token[1] == '6');
275     color_type = PNG_COLOR_TYPE_RGB;
276     get_token(pnm_file, width_token);
277     sscanf (width_token, "%lu", &ul_width);
278     width = (png_uint_32) ul_width;
279     get_token(pnm_file, height_token);
280     sscanf (height_token, "%lu", &ul_height);
281     height = (png_uint_32) ul_height;
282     get_token(pnm_file, maxval_token);
283     sscanf (maxval_token, "%lu", &ul_maxval);
284     maxval = (png_uint_32) ul_maxval;
285     if (maxval <= 1)
286       bit_depth = 1;
287     else if (maxval <= 3)
288       bit_depth = 2;
289     else if (maxval <= 15)
290       bit_depth = 4;
291     else if (maxval <= 255)
292       bit_depth = 8;
293     else /* if (maxval <= 65535) */
294       bit_depth = 16;
295   }
296   else
297   {
298     return FALSE;
299   }
300
301   /* read header of PGM file with alpha channel */
302
303   if (alpha)
304   {
305     if (color_type == PNG_COLOR_TYPE_GRAY)
306       color_type = PNG_COLOR_TYPE_GRAY_ALPHA;
307     if (color_type == PNG_COLOR_TYPE_RGB)
308       color_type = PNG_COLOR_TYPE_RGB_ALPHA;
309
310     get_token(alpha_file, type_token);
311     if (type_token[0] != 'P')
312     {
313       return FALSE;
314     }
315     else if ((type_token[1] == '2') || (type_token[1] == '5'))
316     {
317       alpha_raw = (type_token[1] == '5');
318       get_token(alpha_file, width_token);
319       sscanf (width_token, "%lu", &ul_alpha_width);
320       alpha_width=(png_uint_32) ul_alpha_width;
321       if (alpha_width != width)
322         return FALSE;
323       get_token(alpha_file, height_token);
324       sscanf (height_token, "%lu", &ul_alpha_height);
325       alpha_height = (png_uint_32) ul_alpha_height;
326       if (alpha_height != height)
327         return FALSE;
328       get_token(alpha_file, maxval_token);
329       sscanf (maxval_token, "%lu", &ul_maxval);
330       maxval = (png_uint_32) ul_maxval;
331       if (maxval <= 1)
332         alpha_depth = 1;
333       else if (maxval <= 3)
334         alpha_depth = 2;
335       else if (maxval <= 15)
336         alpha_depth = 4;
337       else if (maxval <= 255)
338         alpha_depth = 8;
339       else /* if (maxval <= 65535) */
340         alpha_depth = 16;
341       if (alpha_depth != bit_depth)
342         return FALSE;
343     }
344     else
345     {
346       return FALSE;
347     }
348   } /* end if alpha */
349
350   /* calculate the number of channels and store alpha-presence */
351   if (color_type == PNG_COLOR_TYPE_GRAY)
352     channels = 1;
353   else if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
354     channels = 2;
355   else if (color_type == PNG_COLOR_TYPE_RGB)
356     channels = 3;
357   else if (color_type == PNG_COLOR_TYPE_RGB_ALPHA)
358     channels = 4;
359   else
360     channels = 0; /* should not happen */
361
362   alpha_present = (channels - 1) % 2;
363
364 #if defined(PNG_WRITE_INVERT_SUPPORTED) || defined(PNG_WRITE_PACK_SUPPORTED)
365   if (packed_bitmap)
366     /* row data is as many bytes as can fit width x channels x bit_depth */
367     row_bytes = (width * channels * bit_depth + 7) / 8;
368   else
369 #endif
370     /* row_bytes is the width x number of channels x (bit-depth / 8) */
371     row_bytes = width * channels * ((bit_depth <= 8) ? 1 : 2);
372
373   if ((png_pixels = (png_byte *)
374      malloc (row_bytes * height * sizeof (png_byte))) == NULL)
375     return FALSE;
376
377   /* read data from PNM file */
378   pix_ptr = png_pixels;
379
380   for (row = 0; row < (int) height; row++)
381   {
382 #if defined(PNG_WRITE_INVERT_SUPPORTED) || defined(PNG_WRITE_PACK_SUPPORTED)
383     if (packed_bitmap) {
384       for (i = 0; i < (int) row_bytes; i++)
385         /* png supports this format natively so no conversion is needed */
386         *pix_ptr++ = get_data (pnm_file, 8);
387     } else
388 #endif
389     {
390       for (col = 0; col < (int) width; col++)
391       {
392         for (i = 0; i < (channels - alpha_present); i++)
393         {
394           if (raw)
395             *pix_ptr++ = get_data (pnm_file, bit_depth);
396           else
397             if (bit_depth <= 8)
398               *pix_ptr++ = get_value (pnm_file, bit_depth);
399             else
400             {
401               tmp16 = get_value (pnm_file, bit_depth);
402               *pix_ptr = (png_byte) ((tmp16 >> 8) & 0xFF);
403               pix_ptr++;
404               *pix_ptr = (png_byte) (tmp16 & 0xFF);
405               pix_ptr++;
406             }
407         }
408
409         if (alpha) /* read alpha-channel from pgm file */
410         {
411           if (alpha_raw)
412             *pix_ptr++ = get_data (alpha_file, alpha_depth);
413           else
414             if (alpha_depth <= 8)
415               *pix_ptr++ = get_value (alpha_file, bit_depth);
416             else
417             {
418               tmp16 = get_value (alpha_file, bit_depth);
419               *pix_ptr++ = (png_byte) ((tmp16 >> 8) & 0xFF);
420               *pix_ptr++ = (png_byte) (tmp16 & 0xFF);
421             }
422         } /* if alpha */
423       } /* if packed_bitmap */
424     } /* end for col */
425   } /* end for row */
426
427   /* prepare the standard PNG structures */
428   png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
429   if (!png_ptr)
430   {
431     return FALSE;
432   }
433   info_ptr = png_create_info_struct (png_ptr);
434   if (!info_ptr)
435   {
436     png_destroy_write_struct (&png_ptr, (png_infopp) NULL);
437     return FALSE;
438   }
439
440 #if defined(PNG_WRITE_INVERT_SUPPORTED) || defined(PNG_WRITE_PACK_SUPPORTED)
441   if (packed_bitmap == TRUE)
442   {
443     png_set_packing (png_ptr);
444     png_set_invert_mono (png_ptr);
445   }
446 #endif
447
448   /* setjmp() must be called in every function that calls a PNG-reading libpng function */
449   if (setjmp (png_jmpbuf(png_ptr)))
450   {
451     png_destroy_write_struct (&png_ptr, (png_infopp) NULL);
452     return FALSE;
453   }
454
455   /* initialize the png structure */
456   png_init_io (png_ptr, png_file);
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   /* write the file header information */
464   png_write_info (png_ptr, info_ptr);
465
466   /* if needed we will allocate memory for an new array of row-pointers */
467   if (row_pointers == (unsigned char**) NULL)
468   {
469     if ((row_pointers = (png_byte **)
470         malloc (height * sizeof (png_bytep))) == NULL)
471     {
472       png_destroy_write_struct (&png_ptr, (png_infopp) NULL);
473       return FALSE;
474     }
475   }
476
477   /* set the individual row_pointers to point at the correct offsets */
478   for (i = 0; i < (int) height; i++)
479     row_pointers[i] = png_pixels + i * row_bytes;
480
481   /* write out the entire image data in one call */
482   png_write_image (png_ptr, row_pointers);
483
484   /* write the additional chunks to the PNG file (not really needed) */
485   png_write_end (png_ptr, info_ptr);
486
487   /* clean up after the write, and free any memory allocated */
488   png_destroy_write_struct (&png_ptr, (png_infopp) NULL);
489
490   if (row_pointers != (unsigned char**) NULL)
491     free (row_pointers);
492   if (png_pixels != (unsigned char*) NULL)
493     free (png_pixels);
494
495   return TRUE;
496 } /* end of pnm2png */
497
498 /*
499  * get_token() - gets the first string after whitespace
500  */
501
502 void get_token(FILE *pnm_file, char *token)
503 {
504   int i = 0;
505   int ret;
506
507   /* remove white-space and comment lines */
508   do
509   {
510     ret = fgetc(pnm_file);
511     if (ret == '#') {
512       /* the rest of this line is a comment */
513       do
514       {
515         ret = fgetc(pnm_file);
516       }
517       while ((ret != '\n') && (ret != '\r') && (ret != EOF));
518     }
519     if (ret == EOF) break;
520     token[i] = (unsigned char) ret;
521   }
522   while ((token[i] == '\n') || (token[i] == '\r') || (token[i] == ' '));
523
524   /* read string */
525   do
526   {
527     ret = fgetc(pnm_file);
528     if (ret == EOF) break;
529     i++;
530     token[i] = (unsigned char) ret;
531   }
532   while ((token[i] != '\n') && (token[i] != '\r') && (token[i] != ' '));
533
534   token[i] = '\0';
535
536   return;
537 }
538
539 /*
540  * get_data() - takes first byte and converts into next pixel value,
541  *        taking as much bits as defined by bit-depth and
542  *        using the bit-depth to fill up a byte (0Ah -> AAh)
543  */
544
545 png_uint_32 get_data (FILE *pnm_file, int depth)
546 {
547   static int bits_left = 0;
548   static int old_value = 0;
549   static int mask = 0;
550   int i;
551   png_uint_32 ret_value;
552
553   if (mask == 0)
554     for (i = 0; i < depth; i++)
555       mask = (mask >> 1) | 0x80;
556
557   if (bits_left <= 0)
558   {
559     old_value = fgetc (pnm_file);
560     bits_left = 8;
561   }
562
563   ret_value = old_value & mask;
564   for (i = 1; i < (8 / depth); i++)
565     ret_value = ret_value || (ret_value >> depth);
566
567   old_value = (old_value << depth) & 0xFF;
568   bits_left -= depth;
569
570   return ret_value;
571 }
572
573 /*
574  * get_value() - takes first (numeric) string and converts into number,
575  *         using the bit-depth to fill up a byte (0Ah -> AAh)
576  */
577
578 png_uint_32 get_value (FILE *pnm_file, int depth)
579 {
580   static png_uint_32 mask = 0;
581   png_byte token[16];
582   unsigned long ul_ret_value;
583   png_uint_32 ret_value;
584   int i = 0;
585
586   if (mask == 0)
587     for (i = 0; i < depth; i++)
588       mask = (mask << 1) | 0x01;
589
590   get_token (pnm_file, (char *) token);
591   sscanf ((const char *) token, "%lu", &ul_ret_value);
592   ret_value = (png_uint_32) ul_ret_value;
593
594   ret_value &= mask;
595
596   if (depth < 8)
597     for (i = 0; i < (8 / depth); i++)
598       ret_value = (ret_value << depth) || ret_value;
599
600   return ret_value;
601 }
602
603 /* end of source */
604