(root)/
libpng-1.6.40/
contrib/
pngminus/
png2pnm.c
       1  /*
       2   *  png2pnm.c --- conversion from PNG-file to PGM/PPM-file
       3   *  copyright (C) 1999-2019 by Willem van Schaik <willem at schaik dot com>
       4   *
       5   *  This software is released under the MIT license. For conditions of
       6   *  distribution and use, see the LICENSE file part of this package.
       7   */
       8  
       9  #include <stdio.h>
      10  #include <stdlib.h>
      11  #include <fcntl.h>
      12  
      13  #ifndef BOOL
      14  #define BOOL unsigned char
      15  #endif
      16  #ifndef TRUE
      17  #define TRUE (BOOL) 1
      18  #endif
      19  #ifndef FALSE
      20  #define FALSE (BOOL) 0
      21  #endif
      22  
      23  /* make png2pnm verbose so we can find problems (needs to be before png.h) */
      24  #ifndef PNG_DEBUG
      25  #define PNG_DEBUG 0
      26  #endif
      27  
      28  #include "png.h"
      29  
      30  /* function prototypes */
      31  
      32  int main (int argc, char *argv[]);
      33  void usage ();
      34  BOOL png2pnm (FILE *png_file, FILE *pnm_file, FILE *alpha_file,
      35                BOOL raw, BOOL alpha);
      36  
      37  /*
      38   *  main
      39   */
      40  
      41  int main (int argc, char *argv[])
      42  {
      43    FILE *fp_rd = stdin;
      44    FILE *fp_wr = stdout;
      45    FILE *fp_al = NULL;
      46    BOOL raw = TRUE;
      47    BOOL alpha = FALSE;
      48    int argi;
      49  
      50    for (argi = 1; argi < argc; argi++)
      51    {
      52      if (argv[argi][0] == '-')
      53      {
      54        switch (argv[argi][1])
      55        {
      56          case 'n':
      57            raw = FALSE;
      58            break;
      59          case 'r':
      60            raw = TRUE;
      61            break;
      62          case 'a':
      63            alpha = TRUE;
      64            argi++;
      65            if ((fp_al = fopen (argv[argi], "wb")) == NULL)
      66            {
      67              fprintf (stderr, "PNM2PNG\n");
      68              fprintf (stderr, "Error:  cannot create alpha-channel file %s\n",
      69                       argv[argi]);
      70              exit (1);
      71            }
      72            break;
      73          case 'h':
      74          case '?':
      75            usage ();
      76            exit (0);
      77            break;
      78          default:
      79            fprintf (stderr, "PNG2PNM\n");
      80            fprintf (stderr, "Error:  unknown option %s\n", argv[argi]);
      81            usage ();
      82            exit (1);
      83            break;
      84        } /* end switch */
      85      }
      86      else if (fp_rd == stdin)
      87      {
      88        if ((fp_rd = fopen (argv[argi], "rb")) == NULL)
      89        {
      90          fprintf (stderr, "PNG2PNM\n");
      91          fprintf (stderr, "Error:  file %s does not exist\n", argv[argi]);
      92          exit (1);
      93        }
      94      }
      95      else if (fp_wr == stdout)
      96      {
      97        if ((fp_wr = fopen (argv[argi], "wb")) == NULL)
      98        {
      99          fprintf (stderr, "PNG2PNM\n");
     100          fprintf (stderr, "Error:  cannot create file %s\n", argv[argi]);
     101          exit (1);
     102        }
     103      }
     104      else
     105      {
     106        fprintf (stderr, "PNG2PNM\n");
     107        fprintf (stderr, "Error:  too many parameters\n");
     108        usage ();
     109        exit (1);
     110      }
     111    } /* end for */
     112  
     113  #if defined(O_BINARY) && (O_BINARY != 0)
     114    /* set stdin/stdout if required to binary */
     115    if (fp_rd == stdin)
     116      setmode (fileno (stdin), O_BINARY);
     117    if ((raw) && (fp_wr == stdout))
     118      setmode (fileno (stdout), O_BINARY);
     119  #endif
     120  
     121    /* call the conversion program itself */
     122    if (png2pnm (fp_rd, fp_wr, fp_al, raw, alpha) == FALSE)
     123    {
     124      fprintf (stderr, "PNG2PNM\n");
     125      fprintf (stderr, "Error:  unsuccessful conversion of PNG-image\n");
     126      exit (1);
     127    }
     128  
     129    /* close input file */
     130    fclose (fp_rd);
     131    /* close output file */
     132    fclose (fp_wr);
     133    /* close alpha file */
     134    if (alpha)
     135      fclose (fp_al);
     136  
     137    return 0;
     138  }
     139  
     140  /*
     141   *  usage
     142   */
     143  
     144  void usage ()
     145  {
     146    fprintf (stderr, "PNG2PNM\n");
     147    fprintf (stderr, "   by Willem van Schaik, 1999\n");
     148    fprintf (stderr, "Usage:  png2pnm [options] <file>.png [<file>.pnm]\n");
     149    fprintf (stderr, "   or:  ... | png2pnm [options]\n");
     150    fprintf (stderr, "Options:\n");
     151    fprintf (stderr,
     152        "   -r[aw]   write pnm-file in binary format (P4/P5/P6) (default)\n");
     153    fprintf (stderr, "   -n[oraw] write pnm-file in ascii format (P1/P2/P3)\n");
     154    fprintf (stderr,
     155        "   -a[lpha] <file>.pgm write PNG alpha channel as pgm-file\n");
     156    fprintf (stderr, "   -h | -?  print this help-information\n");
     157  }
     158  
     159  /*
     160   *  png2pnm
     161   */
     162  
     163  BOOL png2pnm (FILE *png_file, FILE *pnm_file, FILE *alpha_file,
     164                BOOL raw, BOOL alpha)
     165  {
     166    png_struct    *png_ptr = NULL;
     167    png_info      *info_ptr = NULL;
     168    png_byte      buf[8];
     169    png_byte      *png_pixels = NULL;
     170    png_byte      **row_pointers = NULL;
     171    png_byte      *pix_ptr = NULL;
     172    png_uint_32   row_bytes;
     173  
     174    png_uint_32   width;
     175    png_uint_32   height;
     176    int           bit_depth;
     177    int           channels;
     178    int           color_type;
     179    int           alpha_present;
     180    int           row, col;
     181    int           ret;
     182    int           i;
     183    long          dep_16;
     184  
     185    /* read and check signature in PNG file */
     186    ret = fread (buf, 1, 8, png_file);
     187    if (ret != 8)
     188      return FALSE;
     189  
     190    ret = png_sig_cmp (buf, 0, 8);
     191    if (ret != 0)
     192      return FALSE;
     193  
     194    /* create png and info structures */
     195  
     196    png_ptr = png_create_read_struct (png_get_libpng_ver(NULL),
     197                                      NULL, NULL, NULL);
     198    if (!png_ptr)
     199      return FALSE; /* out of memory */
     200  
     201    info_ptr = png_create_info_struct (png_ptr);
     202    if (!info_ptr)
     203    {
     204      png_destroy_read_struct (&png_ptr, NULL, NULL);
     205      return FALSE; /* out of memory */
     206    }
     207  
     208    if (setjmp (png_jmpbuf (png_ptr)))
     209    {
     210      png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
     211      return FALSE;
     212    }
     213  
     214    /* set up the input control for C streams */
     215    png_init_io (png_ptr, png_file);
     216    png_set_sig_bytes (png_ptr, 8); /* we already read the 8 signature bytes */
     217  
     218    /* read the file information */
     219    png_read_info (png_ptr, info_ptr);
     220  
     221    /* get size and bit-depth of the PNG-image */
     222    png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
     223                  NULL, NULL, NULL);
     224  
     225    /* set-up the transformations */
     226  
     227    /* transform paletted images into full-color rgb */
     228    if (color_type == PNG_COLOR_TYPE_PALETTE)
     229      png_set_expand (png_ptr);
     230    /* expand images to bit-depth 8 (only applicable for grayscale images) */
     231    if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
     232      png_set_expand (png_ptr);
     233    /* transform transparency maps into full alpha-channel */
     234    if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS))
     235      png_set_expand (png_ptr);
     236  
     237  #ifdef NJET
     238    /* downgrade 16-bit images to 8-bit */
     239    if (bit_depth == 16)
     240      png_set_strip_16 (png_ptr);
     241    /* transform grayscale images into full-color */
     242    if (color_type == PNG_COLOR_TYPE_GRAY ||
     243        color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
     244      png_set_gray_to_rgb (png_ptr);
     245    /* only if file has a file gamma, we do a correction */
     246    if (png_get_gAMA (png_ptr, info_ptr, &file_gamma))
     247      png_set_gamma (png_ptr, (double) 2.2, file_gamma);
     248  #endif
     249  
     250    /* all transformations have been registered; now update info_ptr data,
     251     * get rowbytes and channels, and allocate image memory */
     252  
     253    png_read_update_info (png_ptr, info_ptr);
     254  
     255    /* get the new color-type and bit-depth (after expansion/stripping) */
     256    png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
     257                  NULL, NULL, NULL);
     258  
     259    /* check for 16-bit files */
     260    if (bit_depth == 16)
     261    {
     262      raw = FALSE;
     263  #if defined(O_BINARY) && (O_BINARY != 0)
     264      setmode (fileno (pnm_file), O_BINARY);
     265  #endif
     266    }
     267  
     268    /* calculate new number of channels and store alpha-presence */
     269    if (color_type == PNG_COLOR_TYPE_GRAY)
     270      channels = 1;
     271    else if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
     272      channels = 2;
     273    else if (color_type == PNG_COLOR_TYPE_RGB)
     274      channels = 3;
     275    else if (color_type == PNG_COLOR_TYPE_RGB_ALPHA)
     276      channels = 4;
     277    else
     278      channels = 0; /* should never happen */
     279    alpha_present = (channels - 1) % 2;
     280  
     281    /* check if alpha is expected to be present in file */
     282    if (alpha && !alpha_present)
     283    {
     284      fprintf (stderr, "PNG2PNM\n");
     285      fprintf (stderr, "Error:  PNG-file doesn't contain alpha channel\n");
     286      exit (1);
     287    }
     288  
     289    /* row_bytes is the width x number of channels x (bit-depth / 8) */
     290    row_bytes = png_get_rowbytes (png_ptr, info_ptr);
     291  
     292    if ((row_bytes == 0) ||
     293        ((size_t) height > (size_t) (-1) / (size_t) row_bytes))
     294    {
     295      /* too big */
     296      png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
     297      return FALSE;
     298    }
     299    if ((png_pixels = (png_byte *)
     300         malloc ((size_t) row_bytes * (size_t) height)) == NULL)
     301    {
     302      png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
     303      return FALSE;
     304    }
     305  
     306    if ((row_pointers = (png_byte **)
     307         malloc ((size_t) height * sizeof (png_byte *))) == NULL)
     308    {
     309      png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
     310      free (png_pixels);
     311      return FALSE;
     312    }
     313  
     314    /* set the individual row_pointers to point at the correct offsets */
     315    for (i = 0; i < ((int) height); i++)
     316      row_pointers[i] = png_pixels + i * row_bytes;
     317  
     318    /* now we can go ahead and just read the whole image */
     319    png_read_image (png_ptr, row_pointers);
     320  
     321    /* read rest of file, and get additional chunks in info_ptr - REQUIRED */
     322    png_read_end (png_ptr, info_ptr);
     323  
     324    /* clean up after the read, and free any memory allocated - REQUIRED */
     325    png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
     326  
     327    /* write header of PNM file */
     328  
     329    if ((color_type == PNG_COLOR_TYPE_GRAY) ||
     330        (color_type == PNG_COLOR_TYPE_GRAY_ALPHA))
     331    {
     332      fprintf (pnm_file, "%s\n", (raw) ? "P5" : "P2");
     333      fprintf (pnm_file, "%d %d\n", (int) width, (int) height);
     334      fprintf (pnm_file, "%ld\n", ((1L << (int) bit_depth) - 1L));
     335    }
     336    else if ((color_type == PNG_COLOR_TYPE_RGB) ||
     337             (color_type == PNG_COLOR_TYPE_RGB_ALPHA))
     338    {
     339      fprintf (pnm_file, "%s\n", (raw) ? "P6" : "P3");
     340      fprintf (pnm_file, "%d %d\n", (int) width, (int) height);
     341      fprintf (pnm_file, "%ld\n", ((1L << (int) bit_depth) - 1L));
     342    }
     343  
     344    /* write header of PGM file with alpha channel */
     345  
     346    if ((alpha) &&
     347        ((color_type == PNG_COLOR_TYPE_GRAY_ALPHA) ||
     348         (color_type == PNG_COLOR_TYPE_RGB_ALPHA)))
     349    {
     350      fprintf (alpha_file, "%s\n", (raw) ? "P5" : "P2");
     351      fprintf (alpha_file, "%d %d\n", (int) width, (int) height);
     352      fprintf (alpha_file, "%ld\n", ((1L << (int) bit_depth) - 1L));
     353    }
     354  
     355    /* write data to PNM file */
     356    pix_ptr = png_pixels;
     357  
     358    for (row = 0; row < (int) height; row++)
     359    {
     360      for (col = 0; col < (int) width; col++)
     361      {
     362        for (i = 0; i < (channels - alpha_present); i++)
     363        {
     364          if (raw)
     365          {
     366            fputc ((int) *pix_ptr++, pnm_file);
     367          }
     368          else
     369          {
     370            if (bit_depth == 16)
     371            {
     372              dep_16 = (long) *pix_ptr++;
     373              fprintf (pnm_file, "%ld ", (dep_16 << 8) + ((long) *pix_ptr++));
     374            }
     375            else
     376            {
     377              fprintf (pnm_file, "%ld ", (long) *pix_ptr++);
     378            }
     379          }
     380        }
     381        if (alpha_present)
     382        {
     383          if (!alpha)
     384          {
     385            pix_ptr++; /* alpha */
     386            if (bit_depth == 16)
     387              pix_ptr++;
     388          }
     389          else /* output alpha-channel as pgm file */
     390          {
     391            if (raw)
     392            {
     393              fputc ((int) *pix_ptr++, alpha_file);
     394            }
     395            else
     396            {
     397              if (bit_depth == 16)
     398              {
     399                dep_16 = (long) *pix_ptr++;
     400                fprintf (alpha_file, "%ld ", (dep_16 << 8) + (long) *pix_ptr++);
     401              }
     402              else
     403              {
     404                fprintf (alpha_file, "%ld ", (long) *pix_ptr++);
     405              }
     406            }
     407          }
     408        } /* end if alpha_present */
     409  
     410        if (!raw)
     411          if (col % 4 == 3)
     412            fprintf (pnm_file, "\n");
     413      } /* end for col */
     414  
     415      if (!raw)
     416        if (col % 4 != 0)
     417          fprintf (pnm_file, "\n");
     418    } /* end for row */
     419  
     420    if (row_pointers != NULL)
     421      free (row_pointers);
     422    if (png_pixels != NULL)
     423      free (png_pixels);
     424  
     425    return TRUE;
     426  
     427  } /* end of source */