libpng/pngread.c
Glenn Randers-Pehrson 31aee0d0c0 [devel]
Fixed point APIs are now supported throughout (no missing APIs).
  Internal fixed point arithmetic support exists for all internal floating
    point operations.
  sCAL validates the floating point strings it is passed.
  Safe, albeit rudimentary, Watcom support is provided by PNG_API_RULE==2
  Two new APIs exist to get the number of passes without turning on the
    PNG_INTERLACE transform and to get the number of rows in the current
    pass.
  A new test program, pngvalid.c, validates the gamma code.
  Errors in the 16 bit gamma correction (overflows) have been corrected.
  cHRM chunk testing is done consistently (previously the floating point
    API bypassed it, because the test really didn't work on FP, now the test
    is performed on the actual values to be stored in the PNG file so it
    works in the FP case too.)
  Most floating point APIs now simply call the fixed point APIs after
    converting the values to the fixed point form used in the PNG file.
  The standard headers no longer include zlib.h, which is currently only
    required for pngstruct.h and can therefore be internal.
  (Patches by John Bowler)
2010-07-29 17:39:14 -05:00

1490 lines
42 KiB
C

/* pngread.c - read a PNG file
*
* Last changed in libpng 1.5.0 [July 29, 2010]
* Copyright (c) 1998-2010 Glenn Randers-Pehrson
* (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
* (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
*
* This code is released under the libpng license.
* For conditions of distribution and use, see the disclaimer
* and license in png.h
*
* This file contains routines that an application calls directly to
* read a PNG file or stream.
*/
#include "pngpriv.h"
#ifdef PNG_READ_SUPPORTED
/* Create a PNG structure for reading, and allocate any memory needed. */
png_structp PNGAPI
png_create_read_struct(png_const_charp user_png_ver, png_voidp error_ptr,
png_error_ptr error_fn, png_error_ptr warn_fn)
{
#ifdef PNG_USER_MEM_SUPPORTED
return (png_create_read_struct_2(user_png_ver, error_ptr, error_fn,
warn_fn, NULL, NULL, NULL));
}
/* Alternate create PNG structure for reading, and allocate any memory
* needed.
*/
png_structp PNGAPI
png_create_read_struct_2(png_const_charp user_png_ver, png_voidp error_ptr,
png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr,
png_malloc_ptr malloc_fn, png_free_ptr free_fn)
{
#endif /* PNG_USER_MEM_SUPPORTED */
#ifdef PNG_SETJMP_SUPPORTED
volatile
#endif
png_structp png_ptr;
volatile int png_cleanup_needed = 0;
#ifdef PNG_SETJMP_SUPPORTED
#ifdef USE_FAR_KEYWORD
jmp_buf png_jmpbuf;
#endif
#endif
int i;
png_debug(1, "in png_create_read_struct");
#ifdef PNG_USER_MEM_SUPPORTED
png_ptr = (png_structp)png_create_struct_2(PNG_STRUCT_PNG,
malloc_fn, mem_ptr);
#else
png_ptr = (png_structp)png_create_struct(PNG_STRUCT_PNG);
#endif
if (png_ptr == NULL)
return (NULL);
/* Added at libpng-1.2.6 */
#ifdef PNG_USER_LIMITS_SUPPORTED
png_ptr->user_width_max = PNG_USER_WIDTH_MAX;
png_ptr->user_height_max = PNG_USER_HEIGHT_MAX;
# ifdef PNG_USER_CHUNK_CACHE_MAX
/* Added at libpng-1.2.43 and 1.4.0 */
png_ptr->user_chunk_cache_max = PNG_USER_CHUNK_CACHE_MAX;
# endif
# ifdef PNG_SET_USER_CHUNK_MALLOC_MAX
/* Added at libpng-1.2.43 and 1.4.1 */
png_ptr->user_chunk_malloc_max = PNG_USER_CHUNK_MALLOC_MAX;
# endif
#endif
#ifdef PNG_SETJMP_SUPPORTED
/* Applications that neglect to set up their own setjmp() and then
encounter a png_error() will longjmp here. Since the jmpbuf is
then meaningless we abort instead of returning. */
#ifdef USE_FAR_KEYWORD
if (setjmp(png_jmpbuf))
#else
if (setjmp(png_jmpbuf(png_ptr))) /* Sets longjmp to match setjmp */
#endif
PNG_ABORT();
#ifdef USE_FAR_KEYWORD
png_memcpy(png_jmpbuf(png_ptr), png_jmpbuf, png_sizeof(jmp_buf));
#endif
#endif /* PNG_SETJMP_SUPPORTED */
#ifdef PNG_USER_MEM_SUPPORTED
png_set_mem_fn(png_ptr, mem_ptr, malloc_fn, free_fn);
#endif
png_set_error_fn(png_ptr, error_ptr, error_fn, warn_fn);
if (user_png_ver)
{
i = 0;
do
{
if (user_png_ver[i] != png_libpng_ver[i])
png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH;
} while (png_libpng_ver[i++]);
}
else
png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH;
if (png_ptr->flags & PNG_FLAG_LIBRARY_MISMATCH)
{
/* Libpng 0.90 and later are binary incompatible with libpng 0.89, so
* we must recompile any applications that use any older library version.
* For versions after libpng 1.0, we will be compatible, so we need
* only check the first digit.
*/
if (user_png_ver == NULL || user_png_ver[0] != png_libpng_ver[0] ||
(user_png_ver[0] == '1' && user_png_ver[2] != png_libpng_ver[2]) ||
(user_png_ver[0] == '0' && user_png_ver[2] < '9'))
{
#ifdef PNG_CONSOLE_IO_SUPPORTED
char msg[80];
if (user_png_ver)
{
png_snprintf2(msg, 80,
"Application built with libpng-%.20s"
" but running with %.20s",
user_png_ver,
png_libpng_ver);
png_warning(png_ptr, msg);
}
#else
png_warning(png_ptr,
"Incompatible libpng version in application and library");
#endif
#ifdef PNG_ERROR_NUMBERS_SUPPORTED
png_ptr->flags = 0;
#endif
png_cleanup_needed = 1;
}
}
if (!png_cleanup_needed)
{
/* Initialize zbuf - compression buffer */
png_ptr->zbuf_size = PNG_ZBUF_SIZE;
png_ptr->zbuf = (png_bytep)png_malloc_warn(png_ptr, png_ptr->zbuf_size);
if (png_ptr->zbuf == NULL)
png_cleanup_needed = 1;
}
png_ptr->zstream.zalloc = png_zalloc;
png_ptr->zstream.zfree = png_zfree;
png_ptr->zstream.opaque = (voidpf)png_ptr;
if (!png_cleanup_needed)
{
switch (inflateInit(&png_ptr->zstream))
{
case Z_OK:
break; /* Do nothing */
case Z_MEM_ERROR:
png_warning(png_ptr, "zlib memory error");
png_cleanup_needed = 1;
break;
case Z_STREAM_ERROR:
png_warning(png_ptr, "zlib stream error");
png_cleanup_needed = 1;
break;
case Z_VERSION_ERROR:
png_warning(png_ptr, "zlib version error");
png_cleanup_needed = 1;
break;
default: png_warning(png_ptr, "Unknown zlib error");
png_cleanup_needed = 1;
}
}
if (png_cleanup_needed)
{
/* Clean up PNG structure and deallocate any memory. */
png_free(png_ptr, png_ptr->zbuf);
png_ptr->zbuf = NULL;
#ifdef PNG_USER_MEM_SUPPORTED
png_destroy_struct_2((png_voidp)png_ptr,
(png_free_ptr)free_fn, (png_voidp)mem_ptr);
#else
png_destroy_struct((png_voidp)png_ptr);
#endif
return (NULL);
}
png_ptr->zstream.next_out = png_ptr->zbuf;
png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
png_set_read_fn(png_ptr, NULL, NULL);
return (png_ptr);
}
#ifdef PNG_SEQUENTIAL_READ_SUPPORTED
/* Read the information before the actual image data. This has been
* changed in v0.90 to allow reading a file that already has the magic
* bytes read from the stream. You can tell libpng how many bytes have
* been read from the beginning of the stream (up to the maximum of 8)
* via png_set_sig_bytes(), and we will only check the remaining bytes
* here. The application can then have access to the signature bytes we
* read if it is determined that this isn't a valid PNG file.
*/
void PNGAPI
png_read_info(png_structp png_ptr, png_infop info_ptr)
{
png_debug(1, "in png_read_info");
if (png_ptr == NULL || info_ptr == NULL)
return;
/* If we haven't checked all of the PNG signature bytes, do so now. */
if (png_ptr->sig_bytes < 8)
{
png_size_t num_checked = png_ptr->sig_bytes,
num_to_check = 8 - num_checked;
#ifdef PNG_IO_STATE_SUPPORTED
png_ptr->io_state = PNG_IO_READING | PNG_IO_SIGNATURE;
#endif
png_read_data(png_ptr, &(info_ptr->signature[num_checked]), num_to_check);
png_ptr->sig_bytes = 8;
if (png_sig_cmp(info_ptr->signature, num_checked, num_to_check))
{
if (num_checked < 4 &&
png_sig_cmp(info_ptr->signature, num_checked, num_to_check - 4))
png_error(png_ptr, "Not a PNG file");
else
png_error(png_ptr, "PNG file corrupted by ASCII conversion");
}
if (num_checked < 3)
png_ptr->mode |= PNG_HAVE_PNG_SIGNATURE;
}
for (;;)
{
PNG_IHDR;
PNG_IDAT;
PNG_IEND;
PNG_PLTE;
#ifdef PNG_READ_bKGD_SUPPORTED
PNG_bKGD;
#endif
#ifdef PNG_READ_cHRM_SUPPORTED
PNG_cHRM;
#endif
#ifdef PNG_READ_gAMA_SUPPORTED
PNG_gAMA;
#endif
#ifdef PNG_READ_hIST_SUPPORTED
PNG_hIST;
#endif
#ifdef PNG_READ_iCCP_SUPPORTED
PNG_iCCP;
#endif
#ifdef PNG_READ_iTXt_SUPPORTED
PNG_iTXt;
#endif
#ifdef PNG_READ_oFFs_SUPPORTED
PNG_oFFs;
#endif
#ifdef PNG_READ_pCAL_SUPPORTED
PNG_pCAL;
#endif
#ifdef PNG_READ_pHYs_SUPPORTED
PNG_pHYs;
#endif
#ifdef PNG_READ_sBIT_SUPPORTED
PNG_sBIT;
#endif
#ifdef PNG_READ_sCAL_SUPPORTED
PNG_sCAL;
#endif
#ifdef PNG_READ_sPLT_SUPPORTED
PNG_sPLT;
#endif
#ifdef PNG_READ_sRGB_SUPPORTED
PNG_sRGB;
#endif
#ifdef PNG_READ_tEXt_SUPPORTED
PNG_tEXt;
#endif
#ifdef PNG_READ_tIME_SUPPORTED
PNG_tIME;
#endif
#ifdef PNG_READ_tRNS_SUPPORTED
PNG_tRNS;
#endif
#ifdef PNG_READ_zTXt_SUPPORTED
PNG_zTXt;
#endif
png_uint_32 length = png_read_chunk_header(png_ptr);
PNG_CONST png_bytep chunk_name = png_ptr->chunk_name;
/* This should be a binary subdivision search or a hash for
* matching the chunk name rather than a linear search.
*/
if (!png_memcmp(chunk_name, png_IDAT, 4))
if (png_ptr->mode & PNG_AFTER_IDAT)
png_ptr->mode |= PNG_HAVE_CHUNK_AFTER_IDAT;
if (!png_memcmp(chunk_name, png_IHDR, 4))
png_handle_IHDR(png_ptr, info_ptr, length);
else if (!png_memcmp(chunk_name, png_IEND, 4))
png_handle_IEND(png_ptr, info_ptr, length);
#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
else if (png_handle_as_unknown(png_ptr, chunk_name))
{
if (!png_memcmp(chunk_name, png_IDAT, 4))
png_ptr->mode |= PNG_HAVE_IDAT;
png_handle_unknown(png_ptr, info_ptr, length);
if (!png_memcmp(chunk_name, png_PLTE, 4))
png_ptr->mode |= PNG_HAVE_PLTE;
else if (!png_memcmp(chunk_name, png_IDAT, 4))
{
if (!(png_ptr->mode & PNG_HAVE_IHDR))
png_error(png_ptr, "Missing IHDR before IDAT");
else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE &&
!(png_ptr->mode & PNG_HAVE_PLTE))
png_error(png_ptr, "Missing PLTE before IDAT");
break;
}
}
#endif
else if (!png_memcmp(chunk_name, png_PLTE, 4))
png_handle_PLTE(png_ptr, info_ptr, length);
else if (!png_memcmp(chunk_name, png_IDAT, 4))
{
if (!(png_ptr->mode & PNG_HAVE_IHDR))
png_error(png_ptr, "Missing IHDR before IDAT");
else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE &&
!(png_ptr->mode & PNG_HAVE_PLTE))
png_error(png_ptr, "Missing PLTE before IDAT");
png_ptr->idat_size = length;
png_ptr->mode |= PNG_HAVE_IDAT;
break;
}
#ifdef PNG_READ_bKGD_SUPPORTED
else if (!png_memcmp(chunk_name, png_bKGD, 4))
png_handle_bKGD(png_ptr, info_ptr, length);
#endif
#ifdef PNG_READ_cHRM_SUPPORTED
else if (!png_memcmp(chunk_name, png_cHRM, 4))
png_handle_cHRM(png_ptr, info_ptr, length);
#endif
#ifdef PNG_READ_gAMA_SUPPORTED
else if (!png_memcmp(chunk_name, png_gAMA, 4))
png_handle_gAMA(png_ptr, info_ptr, length);
#endif
#ifdef PNG_READ_hIST_SUPPORTED
else if (!png_memcmp(chunk_name, png_hIST, 4))
png_handle_hIST(png_ptr, info_ptr, length);
#endif
#ifdef PNG_READ_oFFs_SUPPORTED
else if (!png_memcmp(chunk_name, png_oFFs, 4))
png_handle_oFFs(png_ptr, info_ptr, length);
#endif
#ifdef PNG_READ_pCAL_SUPPORTED
else if (!png_memcmp(chunk_name, png_pCAL, 4))
png_handle_pCAL(png_ptr, info_ptr, length);
#endif
#ifdef PNG_READ_sCAL_SUPPORTED
else if (!png_memcmp(chunk_name, png_sCAL, 4))
png_handle_sCAL(png_ptr, info_ptr, length);
#endif
#ifdef PNG_READ_pHYs_SUPPORTED
else if (!png_memcmp(chunk_name, png_pHYs, 4))
png_handle_pHYs(png_ptr, info_ptr, length);
#endif
#ifdef PNG_READ_sBIT_SUPPORTED
else if (!png_memcmp(chunk_name, png_sBIT, 4))
png_handle_sBIT(png_ptr, info_ptr, length);
#endif
#ifdef PNG_READ_sRGB_SUPPORTED
else if (!png_memcmp(chunk_name, png_sRGB, 4))
png_handle_sRGB(png_ptr, info_ptr, length);
#endif
#ifdef PNG_READ_iCCP_SUPPORTED
else if (!png_memcmp(chunk_name, png_iCCP, 4))
png_handle_iCCP(png_ptr, info_ptr, length);
#endif
#ifdef PNG_READ_sPLT_SUPPORTED
else if (!png_memcmp(chunk_name, png_sPLT, 4))
png_handle_sPLT(png_ptr, info_ptr, length);
#endif
#ifdef PNG_READ_tEXt_SUPPORTED
else if (!png_memcmp(chunk_name, png_tEXt, 4))
png_handle_tEXt(png_ptr, info_ptr, length);
#endif
#ifdef PNG_READ_tIME_SUPPORTED
else if (!png_memcmp(chunk_name, png_tIME, 4))
png_handle_tIME(png_ptr, info_ptr, length);
#endif
#ifdef PNG_READ_tRNS_SUPPORTED
else if (!png_memcmp(chunk_name, png_tRNS, 4))
png_handle_tRNS(png_ptr, info_ptr, length);
#endif
#ifdef PNG_READ_zTXt_SUPPORTED
else if (!png_memcmp(chunk_name, png_zTXt, 4))
png_handle_zTXt(png_ptr, info_ptr, length);
#endif
#ifdef PNG_READ_iTXt_SUPPORTED
else if (!png_memcmp(chunk_name, png_iTXt, 4))
png_handle_iTXt(png_ptr, info_ptr, length);
#endif
else
png_handle_unknown(png_ptr, info_ptr, length);
}
}
#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */
/* Optional call to update the users info_ptr structure */
void PNGAPI
png_read_update_info(png_structp png_ptr, png_infop info_ptr)
{
png_debug(1, "in png_read_update_info");
if (png_ptr == NULL)
return;
if (!(png_ptr->flags & PNG_FLAG_ROW_INIT))
png_read_start_row(png_ptr);
else
png_warning(png_ptr,
"Ignoring extra png_read_update_info() call;"
" row buffer not reallocated");
png_read_transform_info(png_ptr, info_ptr);
}
#ifdef PNG_SEQUENTIAL_READ_SUPPORTED
/* Initialize palette, background, etc, after transformations
* are set, but before any reading takes place. This allows
* the user to obtain a gamma-corrected palette, for example.
* If the user doesn't call this, we will do it ourselves.
*/
void PNGAPI
png_start_read_image(png_structp png_ptr)
{
png_debug(1, "in png_start_read_image");
if (png_ptr == NULL)
return;
if (!(png_ptr->flags & PNG_FLAG_ROW_INIT))
png_read_start_row(png_ptr);
else
png_warning(png_ptr,
"Ignoring extra png_start_read_image() call;"
" row buffer not reallocated");
}
#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */
#ifdef PNG_SEQUENTIAL_READ_SUPPORTED
void PNGAPI
png_read_row(png_structp png_ptr, png_bytep row, png_bytep dsp_row)
{
PNG_IDAT;
PNG_CONST int png_pass_dsp_mask[7] = {0xff, 0x0f, 0xff, 0x33, 0xff, 0x55,
0xff};
PNG_CONST int png_pass_mask[7] = {0x80, 0x08, 0x88, 0x22, 0xaa, 0x55, 0xff};
int ret;
if (png_ptr == NULL)
return;
png_debug2(1, "in png_read_row (row %lu, pass %d)",
(unsigned long) png_ptr->row_number, png_ptr->pass);
if (!(png_ptr->flags & PNG_FLAG_ROW_INIT))
png_read_start_row(png_ptr);
if (png_ptr->row_number == 0 && png_ptr->pass == 0)
{
/* Check for transforms that have been set but were defined out */
#if defined(PNG_WRITE_INVERT_SUPPORTED) && !defined(PNG_READ_INVERT_SUPPORTED)
if (png_ptr->transformations & PNG_INVERT_MONO)
png_warning(png_ptr, "PNG_READ_INVERT_SUPPORTED is not defined");
#endif
#if defined(PNG_WRITE_FILLER_SUPPORTED) && !defined(PNG_READ_FILLER_SUPPORTED)
if (png_ptr->transformations & PNG_FILLER)
png_warning(png_ptr, "PNG_READ_FILLER_SUPPORTED is not defined");
#endif
#if defined(PNG_WRITE_PACKSWAP_SUPPORTED) && \
!defined(PNG_READ_PACKSWAP_SUPPORTED)
if (png_ptr->transformations & PNG_PACKSWAP)
png_warning(png_ptr, "PNG_READ_PACKSWAP_SUPPORTED is not defined");
#endif
#if defined(PNG_WRITE_PACK_SUPPORTED) && !defined(PNG_READ_PACK_SUPPORTED)
if (png_ptr->transformations & PNG_PACK)
png_warning(png_ptr, "PNG_READ_PACK_SUPPORTED is not defined");
#endif
#if defined(PNG_WRITE_SHIFT_SUPPORTED) && !defined(PNG_READ_SHIFT_SUPPORTED)
if (png_ptr->transformations & PNG_SHIFT)
png_warning(png_ptr, "PNG_READ_SHIFT_SUPPORTED is not defined");
#endif
#if defined(PNG_WRITE_BGR_SUPPORTED) && !defined(PNG_READ_BGR_SUPPORTED)
if (png_ptr->transformations & PNG_BGR)
png_warning(png_ptr, "PNG_READ_BGR_SUPPORTED is not defined");
#endif
#if defined(PNG_WRITE_SWAP_SUPPORTED) && !defined(PNG_READ_SWAP_SUPPORTED)
if (png_ptr->transformations & PNG_SWAP_BYTES)
png_warning(png_ptr, "PNG_READ_SWAP_SUPPORTED is not defined");
#endif
}
#ifdef PNG_READ_INTERLACING_SUPPORTED
/* If interlaced and we do not need a new row, combine row and return */
if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE))
{
switch (png_ptr->pass)
{
case 0:
if (png_ptr->row_number & 0x07)
{
if (dsp_row != NULL)
png_combine_row(png_ptr, dsp_row,
png_pass_dsp_mask[png_ptr->pass]);
png_read_finish_row(png_ptr);
return;
}
break;
case 1:
if ((png_ptr->row_number & 0x07) || png_ptr->width < 5)
{
if (dsp_row != NULL)
png_combine_row(png_ptr, dsp_row,
png_pass_dsp_mask[png_ptr->pass]);
png_read_finish_row(png_ptr);
return;
}
break;
case 2:
if ((png_ptr->row_number & 0x07) != 4)
{
if (dsp_row != NULL && (png_ptr->row_number & 4))
png_combine_row(png_ptr, dsp_row,
png_pass_dsp_mask[png_ptr->pass]);
png_read_finish_row(png_ptr);
return;
}
break;
case 3:
if ((png_ptr->row_number & 3) || png_ptr->width < 3)
{
if (dsp_row != NULL)
png_combine_row(png_ptr, dsp_row,
png_pass_dsp_mask[png_ptr->pass]);
png_read_finish_row(png_ptr);
return;
}
break;
case 4:
if ((png_ptr->row_number & 3) != 2)
{
if (dsp_row != NULL && (png_ptr->row_number & 2))
png_combine_row(png_ptr, dsp_row,
png_pass_dsp_mask[png_ptr->pass]);
png_read_finish_row(png_ptr);
return;
}
break;
case 5:
if ((png_ptr->row_number & 1) || png_ptr->width < 2)
{
if (dsp_row != NULL)
png_combine_row(png_ptr, dsp_row,
png_pass_dsp_mask[png_ptr->pass]);
png_read_finish_row(png_ptr);
return;
}
break;
case 6:
if (!(png_ptr->row_number & 1))
{
png_read_finish_row(png_ptr);
return;
}
break;
}
}
#endif
if (!(png_ptr->mode & PNG_HAVE_IDAT))
png_error(png_ptr, "Invalid attempt to read row data");
png_ptr->zstream.next_out = png_ptr->row_buf;
png_ptr->zstream.avail_out =
(uInt)(PNG_ROWBYTES(png_ptr->pixel_depth,
png_ptr->iwidth) + 1);
do
{
if (!(png_ptr->zstream.avail_in))
{
while (!png_ptr->idat_size)
{
png_crc_finish(png_ptr, 0);
png_ptr->idat_size = png_read_chunk_header(png_ptr);
if (png_memcmp(png_ptr->chunk_name, png_IDAT, 4))
png_error(png_ptr, "Not enough image data");
}
png_ptr->zstream.avail_in = (uInt)png_ptr->zbuf_size;
png_ptr->zstream.next_in = png_ptr->zbuf;
if (png_ptr->zbuf_size > png_ptr->idat_size)
png_ptr->zstream.avail_in = (uInt)png_ptr->idat_size;
png_crc_read(png_ptr, png_ptr->zbuf,
(png_size_t)png_ptr->zstream.avail_in);
png_ptr->idat_size -= png_ptr->zstream.avail_in;
}
ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH);
if (ret == Z_STREAM_END)
{
if (png_ptr->zstream.avail_out || png_ptr->zstream.avail_in ||
png_ptr->idat_size)
png_benign_error(png_ptr, "Extra compressed data");
png_ptr->mode |= PNG_AFTER_IDAT;
png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED;
break;
}
if (ret != Z_OK)
png_error(png_ptr, png_ptr->zstream.msg ? png_ptr->zstream.msg :
"Decompression error");
} while (png_ptr->zstream.avail_out);
png_ptr->row_info.color_type = png_ptr->color_type;
png_ptr->row_info.width = png_ptr->iwidth;
png_ptr->row_info.channels = png_ptr->channels;
png_ptr->row_info.bit_depth = png_ptr->bit_depth;
png_ptr->row_info.pixel_depth = png_ptr->pixel_depth;
png_ptr->row_info.rowbytes = PNG_ROWBYTES(png_ptr->row_info.pixel_depth,
png_ptr->row_info.width);
if (png_ptr->row_buf[0])
png_read_filter_row(png_ptr, &(png_ptr->row_info),
png_ptr->row_buf + 1, png_ptr->prev_row + 1,
(int)(png_ptr->row_buf[0]));
png_memcpy(png_ptr->prev_row, png_ptr->row_buf, png_ptr->rowbytes + 1);
#ifdef PNG_MNG_FEATURES_SUPPORTED
if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) &&
(png_ptr->filter_type == PNG_INTRAPIXEL_DIFFERENCING))
{
/* Intrapixel differencing */
png_do_read_intrapixel(&(png_ptr->row_info), png_ptr->row_buf + 1);
}
#endif
if (png_ptr->transformations || (png_ptr->flags&PNG_FLAG_STRIP_ALPHA))
png_do_read_transformations(png_ptr);
#ifdef PNG_READ_INTERLACING_SUPPORTED
/* Blow up interlaced rows to full size */
if (png_ptr->interlaced &&
(png_ptr->transformations & PNG_INTERLACE))
{
if (png_ptr->pass < 6)
/* Old interface (pre-1.0.9):
* png_do_read_interlace(&(png_ptr->row_info),
* png_ptr->row_buf + 1, png_ptr->pass, png_ptr->transformations);
*/
png_do_read_interlace(png_ptr);
if (dsp_row != NULL)
png_combine_row(png_ptr, dsp_row, png_pass_dsp_mask[png_ptr->pass]);
if (row != NULL)
png_combine_row(png_ptr, row, png_pass_mask[png_ptr->pass]);
}
else
#endif
{
if (row != NULL)
png_combine_row(png_ptr, row, 0xff);
if (dsp_row != NULL)
png_combine_row(png_ptr, dsp_row, 0xff);
}
png_read_finish_row(png_ptr);
if (png_ptr->read_row_fn != NULL)
(*(png_ptr->read_row_fn))(png_ptr, png_ptr->row_number, png_ptr->pass);
}
#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */
#ifdef PNG_SEQUENTIAL_READ_SUPPORTED
/* Read one or more rows of image data. If the image is interlaced,
* and png_set_interlace_handling() has been called, the rows need to
* contain the contents of the rows from the previous pass. If the
* image has alpha or transparency, and png_handle_alpha()[*] has been
* called, the rows contents must be initialized to the contents of the
* screen.
*
* "row" holds the actual image, and pixels are placed in it
* as they arrive. If the image is displayed after each pass, it will
* appear to "sparkle" in. "display_row" can be used to display a
* "chunky" progressive image, with finer detail added as it becomes
* available. If you do not want this "chunky" display, you may pass
* NULL for display_row. If you do not want the sparkle display, and
* you have not called png_handle_alpha(), you may pass NULL for rows.
* If you have called png_handle_alpha(), and the image has either an
* alpha channel or a transparency chunk, you must provide a buffer for
* rows. In this case, you do not have to provide a display_row buffer
* also, but you may. If the image is not interlaced, or if you have
* not called png_set_interlace_handling(), the display_row buffer will
* be ignored, so pass NULL to it.
*
* [*] png_handle_alpha() does not exist yet, as of this version of libpng
*/
void PNGAPI
png_read_rows(png_structp png_ptr, png_bytepp row,
png_bytepp display_row, png_uint_32 num_rows)
{
png_uint_32 i;
png_bytepp rp;
png_bytepp dp;
png_debug(1, "in png_read_rows");
if (png_ptr == NULL)
return;
rp = row;
dp = display_row;
if (rp != NULL && dp != NULL)
for (i = 0; i < num_rows; i++)
{
png_bytep rptr = *rp++;
png_bytep dptr = *dp++;
png_read_row(png_ptr, rptr, dptr);
}
else if (rp != NULL)
for (i = 0; i < num_rows; i++)
{
png_bytep rptr = *rp;
png_read_row(png_ptr, rptr, NULL);
rp++;
}
else if (dp != NULL)
for (i = 0; i < num_rows; i++)
{
png_bytep dptr = *dp;
png_read_row(png_ptr, NULL, dptr);
dp++;
}
}
#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */
#ifdef PNG_SEQUENTIAL_READ_SUPPORTED
/* Read the entire image. If the image has an alpha channel or a tRNS
* chunk, and you have called png_handle_alpha()[*], you will need to
* initialize the image to the current image that PNG will be overlaying.
* We set the num_rows again here, in case it was incorrectly set in
* png_read_start_row() by a call to png_read_update_info() or
* png_start_read_image() if png_set_interlace_handling() wasn't called
* prior to either of these functions like it should have been. You can
* only call this function once. If you desire to have an image for
* each pass of a interlaced image, use png_read_rows() instead.
*
* [*] png_handle_alpha() does not exist yet, as of this version of libpng
*/
void PNGAPI
png_read_image(png_structp png_ptr, png_bytepp image)
{
png_uint_32 i, image_height;
int pass, j;
png_bytepp rp;
png_debug(1, "in png_read_image");
if (png_ptr == NULL)
return;
#ifdef PNG_READ_INTERLACING_SUPPORTED
if (!(png_ptr->flags & PNG_FLAG_ROW_INIT))
{
pass = png_set_interlace_handling(png_ptr);
/* And make sure transforms are initialized. */
png_start_read_image(png_ptr);
}
else
{
if (!(png_ptr->transformations & PNG_INTERLACE))
{
/* Caller called png_start_read_image or png_read_update_info without
* first turning on the PNG_INTERLACE transform. We can fix this here,
* but the caller should do it!
*/
png_warning(png_ptr, "Interlace handling should be turned on when "
"using png_read_image");
/* Make sure this is set correctly */
png_ptr->num_rows = png_ptr->height;
}
/* Obtain the pass number, which also turns on the PNG_INTERLACE flag in
* the above error case.
*/
pass = png_set_interlace_handling(png_ptr);
}
#else
if (png_ptr->interlaced)
png_error(png_ptr,
"Cannot read interlaced image -- interlace handler disabled");
pass = 1;
#endif
image_height=png_ptr->height;
for (j = 0; j < pass; j++)
{
rp = image;
for (i = 0; i < image_height; i++)
{
png_read_row(png_ptr, *rp, NULL);
rp++;
}
}
}
#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */
#ifdef PNG_SEQUENTIAL_READ_SUPPORTED
/* Read the end of the PNG file. Will not read past the end of the
* file, will verify the end is accurate, and will read any comments
* or time information at the end of the file, if info is not NULL.
*/
void PNGAPI
png_read_end(png_structp png_ptr, png_infop info_ptr)
{
png_debug(1, "in png_read_end");
if (png_ptr == NULL)
return;
png_crc_finish(png_ptr, 0); /* Finish off CRC from last IDAT chunk */
do
{
PNG_IHDR;
PNG_IDAT;
PNG_IEND;
PNG_PLTE;
#ifdef PNG_READ_bKGD_SUPPORTED
PNG_bKGD;
#endif
#ifdef PNG_READ_cHRM_SUPPORTED
PNG_cHRM;
#endif
#ifdef PNG_READ_gAMA_SUPPORTED
PNG_gAMA;
#endif
#ifdef PNG_READ_hIST_SUPPORTED
PNG_hIST;
#endif
#ifdef PNG_READ_iCCP_SUPPORTED
PNG_iCCP;
#endif
#ifdef PNG_READ_iTXt_SUPPORTED
PNG_iTXt;
#endif
#ifdef PNG_READ_oFFs_SUPPORTED
PNG_oFFs;
#endif
#ifdef PNG_READ_pCAL_SUPPORTED
PNG_pCAL;
#endif
#ifdef PNG_READ_pHYs_SUPPORTED
PNG_pHYs;
#endif
#ifdef PNG_READ_sBIT_SUPPORTED
PNG_sBIT;
#endif
#ifdef PNG_READ_sCAL_SUPPORTED
PNG_sCAL;
#endif
#ifdef PNG_READ_sPLT_SUPPORTED
PNG_sPLT;
#endif
#ifdef PNG_READ_sRGB_SUPPORTED
PNG_sRGB;
#endif
#ifdef PNG_READ_tEXt_SUPPORTED
PNG_tEXt;
#endif
#ifdef PNG_READ_tIME_SUPPORTED
PNG_tIME;
#endif
#ifdef PNG_READ_tRNS_SUPPORTED
PNG_tRNS;
#endif
#ifdef PNG_READ_zTXt_SUPPORTED
PNG_zTXt;
#endif
png_uint_32 length = png_read_chunk_header(png_ptr);
PNG_CONST png_bytep chunk_name = png_ptr->chunk_name;
if (!png_memcmp(chunk_name, png_IHDR, 4))
png_handle_IHDR(png_ptr, info_ptr, length);
else if (!png_memcmp(chunk_name, png_IEND, 4))
png_handle_IEND(png_ptr, info_ptr, length);
#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
else if (png_handle_as_unknown(png_ptr, chunk_name))
{
if (!png_memcmp(chunk_name, png_IDAT, 4))
{
if ((length > 0) || (png_ptr->mode & PNG_HAVE_CHUNK_AFTER_IDAT))
png_benign_error(png_ptr, "Too many IDATs found");
}
png_handle_unknown(png_ptr, info_ptr, length);
if (!png_memcmp(chunk_name, png_PLTE, 4))
png_ptr->mode |= PNG_HAVE_PLTE;
}
#endif
else if (!png_memcmp(chunk_name, png_IDAT, 4))
{
/* Zero length IDATs are legal after the last IDAT has been
* read, but not after other chunks have been read.
*/
if ((length > 0) || (png_ptr->mode & PNG_HAVE_CHUNK_AFTER_IDAT))
png_benign_error(png_ptr, "Too many IDATs found");
png_crc_finish(png_ptr, length);
}
else if (!png_memcmp(chunk_name, png_PLTE, 4))
png_handle_PLTE(png_ptr, info_ptr, length);
#ifdef PNG_READ_bKGD_SUPPORTED
else if (!png_memcmp(chunk_name, png_bKGD, 4))
png_handle_bKGD(png_ptr, info_ptr, length);
#endif
#ifdef PNG_READ_cHRM_SUPPORTED
else if (!png_memcmp(chunk_name, png_cHRM, 4))
png_handle_cHRM(png_ptr, info_ptr, length);
#endif
#ifdef PNG_READ_gAMA_SUPPORTED
else if (!png_memcmp(chunk_name, png_gAMA, 4))
png_handle_gAMA(png_ptr, info_ptr, length);
#endif
#ifdef PNG_READ_hIST_SUPPORTED
else if (!png_memcmp(chunk_name, png_hIST, 4))
png_handle_hIST(png_ptr, info_ptr, length);
#endif
#ifdef PNG_READ_oFFs_SUPPORTED
else if (!png_memcmp(chunk_name, png_oFFs, 4))
png_handle_oFFs(png_ptr, info_ptr, length);
#endif
#ifdef PNG_READ_pCAL_SUPPORTED
else if (!png_memcmp(chunk_name, png_pCAL, 4))
png_handle_pCAL(png_ptr, info_ptr, length);
#endif
#ifdef PNG_READ_sCAL_SUPPORTED
else if (!png_memcmp(chunk_name, png_sCAL, 4))
png_handle_sCAL(png_ptr, info_ptr, length);
#endif
#ifdef PNG_READ_pHYs_SUPPORTED
else if (!png_memcmp(chunk_name, png_pHYs, 4))
png_handle_pHYs(png_ptr, info_ptr, length);
#endif
#ifdef PNG_READ_sBIT_SUPPORTED
else if (!png_memcmp(chunk_name, png_sBIT, 4))
png_handle_sBIT(png_ptr, info_ptr, length);
#endif
#ifdef PNG_READ_sRGB_SUPPORTED
else if (!png_memcmp(chunk_name, png_sRGB, 4))
png_handle_sRGB(png_ptr, info_ptr, length);
#endif
#ifdef PNG_READ_iCCP_SUPPORTED
else if (!png_memcmp(chunk_name, png_iCCP, 4))
png_handle_iCCP(png_ptr, info_ptr, length);
#endif
#ifdef PNG_READ_sPLT_SUPPORTED
else if (!png_memcmp(chunk_name, png_sPLT, 4))
png_handle_sPLT(png_ptr, info_ptr, length);
#endif
#ifdef PNG_READ_tEXt_SUPPORTED
else if (!png_memcmp(chunk_name, png_tEXt, 4))
png_handle_tEXt(png_ptr, info_ptr, length);
#endif
#ifdef PNG_READ_tIME_SUPPORTED
else if (!png_memcmp(chunk_name, png_tIME, 4))
png_handle_tIME(png_ptr, info_ptr, length);
#endif
#ifdef PNG_READ_tRNS_SUPPORTED
else if (!png_memcmp(chunk_name, png_tRNS, 4))
png_handle_tRNS(png_ptr, info_ptr, length);
#endif
#ifdef PNG_READ_zTXt_SUPPORTED
else if (!png_memcmp(chunk_name, png_zTXt, 4))
png_handle_zTXt(png_ptr, info_ptr, length);
#endif
#ifdef PNG_READ_iTXt_SUPPORTED
else if (!png_memcmp(chunk_name, png_iTXt, 4))
png_handle_iTXt(png_ptr, info_ptr, length);
#endif
else
png_handle_unknown(png_ptr, info_ptr, length);
} while (!(png_ptr->mode & PNG_HAVE_IEND));
}
#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */
/* Free all memory used by the read */
void PNGAPI
png_destroy_read_struct(png_structpp png_ptr_ptr, png_infopp info_ptr_ptr,
png_infopp end_info_ptr_ptr)
{
png_structp png_ptr = NULL;
png_infop info_ptr = NULL, end_info_ptr = NULL;
#ifdef PNG_USER_MEM_SUPPORTED
png_free_ptr free_fn = NULL;
png_voidp mem_ptr = NULL;
#endif
png_debug(1, "in png_destroy_read_struct");
if (png_ptr_ptr != NULL)
png_ptr = *png_ptr_ptr;
if (png_ptr == NULL)
return;
#ifdef PNG_USER_MEM_SUPPORTED
free_fn = png_ptr->free_fn;
mem_ptr = png_ptr->mem_ptr;
#endif
if (info_ptr_ptr != NULL)
info_ptr = *info_ptr_ptr;
if (end_info_ptr_ptr != NULL)
end_info_ptr = *end_info_ptr_ptr;
png_read_destroy(png_ptr, info_ptr, end_info_ptr);
if (info_ptr != NULL)
{
#ifdef PNG_TEXT_SUPPORTED
png_free_data(png_ptr, info_ptr, PNG_FREE_TEXT, -1);
#endif
#ifdef PNG_USER_MEM_SUPPORTED
png_destroy_struct_2((png_voidp)info_ptr, (png_free_ptr)free_fn,
(png_voidp)mem_ptr);
#else
png_destroy_struct((png_voidp)info_ptr);
#endif
*info_ptr_ptr = NULL;
}
if (end_info_ptr != NULL)
{
#ifdef PNG_READ_TEXT_SUPPORTED
png_free_data(png_ptr, end_info_ptr, PNG_FREE_TEXT, -1);
#endif
#ifdef PNG_USER_MEM_SUPPORTED
png_destroy_struct_2((png_voidp)end_info_ptr, (png_free_ptr)free_fn,
(png_voidp)mem_ptr);
#else
png_destroy_struct((png_voidp)end_info_ptr);
#endif
*end_info_ptr_ptr = NULL;
}
if (png_ptr != NULL)
{
#ifdef PNG_USER_MEM_SUPPORTED
png_destroy_struct_2((png_voidp)png_ptr, (png_free_ptr)free_fn,
(png_voidp)mem_ptr);
#else
png_destroy_struct((png_voidp)png_ptr);
#endif
*png_ptr_ptr = NULL;
}
}
/* Free all memory used by the read (old method) */
void /* PRIVATE */
png_read_destroy(png_structp png_ptr, png_infop info_ptr,
png_infop end_info_ptr)
{
#ifdef PNG_SETJMP_SUPPORTED
jmp_buf tmp_jmp;
#endif
png_error_ptr error_fn;
png_error_ptr warning_fn;
png_voidp error_ptr;
#ifdef PNG_USER_MEM_SUPPORTED
png_free_ptr free_fn;
#endif
png_debug(1, "in png_read_destroy");
if (info_ptr != NULL)
png_info_destroy(png_ptr, info_ptr);
if (end_info_ptr != NULL)
png_info_destroy(png_ptr, end_info_ptr);
png_free(png_ptr, png_ptr->zbuf);
png_free(png_ptr, png_ptr->big_row_buf);
png_free(png_ptr, png_ptr->prev_row);
png_free(png_ptr, png_ptr->chunkdata);
#ifdef PNG_READ_QUANTIZE_SUPPORTED
png_free(png_ptr, png_ptr->palette_lookup);
png_free(png_ptr, png_ptr->quantize_index);
#endif
#ifdef PNG_READ_GAMMA_SUPPORTED
png_free(png_ptr, png_ptr->gamma_table);
#endif
#ifdef PNG_READ_BACKGROUND_SUPPORTED
png_free(png_ptr, png_ptr->gamma_from_1);
png_free(png_ptr, png_ptr->gamma_to_1);
#endif
if (png_ptr->free_me & PNG_FREE_PLTE)
png_zfree(png_ptr, png_ptr->palette);
png_ptr->free_me &= ~PNG_FREE_PLTE;
#if defined(PNG_tRNS_SUPPORTED) || \
defined(PNG_READ_EXPAND_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
if (png_ptr->free_me & PNG_FREE_TRNS)
png_free(png_ptr, png_ptr->trans_alpha);
png_ptr->free_me &= ~PNG_FREE_TRNS;
#endif
#ifdef PNG_READ_hIST_SUPPORTED
if (png_ptr->free_me & PNG_FREE_HIST)
png_free(png_ptr, png_ptr->hist);
png_ptr->free_me &= ~PNG_FREE_HIST;
#endif
#ifdef PNG_READ_GAMMA_SUPPORTED
if (png_ptr->gamma_16_table != NULL)
{
int i;
int istop = (1 << (8 - png_ptr->gamma_shift));
for (i = 0; i < istop; i++)
{
png_free(png_ptr, png_ptr->gamma_16_table[i]);
}
png_free(png_ptr, png_ptr->gamma_16_table);
}
#ifdef PNG_READ_BACKGROUND_SUPPORTED
if (png_ptr->gamma_16_from_1 != NULL)
{
int i;
int istop = (1 << (8 - png_ptr->gamma_shift));
for (i = 0; i < istop; i++)
{
png_free(png_ptr, png_ptr->gamma_16_from_1[i]);
}
png_free(png_ptr, png_ptr->gamma_16_from_1);
}
if (png_ptr->gamma_16_to_1 != NULL)
{
int i;
int istop = (1 << (8 - png_ptr->gamma_shift));
for (i = 0; i < istop; i++)
{
png_free(png_ptr, png_ptr->gamma_16_to_1[i]);
}
png_free(png_ptr, png_ptr->gamma_16_to_1);
}
#endif
#endif
#ifdef PNG_TIME_RFC1123_SUPPORTED
png_free(png_ptr, png_ptr->time_buffer);
#endif
inflateEnd(&png_ptr->zstream);
#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
png_free(png_ptr, png_ptr->save_buffer);
#endif
#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
#ifdef PNG_TEXT_SUPPORTED
png_free(png_ptr, png_ptr->current_text);
#endif /* PNG_TEXT_SUPPORTED */
#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */
/* Save the important info out of the png_struct, in case it is
* being used again.
*/
#ifdef PNG_SETJMP_SUPPORTED
png_memcpy(tmp_jmp, png_ptr->png_jmpbuf, png_sizeof(jmp_buf));
#endif
error_fn = png_ptr->error_fn;
warning_fn = png_ptr->warning_fn;
error_ptr = png_ptr->error_ptr;
#ifdef PNG_USER_MEM_SUPPORTED
free_fn = png_ptr->free_fn;
#endif
png_memset(png_ptr, 0, png_sizeof(png_struct));
png_ptr->error_fn = error_fn;
png_ptr->warning_fn = warning_fn;
png_ptr->error_ptr = error_ptr;
#ifdef PNG_USER_MEM_SUPPORTED
png_ptr->free_fn = free_fn;
#endif
#ifdef PNG_SETJMP_SUPPORTED
png_memcpy(png_ptr->png_jmpbuf, tmp_jmp, png_sizeof(jmp_buf));
#endif
}
void PNGAPI
png_set_read_status_fn(png_structp png_ptr, png_read_status_ptr read_row_fn)
{
if (png_ptr == NULL)
return;
png_ptr->read_row_fn = read_row_fn;
}
#ifdef PNG_SEQUENTIAL_READ_SUPPORTED
#ifdef PNG_INFO_IMAGE_SUPPORTED
void PNGAPI
png_read_png(png_structp png_ptr, png_infop info_ptr,
int transforms,
voidp params)
{
int row;
if (png_ptr == NULL)
return;
/* png_read_info() gives us all of the information from the
* PNG file before the first IDAT (image data chunk).
*/
png_read_info(png_ptr, info_ptr);
if (info_ptr->height > PNG_UINT_32_MAX/png_sizeof(png_bytep))
png_error(png_ptr, "Image is too high to process with png_read_png()");
/* -------------- image transformations start here ------------------- */
#ifdef PNG_READ_16_TO_8_SUPPORTED
/* Tell libpng to strip 16 bit/color files down to 8 bits per color.
*/
if (transforms & PNG_TRANSFORM_STRIP_16)
png_set_strip_16(png_ptr);
#endif
#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED
/* Strip alpha bytes from the input data without combining with
* the background (not recommended).
*/
if (transforms & PNG_TRANSFORM_STRIP_ALPHA)
png_set_strip_alpha(png_ptr);
#endif
#if defined(PNG_READ_PACK_SUPPORTED) && !defined(PNG_READ_EXPAND_SUPPORTED)
/* Extract multiple pixels with bit depths of 1, 2, or 4 from a single
* byte into separate bytes (useful for paletted and grayscale images).
*/
if (transforms & PNG_TRANSFORM_PACKING)
png_set_packing(png_ptr);
#endif
#ifdef PNG_READ_PACKSWAP_SUPPORTED
/* Change the order of packed pixels to least significant bit first
* (not useful if you are using png_set_packing).
*/
if (transforms & PNG_TRANSFORM_PACKSWAP)
png_set_packswap(png_ptr);
#endif
#ifdef PNG_READ_EXPAND_SUPPORTED
/* Expand paletted colors into true RGB triplets
* Expand grayscale images to full 8 bits from 1, 2, or 4 bits/pixel
* Expand paletted or RGB images with transparency to full alpha
* channels so the data will be available as RGBA quartets.
*/
if (transforms & PNG_TRANSFORM_EXPAND)
if ((png_ptr->bit_depth < 8) ||
(png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) ||
(png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)))
png_set_expand(png_ptr);
#endif
/* We don't handle background color or gamma transformation or quantizing.
*/
#ifdef PNG_READ_INVERT_SUPPORTED
/* Invert monochrome files to have 0 as white and 1 as black
*/
if (transforms & PNG_TRANSFORM_INVERT_MONO)
png_set_invert_mono(png_ptr);
#endif
#ifdef PNG_READ_SHIFT_SUPPORTED
/* If you want to shift the pixel values from the range [0,255] or
* [0,65535] to the original [0,7] or [0,31], or whatever range the
* colors were originally in:
*/
if ((transforms & PNG_TRANSFORM_SHIFT)
&& png_get_valid(png_ptr, info_ptr, PNG_INFO_sBIT))
{
png_color_8p sig_bit;
png_get_sBIT(png_ptr, info_ptr, &sig_bit);
png_set_shift(png_ptr, sig_bit);
}
#endif
#ifdef PNG_READ_BGR_SUPPORTED
/* Flip the RGB pixels to BGR (or RGBA to BGRA) */
if (transforms & PNG_TRANSFORM_BGR)
png_set_bgr(png_ptr);
#endif
#ifdef PNG_READ_SWAP_ALPHA_SUPPORTED
/* Swap the RGBA or GA data to ARGB or AG (or BGRA to ABGR) */
if (transforms & PNG_TRANSFORM_SWAP_ALPHA)
png_set_swap_alpha(png_ptr);
#endif
#ifdef PNG_READ_SWAP_SUPPORTED
/* Swap bytes of 16 bit files to least significant byte first */
if (transforms & PNG_TRANSFORM_SWAP_ENDIAN)
png_set_swap(png_ptr);
#endif
/* Added at libpng-1.2.41 */
#ifdef PNG_READ_INVERT_ALPHA_SUPPORTED
/* Invert the alpha channel from opacity to transparency */
if (transforms & PNG_TRANSFORM_INVERT_ALPHA)
png_set_invert_alpha(png_ptr);
#endif
/* Added at libpng-1.2.41 */
#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED
/* Expand grayscale image to RGB */
if (transforms & PNG_TRANSFORM_GRAY_TO_RGB)
png_set_gray_to_rgb(png_ptr);
#endif
/* We don't handle adding filler bytes */
/* Optional call to gamma correct and add the background to the palette
* and update info structure. REQUIRED if you are expecting libpng to
* update the palette for you (i.e., you selected such a transform above).
*/
png_read_update_info(png_ptr, info_ptr);
/* -------------- image transformations end here ------------------- */
png_free_data(png_ptr, info_ptr, PNG_FREE_ROWS, 0);
if (info_ptr->row_pointers == NULL)
{
png_uint_32 iptr;
info_ptr->row_pointers = (png_bytepp)png_malloc(png_ptr,
info_ptr->height * png_sizeof(png_bytep));
for (iptr=0; iptr<info_ptr->height; iptr++)
info_ptr->row_pointers[iptr] = NULL;
info_ptr->free_me |= PNG_FREE_ROWS;
for (row = 0; row < (int)info_ptr->height; row++)
info_ptr->row_pointers[row] = (png_bytep)png_malloc(png_ptr,
png_get_rowbytes(png_ptr, info_ptr));
}
png_read_image(png_ptr, info_ptr->row_pointers);
info_ptr->valid |= PNG_INFO_IDAT;
/* Read rest of file, and get additional chunks in info_ptr - REQUIRED */
png_read_end(png_ptr, info_ptr);
transforms = transforms; /* Quiet compiler warnings */
params = params;
}
#endif /* PNG_INFO_IMAGE_SUPPORTED */
#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */
#endif /* PNG_READ_SUPPORTED */