📄 pngrutil.c
字号:
/* pngrutil.c - utilities to read a PNG file
*
* libpng 1.0.3 - January 14, 1999
* For conditions of distribution and use, see copyright notice in png.h
* Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
* Copyright (c) 1996, 1997 Andreas Dilger
* Copyright (c) 1998, 1999 Glenn Randers-Pehrson
*
* This file contains routines that are only called from within
* libpng itself during the course of reading an image.
*/
#define PNG_INTERNAL
#include "png.h"
#ifndef PNG_READ_BIG_ENDIAN_SUPPORTED
/* Grab an unsigned 32-bit integer from a buffer in big-endian format. */
png_uint_32
png_get_uint_32(png_bytep buf)
{
png_uint_32 i = ((png_uint_32)(*buf) << 24) +
((png_uint_32)(*(buf + 1)) << 16) +
((png_uint_32)(*(buf + 2)) << 8) +
(png_uint_32)(*(buf + 3));
return (i);
}
#if defined(PNG_READ_pCAL_SUPPORTED)
/* Grab a signed 32-bit integer from a buffer in big-endian format. The
* data is stored in the PNG file in two's complement format, and it is
* assumed that the machine format for signed integers is the same. */
png_int_32
png_get_int_32(png_bytep buf)
{
png_int_32 i = ((png_int_32)(*buf) << 24) +
((png_int_32)(*(buf + 1)) << 16) +
((png_int_32)(*(buf + 2)) << 8) +
(png_int_32)(*(buf + 3));
return (i);
}
#endif /* PNG_READ_pCAL_SUPPORTED */
/* Grab an unsigned 16-bit integer from a buffer in big-endian format. */
png_uint_16
png_get_uint_16(png_bytep buf)
{
png_uint_16 i = (png_uint_16)(((png_uint_16)(*buf) << 8) +
(png_uint_16)(*(buf + 1)));
return (i);
}
#endif /* PNG_READ_BIG_ENDIAN_SUPPORTED */
/* Read data, and (optionally) run it through the CRC. */
void
png_crc_read(png_structp png_ptr, png_bytep buf, png_size_t length)
{
png_read_data(png_ptr, buf, length);
png_calculate_crc(png_ptr, buf, length);
}
/* Optionally skip data and then check the CRC. Depending on whether we
are reading a ancillary or critical chunk, and how the program has set
things up, we may calculate the CRC on the data and print a message.
Returns '1' if there was a CRC error, '0' otherwise. */
int
png_crc_finish(png_structp png_ptr, png_uint_32 skip)
{
png_size_t i;
png_size_t istop = png_ptr->zbuf_size;
for (i = (png_size_t)skip; i > istop; i -= istop)
{
png_crc_read(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size);
}
if (i)
{
png_crc_read(png_ptr, png_ptr->zbuf, i);
}
if (png_crc_error(png_ptr))
{
if ((png_ptr->chunk_name[0] & 0x20 && /* Ancillary */
!(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN)) ||
(!(png_ptr->chunk_name[0] & 0x20) && /* Critical */
png_ptr->flags & PNG_FLAG_CRC_CRITICAL_USE))
{
png_chunk_warning(png_ptr, "CRC error");
}
else
{
png_chunk_error(png_ptr, "CRC error");
}
return (1);
}
return (0);
}
/* Compare the CRC stored in the PNG file with that calculated by libpng from
the data it has read thus far. */
int
png_crc_error(png_structp png_ptr)
{
png_byte crc_bytes[4];
png_uint_32 crc;
int need_crc = 1;
if (png_ptr->chunk_name[0] & 0x20) /* ancillary */
{
if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_MASK) ==
(PNG_FLAG_CRC_ANCILLARY_USE | PNG_FLAG_CRC_ANCILLARY_NOWARN))
need_crc = 0;
}
else /* critical */
{
if (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE)
need_crc = 0;
}
png_read_data(png_ptr, crc_bytes, 4);
if (need_crc)
{
crc = png_get_uint_32(crc_bytes);
return ((int)(crc != png_ptr->crc));
}
else
return (0);
}
/* read and check the IDHR chunk */
void
png_handle_IHDR(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
{
png_byte buf[13];
png_uint_32 width, height;
int bit_depth, color_type, compression_type, filter_type;
int interlace_type;
png_debug(1, "in png_handle_IHDR\n");
if (png_ptr->mode != PNG_BEFORE_IHDR)
png_error(png_ptr, "Out of place IHDR");
/* check the length */
if (length != 13)
png_error(png_ptr, "Invalid IHDR chunk");
png_ptr->mode |= PNG_HAVE_IHDR;
png_crc_read(png_ptr, buf, 13);
png_crc_finish(png_ptr, 0);
width = png_get_uint_32(buf);
height = png_get_uint_32(buf + 4);
bit_depth = buf[8];
color_type = buf[9];
compression_type = buf[10];
filter_type = buf[11];
interlace_type = buf[12];
/* check for width and height valid values */
if (width == 0 || width > (png_uint_32)2147483647L || height == 0 ||
height > (png_uint_32)2147483647L)
png_error(png_ptr, "Invalid image size in IHDR");
/* check other values */
if (bit_depth != 1 && bit_depth != 2 && bit_depth != 4 &&
bit_depth != 8 && bit_depth != 16)
png_error(png_ptr, "Invalid bit depth in IHDR");
if (color_type < 0 || color_type == 1 ||
color_type == 5 || color_type > 6)
png_error(png_ptr, "Invalid color type in IHDR");
if ((color_type == PNG_COLOR_TYPE_PALETTE && bit_depth) > 8 ||
((color_type == PNG_COLOR_TYPE_RGB ||
color_type == PNG_COLOR_TYPE_GRAY_ALPHA ||
color_type == PNG_COLOR_TYPE_RGB_ALPHA) && bit_depth < 8))
png_error(png_ptr, "Invalid color type/bit depth combination in IHDR");
if (interlace_type >= PNG_INTERLACE_LAST)
png_error(png_ptr, "Unknown interlace method in IHDR");
if (compression_type != PNG_COMPRESSION_TYPE_BASE)
png_error(png_ptr, "Unknown compression method in IHDR");
if (filter_type != PNG_FILTER_TYPE_BASE)
png_error(png_ptr, "Unknown filter method in IHDR");
/* set internal variables */
png_ptr->width = width;
png_ptr->height = height;
png_ptr->bit_depth = (png_byte)bit_depth;
png_ptr->interlaced = (png_byte)interlace_type;
png_ptr->color_type = (png_byte)color_type;
/* find number of channels */
switch (png_ptr->color_type)
{
case PNG_COLOR_TYPE_GRAY:
case PNG_COLOR_TYPE_PALETTE:
png_ptr->channels = 1;
break;
case PNG_COLOR_TYPE_RGB:
png_ptr->channels = 3;
break;
case PNG_COLOR_TYPE_GRAY_ALPHA:
png_ptr->channels = 2;
break;
case PNG_COLOR_TYPE_RGB_ALPHA:
png_ptr->channels = 4;
break;
}
/* set up other useful info */
png_ptr->pixel_depth = (png_byte)(png_ptr->bit_depth *
png_ptr->channels);
png_ptr->rowbytes = ((png_ptr->width *
(png_uint_32)png_ptr->pixel_depth + 7) >> 3);
png_debug1(3,"bit_depth = %d\n", png_ptr->bit_depth);
png_debug1(3,"channels = %d\n", png_ptr->channels);
png_debug1(3,"rowbytes = %d\n", png_ptr->rowbytes);
png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth,
color_type, interlace_type, compression_type, filter_type);
}
/* read and check the palette */
void
png_handle_PLTE(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
{
png_colorp palette;
int num, i;
png_debug(1, "in png_handle_PLTE\n");
if (!(png_ptr->mode & PNG_HAVE_IHDR))
png_error(png_ptr, "Missing IHDR before PLTE");
else if (png_ptr->mode & PNG_HAVE_IDAT)
{
png_warning(png_ptr, "Invalid PLTE after IDAT");
png_crc_finish(png_ptr, length);
return;
}
else if (png_ptr->mode & PNG_HAVE_PLTE)
png_error(png_ptr, "Duplicate PLTE chunk");
png_ptr->mode |= PNG_HAVE_PLTE;
#if !defined(PNG_READ_OPT_PLTE_SUPPORTED)
if (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE)
{
png_crc_finish(png_ptr, length);
return;
}
#endif
if (length % 3)
{
if (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE)
{
png_warning(png_ptr, "Invalid palette chunk");
png_crc_finish(png_ptr, length);
return;
}
else
{
png_error(png_ptr, "Invalid palette chunk");
}
}
num = (int)length / 3;
palette = (png_colorp)png_zalloc(png_ptr, (uInt)num, sizeof (png_color));
png_ptr->flags |= PNG_FLAG_FREE_PALETTE;
for (i = 0; i < num; i++)
{
png_byte buf[3];
png_crc_read(png_ptr, buf, 3);
/* don't depend upon png_color being any order */
palette[i].red = buf[0];
palette[i].green = buf[1];
palette[i].blue = buf[2];
}
/* If we actually NEED the PLTE chunk (ie for a paletted image), we do
whatever the normal CRC configuration tells us. However, if we
have an RGB image, the PLTE can be considered ancillary, so
we will act as though it is. */
#if !defined(PNG_READ_OPT_PLTE_SUPPORTED)
if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
#endif
{
png_crc_finish(png_ptr, 0);
}
#if !defined(PNG_READ_OPT_PLTE_SUPPORTED)
else if (png_crc_error(png_ptr)) /* Only if we have a CRC error */
{
/* If we don't want to use the data from an ancillary chunk,
we have two options: an error abort, or a warning and we
ignore the data in this chunk (which should be OK, since
it's considered ancillary for a RGB or RGBA image). */
if (!(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_USE))
{
if (png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN)
{
png_chunk_error(png_ptr, "CRC error");
}
else
{
png_chunk_warning(png_ptr, "CRC error");
png_ptr->flags &= ~PNG_FLAG_FREE_PALETTE;
png_zfree(png_ptr, palette);
return;
}
}
/* Otherwise, we (optionally) emit a warning and use the chunk. */
else if (!(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN))
{
png_chunk_warning(png_ptr, "CRC error");
}
}
#endif
png_ptr->palette = palette;
png_ptr->num_palette = (png_uint_16)num;
png_set_PLTE(png_ptr, info_ptr, palette, num);
#if defined (PNG_READ_tRNS_SUPPORTED)
if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
{
if (info_ptr != NULL && info_ptr->valid & PNG_INFO_tRNS)
{
if (png_ptr->num_trans > png_ptr->num_palette)
{
png_warning(png_ptr, "Truncating incorrect tRNS chunk length");
png_ptr->num_trans = png_ptr->num_palette;
}
}
}
#endif
}
void
png_handle_IEND(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
{
png_debug(1, "in png_handle_IEND\n");
if (!(png_ptr->mode & PNG_HAVE_IHDR) || !(png_ptr->mode & PNG_HAVE_IDAT))
{
png_error(png_ptr, "No image in file");
/* to quiet compiler warnings about unused info_ptr */
if (info_ptr == NULL)
return;
}
png_ptr->mode |= PNG_AFTER_IDAT | PNG_HAVE_IEND;
if (length != 0)
{
png_warning(png_ptr, "Incorrect IEND chunk length");
}
png_crc_finish(png_ptr, length);
}
#if defined(PNG_READ_gAMA_SUPPORTED)
void
png_handle_gAMA(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
{
png_uint_32 igamma;
float file_gamma;
png_byte buf[4];
png_debug(1, "in png_handle_gAMA\n");
if (!(png_ptr->mode & PNG_HAVE_IHDR))
png_error(png_ptr, "Missing IHDR before gAMA");
else if (png_ptr->mode & PNG_HAVE_IDAT)
{
png_warning(png_ptr, "Invalid gAMA after IDAT");
png_crc_finish(png_ptr, length);
return;
}
else if (png_ptr->mode & PNG_HAVE_PLTE)
/* Should be an error, but we can cope with it */
png_warning(png_ptr, "Out of place gAMA chunk");
else if (info_ptr != NULL && info_ptr->valid & PNG_INFO_gAMA
#if defined(PNG_READ_sRGB_SUPPORTED)
&& !(info_ptr->valid & PNG_INFO_sRGB)
#endif
)
{
png_warning(png_ptr, "Duplicate gAMA chunk");
png_crc_finish(png_ptr, length);
return;
}
if (length != 4)
{
png_warning(png_ptr, "Incorrect gAMA chunk length");
png_crc_finish(png_ptr, length);
return;
}
png_crc_read(png_ptr, buf, 4);
if (png_crc_finish(png_ptr, 0))
return;
igamma = png_get_uint_32(buf);
/* check for zero gamma */
if (igamma == 0)
return;
#if defined(PNG_READ_sRGB_SUPPORTED)
if (info_ptr->valid & PNG_INFO_sRGB)
if(igamma != (png_uint_32)45000L)
{
png_warning(png_ptr,
"Ignoring incorrect gAMA value when sRGB is also present");
#ifndef PNG_NO_CONSOLE_IO
fprintf(stderr, "igamma = %lu\n", igamma);
#endif
return;
}
#endif /* PNG_READ_sRGB_SUPPORTED */
file_gamma = (float)igamma / (float)100000.0;
#ifdef PNG_READ_GAMMA_SUPPORTED
png_ptr->gamma = file_gamma;
#endif
png_set_gAMA(png_ptr, info_ptr, file_gamma);
}
#endif
#if defined(PNG_READ_sBIT_SUPPORTED)
void
png_handle_sBIT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -