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