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