Home | History | Annotate | Download | only in pngminus
      1 /*
      2  *  png2pnm.c --- conversion from PNG-file to PGM/PPM-file
      3  *  copyright (C) 1999 by Willem van Schaik <willem (at) 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 #ifdef __TURBOC__
     34 #define STDIN  0
     35 #define STDOUT 1
     36 #define STDERR 2
     37 #endif
     38 
     39 /* to make png2pnm verbose so we can find problems (needs to be before png.h) */
     40 #ifndef PNG_DEBUG
     41 #define PNG_DEBUG 0
     42 #endif
     43 
     44 #include "png.h"
     45 
     46 /* Define png_jmpbuf() in case we are using a pre-1.0.6 version of libpng */
     47 #ifndef png_jmpbuf
     48 #  define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf)
     49 #endif
     50 
     51 /* function prototypes */
     52 
     53 int  main (int argc, char *argv[]);
     54 void usage ();
     55 BOOL png2pnm (FILE *png_file, FILE *pnm_file, FILE *alpha_file, BOOL raw, BOOL alpha);
     56 
     57 /*
     58  *  main
     59  */
     60 
     61 int main(int argc, char *argv[])
     62 {
     63   FILE *fp_rd = stdin;
     64   FILE *fp_wr = stdout;
     65   FILE *fp_al = NULL;
     66   BOOL raw = TRUE;
     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 'n':
     77           raw = FALSE;
     78           break;
     79         case 'r':
     80           raw = TRUE;
     81           break;
     82         case 'a':
     83           alpha = TRUE;
     84           argi++;
     85           if ((fp_al = fopen (argv[argi], "wb")) == NULL)
     86           {
     87             fprintf (stderr, "PNM2PNG\n");
     88             fprintf (stderr, "Error:  can not create alpha-channel file %s\n", 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, "PNG2PNM\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, "PNG2PNM\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, "PNG2PNM\n");
    119         fprintf (stderr, "Error:  can not create file %s\n", argv[argi]);
    120         exit (1);
    121       }
    122     }
    123     else
    124     {
    125       fprintf (stderr, "PNG2PNM\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 if required to binary */
    134   if (fp_rd == stdin)
    135   {
    136     setmode (STDIN, O_BINARY);
    137   }
    138   if ((raw) && (fp_wr == stdout))
    139   {
    140     setmode (STDOUT, O_BINARY);
    141   }
    142 #endif
    143 
    144   /* call the conversion program itself */
    145   if (png2pnm (fp_rd, fp_wr, fp_al, raw, alpha) == FALSE)
    146   {
    147     fprintf (stderr, "PNG2PNM\n");
    148     fprintf (stderr, "Error:  unsuccessful conversion of 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, "PNG2PNM\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:  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");
    183 }
    184 
    185 /*
    186  *  png2pnm
    187  */
    188 
    189 BOOL png2pnm (FILE *png_file, FILE *pnm_file, FILE *alpha_file, BOOL raw, BOOL alpha)
    190 {
    191   png_struct    *png_ptr = NULL;
    192   png_info        *info_ptr = NULL;
    193   png_byte      buf[8];
    194   png_byte      *png_pixels = NULL;
    195   png_byte      **row_pointers = NULL;
    196   png_byte      *pix_ptr = NULL;
    197   png_uint_32   row_bytes;
    198 
    199   png_uint_32   width;
    200   png_uint_32   height;
    201   int           bit_depth;
    202   int           channels;
    203   int           color_type;
    204   int           alpha_present;
    205   int           row, col;
    206   int           ret;
    207   int           i;
    208   long          dep_16;
    209 
    210   /* read and check signature in PNG file */
    211   ret = fread (buf, 1, 8, png_file);
    212   if (ret != 8)
    213     return FALSE;
    214 
    215   ret = png_sig_cmp (buf, 0, 8);
    216   if (ret)
    217     return FALSE;
    218 
    219   /* create png and info structures */
    220 
    221   png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING,
    222     NULL, NULL, NULL);
    223   if (!png_ptr)
    224     return FALSE;   /* out of memory */
    225 
    226   info_ptr = png_create_info_struct (png_ptr);
    227   if (!info_ptr)
    228   {
    229     png_destroy_read_struct (&png_ptr, NULL, NULL);
    230     return FALSE;   /* out of memory */
    231   }
    232 
    233   if (setjmp (png_jmpbuf(png_ptr)))
    234   {
    235     png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
    236     return FALSE;
    237   }
    238 
    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 */
    242 
    243   /* read the file information */
    244   png_read_info (png_ptr, info_ptr);
    245 
    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,
    249     NULL, NULL, NULL);
    250 
    251   /* set-up the transformations */
    252 
    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);
    262 
    263 #ifdef NJET
    264   /* downgrade 16-bit images to 8 bit */
    265   if (bit_depth == 16)
    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);
    274 #endif
    275 
    276   /* all transformations have been registered; now update info_ptr data,
    277    * get rowbytes and channels, and allocate image memory */
    278 
    279   png_read_update_info (png_ptr, info_ptr);
    280 
    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,
    283     NULL, NULL, NULL);
    284 
    285   /* check for 16-bit files */
    286   if (bit_depth == 16)
    287   {
    288     raw = FALSE;
    289 #ifdef __TURBOC__
    290     pnm_file->flags &= ~((unsigned) _F_BIN);
    291 #endif
    292   }
    293 
    294   /* calculate new number of channels and store alpha-presence */
    295   if (color_type == PNG_COLOR_TYPE_GRAY)
    296     channels = 1;
    297   else if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
    298     channels = 2;
    299   else if (color_type == PNG_COLOR_TYPE_RGB)
    300     channels = 3;
    301   else if (color_type == PNG_COLOR_TYPE_RGB_ALPHA)
    302     channels = 4;
    303   else
    304     channels = 0; /* should never happen */
    305   alpha_present = (channels - 1) % 2;
    306 
    307   /* check if alpha is expected to be present in file */
    308   if (alpha && !alpha_present)
    309   {
    310     fprintf (stderr, "PNG2PNM\n");
    311     fprintf (stderr, "Error:  PNG-file doesn't contain alpha channel\n");
    312     exit (1);
    313   }
    314 
    315   /* row_bytes is the width x number of channels x (bit-depth / 8) */
    316   row_bytes = png_get_rowbytes (png_ptr, info_ptr);
    317 
    318   if ((png_pixels = (png_byte *) malloc (row_bytes * height * sizeof (png_byte))) == NULL) {
    319     png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
    320     return FALSE;
    321   }
    322 
    323   if ((row_pointers = (png_byte **) malloc (height * sizeof (png_bytep))) == NULL)
    324   {
    325     png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
    326     free (png_pixels);
    327     png_pixels = NULL;
    328     return FALSE;
    329   }
    330 
    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;
    334 
    335   /* now we can go ahead and just read the whole image */
    336   png_read_image (png_ptr, row_pointers);
    337 
    338   /* read rest of file, and get additional chunks in info_ptr - REQUIRED */
    339   png_read_end (png_ptr, info_ptr);
    340 
    341   /* clean up after the read, and free any memory allocated - REQUIRED */
    342   png_destroy_read_struct (&png_ptr, &info_ptr, (png_infopp) NULL);
    343 
    344   /* write header of PNM file */
    345 
    346   if ((color_type == PNG_COLOR_TYPE_GRAY) ||
    347       (color_type == PNG_COLOR_TYPE_GRAY_ALPHA))
    348   {
    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));
    352   }
    353   else if ((color_type == PNG_COLOR_TYPE_RGB) ||
    354            (color_type == PNG_COLOR_TYPE_RGB_ALPHA))
    355   {
    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));
    359   }
    360 
    361   /* write header of PGM file with alpha channel */
    362 
    363   if ((alpha) &&
    364       ((color_type == PNG_COLOR_TYPE_GRAY_ALPHA) ||
    365        (color_type == PNG_COLOR_TYPE_RGB_ALPHA)))
    366   {
    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));
    370   }
    371 
    372   /* write data to PNM file */
    373   pix_ptr = png_pixels;
    374 
    375   for (row = 0; row < height; row++)
    376   {
    377     for (col = 0; col < width; col++)
    378     {
    379       for (i = 0; i < (channels - alpha_present); i++)
    380       {
    381         if (raw)
    382           fputc ((int) *pix_ptr++ , pnm_file);
    383         else
    384           if (bit_depth == 16){
    385             dep_16 = (long) *pix_ptr++;
    386             fprintf (pnm_file, "%ld ", (dep_16 << 8) + ((long) *pix_ptr++));
    387           }
    388           else
    389             fprintf (pnm_file, "%ld ", (long) *pix_ptr++);
    390       }
    391       if (alpha_present)
    392       {
    393         if (!alpha)
    394         {
    395           pix_ptr++; /* alpha */
    396           if (bit_depth == 16)
    397             pix_ptr++;
    398         }
    399         else /* output alpha-channel as pgm file */
    400         {
    401           if (raw)
    402             fputc ((int) *pix_ptr++ , alpha_file);
    403           else
    404             if (bit_depth == 16){
    405               dep_16 = (long) *pix_ptr++;
    406               fprintf (alpha_file, "%ld ", (dep_16 << 8) + (long) *pix_ptr++);
    407             }
    408             else
    409               fprintf (alpha_file, "%ld ", (long) *pix_ptr++);
    410         }
    411       } /* if alpha_present */
    412 
    413       if (!raw)
    414         if (col % 4 == 3)
    415           fprintf (pnm_file, "\n");
    416     } /* end for col */
    417 
    418     if (!raw)
    419       if (col % 4 != 0)
    420         fprintf (pnm_file, "\n");
    421   } /* end for row */
    422 
    423   if (row_pointers != (unsigned char**) NULL)
    424     free (row_pointers);
    425   if (png_pixels != (unsigned char*) NULL)
    426     free (png_pixels);
    427 
    428   return TRUE;
    429 
    430 } /* end of source */
    431 
    432