(root)/
libpng-1.6.40/
contrib/
gregbook/
readpng.c
       1  /*---------------------------------------------------------------------------
       2  
       3     rpng - simple PNG display program                              readpng.c
       4  
       5    ---------------------------------------------------------------------------
       6  
       7        Copyright (c) 1998-2007,2017 Greg Roelofs.  All rights reserved.
       8  
       9        This software is provided "as is," without warranty of any kind,
      10        express or implied.  In no event shall the author or contributors
      11        be held liable for any damages arising in any way from the use of
      12        this software.
      13  
      14        The contents of this file are DUAL-LICENSED.  You may modify and/or
      15        redistribute this software according to the terms of one of the
      16        following two licenses (at your option):
      17  
      18  
      19        LICENSE 1 ("BSD-like with advertising clause"):
      20  
      21        Permission is granted to anyone to use this software for any purpose,
      22        including commercial applications, and to alter it and redistribute
      23        it freely, subject to the following restrictions:
      24  
      25        1. Redistributions of source code must retain the above copyright
      26           notice, disclaimer, and this list of conditions.
      27        2. Redistributions in binary form must reproduce the above copyright
      28           notice, disclaimer, and this list of conditions in the documenta-
      29           tion and/or other materials provided with the distribution.
      30        3. All advertising materials mentioning features or use of this
      31           software must display the following acknowledgment:
      32  
      33              This product includes software developed by Greg Roelofs
      34              and contributors for the book, "PNG: The Definitive Guide,"
      35              published by O'Reilly and Associates.
      36  
      37  
      38        LICENSE 2 (GNU GPL v2 or later):
      39  
      40        This program is free software; you can redistribute it and/or modify
      41        it under the terms of the GNU General Public License as published by
      42        the Free Software Foundation; either version 2 of the License, or
      43        (at your option) any later version.
      44  
      45        This program is distributed in the hope that it will be useful,
      46        but WITHOUT ANY WARRANTY; without even the implied warranty of
      47        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      48        GNU General Public License for more details.
      49  
      50        You should have received a copy of the GNU General Public License
      51        along with this program; if not, write to the Free Software Foundation,
      52        Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
      53  
      54    ---------------------------------------------------------------------------*/
      55  
      56  #include <stdio.h>
      57  #include <stdlib.h>
      58  #include <zlib.h>
      59  
      60  #include "png.h"        /* libpng header */
      61  #include "readpng.h"    /* typedefs, common macros, public prototypes */
      62  
      63  /* future versions of libpng will provide this macro: */
      64  #ifndef png_jmpbuf
      65  #  define png_jmpbuf(png_ptr)   ((png_ptr)->jmpbuf)
      66  #endif
      67  
      68  
      69  static png_structp png_ptr = NULL;
      70  static png_infop info_ptr = NULL;
      71  
      72  png_uint_32  width, height;
      73  int  bit_depth, color_type;
      74  uch  *image_data = NULL;
      75  
      76  
      77  void readpng_version_info(void)
      78  {
      79      fprintf(stderr, "   Compiled with libpng %s; using libpng %s.\n",
      80        PNG_LIBPNG_VER_STRING, png_libpng_ver);
      81      fprintf(stderr, "   Compiled with zlib %s; using zlib %s.\n",
      82        ZLIB_VERSION, zlib_version);
      83  }
      84  
      85  
      86  /* return value = 0 for success, 1 for bad sig, 2 for bad IHDR, 4 for no mem */
      87  
      88  int readpng_init(FILE *infile, ulg *pWidth, ulg *pHeight)
      89  {
      90      uch sig[8];
      91  
      92  
      93      /* first do a quick check that the file really is a PNG image; could
      94       * have used slightly more general png_sig_cmp() function instead */
      95  
      96      fread(sig, 1, 8, infile);
      97      if (png_sig_cmp(sig, 0, 8))
      98          return 1;   /* bad signature */
      99  
     100  
     101      /* could pass pointers to user-defined error handlers instead of NULLs: */
     102  
     103      png_ptr = png_create_read_struct(png_get_libpng_ver(NULL), NULL, NULL,
     104          NULL);
     105      if (!png_ptr)
     106          return 4;   /* out of memory */
     107  
     108      info_ptr = png_create_info_struct(png_ptr);
     109      if (!info_ptr) {
     110          png_destroy_read_struct(&png_ptr, NULL, NULL);
     111          return 4;   /* out of memory */
     112      }
     113  
     114  
     115      /* we could create a second info struct here (end_info), but it's only
     116       * useful if we want to keep pre- and post-IDAT chunk info separated
     117       * (mainly for PNG-aware image editors and converters) */
     118  
     119  
     120      /* setjmp() must be called in every function that calls a PNG-reading
     121       * libpng function */
     122  
     123      if (setjmp(png_jmpbuf(png_ptr))) {
     124          png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
     125          return 2;
     126      }
     127  
     128  
     129      png_init_io(png_ptr, infile);
     130      png_set_sig_bytes(png_ptr, 8);  /* we already read the 8 signature bytes */
     131  
     132      png_read_info(png_ptr, info_ptr);  /* read all PNG info up to image data */
     133  
     134  
     135      /* alternatively, could make separate calls to png_get_image_width(),
     136       * etc., but want bit_depth and color_type for later [don't care about
     137       * compression_type and filter_type => NULLs] */
     138  
     139      png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
     140        NULL, NULL, NULL);
     141      *pWidth = width;
     142      *pHeight = height;
     143  
     144  
     145      /* OK, that's all we need for now; return happy */
     146  
     147      return 0;
     148  }
     149  
     150  
     151  
     152  
     153  /* returns 0 if succeeds, 1 if fails due to no bKGD chunk, 2 if libpng error;
     154   * scales values to 8-bit if necessary */
     155  
     156  int readpng_get_bgcolor(uch *red, uch *green, uch *blue)
     157  {
     158      png_color_16p pBackground;
     159  
     160  
     161      /* setjmp() must be called in every function that calls a PNG-reading
     162       * libpng function */
     163  
     164      if (setjmp(png_jmpbuf(png_ptr))) {
     165          png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
     166          return 2;
     167      }
     168  
     169  
     170      if (!png_get_valid(png_ptr, info_ptr, PNG_INFO_bKGD))
     171          return 1;
     172  
     173      /* it is not obvious from the libpng documentation, but this function
     174       * takes a pointer to a pointer, and it always returns valid red, green
     175       * and blue values, regardless of color_type: */
     176  
     177      png_get_bKGD(png_ptr, info_ptr, &pBackground);
     178  
     179  
     180      /* however, it always returns the raw bKGD data, regardless of any
     181       * bit-depth transformations, so check depth and adjust if necessary */
     182  
     183      if (bit_depth == 16) {
     184          *red   = pBackground->red   >> 8;
     185          *green = pBackground->green >> 8;
     186          *blue  = pBackground->blue  >> 8;
     187      } else if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) {
     188          if (bit_depth == 1)
     189              *red = *green = *blue = pBackground->gray? 255 : 0;
     190          else if (bit_depth == 2)
     191              *red = *green = *blue = (255/3) * pBackground->gray;
     192          else /* bit_depth == 4 */
     193              *red = *green = *blue = (255/15) * pBackground->gray;
     194      } else {
     195          *red   = (uch)pBackground->red;
     196          *green = (uch)pBackground->green;
     197          *blue  = (uch)pBackground->blue;
     198      }
     199  
     200      return 0;
     201  }
     202  
     203  
     204  
     205  
     206  /* display_exponent == LUT_exponent * CRT_exponent */
     207  
     208  uch *readpng_get_image(double display_exponent, int *pChannels, ulg *pRowbytes)
     209  {
     210      double  gamma;
     211      png_uint_32  i, rowbytes;
     212      png_bytepp  row_pointers = NULL;
     213  
     214  
     215      /* setjmp() must be called in every function that calls a PNG-reading
     216       * libpng function */
     217  
     218      if (setjmp(png_jmpbuf(png_ptr))) {
     219          free(image_data);
     220          image_data = NULL;
     221          free(row_pointers);
     222          row_pointers = NULL;
     223          png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
     224          return NULL;
     225      }
     226  
     227  
     228      /* expand palette images to RGB, low-bit-depth grayscale images to 8 bits,
     229       * transparency chunks to full alpha channel; strip 16-bit-per-sample
     230       * images to 8 bits per sample; and convert grayscale to RGB[A] */
     231  
     232      if (color_type == PNG_COLOR_TYPE_PALETTE)
     233          png_set_expand(png_ptr);
     234      if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
     235          png_set_expand(png_ptr);
     236      if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
     237          png_set_expand(png_ptr);
     238  #ifdef PNG_READ_16_TO_8_SUPPORTED
     239      if (bit_depth == 16)
     240  #  ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED
     241          png_set_scale_16(png_ptr);
     242  #  else
     243          png_set_strip_16(png_ptr);
     244  #  endif
     245  #endif
     246      if (color_type == PNG_COLOR_TYPE_GRAY ||
     247          color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
     248          png_set_gray_to_rgb(png_ptr);
     249  
     250  
     251      /* unlike the example in the libpng documentation, we have *no* idea where
     252       * this file may have come from--so if it doesn't have a file gamma, don't
     253       * do any correction ("do no harm") */
     254  
     255      if (png_get_gAMA(png_ptr, info_ptr, &gamma))
     256          png_set_gamma(png_ptr, display_exponent, gamma);
     257  
     258  
     259      /* all transformations have been registered; now update info_ptr data,
     260       * get rowbytes and channels, and allocate image memory */
     261  
     262      png_read_update_info(png_ptr, info_ptr);
     263  
     264      *pRowbytes = rowbytes = png_get_rowbytes(png_ptr, info_ptr);
     265      *pChannels = (int)png_get_channels(png_ptr, info_ptr);
     266  
     267      /* Guard against integer overflow */
     268      if (height > ((size_t)(-1))/rowbytes) {
     269          fprintf(stderr, "readpng:  image_data buffer would be too large\n",
     270          return NULL;
     271      }
     272  
     273      if ((image_data = (uch *)malloc(rowbytes*height)) == NULL) {
     274          png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
     275          return NULL;
     276      }
     277      if ((row_pointers = (png_bytepp)malloc(height*sizeof(png_bytep))) == NULL) {
     278          png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
     279          free(image_data);
     280          image_data = NULL;
     281          return NULL;
     282      }
     283  
     284      Trace((stderr, "readpng_get_image:  channels = %d, rowbytes = %ld, height = %ld\n",
     285          *pChannels, rowbytes, height));
     286  
     287  
     288      /* set the individual row_pointers to point at the correct offsets */
     289  
     290      for (i = 0;  i < height;  ++i)
     291          row_pointers[i] = image_data + i*rowbytes;
     292  
     293  
     294      /* now we can go ahead and just read the whole image */
     295  
     296      png_read_image(png_ptr, row_pointers);
     297  
     298  
     299      /* and we're done!  (png_read_end() can be omitted if no processing of
     300       * post-IDAT text/time/etc. is desired) */
     301  
     302      free(row_pointers);
     303      row_pointers = NULL;
     304  
     305      png_read_end(png_ptr, NULL);
     306  
     307      return image_data;
     308  }
     309  
     310  
     311  void readpng_cleanup(int free_image_data)
     312  {
     313      if (free_image_data && image_data) {
     314          free(image_data);
     315          image_data = NULL;
     316      }
     317  
     318      if (png_ptr && info_ptr) {
     319          png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
     320          png_ptr = NULL;
     321          info_ptr = NULL;
     322      }
     323  }