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 
     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 
    534