mirror of
https://github.com/opencv/opencv.git
synced 2026-09-25 04:09:57 +03:00
Updated libpng to v1.6.51 and added RISC-V optimimizations.
This commit is contained in:
Vendored
+43
-1
@@ -172,7 +172,7 @@ if(TARGET_ARCH MATCHES "^(loongarch)")
|
||||
set_source_files_properties(${libpng_loongarch_sources}
|
||||
PROPERTIES
|
||||
COMPILE_FLAGS "-mlsx")
|
||||
list(APPEND lib_srcs ${libpng_loongarch_sources})
|
||||
list(APPEND lib_srcs ${libpng_loongarch_sources})
|
||||
add_definitions(-DPNG_LOONGARCH_LSX_OPT=1)
|
||||
else()
|
||||
message(FATAL_ERROR "Compiler does not support -mlsx option")
|
||||
@@ -182,6 +182,43 @@ if(TARGET_ARCH MATCHES "^(loongarch)")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Set definitions and sources for RISC-V.
|
||||
if(PNG_TARGET_ARCHITECTURE MATCHES "^(riscv)")
|
||||
include(CheckCCompilerFlag)
|
||||
set(PNG_RISCV_RVV_POSSIBLE_VALUES on off)
|
||||
set(PNG_RISCV_RVV "off"
|
||||
CACHE STRING "Enable RISC-V Vector optimizations: on|off; off is default")
|
||||
set_property(CACHE PNG_RISCV_RVV
|
||||
PROPERTY STRINGS ${PNG_RISCV_RVV_POSSIBLE_VALUES})
|
||||
list(FIND PNG_RISCV_RVV_POSSIBLE_VALUES ${PNG_RISCV_RVV} index)
|
||||
if(index EQUAL -1)
|
||||
message(FATAL_ERROR "PNG_RISCV_RVV must be one of [${PNG_RISCV_RVV_POSSIBLE_VALUES}]")
|
||||
elseif(NOT PNG_RISCV_RVV STREQUAL "off")
|
||||
|
||||
check_c_source_compiles("
|
||||
#include <riscv_vector.h>
|
||||
int main() {
|
||||
const float src[] = { 0.0f, 0.0f, 0.0f, 0.0f };
|
||||
uint64_t ptr[2] = {0x0908060504020100, 0xFFFFFFFF0E0D0C0A};
|
||||
vuint8m1_t a = __riscv_vreinterpret_v_u64m1_u8m1(__riscv_vle64_v_u64m1(ptr, 2));
|
||||
vfloat32m1_t val = __riscv_vle32_v_f32m1((const float*)(src), 4);
|
||||
return (int)__riscv_vfmv_f_s_f32m1_f32(val);
|
||||
}" COMPILER_SUPPORTS_RVV)
|
||||
|
||||
if(NOT COMPILER_SUPPORTS_RVV)
|
||||
message(FATAL_ERROR "Compiler does not support RISC-V Vector extension or its unable to detect it")
|
||||
endif()
|
||||
list(APPEND lib_srcs riscv/filter_rvv_intrinsics.c riscv/riscv_init.c)
|
||||
if(PNG_RISCV_RVV STREQUAL "on")
|
||||
add_definitions(-DPNG_RISCV_RVV_OPT=2)
|
||||
else()
|
||||
add_definitions(-DPNG_RISCV_RVV_OPT=0)
|
||||
endif()
|
||||
else()
|
||||
add_definitions(-DPNG_RISCV_RVV_OPT=0)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
else(PNG_HARDWARE_OPTIMIZATIONS)
|
||||
|
||||
# Set definitions and sources for ARM.
|
||||
@@ -209,6 +246,11 @@ if(TARGET_ARCH MATCHES "^(loongarch)")
|
||||
add_definitions(-DPNG_LOONGARCH_LSX_OPT=0)
|
||||
endif()
|
||||
|
||||
# Set definitions and sources for RISC-V.
|
||||
if(PNG_TARGET_ARCHITECTURE MATCHES "^(riscv)")
|
||||
add_definitions(-DPNG_RISCV_RVV_OPT=0)
|
||||
endif()
|
||||
|
||||
endif(PNG_HARDWARE_OPTIMIZATIONS)
|
||||
|
||||
# ----------------------------------------------------------------------------------
|
||||
|
||||
Vendored
+4
-4
@@ -35,14 +35,14 @@
|
||||
#ifndef PNG_ARM_NEON_FILE
|
||||
# if defined(__aarch64__) || defined(_M_ARM64)
|
||||
/* ARM Neon is expected to be unconditionally available on ARM64. */
|
||||
# error "PNG_ARM_NEON_CHECK_SUPPORTED must not be defined on ARM64"
|
||||
# error PNG_ARM_NEON_CHECK_SUPPORTED must not be defined on ARM64
|
||||
# elif defined(__ARM_NEON__) || defined(__ARM_NEON)
|
||||
/* ARM Neon is expected to be available on the target CPU architecture. */
|
||||
# error "PNG_ARM_NEON_CHECK_SUPPORTED must not be defined on this CPU arch"
|
||||
# error PNG_ARM_NEON_CHECK_SUPPORTED must not be defined on this CPU arch
|
||||
# elif defined(__linux__)
|
||||
# define PNG_ARM_NEON_FILE "contrib/arm-neon/linux.c"
|
||||
# else
|
||||
# error "No support for run-time ARM Neon checking; use compile-time options"
|
||||
# error No support for run-time ARM Neon checking; use compile-time options
|
||||
# endif
|
||||
#endif
|
||||
|
||||
@@ -53,7 +53,7 @@ static int png_have_neon(png_structp png_ptr);
|
||||
#endif /* PNG_ARM_NEON_CHECK_SUPPORTED */
|
||||
|
||||
#ifndef PNG_ALIGNED_MEMORY_SUPPORTED
|
||||
# error "ALIGNED_MEMORY is required; set: -DPNG_ALIGNED_MEMORY_SUPPORTED"
|
||||
# error ALIGNED_MEMORY is required; please define PNG_ALIGNED_MEMORY_SUPPORTED
|
||||
#endif
|
||||
|
||||
void
|
||||
|
||||
Vendored
+3
-3
@@ -48,7 +48,7 @@ static int png_have_msa(png_structp png_ptr);
|
||||
#include PNG_MIPS_MSA_FILE
|
||||
|
||||
#else /* PNG_MIPS_MSA_FILE */
|
||||
# error "PNG_MIPS_MSA_FILE undefined: no support for run-time MIPS MSA checks"
|
||||
# error PNG_MIPS_MSA_FILE undefined: no support for run-time MIPS MSA checks
|
||||
#endif /* PNG_MIPS_MSA_FILE */
|
||||
#endif /* PNG_MIPS_MSA_CHECK_SUPPORTED */
|
||||
|
||||
@@ -66,12 +66,12 @@ static int png_have_mmi();
|
||||
#include PNG_MIPS_MMI_FILE
|
||||
|
||||
#else /* PNG_MIPS_MMI_FILE */
|
||||
# error "PNG_MIPS_MMI_FILE undefined: no support for run-time MIPS MMI checks"
|
||||
# error PNG_MIPS_MMI_FILE undefined: no support for run-time MIPS MMI checks
|
||||
#endif /* PNG_MIPS_MMI_FILE */
|
||||
#endif /* PNG_MIPS_MMI_CHECK_SUPPORTED*/
|
||||
|
||||
#ifndef PNG_ALIGNED_MEMORY_SUPPORTED
|
||||
# error "ALIGNED_MEMORY is required; set: -DPNG_ALIGNED_MEMORY_SUPPORTED"
|
||||
# error ALIGNED_MEMORY is required; please define PNG_ALIGNED_MEMORY_SUPPORTED
|
||||
#endif
|
||||
|
||||
/* MIPS supports two optimizations: MMI and MSA. The appropriate
|
||||
|
||||
Vendored
+334
-950
@@ -13,7 +13,34 @@
|
||||
#include "pngpriv.h"
|
||||
|
||||
/* Generate a compiler error if there is an old png.h in the search path. */
|
||||
typedef png_libpng_version_1_6_45 Your_png_h_is_not_version_1_6_45;
|
||||
typedef png_libpng_version_1_6_51 Your_png_h_is_not_version_1_6_51;
|
||||
|
||||
/* Sanity check the chunks definitions - PNG_KNOWN_CHUNKS from pngpriv.h and the
|
||||
* corresponding macro definitions. This causes a compile time failure if
|
||||
* something is wrong but generates no code.
|
||||
*
|
||||
* (1) The first check is that the PNG_CHUNK(cHNK, index) 'index' values must
|
||||
* increment from 0 to the last value.
|
||||
*/
|
||||
#define PNG_CHUNK(cHNK, index) != (index) || ((index)+1)
|
||||
|
||||
#if 0 PNG_KNOWN_CHUNKS < 0
|
||||
# error PNG_KNOWN_CHUNKS chunk definitions are not in order
|
||||
#endif
|
||||
|
||||
#undef PNG_CHUNK
|
||||
|
||||
/* (2) The chunk name macros, png_cHNK, must all be valid and defined. Since
|
||||
* this is a preprocessor test undefined pp-tokens come out as zero and will
|
||||
* fail this test.
|
||||
*/
|
||||
#define PNG_CHUNK(cHNK, index) !PNG_CHUNK_NAME_VALID(png_ ## cHNK) ||
|
||||
|
||||
#if PNG_KNOWN_CHUNKS 0
|
||||
# error png_cHNK not defined for some known cHNK
|
||||
#endif
|
||||
|
||||
#undef PNG_CHUNK
|
||||
|
||||
/* Tells libpng that we have already handled the first "num_bytes" bytes
|
||||
* of the PNG file signature. If the PNG data is embedded into another
|
||||
@@ -81,10 +108,16 @@ png_zalloc,(voidpf png_ptr, uInt items, uInt size),PNG_ALLOCATED)
|
||||
if (png_ptr == NULL)
|
||||
return NULL;
|
||||
|
||||
if (items >= (~(png_alloc_size_t)0)/size)
|
||||
/* This check against overflow is vestigial, dating back from
|
||||
* the old times when png_zalloc used to be an exported function.
|
||||
* We're still keeping it here for now, as an extra-cautious
|
||||
* prevention against programming errors inside zlib, although it
|
||||
* should rather be a debug-time assertion instead.
|
||||
*/
|
||||
if (size != 0 && items >= (~(png_alloc_size_t)0) / size)
|
||||
{
|
||||
png_warning (png_voidcast(png_structrp, png_ptr),
|
||||
"Potential overflow in png_zalloc()");
|
||||
png_warning(png_voidcast(png_structrp, png_ptr),
|
||||
"Potential overflow in png_zalloc()");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -211,10 +244,6 @@ png_user_version_check(png_structrp png_ptr, png_const_charp user_png_ver)
|
||||
png_warning(png_ptr, m);
|
||||
#endif
|
||||
|
||||
#ifdef PNG_ERROR_NUMBERS_SUPPORTED
|
||||
png_ptr->flags = 0;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -241,21 +270,23 @@ png_create_png_struct,(png_const_charp user_png_ver, png_voidp error_ptr,
|
||||
*/
|
||||
memset(&create_struct, 0, (sizeof create_struct));
|
||||
|
||||
/* Added at libpng-1.2.6 */
|
||||
# ifdef PNG_USER_LIMITS_SUPPORTED
|
||||
create_struct.user_width_max = PNG_USER_WIDTH_MAX;
|
||||
create_struct.user_height_max = PNG_USER_HEIGHT_MAX;
|
||||
|
||||
# ifdef PNG_USER_CHUNK_CACHE_MAX
|
||||
/* Added at libpng-1.2.43 and 1.4.0 */
|
||||
create_struct.user_chunk_cache_max = PNG_USER_CHUNK_CACHE_MAX;
|
||||
# endif
|
||||
|
||||
# ifdef PNG_USER_CHUNK_MALLOC_MAX
|
||||
/* Added at libpng-1.2.43 and 1.4.1, required only for read but exists
|
||||
* in png_struct regardless.
|
||||
*/
|
||||
# if PNG_USER_CHUNK_MALLOC_MAX > 0 /* default to compile-time limit */
|
||||
create_struct.user_chunk_malloc_max = PNG_USER_CHUNK_MALLOC_MAX;
|
||||
|
||||
/* No compile-time limit, so initialize to the system limit: */
|
||||
# elif defined PNG_MAX_MALLOC_64K /* legacy system limit */
|
||||
create_struct.user_chunk_malloc_max = 65536U;
|
||||
|
||||
# else /* modern system limit SIZE_MAX (C99) */
|
||||
create_struct.user_chunk_malloc_max = PNG_SIZE_MAX;
|
||||
# endif
|
||||
# endif
|
||||
|
||||
@@ -597,13 +628,6 @@ png_free_data(png_const_structrp png_ptr, png_inforp info_ptr, png_uint_32 mask,
|
||||
/* Free any eXIf entry */
|
||||
if (((mask & PNG_FREE_EXIF) & info_ptr->free_me) != 0)
|
||||
{
|
||||
# ifdef PNG_READ_eXIf_SUPPORTED
|
||||
if (info_ptr->eXIf_buf)
|
||||
{
|
||||
png_free(png_ptr, info_ptr->eXIf_buf);
|
||||
info_ptr->eXIf_buf = NULL;
|
||||
}
|
||||
# endif
|
||||
if (info_ptr->exif)
|
||||
{
|
||||
png_free(png_ptr, info_ptr->exif);
|
||||
@@ -678,7 +702,7 @@ png_get_io_ptr(png_const_structrp png_ptr)
|
||||
* function of your own because "FILE *" isn't necessarily available.
|
||||
*/
|
||||
void PNGAPI
|
||||
png_init_io(png_structrp png_ptr, png_FILE_p fp)
|
||||
png_init_io(png_structrp png_ptr, FILE *fp)
|
||||
{
|
||||
png_debug(1, "in png_init_io");
|
||||
|
||||
@@ -793,7 +817,7 @@ png_get_copyright(png_const_structrp png_ptr)
|
||||
return PNG_STRING_COPYRIGHT
|
||||
#else
|
||||
return PNG_STRING_NEWLINE \
|
||||
"libpng version 1.6.45" PNG_STRING_NEWLINE \
|
||||
"libpng version 1.6.51" PNG_STRING_NEWLINE \
|
||||
"Copyright (c) 2018-2025 Cosmin Truta" PNG_STRING_NEWLINE \
|
||||
"Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson" \
|
||||
PNG_STRING_NEWLINE \
|
||||
@@ -1038,169 +1062,6 @@ png_zstream_error(png_structrp png_ptr, int ret)
|
||||
}
|
||||
}
|
||||
|
||||
/* png_convert_size: a PNGAPI but no longer in png.h, so deleted
|
||||
* at libpng 1.5.5!
|
||||
*/
|
||||
|
||||
/* Added at libpng version 1.2.34 and 1.4.0 (moved from pngset.c) */
|
||||
#ifdef PNG_GAMMA_SUPPORTED /* always set if COLORSPACE */
|
||||
static int
|
||||
png_colorspace_check_gamma(png_const_structrp png_ptr,
|
||||
png_colorspacerp colorspace, png_fixed_point gAMA, int from)
|
||||
/* This is called to check a new gamma value against an existing one. The
|
||||
* routine returns false if the new gamma value should not be written.
|
||||
*
|
||||
* 'from' says where the new gamma value comes from:
|
||||
*
|
||||
* 0: the new gamma value is the libpng estimate for an ICC profile
|
||||
* 1: the new gamma value comes from a gAMA chunk
|
||||
* 2: the new gamma value comes from an sRGB chunk
|
||||
*/
|
||||
{
|
||||
png_fixed_point gtest;
|
||||
|
||||
if ((colorspace->flags & PNG_COLORSPACE_HAVE_GAMMA) != 0 &&
|
||||
(png_muldiv(>est, colorspace->gamma, PNG_FP_1, gAMA) == 0 ||
|
||||
png_gamma_significant(gtest) != 0))
|
||||
{
|
||||
/* Either this is an sRGB image, in which case the calculated gamma
|
||||
* approximation should match, or this is an image with a profile and the
|
||||
* value libpng calculates for the gamma of the profile does not match the
|
||||
* value recorded in the file. The former, sRGB, case is an error, the
|
||||
* latter is just a warning.
|
||||
*/
|
||||
if ((colorspace->flags & PNG_COLORSPACE_FROM_sRGB) != 0 || from == 2)
|
||||
{
|
||||
png_chunk_report(png_ptr, "gamma value does not match sRGB",
|
||||
PNG_CHUNK_ERROR);
|
||||
/* Do not overwrite an sRGB value */
|
||||
return from == 2;
|
||||
}
|
||||
|
||||
else /* sRGB tag not involved */
|
||||
{
|
||||
png_chunk_report(png_ptr, "gamma value does not match libpng estimate",
|
||||
PNG_CHUNK_WARNING);
|
||||
return from == 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void /* PRIVATE */
|
||||
png_colorspace_set_gamma(png_const_structrp png_ptr,
|
||||
png_colorspacerp colorspace, png_fixed_point gAMA)
|
||||
{
|
||||
/* Changed in libpng-1.5.4 to limit the values to ensure overflow can't
|
||||
* occur. Since the fixed point representation is asymmetrical it is
|
||||
* possible for 1/gamma to overflow the limit of 21474 and this means the
|
||||
* gamma value must be at least 5/100000 and hence at most 20000.0. For
|
||||
* safety the limits here are a little narrower. The values are 0.00016 to
|
||||
* 6250.0, which are truly ridiculous gamma values (and will produce
|
||||
* displays that are all black or all white.)
|
||||
*
|
||||
* In 1.6.0 this test replaces the ones in pngrutil.c, in the gAMA chunk
|
||||
* handling code, which only required the value to be >0.
|
||||
*/
|
||||
png_const_charp errmsg;
|
||||
|
||||
if (gAMA < 16 || gAMA > 625000000)
|
||||
errmsg = "gamma value out of range";
|
||||
|
||||
# ifdef PNG_READ_gAMA_SUPPORTED
|
||||
/* Allow the application to set the gamma value more than once */
|
||||
else if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0 &&
|
||||
(colorspace->flags & PNG_COLORSPACE_FROM_gAMA) != 0)
|
||||
errmsg = "duplicate";
|
||||
# endif
|
||||
|
||||
/* Do nothing if the colorspace is already invalid */
|
||||
else if ((colorspace->flags & PNG_COLORSPACE_INVALID) != 0)
|
||||
return;
|
||||
|
||||
else
|
||||
{
|
||||
if (png_colorspace_check_gamma(png_ptr, colorspace, gAMA,
|
||||
1/*from gAMA*/) != 0)
|
||||
{
|
||||
/* Store this gamma value. */
|
||||
colorspace->gamma = gAMA;
|
||||
colorspace->flags |=
|
||||
(PNG_COLORSPACE_HAVE_GAMMA | PNG_COLORSPACE_FROM_gAMA);
|
||||
}
|
||||
|
||||
/* At present if the check_gamma test fails the gamma of the colorspace is
|
||||
* not updated however the colorspace is not invalidated. This
|
||||
* corresponds to the case where the existing gamma comes from an sRGB
|
||||
* chunk or profile. An error message has already been output.
|
||||
*/
|
||||
return;
|
||||
}
|
||||
|
||||
/* Error exit - errmsg has been set. */
|
||||
colorspace->flags |= PNG_COLORSPACE_INVALID;
|
||||
png_chunk_report(png_ptr, errmsg, PNG_CHUNK_WRITE_ERROR);
|
||||
}
|
||||
|
||||
void /* PRIVATE */
|
||||
png_colorspace_sync_info(png_const_structrp png_ptr, png_inforp info_ptr)
|
||||
{
|
||||
if ((info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) != 0)
|
||||
{
|
||||
/* Everything is invalid */
|
||||
info_ptr->valid &= ~(PNG_INFO_gAMA|PNG_INFO_cHRM|PNG_INFO_sRGB|
|
||||
PNG_INFO_iCCP);
|
||||
|
||||
# ifdef PNG_COLORSPACE_SUPPORTED
|
||||
/* Clean up the iCCP profile now if it won't be used. */
|
||||
png_free_data(png_ptr, info_ptr, PNG_FREE_ICCP, -1/*not used*/);
|
||||
# else
|
||||
PNG_UNUSED(png_ptr)
|
||||
# endif
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
# ifdef PNG_COLORSPACE_SUPPORTED
|
||||
/* Leave the INFO_iCCP flag set if the pngset.c code has already set
|
||||
* it; this allows a PNG to contain a profile which matches sRGB and
|
||||
* yet still have that profile retrievable by the application.
|
||||
*/
|
||||
if ((info_ptr->colorspace.flags & PNG_COLORSPACE_MATCHES_sRGB) != 0)
|
||||
info_ptr->valid |= PNG_INFO_sRGB;
|
||||
|
||||
else
|
||||
info_ptr->valid &= ~PNG_INFO_sRGB;
|
||||
|
||||
if ((info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_ENDPOINTS) != 0)
|
||||
info_ptr->valid |= PNG_INFO_cHRM;
|
||||
|
||||
else
|
||||
info_ptr->valid &= ~PNG_INFO_cHRM;
|
||||
# endif
|
||||
|
||||
if ((info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_GAMMA) != 0)
|
||||
info_ptr->valid |= PNG_INFO_gAMA;
|
||||
|
||||
else
|
||||
info_ptr->valid &= ~PNG_INFO_gAMA;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef PNG_READ_SUPPORTED
|
||||
void /* PRIVATE */
|
||||
png_colorspace_sync(png_const_structrp png_ptr, png_inforp info_ptr)
|
||||
{
|
||||
if (info_ptr == NULL) /* reduce code size; check here not in the caller */
|
||||
return;
|
||||
|
||||
info_ptr->colorspace = png_ptr->colorspace;
|
||||
png_colorspace_sync_info(png_ptr, info_ptr);
|
||||
}
|
||||
#endif
|
||||
#endif /* GAMMA */
|
||||
|
||||
#ifdef PNG_COLORSPACE_SUPPORTED
|
||||
static png_int_32
|
||||
png_fp_add(png_int_32 addend0, png_int_32 addend1, int *error)
|
||||
@@ -1269,9 +1130,10 @@ png_safe_add(png_int_32 *addend0_and_result, png_int_32 addend1,
|
||||
* non-zero on a parameter error. The X, Y and Z values are required to be
|
||||
* positive and less than 1.0.
|
||||
*/
|
||||
static int
|
||||
int /* PRIVATE */
|
||||
png_xy_from_XYZ(png_xy *xy, const png_XYZ *XYZ)
|
||||
{
|
||||
/* NOTE: returns 0 on success, 1 means error. */
|
||||
png_int_32 d, dred, dgreen, dblue, dwhite, whiteX, whiteY;
|
||||
|
||||
/* 'd' in each of the blocks below is just X+Y+Z for each component,
|
||||
@@ -1334,9 +1196,10 @@ png_xy_from_XYZ(png_xy *xy, const png_XYZ *XYZ)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
int /* PRIVATE */
|
||||
png_XYZ_from_xy(png_XYZ *XYZ, const png_xy *xy)
|
||||
{
|
||||
/* NOTE: returns 0 on success, 1 means error. */
|
||||
png_fixed_point red_inverse, green_inverse, blue_scale;
|
||||
png_fixed_point left, right, denominator;
|
||||
|
||||
@@ -1544,56 +1407,59 @@ png_XYZ_from_xy(png_XYZ *XYZ, const png_xy *xy)
|
||||
* Adobe Wide Gamut RGB
|
||||
* 0.258728243040113 0.724682314948566 0.016589442011321
|
||||
*/
|
||||
int error = 0;
|
||||
{
|
||||
int error = 0;
|
||||
|
||||
/* By the argument above overflow should be impossible here, however the
|
||||
* code now simply returns a failure code. The xy subtracts in the arguments
|
||||
* to png_muldiv are *not* checked for overflow because the checks at the
|
||||
* start guarantee they are in the range 0..110000 and png_fixed_point is a
|
||||
* 32-bit signed number.
|
||||
*/
|
||||
if (png_muldiv(&left, xy->greenx-xy->bluex, xy->redy - xy->bluey, 8) == 0)
|
||||
return 1;
|
||||
if (png_muldiv(&right, xy->greeny-xy->bluey, xy->redx - xy->bluex, 8) == 0)
|
||||
return 1;
|
||||
denominator = png_fp_sub(left, right, &error);
|
||||
if (error) return 1;
|
||||
/* By the argument above overflow should be impossible here, however the
|
||||
* code now simply returns a failure code. The xy subtracts in the
|
||||
* arguments to png_muldiv are *not* checked for overflow because the
|
||||
* checks at the start guarantee they are in the range 0..110000 and
|
||||
* png_fixed_point is a 32-bit signed number.
|
||||
*/
|
||||
if (png_muldiv(&left, xy->greenx-xy->bluex, xy->redy - xy->bluey, 8) == 0)
|
||||
return 1;
|
||||
if (png_muldiv(&right, xy->greeny-xy->bluey, xy->redx - xy->bluex, 8) ==
|
||||
0)
|
||||
return 1;
|
||||
denominator = png_fp_sub(left, right, &error);
|
||||
if (error) return 1;
|
||||
|
||||
/* Now find the red numerator. */
|
||||
if (png_muldiv(&left, xy->greenx-xy->bluex, xy->whitey-xy->bluey, 8) == 0)
|
||||
return 1;
|
||||
if (png_muldiv(&right, xy->greeny-xy->bluey, xy->whitex-xy->bluex, 8) == 0)
|
||||
return 1;
|
||||
/* Now find the red numerator. */
|
||||
if (png_muldiv(&left, xy->greenx-xy->bluex, xy->whitey-xy->bluey, 8) == 0)
|
||||
return 1;
|
||||
if (png_muldiv(&right, xy->greeny-xy->bluey, xy->whitex-xy->bluex, 8) ==
|
||||
0)
|
||||
return 1;
|
||||
|
||||
/* Overflow is possible here and it indicates an extreme set of PNG cHRM
|
||||
* chunk values. This calculation actually returns the reciprocal of the
|
||||
* scale value because this allows us to delay the multiplication of white-y
|
||||
* into the denominator, which tends to produce a small number.
|
||||
*/
|
||||
if (png_muldiv(&red_inverse, xy->whitey, denominator,
|
||||
png_fp_sub(left, right, &error)) == 0 || error ||
|
||||
red_inverse <= xy->whitey /* r+g+b scales = white scale */)
|
||||
return 1;
|
||||
/* Overflow is possible here and it indicates an extreme set of PNG cHRM
|
||||
* chunk values. This calculation actually returns the reciprocal of the
|
||||
* scale value because this allows us to delay the multiplication of
|
||||
* white-y into the denominator, which tends to produce a small number.
|
||||
*/
|
||||
if (png_muldiv(&red_inverse, xy->whitey, denominator,
|
||||
png_fp_sub(left, right, &error)) == 0 || error ||
|
||||
red_inverse <= xy->whitey /* r+g+b scales = white scale */)
|
||||
return 1;
|
||||
|
||||
/* Similarly for green_inverse: */
|
||||
if (png_muldiv(&left, xy->redy-xy->bluey, xy->whitex-xy->bluex, 8) == 0)
|
||||
return 1;
|
||||
if (png_muldiv(&right, xy->redx-xy->bluex, xy->whitey-xy->bluey, 8) == 0)
|
||||
return 1;
|
||||
if (png_muldiv(&green_inverse, xy->whitey, denominator,
|
||||
png_fp_sub(left, right, &error)) == 0 || error ||
|
||||
green_inverse <= xy->whitey)
|
||||
return 1;
|
||||
|
||||
/* And the blue scale, the checks above guarantee this can't overflow but it
|
||||
* can still produce 0 for extreme cHRM values.
|
||||
*/
|
||||
blue_scale = png_fp_sub(png_fp_sub(png_reciprocal(xy->whitey),
|
||||
png_reciprocal(red_inverse), &error),
|
||||
png_reciprocal(green_inverse), &error);
|
||||
if (error || blue_scale <= 0)
|
||||
return 1;
|
||||
/* Similarly for green_inverse: */
|
||||
if (png_muldiv(&left, xy->redy-xy->bluey, xy->whitex-xy->bluex, 8) == 0)
|
||||
return 1;
|
||||
if (png_muldiv(&right, xy->redx-xy->bluex, xy->whitey-xy->bluey, 8) == 0)
|
||||
return 1;
|
||||
if (png_muldiv(&green_inverse, xy->whitey, denominator,
|
||||
png_fp_sub(left, right, &error)) == 0 || error ||
|
||||
green_inverse <= xy->whitey)
|
||||
return 1;
|
||||
|
||||
/* And the blue scale, the checks above guarantee this can't overflow but
|
||||
* it can still produce 0 for extreme cHRM values.
|
||||
*/
|
||||
blue_scale = png_fp_sub(png_fp_sub(png_reciprocal(xy->whitey),
|
||||
png_reciprocal(red_inverse), &error),
|
||||
png_reciprocal(green_inverse), &error);
|
||||
if (error || blue_scale <= 0)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* And fill in the png_XYZ. Again the subtracts are safe because of the
|
||||
* checks on the xy values at the start (the subtracts just calculate the
|
||||
@@ -1625,239 +1491,9 @@ png_XYZ_from_xy(png_XYZ *XYZ, const png_xy *xy)
|
||||
|
||||
return 0; /*success*/
|
||||
}
|
||||
#endif /* COLORSPACE */
|
||||
|
||||
static int
|
||||
png_XYZ_normalize(png_XYZ *XYZ)
|
||||
{
|
||||
png_int_32 Y, Ytemp;
|
||||
|
||||
/* Normalize by scaling so the sum of the end-point Y values is PNG_FP_1. */
|
||||
Ytemp = XYZ->red_Y;
|
||||
if (png_safe_add(&Ytemp, XYZ->green_Y, XYZ->blue_Y))
|
||||
return 1;
|
||||
|
||||
Y = Ytemp;
|
||||
|
||||
if (Y != PNG_FP_1)
|
||||
{
|
||||
if (png_muldiv(&XYZ->red_X, XYZ->red_X, PNG_FP_1, Y) == 0)
|
||||
return 1;
|
||||
if (png_muldiv(&XYZ->red_Y, XYZ->red_Y, PNG_FP_1, Y) == 0)
|
||||
return 1;
|
||||
if (png_muldiv(&XYZ->red_Z, XYZ->red_Z, PNG_FP_1, Y) == 0)
|
||||
return 1;
|
||||
|
||||
if (png_muldiv(&XYZ->green_X, XYZ->green_X, PNG_FP_1, Y) == 0)
|
||||
return 1;
|
||||
if (png_muldiv(&XYZ->green_Y, XYZ->green_Y, PNG_FP_1, Y) == 0)
|
||||
return 1;
|
||||
if (png_muldiv(&XYZ->green_Z, XYZ->green_Z, PNG_FP_1, Y) == 0)
|
||||
return 1;
|
||||
|
||||
if (png_muldiv(&XYZ->blue_X, XYZ->blue_X, PNG_FP_1, Y) == 0)
|
||||
return 1;
|
||||
if (png_muldiv(&XYZ->blue_Y, XYZ->blue_Y, PNG_FP_1, Y) == 0)
|
||||
return 1;
|
||||
if (png_muldiv(&XYZ->blue_Z, XYZ->blue_Z, PNG_FP_1, Y) == 0)
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
png_colorspace_endpoints_match(const png_xy *xy1, const png_xy *xy2, int delta)
|
||||
{
|
||||
/* Allow an error of +/-0.01 (absolute value) on each chromaticity */
|
||||
if (PNG_OUT_OF_RANGE(xy1->whitex, xy2->whitex,delta) ||
|
||||
PNG_OUT_OF_RANGE(xy1->whitey, xy2->whitey,delta) ||
|
||||
PNG_OUT_OF_RANGE(xy1->redx, xy2->redx, delta) ||
|
||||
PNG_OUT_OF_RANGE(xy1->redy, xy2->redy, delta) ||
|
||||
PNG_OUT_OF_RANGE(xy1->greenx, xy2->greenx,delta) ||
|
||||
PNG_OUT_OF_RANGE(xy1->greeny, xy2->greeny,delta) ||
|
||||
PNG_OUT_OF_RANGE(xy1->bluex, xy2->bluex, delta) ||
|
||||
PNG_OUT_OF_RANGE(xy1->bluey, xy2->bluey, delta))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Added in libpng-1.6.0, a different check for the validity of a set of cHRM
|
||||
* chunk chromaticities. Earlier checks used to simply look for the overflow
|
||||
* condition (where the determinant of the matrix to solve for XYZ ends up zero
|
||||
* because the chromaticity values are not all distinct.) Despite this it is
|
||||
* theoretically possible to produce chromaticities that are apparently valid
|
||||
* but that rapidly degrade to invalid, potentially crashing, sets because of
|
||||
* arithmetic inaccuracies when calculations are performed on them. The new
|
||||
* check is to round-trip xy -> XYZ -> xy and then check that the result is
|
||||
* within a small percentage of the original.
|
||||
*/
|
||||
static int
|
||||
png_colorspace_check_xy(png_XYZ *XYZ, const png_xy *xy)
|
||||
{
|
||||
int result;
|
||||
png_xy xy_test;
|
||||
|
||||
/* As a side-effect this routine also returns the XYZ endpoints. */
|
||||
result = png_XYZ_from_xy(XYZ, xy);
|
||||
if (result != 0)
|
||||
return result;
|
||||
|
||||
result = png_xy_from_XYZ(&xy_test, XYZ);
|
||||
if (result != 0)
|
||||
return result;
|
||||
|
||||
if (png_colorspace_endpoints_match(xy, &xy_test,
|
||||
5/*actually, the math is pretty accurate*/) != 0)
|
||||
return 0;
|
||||
|
||||
/* Too much slip */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* This is the check going the other way. The XYZ is modified to normalize it
|
||||
* (another side-effect) and the xy chromaticities are returned.
|
||||
*/
|
||||
static int
|
||||
png_colorspace_check_XYZ(png_xy *xy, png_XYZ *XYZ)
|
||||
{
|
||||
int result;
|
||||
png_XYZ XYZtemp;
|
||||
|
||||
result = png_XYZ_normalize(XYZ);
|
||||
if (result != 0)
|
||||
return result;
|
||||
|
||||
result = png_xy_from_XYZ(xy, XYZ);
|
||||
if (result != 0)
|
||||
return result;
|
||||
|
||||
XYZtemp = *XYZ;
|
||||
return png_colorspace_check_xy(&XYZtemp, xy);
|
||||
}
|
||||
|
||||
/* Used to check for an endpoint match against sRGB */
|
||||
static const png_xy sRGB_xy = /* From ITU-R BT.709-3 */
|
||||
{
|
||||
/* color x y */
|
||||
/* red */ 64000, 33000,
|
||||
/* green */ 30000, 60000,
|
||||
/* blue */ 15000, 6000,
|
||||
/* white */ 31270, 32900
|
||||
};
|
||||
|
||||
static int
|
||||
png_colorspace_set_xy_and_XYZ(png_const_structrp png_ptr,
|
||||
png_colorspacerp colorspace, const png_xy *xy, const png_XYZ *XYZ,
|
||||
int preferred)
|
||||
{
|
||||
if ((colorspace->flags & PNG_COLORSPACE_INVALID) != 0)
|
||||
return 0;
|
||||
|
||||
/* The consistency check is performed on the chromaticities; this factors out
|
||||
* variations because of the normalization (or not) of the end point Y
|
||||
* values.
|
||||
*/
|
||||
if (preferred < 2 &&
|
||||
(colorspace->flags & PNG_COLORSPACE_HAVE_ENDPOINTS) != 0)
|
||||
{
|
||||
/* The end points must be reasonably close to any we already have. The
|
||||
* following allows an error of up to +/-.001
|
||||
*/
|
||||
if (png_colorspace_endpoints_match(xy, &colorspace->end_points_xy,
|
||||
100) == 0)
|
||||
{
|
||||
colorspace->flags |= PNG_COLORSPACE_INVALID;
|
||||
png_benign_error(png_ptr, "inconsistent chromaticities");
|
||||
return 0; /* failed */
|
||||
}
|
||||
|
||||
/* Only overwrite with preferred values */
|
||||
if (preferred == 0)
|
||||
return 1; /* ok, but no change */
|
||||
}
|
||||
|
||||
colorspace->end_points_xy = *xy;
|
||||
colorspace->end_points_XYZ = *XYZ;
|
||||
colorspace->flags |= PNG_COLORSPACE_HAVE_ENDPOINTS;
|
||||
|
||||
/* The end points are normally quoted to two decimal digits, so allow +/-0.01
|
||||
* on this test.
|
||||
*/
|
||||
if (png_colorspace_endpoints_match(xy, &sRGB_xy, 1000) != 0)
|
||||
colorspace->flags |= PNG_COLORSPACE_ENDPOINTS_MATCH_sRGB;
|
||||
|
||||
else
|
||||
colorspace->flags &= PNG_COLORSPACE_CANCEL(
|
||||
PNG_COLORSPACE_ENDPOINTS_MATCH_sRGB);
|
||||
|
||||
return 2; /* ok and changed */
|
||||
}
|
||||
|
||||
int /* PRIVATE */
|
||||
png_colorspace_set_chromaticities(png_const_structrp png_ptr,
|
||||
png_colorspacerp colorspace, const png_xy *xy, int preferred)
|
||||
{
|
||||
/* We must check the end points to ensure they are reasonable - in the past
|
||||
* color management systems have crashed as a result of getting bogus
|
||||
* colorant values, while this isn't the fault of libpng it is the
|
||||
* responsibility of libpng because PNG carries the bomb and libpng is in a
|
||||
* position to protect against it.
|
||||
*/
|
||||
png_XYZ XYZ;
|
||||
|
||||
switch (png_colorspace_check_xy(&XYZ, xy))
|
||||
{
|
||||
case 0: /* success */
|
||||
return png_colorspace_set_xy_and_XYZ(png_ptr, colorspace, xy, &XYZ,
|
||||
preferred);
|
||||
|
||||
case 1:
|
||||
/* We can't invert the chromaticities so we can't produce value XYZ
|
||||
* values. Likely as not a color management system will fail too.
|
||||
*/
|
||||
colorspace->flags |= PNG_COLORSPACE_INVALID;
|
||||
png_benign_error(png_ptr, "invalid chromaticities");
|
||||
break;
|
||||
|
||||
default:
|
||||
/* libpng is broken; this should be a warning but if it happens we
|
||||
* want error reports so for the moment it is an error.
|
||||
*/
|
||||
colorspace->flags |= PNG_COLORSPACE_INVALID;
|
||||
png_error(png_ptr, "internal error checking chromaticities");
|
||||
}
|
||||
|
||||
return 0; /* failed */
|
||||
}
|
||||
|
||||
int /* PRIVATE */
|
||||
png_colorspace_set_endpoints(png_const_structrp png_ptr,
|
||||
png_colorspacerp colorspace, const png_XYZ *XYZ_in, int preferred)
|
||||
{
|
||||
png_XYZ XYZ = *XYZ_in;
|
||||
png_xy xy;
|
||||
|
||||
switch (png_colorspace_check_XYZ(&xy, &XYZ))
|
||||
{
|
||||
case 0:
|
||||
return png_colorspace_set_xy_and_XYZ(png_ptr, colorspace, &xy, &XYZ,
|
||||
preferred);
|
||||
|
||||
case 1:
|
||||
/* End points are invalid. */
|
||||
colorspace->flags |= PNG_COLORSPACE_INVALID;
|
||||
png_benign_error(png_ptr, "invalid end points");
|
||||
break;
|
||||
|
||||
default:
|
||||
colorspace->flags |= PNG_COLORSPACE_INVALID;
|
||||
png_error(png_ptr, "internal error checking chromaticities");
|
||||
}
|
||||
|
||||
return 0; /* failed */
|
||||
}
|
||||
|
||||
#if defined(PNG_sRGB_SUPPORTED) || defined(PNG_iCCP_SUPPORTED)
|
||||
#ifdef PNG_READ_iCCP_SUPPORTED
|
||||
/* Error message generation */
|
||||
static char
|
||||
png_icc_tag_char(png_uint_32 byte)
|
||||
@@ -1897,15 +1533,12 @@ is_ICC_signature(png_alloc_size_t it)
|
||||
}
|
||||
|
||||
static int
|
||||
png_icc_profile_error(png_const_structrp png_ptr, png_colorspacerp colorspace,
|
||||
png_const_charp name, png_alloc_size_t value, png_const_charp reason)
|
||||
png_icc_profile_error(png_const_structrp png_ptr, png_const_charp name,
|
||||
png_alloc_size_t value, png_const_charp reason)
|
||||
{
|
||||
size_t pos;
|
||||
char message[196]; /* see below for calculation */
|
||||
|
||||
if (colorspace != NULL)
|
||||
colorspace->flags |= PNG_COLORSPACE_INVALID;
|
||||
|
||||
pos = png_safecat(message, (sizeof message), 0, "profile '"); /* 9 chars */
|
||||
pos = png_safecat(message, pos+79, pos, name); /* Truncate to 79 chars */
|
||||
pos = png_safecat(message, (sizeof message), pos, "': "); /* +2 = 90 */
|
||||
@@ -1932,109 +1565,11 @@ png_icc_profile_error(png_const_structrp png_ptr, png_colorspacerp colorspace,
|
||||
pos = png_safecat(message, (sizeof message), pos, reason);
|
||||
PNG_UNUSED(pos)
|
||||
|
||||
/* This is recoverable, but make it unconditionally an app_error on write to
|
||||
* avoid writing invalid ICC profiles into PNG files (i.e., we handle them
|
||||
* on read, with a warning, but on write unless the app turns off
|
||||
* application errors the PNG won't be written.)
|
||||
*/
|
||||
png_chunk_report(png_ptr, message,
|
||||
(colorspace != NULL) ? PNG_CHUNK_ERROR : PNG_CHUNK_WRITE_ERROR);
|
||||
png_chunk_benign_error(png_ptr, message);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* sRGB || iCCP */
|
||||
|
||||
#ifdef PNG_sRGB_SUPPORTED
|
||||
int /* PRIVATE */
|
||||
png_colorspace_set_sRGB(png_const_structrp png_ptr, png_colorspacerp colorspace,
|
||||
int intent)
|
||||
{
|
||||
/* sRGB sets known gamma, end points and (from the chunk) intent. */
|
||||
/* IMPORTANT: these are not necessarily the values found in an ICC profile
|
||||
* because ICC profiles store values adapted to a D50 environment; it is
|
||||
* expected that the ICC profile mediaWhitePointTag will be D50; see the
|
||||
* checks and code elsewhere to understand this better.
|
||||
*
|
||||
* These XYZ values, which are accurate to 5dp, produce rgb to gray
|
||||
* coefficients of (6968,23435,2366), which are reduced (because they add up
|
||||
* to 32769 not 32768) to (6968,23434,2366). These are the values that
|
||||
* libpng has traditionally used (and are the best values given the 15bit
|
||||
* algorithm used by the rgb to gray code.)
|
||||
*/
|
||||
static const png_XYZ sRGB_XYZ = /* D65 XYZ (*not* the D50 adapted values!) */
|
||||
{
|
||||
/* color X Y Z */
|
||||
/* red */ 41239, 21264, 1933,
|
||||
/* green */ 35758, 71517, 11919,
|
||||
/* blue */ 18048, 7219, 95053
|
||||
};
|
||||
|
||||
/* Do nothing if the colorspace is already invalidated. */
|
||||
if ((colorspace->flags & PNG_COLORSPACE_INVALID) != 0)
|
||||
return 0;
|
||||
|
||||
/* Check the intent, then check for existing settings. It is valid for the
|
||||
* PNG file to have cHRM or gAMA chunks along with sRGB, but the values must
|
||||
* be consistent with the correct values. If, however, this function is
|
||||
* called below because an iCCP chunk matches sRGB then it is quite
|
||||
* conceivable that an older app recorded incorrect gAMA and cHRM because of
|
||||
* an incorrect calculation based on the values in the profile - this does
|
||||
* *not* invalidate the profile (though it still produces an error, which can
|
||||
* be ignored.)
|
||||
*/
|
||||
if (intent < 0 || intent >= PNG_sRGB_INTENT_LAST)
|
||||
return png_icc_profile_error(png_ptr, colorspace, "sRGB",
|
||||
(png_alloc_size_t)intent, "invalid sRGB rendering intent");
|
||||
|
||||
if ((colorspace->flags & PNG_COLORSPACE_HAVE_INTENT) != 0 &&
|
||||
colorspace->rendering_intent != intent)
|
||||
return png_icc_profile_error(png_ptr, colorspace, "sRGB",
|
||||
(png_alloc_size_t)intent, "inconsistent rendering intents");
|
||||
|
||||
if ((colorspace->flags & PNG_COLORSPACE_FROM_sRGB) != 0)
|
||||
{
|
||||
png_benign_error(png_ptr, "duplicate sRGB information ignored");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If the standard sRGB cHRM chunk does not match the one from the PNG file
|
||||
* warn but overwrite the value with the correct one.
|
||||
*/
|
||||
if ((colorspace->flags & PNG_COLORSPACE_HAVE_ENDPOINTS) != 0 &&
|
||||
!png_colorspace_endpoints_match(&sRGB_xy, &colorspace->end_points_xy,
|
||||
100))
|
||||
png_chunk_report(png_ptr, "cHRM chunk does not match sRGB",
|
||||
PNG_CHUNK_ERROR);
|
||||
|
||||
/* This check is just done for the error reporting - the routine always
|
||||
* returns true when the 'from' argument corresponds to sRGB (2).
|
||||
*/
|
||||
(void)png_colorspace_check_gamma(png_ptr, colorspace, PNG_GAMMA_sRGB_INVERSE,
|
||||
2/*from sRGB*/);
|
||||
|
||||
/* intent: bugs in GCC force 'int' to be used as the parameter type. */
|
||||
colorspace->rendering_intent = (png_uint_16)intent;
|
||||
colorspace->flags |= PNG_COLORSPACE_HAVE_INTENT;
|
||||
|
||||
/* endpoints */
|
||||
colorspace->end_points_xy = sRGB_xy;
|
||||
colorspace->end_points_XYZ = sRGB_XYZ;
|
||||
colorspace->flags |=
|
||||
(PNG_COLORSPACE_HAVE_ENDPOINTS|PNG_COLORSPACE_ENDPOINTS_MATCH_sRGB);
|
||||
|
||||
/* gamma */
|
||||
colorspace->gamma = PNG_GAMMA_sRGB_INVERSE;
|
||||
colorspace->flags |= PNG_COLORSPACE_HAVE_GAMMA;
|
||||
|
||||
/* Finally record that we have an sRGB profile */
|
||||
colorspace->flags |=
|
||||
(PNG_COLORSPACE_MATCHES_sRGB|PNG_COLORSPACE_FROM_sRGB);
|
||||
|
||||
return 1; /* set */
|
||||
}
|
||||
#endif /* sRGB */
|
||||
|
||||
#ifdef PNG_iCCP_SUPPORTED
|
||||
/* Encoded value of D50 as an ICC XYZNumber. From the ICC 2010 spec the value
|
||||
* is XYZ(0.9642,1.0,0.8249), which scales to:
|
||||
*
|
||||
@@ -2044,21 +1579,19 @@ static const png_byte D50_nCIEXYZ[12] =
|
||||
{ 0x00, 0x00, 0xf6, 0xd6, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd3, 0x2d };
|
||||
|
||||
static int /* bool */
|
||||
icc_check_length(png_const_structrp png_ptr, png_colorspacerp colorspace,
|
||||
png_const_charp name, png_uint_32 profile_length)
|
||||
icc_check_length(png_const_structrp png_ptr, png_const_charp name,
|
||||
png_uint_32 profile_length)
|
||||
{
|
||||
if (profile_length < 132)
|
||||
return png_icc_profile_error(png_ptr, colorspace, name, profile_length,
|
||||
"too short");
|
||||
return png_icc_profile_error(png_ptr, name, profile_length, "too short");
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef PNG_READ_iCCP_SUPPORTED
|
||||
int /* PRIVATE */
|
||||
png_icc_check_length(png_const_structrp png_ptr, png_colorspacerp colorspace,
|
||||
png_const_charp name, png_uint_32 profile_length)
|
||||
png_icc_check_length(png_const_structrp png_ptr, png_const_charp name,
|
||||
png_uint_32 profile_length)
|
||||
{
|
||||
if (!icc_check_length(png_ptr, colorspace, name, profile_length))
|
||||
if (!icc_check_length(png_ptr, name, profile_length))
|
||||
return 0;
|
||||
|
||||
/* This needs to be here because the 'normal' check is in
|
||||
@@ -2067,30 +1600,17 @@ png_icc_check_length(png_const_structrp png_ptr, png_colorspacerp colorspace,
|
||||
* the caller supplies the profile buffer so libpng doesn't allocate it. See
|
||||
* the call to icc_check_length below (the write case).
|
||||
*/
|
||||
# ifdef PNG_SET_USER_LIMITS_SUPPORTED
|
||||
else if (png_ptr->user_chunk_malloc_max > 0 &&
|
||||
png_ptr->user_chunk_malloc_max < profile_length)
|
||||
return png_icc_profile_error(png_ptr, colorspace, name, profile_length,
|
||||
"exceeds application limits");
|
||||
# elif PNG_USER_CHUNK_MALLOC_MAX > 0
|
||||
else if (PNG_USER_CHUNK_MALLOC_MAX < profile_length)
|
||||
return png_icc_profile_error(png_ptr, colorspace, name, profile_length,
|
||||
"exceeds libpng limits");
|
||||
# else /* !SET_USER_LIMITS */
|
||||
/* This will get compiled out on all 32-bit and better systems. */
|
||||
else if (PNG_SIZE_MAX < profile_length)
|
||||
return png_icc_profile_error(png_ptr, colorspace, name, profile_length,
|
||||
"exceeds system limits");
|
||||
# endif /* !SET_USER_LIMITS */
|
||||
if (profile_length > png_chunk_max(png_ptr))
|
||||
return png_icc_profile_error(png_ptr, name, profile_length,
|
||||
"profile too long");
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif /* READ_iCCP */
|
||||
|
||||
int /* PRIVATE */
|
||||
png_icc_check_header(png_const_structrp png_ptr, png_colorspacerp colorspace,
|
||||
png_const_charp name, png_uint_32 profile_length,
|
||||
png_const_bytep profile/* first 132 bytes only */, int color_type)
|
||||
png_icc_check_header(png_const_structrp png_ptr, png_const_charp name,
|
||||
png_uint_32 profile_length,
|
||||
png_const_bytep profile/* first 132 bytes only */, int color_type)
|
||||
{
|
||||
png_uint_32 temp;
|
||||
|
||||
@@ -2101,18 +1621,18 @@ png_icc_check_header(png_const_structrp png_ptr, png_colorspacerp colorspace,
|
||||
*/
|
||||
temp = png_get_uint_32(profile);
|
||||
if (temp != profile_length)
|
||||
return png_icc_profile_error(png_ptr, colorspace, name, temp,
|
||||
return png_icc_profile_error(png_ptr, name, temp,
|
||||
"length does not match profile");
|
||||
|
||||
temp = (png_uint_32) (*(profile+8));
|
||||
if (temp > 3 && (profile_length & 3))
|
||||
return png_icc_profile_error(png_ptr, colorspace, name, profile_length,
|
||||
return png_icc_profile_error(png_ptr, name, profile_length,
|
||||
"invalid length");
|
||||
|
||||
temp = png_get_uint_32(profile+128); /* tag count: 12 bytes/tag */
|
||||
if (temp > 357913930 || /* (2^32-4-132)/12: maximum possible tag count */
|
||||
profile_length < 132+12*temp) /* truncated tag table */
|
||||
return png_icc_profile_error(png_ptr, colorspace, name, temp,
|
||||
return png_icc_profile_error(png_ptr, name, temp,
|
||||
"tag count too large");
|
||||
|
||||
/* The 'intent' must be valid or we can't store it, ICC limits the intent to
|
||||
@@ -2120,14 +1640,14 @@ png_icc_check_header(png_const_structrp png_ptr, png_colorspacerp colorspace,
|
||||
*/
|
||||
temp = png_get_uint_32(profile+64);
|
||||
if (temp >= 0xffff) /* The ICC limit */
|
||||
return png_icc_profile_error(png_ptr, colorspace, name, temp,
|
||||
return png_icc_profile_error(png_ptr, name, temp,
|
||||
"invalid rendering intent");
|
||||
|
||||
/* This is just a warning because the profile may be valid in future
|
||||
* versions.
|
||||
*/
|
||||
if (temp >= PNG_sRGB_INTENT_LAST)
|
||||
(void)png_icc_profile_error(png_ptr, NULL, name, temp,
|
||||
(void)png_icc_profile_error(png_ptr, name, temp,
|
||||
"intent outside defined range");
|
||||
|
||||
/* At this point the tag table can't be checked because it hasn't necessarily
|
||||
@@ -2144,7 +1664,7 @@ png_icc_check_header(png_const_structrp png_ptr, png_colorspacerp colorspace,
|
||||
*/
|
||||
temp = png_get_uint_32(profile+36); /* signature 'ascp' */
|
||||
if (temp != 0x61637370)
|
||||
return png_icc_profile_error(png_ptr, colorspace, name, temp,
|
||||
return png_icc_profile_error(png_ptr, name, temp,
|
||||
"invalid signature");
|
||||
|
||||
/* Currently the PCS illuminant/adopted white point (the computational
|
||||
@@ -2155,7 +1675,7 @@ png_icc_check_header(png_const_structrp png_ptr, png_colorspacerp colorspace,
|
||||
* following is just a warning.
|
||||
*/
|
||||
if (memcmp(profile+68, D50_nCIEXYZ, 12) != 0)
|
||||
(void)png_icc_profile_error(png_ptr, NULL, name, 0/*no tag value*/,
|
||||
(void)png_icc_profile_error(png_ptr, name, 0/*no tag value*/,
|
||||
"PCS illuminant is not D50");
|
||||
|
||||
/* The PNG spec requires this:
|
||||
@@ -2183,18 +1703,18 @@ png_icc_check_header(png_const_structrp png_ptr, png_colorspacerp colorspace,
|
||||
{
|
||||
case 0x52474220: /* 'RGB ' */
|
||||
if ((color_type & PNG_COLOR_MASK_COLOR) == 0)
|
||||
return png_icc_profile_error(png_ptr, colorspace, name, temp,
|
||||
return png_icc_profile_error(png_ptr, name, temp,
|
||||
"RGB color space not permitted on grayscale PNG");
|
||||
break;
|
||||
|
||||
case 0x47524159: /* 'GRAY' */
|
||||
if ((color_type & PNG_COLOR_MASK_COLOR) != 0)
|
||||
return png_icc_profile_error(png_ptr, colorspace, name, temp,
|
||||
return png_icc_profile_error(png_ptr, name, temp,
|
||||
"Gray color space not permitted on RGB PNG");
|
||||
break;
|
||||
|
||||
default:
|
||||
return png_icc_profile_error(png_ptr, colorspace, name, temp,
|
||||
return png_icc_profile_error(png_ptr, name, temp,
|
||||
"invalid ICC profile color space");
|
||||
}
|
||||
|
||||
@@ -2219,7 +1739,7 @@ png_icc_check_header(png_const_structrp png_ptr, png_colorspacerp colorspace,
|
||||
|
||||
case 0x61627374: /* 'abst' */
|
||||
/* May not be embedded in an image */
|
||||
return png_icc_profile_error(png_ptr, colorspace, name, temp,
|
||||
return png_icc_profile_error(png_ptr, name, temp,
|
||||
"invalid embedded Abstract ICC profile");
|
||||
|
||||
case 0x6c696e6b: /* 'link' */
|
||||
@@ -2229,7 +1749,7 @@ png_icc_check_header(png_const_structrp png_ptr, png_colorspacerp colorspace,
|
||||
* therefore a DeviceLink profile should not be found embedded in a
|
||||
* PNG.
|
||||
*/
|
||||
return png_icc_profile_error(png_ptr, colorspace, name, temp,
|
||||
return png_icc_profile_error(png_ptr, name, temp,
|
||||
"unexpected DeviceLink ICC profile class");
|
||||
|
||||
case 0x6e6d636c: /* 'nmcl' */
|
||||
@@ -2237,7 +1757,7 @@ png_icc_check_header(png_const_structrp png_ptr, png_colorspacerp colorspace,
|
||||
* contain an AToB0 tag that is open to misinterpretation. Almost
|
||||
* certainly it will fail the tests below.
|
||||
*/
|
||||
(void)png_icc_profile_error(png_ptr, NULL, name, temp,
|
||||
(void)png_icc_profile_error(png_ptr, name, temp,
|
||||
"unexpected NamedColor ICC profile class");
|
||||
break;
|
||||
|
||||
@@ -2247,7 +1767,7 @@ png_icc_check_header(png_const_structrp png_ptr, png_colorspacerp colorspace,
|
||||
* tag content to ensure they are backward compatible with one of the
|
||||
* understood profiles.
|
||||
*/
|
||||
(void)png_icc_profile_error(png_ptr, NULL, name, temp,
|
||||
(void)png_icc_profile_error(png_ptr, name, temp,
|
||||
"unrecognized ICC profile class");
|
||||
break;
|
||||
}
|
||||
@@ -2263,7 +1783,7 @@ png_icc_check_header(png_const_structrp png_ptr, png_colorspacerp colorspace,
|
||||
break;
|
||||
|
||||
default:
|
||||
return png_icc_profile_error(png_ptr, colorspace, name, temp,
|
||||
return png_icc_profile_error(png_ptr, name, temp,
|
||||
"unexpected ICC PCS encoding");
|
||||
}
|
||||
|
||||
@@ -2271,9 +1791,9 @@ png_icc_check_header(png_const_structrp png_ptr, png_colorspacerp colorspace,
|
||||
}
|
||||
|
||||
int /* PRIVATE */
|
||||
png_icc_check_tag_table(png_const_structrp png_ptr, png_colorspacerp colorspace,
|
||||
png_const_charp name, png_uint_32 profile_length,
|
||||
png_const_bytep profile /* header plus whole tag table */)
|
||||
png_icc_check_tag_table(png_const_structrp png_ptr, png_const_charp name,
|
||||
png_uint_32 profile_length,
|
||||
png_const_bytep profile /* header plus whole tag table */)
|
||||
{
|
||||
png_uint_32 tag_count = png_get_uint_32(profile+128);
|
||||
png_uint_32 itag;
|
||||
@@ -2299,7 +1819,7 @@ png_icc_check_tag_table(png_const_structrp png_ptr, png_colorspacerp colorspace,
|
||||
* profile.
|
||||
*/
|
||||
if (tag_start > profile_length || tag_length > profile_length - tag_start)
|
||||
return png_icc_profile_error(png_ptr, colorspace, name, tag_id,
|
||||
return png_icc_profile_error(png_ptr, name, tag_id,
|
||||
"ICC profile tag outside profile");
|
||||
|
||||
if ((tag_start & 3) != 0)
|
||||
@@ -2308,307 +1828,132 @@ png_icc_check_tag_table(png_const_structrp png_ptr, png_colorspacerp colorspace,
|
||||
* only a warning here because libpng does not care about the
|
||||
* alignment.
|
||||
*/
|
||||
(void)png_icc_profile_error(png_ptr, NULL, name, tag_id,
|
||||
(void)png_icc_profile_error(png_ptr, name, tag_id,
|
||||
"ICC profile tag start not a multiple of 4");
|
||||
}
|
||||
}
|
||||
|
||||
return 1; /* success, maybe with warnings */
|
||||
}
|
||||
|
||||
#ifdef PNG_sRGB_SUPPORTED
|
||||
#if PNG_sRGB_PROFILE_CHECKS >= 0
|
||||
/* Information about the known ICC sRGB profiles */
|
||||
static const struct
|
||||
{
|
||||
png_uint_32 adler, crc, length;
|
||||
png_uint_32 md5[4];
|
||||
png_byte have_md5;
|
||||
png_byte is_broken;
|
||||
png_uint_16 intent;
|
||||
|
||||
# define PNG_MD5(a,b,c,d) { a, b, c, d }, (a!=0)||(b!=0)||(c!=0)||(d!=0)
|
||||
# define PNG_ICC_CHECKSUM(adler, crc, md5, intent, broke, date, length, fname)\
|
||||
{ adler, crc, length, md5, broke, intent },
|
||||
|
||||
} png_sRGB_checks[] =
|
||||
{
|
||||
/* This data comes from contrib/tools/checksum-icc run on downloads of
|
||||
* all four ICC sRGB profiles from www.color.org.
|
||||
*/
|
||||
/* adler32, crc32, MD5[4], intent, date, length, file-name */
|
||||
PNG_ICC_CHECKSUM(0x0a3fd9f6, 0x3b8772b9,
|
||||
PNG_MD5(0x29f83dde, 0xaff255ae, 0x7842fae4, 0xca83390d), 0, 0,
|
||||
"2009/03/27 21:36:31", 3048, "sRGB_IEC61966-2-1_black_scaled.icc")
|
||||
|
||||
/* ICC sRGB v2 perceptual no black-compensation: */
|
||||
PNG_ICC_CHECKSUM(0x4909e5e1, 0x427ebb21,
|
||||
PNG_MD5(0xc95bd637, 0xe95d8a3b, 0x0df38f99, 0xc1320389), 1, 0,
|
||||
"2009/03/27 21:37:45", 3052, "sRGB_IEC61966-2-1_no_black_scaling.icc")
|
||||
|
||||
PNG_ICC_CHECKSUM(0xfd2144a1, 0x306fd8ae,
|
||||
PNG_MD5(0xfc663378, 0x37e2886b, 0xfd72e983, 0x8228f1b8), 0, 0,
|
||||
"2009/08/10 17:28:01", 60988, "sRGB_v4_ICC_preference_displayclass.icc")
|
||||
|
||||
/* ICC sRGB v4 perceptual */
|
||||
PNG_ICC_CHECKSUM(0x209c35d2, 0xbbef7812,
|
||||
PNG_MD5(0x34562abf, 0x994ccd06, 0x6d2c5721, 0xd0d68c5d), 0, 0,
|
||||
"2007/07/25 00:05:37", 60960, "sRGB_v4_ICC_preference.icc")
|
||||
|
||||
/* The following profiles have no known MD5 checksum. If there is a match
|
||||
* on the (empty) MD5 the other fields are used to attempt a match and
|
||||
* a warning is produced. The first two of these profiles have a 'cprt' tag
|
||||
* which suggests that they were also made by Hewlett Packard.
|
||||
*/
|
||||
PNG_ICC_CHECKSUM(0xa054d762, 0x5d5129ce,
|
||||
PNG_MD5(0x00000000, 0x00000000, 0x00000000, 0x00000000), 1, 0,
|
||||
"2004/07/21 18:57:42", 3024, "sRGB_IEC61966-2-1_noBPC.icc")
|
||||
|
||||
/* This is a 'mntr' (display) profile with a mediaWhitePointTag that does not
|
||||
* match the D50 PCS illuminant in the header (it is in fact the D65 values,
|
||||
* so the white point is recorded as the un-adapted value.) The profiles
|
||||
* below only differ in one byte - the intent - and are basically the same as
|
||||
* the previous profile except for the mediaWhitePointTag error and a missing
|
||||
* chromaticAdaptationTag.
|
||||
*/
|
||||
PNG_ICC_CHECKSUM(0xf784f3fb, 0x182ea552,
|
||||
PNG_MD5(0x00000000, 0x00000000, 0x00000000, 0x00000000), 0, 1/*broken*/,
|
||||
"1998/02/09 06:49:00", 3144, "HP-Microsoft sRGB v2 perceptual")
|
||||
|
||||
PNG_ICC_CHECKSUM(0x0398f3fc, 0xf29e526d,
|
||||
PNG_MD5(0x00000000, 0x00000000, 0x00000000, 0x00000000), 1, 1/*broken*/,
|
||||
"1998/02/09 06:49:00", 3144, "HP-Microsoft sRGB v2 media-relative")
|
||||
};
|
||||
|
||||
static int
|
||||
png_compare_ICC_profile_with_sRGB(png_const_structrp png_ptr,
|
||||
png_const_bytep profile, uLong adler)
|
||||
{
|
||||
/* The quick check is to verify just the MD5 signature and trust the
|
||||
* rest of the data. Because the profile has already been verified for
|
||||
* correctness this is safe. png_colorspace_set_sRGB will check the 'intent'
|
||||
* field too, so if the profile has been edited with an intent not defined
|
||||
* by sRGB (but maybe defined by a later ICC specification) the read of
|
||||
* the profile will fail at that point.
|
||||
*/
|
||||
|
||||
png_uint_32 length = 0;
|
||||
png_uint_32 intent = 0x10000; /* invalid */
|
||||
#if PNG_sRGB_PROFILE_CHECKS > 1
|
||||
uLong crc = 0; /* the value for 0 length data */
|
||||
#endif
|
||||
unsigned int i;
|
||||
|
||||
#ifdef PNG_SET_OPTION_SUPPORTED
|
||||
/* First see if PNG_SKIP_sRGB_CHECK_PROFILE has been set to "on" */
|
||||
if (((png_ptr->options >> PNG_SKIP_sRGB_CHECK_PROFILE) & 3) ==
|
||||
PNG_OPTION_ON)
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
for (i=0; i < (sizeof png_sRGB_checks) / (sizeof png_sRGB_checks[0]); ++i)
|
||||
{
|
||||
if (png_get_uint_32(profile+84) == png_sRGB_checks[i].md5[0] &&
|
||||
png_get_uint_32(profile+88) == png_sRGB_checks[i].md5[1] &&
|
||||
png_get_uint_32(profile+92) == png_sRGB_checks[i].md5[2] &&
|
||||
png_get_uint_32(profile+96) == png_sRGB_checks[i].md5[3])
|
||||
{
|
||||
/* This may be one of the old HP profiles without an MD5, in that
|
||||
* case we can only use the length and Adler32 (note that these
|
||||
* are not used by default if there is an MD5!)
|
||||
*/
|
||||
# if PNG_sRGB_PROFILE_CHECKS == 0
|
||||
if (png_sRGB_checks[i].have_md5 != 0)
|
||||
return 1+png_sRGB_checks[i].is_broken;
|
||||
# endif
|
||||
|
||||
/* Profile is unsigned or more checks have been configured in. */
|
||||
if (length == 0)
|
||||
{
|
||||
length = png_get_uint_32(profile);
|
||||
intent = png_get_uint_32(profile+64);
|
||||
}
|
||||
|
||||
/* Length *and* intent must match */
|
||||
if (length == (png_uint_32) png_sRGB_checks[i].length &&
|
||||
intent == (png_uint_32) png_sRGB_checks[i].intent)
|
||||
{
|
||||
/* Now calculate the adler32 if not done already. */
|
||||
if (adler == 0)
|
||||
{
|
||||
adler = adler32(0, NULL, 0);
|
||||
adler = adler32(adler, profile, length);
|
||||
}
|
||||
|
||||
if (adler == png_sRGB_checks[i].adler)
|
||||
{
|
||||
/* These basic checks suggest that the data has not been
|
||||
* modified, but if the check level is more than 1 perform
|
||||
* our own crc32 checksum on the data.
|
||||
*/
|
||||
# if PNG_sRGB_PROFILE_CHECKS > 1
|
||||
if (crc == 0)
|
||||
{
|
||||
crc = crc32(0, NULL, 0);
|
||||
crc = crc32(crc, profile, length);
|
||||
}
|
||||
|
||||
/* So this check must pass for the 'return' below to happen.
|
||||
*/
|
||||
if (crc == png_sRGB_checks[i].crc)
|
||||
# endif
|
||||
{
|
||||
if (png_sRGB_checks[i].is_broken != 0)
|
||||
{
|
||||
/* These profiles are known to have bad data that may cause
|
||||
* problems if they are used, therefore attempt to
|
||||
* discourage their use, skip the 'have_md5' warning below,
|
||||
* which is made irrelevant by this error.
|
||||
*/
|
||||
png_chunk_report(png_ptr, "known incorrect sRGB profile",
|
||||
PNG_CHUNK_ERROR);
|
||||
}
|
||||
|
||||
/* Warn that this being done; this isn't even an error since
|
||||
* the profile is perfectly valid, but it would be nice if
|
||||
* people used the up-to-date ones.
|
||||
*/
|
||||
else if (png_sRGB_checks[i].have_md5 == 0)
|
||||
{
|
||||
png_chunk_report(png_ptr,
|
||||
"out-of-date sRGB profile with no signature",
|
||||
PNG_CHUNK_WARNING);
|
||||
}
|
||||
|
||||
return 1+png_sRGB_checks[i].is_broken;
|
||||
}
|
||||
}
|
||||
|
||||
# if PNG_sRGB_PROFILE_CHECKS > 0
|
||||
/* The signature matched, but the profile had been changed in some
|
||||
* way. This probably indicates a data error or uninformed hacking.
|
||||
* Fall through to "no match".
|
||||
*/
|
||||
png_chunk_report(png_ptr,
|
||||
"Not recognizing known sRGB profile that has been edited",
|
||||
PNG_CHUNK_WARNING);
|
||||
break;
|
||||
# endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0; /* no match */
|
||||
}
|
||||
|
||||
void /* PRIVATE */
|
||||
png_icc_set_sRGB(png_const_structrp png_ptr,
|
||||
png_colorspacerp colorspace, png_const_bytep profile, uLong adler)
|
||||
{
|
||||
/* Is this profile one of the known ICC sRGB profiles? If it is, just set
|
||||
* the sRGB information.
|
||||
*/
|
||||
if (png_compare_ICC_profile_with_sRGB(png_ptr, profile, adler) != 0)
|
||||
(void)png_colorspace_set_sRGB(png_ptr, colorspace,
|
||||
(int)/*already checked*/png_get_uint_32(profile+64));
|
||||
}
|
||||
#endif /* PNG_sRGB_PROFILE_CHECKS >= 0 */
|
||||
#endif /* sRGB */
|
||||
|
||||
int /* PRIVATE */
|
||||
png_colorspace_set_ICC(png_const_structrp png_ptr, png_colorspacerp colorspace,
|
||||
png_const_charp name, png_uint_32 profile_length, png_const_bytep profile,
|
||||
int color_type)
|
||||
{
|
||||
if ((colorspace->flags & PNG_COLORSPACE_INVALID) != 0)
|
||||
return 0;
|
||||
|
||||
if (icc_check_length(png_ptr, colorspace, name, profile_length) != 0 &&
|
||||
png_icc_check_header(png_ptr, colorspace, name, profile_length, profile,
|
||||
color_type) != 0 &&
|
||||
png_icc_check_tag_table(png_ptr, colorspace, name, profile_length,
|
||||
profile) != 0)
|
||||
{
|
||||
# if defined(PNG_sRGB_SUPPORTED) && PNG_sRGB_PROFILE_CHECKS >= 0
|
||||
/* If no sRGB support, don't try storing sRGB information */
|
||||
png_icc_set_sRGB(png_ptr, colorspace, profile, 0);
|
||||
# endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Failure case */
|
||||
return 0;
|
||||
}
|
||||
#endif /* iCCP */
|
||||
#endif /* READ_iCCP */
|
||||
|
||||
#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
|
||||
void /* PRIVATE */
|
||||
png_colorspace_set_rgb_coefficients(png_structrp png_ptr)
|
||||
#if (defined PNG_READ_mDCV_SUPPORTED) || (defined PNG_READ_cHRM_SUPPORTED)
|
||||
static int
|
||||
have_chromaticities(png_const_structrp png_ptr)
|
||||
{
|
||||
/* Set the rgb_to_gray coefficients from the colorspace. */
|
||||
if (png_ptr->rgb_to_gray_coefficients_set == 0 &&
|
||||
(png_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_ENDPOINTS) != 0)
|
||||
/* Handle new PNGv3 chunks and the precedence rules to determine whether
|
||||
* png_struct::chromaticities must be processed. Only required for RGB to
|
||||
* gray.
|
||||
*
|
||||
* mDCV: this is the mastering colour space and it is independent of the
|
||||
* encoding so it needs to be used regardless of the encoded space.
|
||||
*
|
||||
* cICP: first in priority but not yet implemented - the chromaticities come
|
||||
* from the 'primaries'.
|
||||
*
|
||||
* iCCP: not supported by libpng (so ignored)
|
||||
*
|
||||
* sRGB: the defaults match sRGB
|
||||
*
|
||||
* cHRM: calculate the coefficients
|
||||
*/
|
||||
# ifdef PNG_READ_mDCV_SUPPORTED
|
||||
if (png_has_chunk(png_ptr, mDCV))
|
||||
return 1;
|
||||
# define check_chromaticities 1
|
||||
# endif /*mDCV*/
|
||||
|
||||
# ifdef PNG_READ_sRGB_SUPPORTED
|
||||
if (png_has_chunk(png_ptr, sRGB))
|
||||
return 0;
|
||||
# endif /*sRGB*/
|
||||
|
||||
# ifdef PNG_READ_cHRM_SUPPORTED
|
||||
if (png_has_chunk(png_ptr, cHRM))
|
||||
return 1;
|
||||
# define check_chromaticities 1
|
||||
# endif /*cHRM*/
|
||||
|
||||
return 0; /* sRGB defaults */
|
||||
}
|
||||
#endif /* READ_mDCV || READ_cHRM */
|
||||
|
||||
void /* PRIVATE */
|
||||
png_set_rgb_coefficients(png_structrp png_ptr)
|
||||
{
|
||||
/* Set the rgb_to_gray coefficients from the colorspace if available. Note
|
||||
* that '_set' means that png_rgb_to_gray was called **and** it successfully
|
||||
* set up the coefficients.
|
||||
*/
|
||||
if (png_ptr->rgb_to_gray_coefficients_set == 0)
|
||||
{
|
||||
/* png_set_background has not been called, get the coefficients from the Y
|
||||
* values of the colorspace colorants.
|
||||
*/
|
||||
png_fixed_point r = png_ptr->colorspace.end_points_XYZ.red_Y;
|
||||
png_fixed_point g = png_ptr->colorspace.end_points_XYZ.green_Y;
|
||||
png_fixed_point b = png_ptr->colorspace.end_points_XYZ.blue_Y;
|
||||
png_fixed_point total = r+g+b;
|
||||
# if check_chromaticities
|
||||
png_XYZ xyz;
|
||||
|
||||
if (total > 0 &&
|
||||
r >= 0 && png_muldiv(&r, r, 32768, total) && r >= 0 && r <= 32768 &&
|
||||
g >= 0 && png_muldiv(&g, g, 32768, total) && g >= 0 && g <= 32768 &&
|
||||
b >= 0 && png_muldiv(&b, b, 32768, total) && b >= 0 && b <= 32768 &&
|
||||
r+g+b <= 32769)
|
||||
if (have_chromaticities(png_ptr) &&
|
||||
png_XYZ_from_xy(&xyz, &png_ptr->chromaticities) == 0)
|
||||
{
|
||||
/* We allow 0 coefficients here. r+g+b may be 32769 if two or
|
||||
* all of the coefficients were rounded up. Handle this by
|
||||
* reducing the *largest* coefficient by 1; this matches the
|
||||
* approach used for the default coefficients in pngrtran.c
|
||||
/* png_set_rgb_to_gray has not set the coefficients, get them from the
|
||||
* Y * values of the colorspace colorants.
|
||||
*/
|
||||
int add = 0;
|
||||
png_fixed_point r = xyz.red_Y;
|
||||
png_fixed_point g = xyz.green_Y;
|
||||
png_fixed_point b = xyz.blue_Y;
|
||||
png_fixed_point total = r+g+b;
|
||||
|
||||
if (r+g+b > 32768)
|
||||
add = -1;
|
||||
else if (r+g+b < 32768)
|
||||
add = 1;
|
||||
|
||||
if (add != 0)
|
||||
if (total > 0 &&
|
||||
r >= 0 && png_muldiv(&r, r, 32768, total) && r >= 0 && r <= 32768 &&
|
||||
g >= 0 && png_muldiv(&g, g, 32768, total) && g >= 0 && g <= 32768 &&
|
||||
b >= 0 && png_muldiv(&b, b, 32768, total) && b >= 0 && b <= 32768 &&
|
||||
r+g+b <= 32769)
|
||||
{
|
||||
if (g >= r && g >= b)
|
||||
g += add;
|
||||
else if (r >= g && r >= b)
|
||||
r += add;
|
||||
/* We allow 0 coefficients here. r+g+b may be 32769 if two or
|
||||
* all of the coefficients were rounded up. Handle this by
|
||||
* reducing the *largest* coefficient by 1; this matches the
|
||||
* approach used for the default coefficients in pngrtran.c
|
||||
*/
|
||||
int add = 0;
|
||||
|
||||
if (r+g+b > 32768)
|
||||
add = -1;
|
||||
else if (r+g+b < 32768)
|
||||
add = 1;
|
||||
|
||||
if (add != 0)
|
||||
{
|
||||
if (g >= r && g >= b)
|
||||
g += add;
|
||||
else if (r >= g && r >= b)
|
||||
r += add;
|
||||
else
|
||||
b += add;
|
||||
}
|
||||
|
||||
/* Check for an internal error. */
|
||||
if (r+g+b != 32768)
|
||||
png_error(png_ptr,
|
||||
"internal error handling cHRM coefficients");
|
||||
|
||||
else
|
||||
b += add;
|
||||
}
|
||||
|
||||
/* Check for an internal error. */
|
||||
if (r+g+b != 32768)
|
||||
png_error(png_ptr,
|
||||
"internal error handling cHRM coefficients");
|
||||
|
||||
else
|
||||
{
|
||||
png_ptr->rgb_to_gray_red_coeff = (png_uint_16)r;
|
||||
png_ptr->rgb_to_gray_green_coeff = (png_uint_16)g;
|
||||
{
|
||||
png_ptr->rgb_to_gray_red_coeff = (png_uint_16)r;
|
||||
png_ptr->rgb_to_gray_green_coeff = (png_uint_16)g;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* This is a png_error at present even though it could be ignored -
|
||||
* it should never happen, but it is important that if it does, the
|
||||
* bug is fixed.
|
||||
*/
|
||||
else
|
||||
png_error(png_ptr, "internal error handling cHRM->XYZ");
|
||||
# endif /* check_chromaticities */
|
||||
{
|
||||
/* Use the historical REC 709 (etc) values: */
|
||||
png_ptr->rgb_to_gray_red_coeff = 6968;
|
||||
png_ptr->rgb_to_gray_green_coeff = 23434;
|
||||
/* png_ptr->rgb_to_gray_blue_coeff = 2366; */
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* READ_RGB_TO_GRAY */
|
||||
|
||||
#endif /* COLORSPACE */
|
||||
|
||||
void /* PRIVATE */
|
||||
png_check_IHDR(png_const_structrp png_ptr,
|
||||
png_uint_32 width, png_uint_32 height, int bit_depth,
|
||||
@@ -3390,7 +2735,27 @@ png_fixed(png_const_structrp png_ptr, double fp, png_const_charp text)
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(PNG_GAMMA_SUPPORTED) || defined(PNG_COLORSPACE_SUPPORTED) ||\
|
||||
#if defined(PNG_FLOATING_POINT_SUPPORTED) && \
|
||||
!defined(PNG_FIXED_POINT_MACRO_SUPPORTED) && \
|
||||
(defined(PNG_cLLI_SUPPORTED) || defined(PNG_mDCV_SUPPORTED))
|
||||
png_uint_32
|
||||
png_fixed_ITU(png_const_structrp png_ptr, double fp, png_const_charp text)
|
||||
{
|
||||
double r = floor(10000 * fp + .5);
|
||||
|
||||
if (r > 2147483647. || r < 0)
|
||||
png_fixed_error(png_ptr, text);
|
||||
|
||||
# ifndef PNG_ERROR_TEXT_SUPPORTED
|
||||
PNG_UNUSED(text)
|
||||
# endif
|
||||
|
||||
return (png_uint_32)r;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_COLORSPACE_SUPPORTED) ||\
|
||||
defined(PNG_INCH_CONVERSIONS_SUPPORTED) || defined(PNG_READ_pHYs_SUPPORTED)
|
||||
/* muldiv functions */
|
||||
/* This API takes signed arguments and rounds the result to the nearest
|
||||
@@ -3398,7 +2763,7 @@ png_fixed(png_const_structrp png_ptr, double fp, png_const_charp text)
|
||||
* the nearest .00001). Overflow and divide by zero are signalled in
|
||||
* the result, a boolean - true on success, false on overflow.
|
||||
*/
|
||||
int
|
||||
int /* PRIVATE */
|
||||
png_muldiv(png_fixed_point_p res, png_fixed_point a, png_int_32 times,
|
||||
png_int_32 divisor)
|
||||
{
|
||||
@@ -3512,27 +2877,7 @@ png_muldiv(png_fixed_point_p res, png_fixed_point a, png_int_32 times,
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* READ_GAMMA || INCH_CONVERSIONS */
|
||||
|
||||
#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_INCH_CONVERSIONS_SUPPORTED)
|
||||
/* The following is for when the caller doesn't much care about the
|
||||
* result.
|
||||
*/
|
||||
png_fixed_point
|
||||
png_muldiv_warn(png_const_structrp png_ptr, png_fixed_point a, png_int_32 times,
|
||||
png_int_32 divisor)
|
||||
{
|
||||
png_fixed_point result;
|
||||
|
||||
if (png_muldiv(&result, a, times, divisor) != 0)
|
||||
return result;
|
||||
|
||||
png_warning(png_ptr, "fixed point overflow ignored");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef PNG_GAMMA_SUPPORTED /* more fixed point functions for gamma */
|
||||
/* Calculate a reciprocal, return 0 on div-by-zero or overflow. */
|
||||
png_fixed_point
|
||||
png_reciprocal(png_fixed_point a)
|
||||
@@ -3551,26 +2896,38 @@ png_reciprocal(png_fixed_point a)
|
||||
|
||||
return 0; /* error/overflow */
|
||||
}
|
||||
#endif /* READ_GAMMA || COLORSPACE || INCH_CONVERSIONS || READ_pHYS */
|
||||
|
||||
#ifdef PNG_READ_GAMMA_SUPPORTED
|
||||
/* This is the shared test on whether a gamma value is 'significant' - whether
|
||||
* it is worth doing gamma correction.
|
||||
*/
|
||||
int /* PRIVATE */
|
||||
png_gamma_significant(png_fixed_point gamma_val)
|
||||
{
|
||||
/* sRGB: 1/2.2 == 0.4545(45)
|
||||
* AdobeRGB: 1/(2+51/256) ~= 0.45471 5dp
|
||||
*
|
||||
* So the correction from AdobeRGB to sRGB (output) is:
|
||||
*
|
||||
* 2.2/(2+51/256) == 1.00035524
|
||||
*
|
||||
* I.e. vanishly small (<4E-4) but still detectable in 16-bit linear (+/-
|
||||
* 23). Note that the Adobe choice seems to be something intended to give an
|
||||
* exact number with 8 binary fractional digits - it is the closest to 2.2
|
||||
* that is possible a base 2 .8p representation.
|
||||
*/
|
||||
return gamma_val < PNG_FP_1 - PNG_GAMMA_THRESHOLD_FIXED ||
|
||||
gamma_val > PNG_FP_1 + PNG_GAMMA_THRESHOLD_FIXED;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef PNG_READ_GAMMA_SUPPORTED
|
||||
#ifdef PNG_16BIT_SUPPORTED
|
||||
#ifndef PNG_FLOATING_ARITHMETIC_SUPPORTED
|
||||
/* A local convenience routine. */
|
||||
static png_fixed_point
|
||||
png_product2(png_fixed_point a, png_fixed_point b)
|
||||
{
|
||||
/* The required result is 1/a * 1/b; the following preserves accuracy. */
|
||||
#ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED
|
||||
/* The required result is a * b; the following preserves accuracy. */
|
||||
#ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED /* Should now be unused */
|
||||
double r = a * 1E-5;
|
||||
r *= b;
|
||||
r = floor(r+.5);
|
||||
@@ -3586,9 +2943,8 @@ png_product2(png_fixed_point a, png_fixed_point b)
|
||||
|
||||
return 0; /* overflow */
|
||||
}
|
||||
#endif /* 16BIT */
|
||||
#endif /* FLOATING_ARITHMETIC */
|
||||
|
||||
/* The inverse of the above. */
|
||||
png_fixed_point
|
||||
png_reciprocal2(png_fixed_point a, png_fixed_point b)
|
||||
{
|
||||
@@ -4241,10 +3597,27 @@ png_destroy_gamma_table(png_structrp png_ptr)
|
||||
* tables, we don't make a full table if we are reducing to 8-bit in
|
||||
* the future. Note also how the gamma_16 tables are segmented so that
|
||||
* we don't need to allocate > 64K chunks for a full 16-bit table.
|
||||
*
|
||||
* TODO: move this to pngrtran.c and make it static. Better yet create
|
||||
* pngcolor.c and put all the PNG_COLORSPACE stuff in there.
|
||||
*/
|
||||
#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \
|
||||
defined(PNG_READ_ALPHA_MODE_SUPPORTED) || \
|
||||
defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
|
||||
# define GAMMA_TRANSFORMS 1 /* #ifdef CSE */
|
||||
#else
|
||||
# define GAMMA_TRANSFORMS 0
|
||||
#endif
|
||||
|
||||
void /* PRIVATE */
|
||||
png_build_gamma_table(png_structrp png_ptr, int bit_depth)
|
||||
{
|
||||
png_fixed_point file_gamma, screen_gamma;
|
||||
png_fixed_point correction;
|
||||
# if GAMMA_TRANSFORMS
|
||||
png_fixed_point file_to_linear, linear_to_screen;
|
||||
# endif
|
||||
|
||||
png_debug(1, "in png_build_gamma_table");
|
||||
|
||||
/* Remove any existing table; this copes with multiple calls to
|
||||
@@ -4259,27 +3632,44 @@ png_build_gamma_table(png_structrp png_ptr, int bit_depth)
|
||||
png_destroy_gamma_table(png_ptr);
|
||||
}
|
||||
|
||||
/* The following fields are set, finally, in png_init_read_transformations.
|
||||
* If file_gamma is 0 (unset) nothing can be done otherwise if screen_gamma
|
||||
* is 0 (unset) there is no gamma correction but to/from linear is possible.
|
||||
*/
|
||||
file_gamma = png_ptr->file_gamma;
|
||||
screen_gamma = png_ptr->screen_gamma;
|
||||
# if GAMMA_TRANSFORMS
|
||||
file_to_linear = png_reciprocal(file_gamma);
|
||||
# endif
|
||||
|
||||
if (screen_gamma > 0)
|
||||
{
|
||||
# if GAMMA_TRANSFORMS
|
||||
linear_to_screen = png_reciprocal(screen_gamma);
|
||||
# endif
|
||||
correction = png_reciprocal2(screen_gamma, file_gamma);
|
||||
}
|
||||
else /* screen gamma unknown */
|
||||
{
|
||||
# if GAMMA_TRANSFORMS
|
||||
linear_to_screen = file_gamma;
|
||||
# endif
|
||||
correction = PNG_FP_1;
|
||||
}
|
||||
|
||||
if (bit_depth <= 8)
|
||||
{
|
||||
png_build_8bit_table(png_ptr, &png_ptr->gamma_table,
|
||||
png_ptr->screen_gamma > 0 ?
|
||||
png_reciprocal2(png_ptr->colorspace.gamma,
|
||||
png_ptr->screen_gamma) : PNG_FP_1);
|
||||
png_build_8bit_table(png_ptr, &png_ptr->gamma_table, correction);
|
||||
|
||||
#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \
|
||||
defined(PNG_READ_ALPHA_MODE_SUPPORTED) || \
|
||||
defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
|
||||
#if GAMMA_TRANSFORMS
|
||||
if ((png_ptr->transformations & (PNG_COMPOSE | PNG_RGB_TO_GRAY)) != 0)
|
||||
{
|
||||
png_build_8bit_table(png_ptr, &png_ptr->gamma_to_1,
|
||||
png_reciprocal(png_ptr->colorspace.gamma));
|
||||
png_build_8bit_table(png_ptr, &png_ptr->gamma_to_1, file_to_linear);
|
||||
|
||||
png_build_8bit_table(png_ptr, &png_ptr->gamma_from_1,
|
||||
png_ptr->screen_gamma > 0 ?
|
||||
png_reciprocal(png_ptr->screen_gamma) :
|
||||
png_ptr->colorspace.gamma/* Probably doing rgb_to_gray */);
|
||||
linear_to_screen);
|
||||
}
|
||||
#endif /* READ_BACKGROUND || READ_ALPHA_MODE || RGB_TO_GRAY */
|
||||
#endif /* GAMMA_TRANSFORMS */
|
||||
}
|
||||
#ifdef PNG_16BIT_SUPPORTED
|
||||
else
|
||||
@@ -4345,32 +3735,26 @@ png_build_gamma_table(png_structrp png_ptr, int bit_depth)
|
||||
* reduced to 8 bits.
|
||||
*/
|
||||
if ((png_ptr->transformations & (PNG_16_TO_8 | PNG_SCALE_16_TO_8)) != 0)
|
||||
png_build_16to8_table(png_ptr, &png_ptr->gamma_16_table, shift,
|
||||
png_ptr->screen_gamma > 0 ? png_product2(png_ptr->colorspace.gamma,
|
||||
png_ptr->screen_gamma) : PNG_FP_1);
|
||||
|
||||
png_build_16to8_table(png_ptr, &png_ptr->gamma_16_table, shift,
|
||||
png_reciprocal(correction));
|
||||
else
|
||||
png_build_16bit_table(png_ptr, &png_ptr->gamma_16_table, shift,
|
||||
png_ptr->screen_gamma > 0 ? png_reciprocal2(png_ptr->colorspace.gamma,
|
||||
png_ptr->screen_gamma) : PNG_FP_1);
|
||||
png_build_16bit_table(png_ptr, &png_ptr->gamma_16_table, shift,
|
||||
correction);
|
||||
|
||||
#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \
|
||||
defined(PNG_READ_ALPHA_MODE_SUPPORTED) || \
|
||||
defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
|
||||
# if GAMMA_TRANSFORMS
|
||||
if ((png_ptr->transformations & (PNG_COMPOSE | PNG_RGB_TO_GRAY)) != 0)
|
||||
{
|
||||
png_build_16bit_table(png_ptr, &png_ptr->gamma_16_to_1, shift,
|
||||
png_reciprocal(png_ptr->colorspace.gamma));
|
||||
file_to_linear);
|
||||
|
||||
/* Notice that the '16 from 1' table should be full precision, however
|
||||
* the lookup on this table still uses gamma_shift, so it can't be.
|
||||
* TODO: fix this.
|
||||
*/
|
||||
png_build_16bit_table(png_ptr, &png_ptr->gamma_16_from_1, shift,
|
||||
png_ptr->screen_gamma > 0 ? png_reciprocal(png_ptr->screen_gamma) :
|
||||
png_ptr->colorspace.gamma/* Probably doing rgb_to_gray */);
|
||||
linear_to_screen);
|
||||
}
|
||||
#endif /* READ_BACKGROUND || READ_ALPHA_MODE || RGB_TO_GRAY */
|
||||
#endif /* GAMMA_TRANSFORMS */
|
||||
}
|
||||
#endif /* 16BIT */
|
||||
}
|
||||
@@ -4585,7 +3969,7 @@ png_image_free_function(png_voidp argument)
|
||||
# ifdef PNG_STDIO_SUPPORTED
|
||||
if (cp->owned_file != 0)
|
||||
{
|
||||
FILE *fp = png_voidcast(FILE*, cp->png_ptr->io_ptr);
|
||||
FILE *fp = png_voidcast(FILE *, cp->png_ptr->io_ptr);
|
||||
cp->owned_file = 0;
|
||||
|
||||
/* Ignore errors here. */
|
||||
|
||||
Vendored
+146
-30
@@ -1,6 +1,6 @@
|
||||
/* png.h - header file for PNG reference library
|
||||
*
|
||||
* libpng version 1.6.45
|
||||
* libpng version 1.6.51
|
||||
*
|
||||
* Copyright (c) 2018-2025 Cosmin Truta
|
||||
* Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
|
||||
@@ -14,7 +14,7 @@
|
||||
* libpng versions 0.89, June 1996, through 0.96, May 1997: Andreas Dilger
|
||||
* libpng versions 0.97, January 1998, through 1.6.35, July 2018:
|
||||
* Glenn Randers-Pehrson
|
||||
* libpng versions 1.6.36, December 2018, through 1.6.45, January 2025:
|
||||
* libpng versions 1.6.36, December 2018, through 1.6.51, November 2025:
|
||||
* Cosmin Truta
|
||||
* See also "Contributing Authors", below.
|
||||
*/
|
||||
@@ -238,7 +238,7 @@
|
||||
* ...
|
||||
* 1.5.30 15 10530 15.so.15.30[.0]
|
||||
* ...
|
||||
* 1.6.45 16 10645 16.so.16.45[.0]
|
||||
* 1.6.51 16 10651 16.so.16.51[.0]
|
||||
*
|
||||
* Henceforth the source version will match the shared-library major and
|
||||
* minor numbers; the shared-library major version number will be used for
|
||||
@@ -274,7 +274,7 @@
|
||||
*/
|
||||
|
||||
/* Version information for png.h - this should match the version in png.c */
|
||||
#define PNG_LIBPNG_VER_STRING "1.6.45"
|
||||
#define PNG_LIBPNG_VER_STRING "1.6.51"
|
||||
#define PNG_HEADER_VERSION_STRING " libpng version " PNG_LIBPNG_VER_STRING "\n"
|
||||
|
||||
/* The versions of shared library builds should stay in sync, going forward */
|
||||
@@ -285,7 +285,7 @@
|
||||
/* These should match the first 3 components of PNG_LIBPNG_VER_STRING: */
|
||||
#define PNG_LIBPNG_VER_MAJOR 1
|
||||
#define PNG_LIBPNG_VER_MINOR 6
|
||||
#define PNG_LIBPNG_VER_RELEASE 45
|
||||
#define PNG_LIBPNG_VER_RELEASE 51
|
||||
|
||||
/* This should be zero for a public release, or non-zero for a
|
||||
* development version.
|
||||
@@ -316,7 +316,7 @@
|
||||
* From version 1.0.1 it is:
|
||||
* XXYYZZ, where XX=major, YY=minor, ZZ=release
|
||||
*/
|
||||
#define PNG_LIBPNG_VER 10645 /* 1.6.45 */
|
||||
#define PNG_LIBPNG_VER 10651 /* 1.6.51 */
|
||||
|
||||
/* Library configuration: these options cannot be changed after
|
||||
* the library has been built.
|
||||
@@ -426,7 +426,7 @@ extern "C" {
|
||||
/* This triggers a compiler error in png.c, if png.c and png.h
|
||||
* do not agree upon the version number.
|
||||
*/
|
||||
typedef char* png_libpng_version_1_6_45;
|
||||
typedef char* png_libpng_version_1_6_51;
|
||||
|
||||
/* Basic control structions. Read libpng-manual.txt or libpng.3 for more info.
|
||||
*
|
||||
@@ -744,7 +744,21 @@ typedef png_unknown_chunk * * png_unknown_chunkpp;
|
||||
#define PNG_INFO_sCAL 0x4000U /* ESR, 1.0.6 */
|
||||
#define PNG_INFO_IDAT 0x8000U /* ESR, 1.0.6 */
|
||||
#define PNG_INFO_eXIf 0x10000U /* GR-P, 1.6.31 */
|
||||
#define PNG_INFO_cICP 0x20000U
|
||||
#define PNG_INFO_cICP 0x20000U /* PNGv3: 1.6.45 */
|
||||
#define PNG_INFO_cLLI 0x40000U /* PNGv3: 1.6.45 */
|
||||
#define PNG_INFO_mDCV 0x80000U /* PNGv3: 1.6.45 */
|
||||
/* APNG: these chunks are stored as unknown, these flags are never set
|
||||
* however they are provided as a convenience for implementors of APNG and
|
||||
* avoids any merge conflicts.
|
||||
*
|
||||
* Private chunks: these chunk names violate the chunk name recommendations
|
||||
* because the chunk definitions have no signature and because the private
|
||||
* chunks with these names have been reserved. Private definitions should
|
||||
* avoid them.
|
||||
*/
|
||||
#define PNG_INFO_acTL 0x100000U /* PNGv3: 1.6.45: unknown */
|
||||
#define PNG_INFO_fcTL 0x200000U /* PNGv3: 1.6.45: unknown */
|
||||
#define PNG_INFO_fdAT 0x400000U /* PNGv3: 1.6.45: unknown */
|
||||
|
||||
/* This is used for the transformation routines, as some of them
|
||||
* change these values for the row. It also should enable using
|
||||
@@ -1556,7 +1570,7 @@ PNG_EXPORT(226, void, png_set_text_compression_method, (png_structrp png_ptr,
|
||||
|
||||
#ifdef PNG_STDIO_SUPPORTED
|
||||
/* Initialize the input/output for the PNG file to the default functions. */
|
||||
PNG_EXPORT(74, void, png_init_io, (png_structrp png_ptr, png_FILE_p fp));
|
||||
PNG_EXPORT(74, void, png_init_io, (png_structrp png_ptr, FILE *fp));
|
||||
#endif
|
||||
|
||||
/* Replace the (error and abort), and warning functions with user
|
||||
@@ -1976,15 +1990,44 @@ PNG_FIXED_EXPORT(233, void, png_set_cHRM_XYZ_fixed, (png_const_structrp png_ptr,
|
||||
|
||||
#ifdef PNG_cICP_SUPPORTED
|
||||
PNG_EXPORT(250, png_uint_32, png_get_cICP, (png_const_structrp png_ptr,
|
||||
png_inforp info_ptr, png_bytep colour_primaries,
|
||||
png_const_inforp info_ptr, png_bytep colour_primaries,
|
||||
png_bytep transfer_function, png_bytep matrix_coefficients,
|
||||
png_bytep video_full_range_flag));
|
||||
#endif
|
||||
|
||||
#ifdef PNG_cICP_SUPPORTED
|
||||
PNG_EXPORT(251, void, png_set_cICP, (png_const_structrp png_ptr,
|
||||
png_inforp info_ptr, png_byte colour_primaries,
|
||||
png_byte transfer_function, png_byte matrix_coefficients,
|
||||
png_byte video_full_range_flag));
|
||||
#endif
|
||||
|
||||
#ifdef PNG_cLLI_SUPPORTED
|
||||
PNG_FP_EXPORT(252, png_uint_32, png_get_cLLI, (png_const_structrp png_ptr,
|
||||
png_const_inforp info_ptr, double *maximum_content_light_level,
|
||||
double *maximum_frame_average_light_level))
|
||||
PNG_FIXED_EXPORT(253, png_uint_32, png_get_cLLI_fixed,
|
||||
(png_const_structrp png_ptr, png_const_inforp info_ptr,
|
||||
/* The values below are in cd/m2 (nits) and are scaled by 10,000; not
|
||||
* 100,000 as in the case of png_fixed_point.
|
||||
*/
|
||||
png_uint_32p maximum_content_light_level_scaled_by_10000,
|
||||
png_uint_32p maximum_frame_average_light_level_scaled_by_10000))
|
||||
#endif
|
||||
|
||||
#ifdef PNG_cLLI_SUPPORTED
|
||||
PNG_FP_EXPORT(254, void, png_set_cLLI, (png_const_structrp png_ptr,
|
||||
png_inforp info_ptr, double maximum_content_light_level,
|
||||
double maximum_frame_average_light_level))
|
||||
PNG_FIXED_EXPORT(255, void, png_set_cLLI_fixed, (png_const_structrp png_ptr,
|
||||
png_inforp info_ptr,
|
||||
/* The values below are in cd/m2 (nits) and are scaled by 10,000; not
|
||||
* 100,000 as in the case of png_fixed_point.
|
||||
*/
|
||||
png_uint_32 maximum_content_light_level_scaled_by_10000,
|
||||
png_uint_32 maximum_frame_average_light_level_scaled_by_10000))
|
||||
#endif
|
||||
|
||||
#ifdef PNG_eXIf_SUPPORTED
|
||||
PNG_EXPORT(246, png_uint_32, png_get_eXIf, (png_const_structrp png_ptr,
|
||||
png_inforp info_ptr, png_bytep *exif));
|
||||
@@ -2029,6 +2072,60 @@ PNG_EXPORT(144, void, png_set_IHDR, (png_const_structrp png_ptr,
|
||||
int color_type, int interlace_method, int compression_method,
|
||||
int filter_method));
|
||||
|
||||
#ifdef PNG_mDCV_SUPPORTED
|
||||
PNG_FP_EXPORT(256, png_uint_32, png_get_mDCV, (png_const_structrp png_ptr,
|
||||
png_const_inforp info_ptr,
|
||||
/* The chromaticities of the mastering display. As cHRM, but independent of
|
||||
* the encoding endpoints in cHRM, or cICP, or iCCP. These values will
|
||||
* always be in the range 0 to 1.3107.
|
||||
*/
|
||||
double *white_x, double *white_y, double *red_x, double *red_y,
|
||||
double *green_x, double *green_y, double *blue_x, double *blue_y,
|
||||
/* Mastering display luminance in cd/m2 (nits). */
|
||||
double *mastering_display_maximum_luminance,
|
||||
double *mastering_display_minimum_luminance))
|
||||
|
||||
PNG_FIXED_EXPORT(257, png_uint_32, png_get_mDCV_fixed,
|
||||
(png_const_structrp png_ptr, png_const_inforp info_ptr,
|
||||
png_fixed_point *int_white_x, png_fixed_point *int_white_y,
|
||||
png_fixed_point *int_red_x, png_fixed_point *int_red_y,
|
||||
png_fixed_point *int_green_x, png_fixed_point *int_green_y,
|
||||
png_fixed_point *int_blue_x, png_fixed_point *int_blue_y,
|
||||
/* Mastering display luminance in cd/m2 (nits) multiplied (scaled) by
|
||||
* 10,000.
|
||||
*/
|
||||
png_uint_32p mastering_display_maximum_luminance_scaled_by_10000,
|
||||
png_uint_32p mastering_display_minimum_luminance_scaled_by_10000))
|
||||
#endif
|
||||
|
||||
#ifdef PNG_mDCV_SUPPORTED
|
||||
PNG_FP_EXPORT(258, void, png_set_mDCV, (png_const_structrp png_ptr,
|
||||
png_inforp info_ptr,
|
||||
/* The chromaticities of the mastering display. As cHRM, but independent of
|
||||
* the encoding endpoints in cHRM, or cICP, or iCCP.
|
||||
*/
|
||||
double white_x, double white_y, double red_x, double red_y, double green_x,
|
||||
double green_y, double blue_x, double blue_y,
|
||||
/* Mastering display luminance in cd/m2 (nits). */
|
||||
double mastering_display_maximum_luminance,
|
||||
double mastering_display_minimum_luminance))
|
||||
|
||||
PNG_FIXED_EXPORT(259, void, png_set_mDCV_fixed, (png_const_structrp png_ptr,
|
||||
png_inforp info_ptr,
|
||||
/* The admissible range of these values is not the full range of a PNG
|
||||
* fixed point value. Negative values cannot be encoded and the maximum
|
||||
* value is about 1.3 */
|
||||
png_fixed_point int_white_x, png_fixed_point int_white_y,
|
||||
png_fixed_point int_red_x, png_fixed_point int_red_y,
|
||||
png_fixed_point int_green_x, png_fixed_point int_green_y,
|
||||
png_fixed_point int_blue_x, png_fixed_point int_blue_y,
|
||||
/* These are PNG unsigned 4 byte values: 31-bit unsigned values. The MSB
|
||||
* must be zero.
|
||||
*/
|
||||
png_uint_32 mastering_display_maximum_luminance_scaled_by_10000,
|
||||
png_uint_32 mastering_display_minimum_luminance_scaled_by_10000))
|
||||
#endif
|
||||
|
||||
#ifdef PNG_oFFs_SUPPORTED
|
||||
PNG_EXPORT(145, png_uint_32, png_get_oFFs, (png_const_structrp png_ptr,
|
||||
png_const_inforp info_ptr, png_int_32 *offset_x, png_int_32 *offset_y,
|
||||
@@ -2991,7 +3088,7 @@ PNG_EXPORT(234, int, png_image_begin_read_from_file, (png_imagep image,
|
||||
*/
|
||||
|
||||
PNG_EXPORT(235, int, png_image_begin_read_from_stdio, (png_imagep image,
|
||||
FILE* file));
|
||||
FILE *file));
|
||||
/* The PNG header is read from the stdio FILE object. */
|
||||
#endif /* STDIO */
|
||||
|
||||
@@ -3066,7 +3163,7 @@ PNG_EXPORT(239, int, png_image_write_to_file, (png_imagep image,
|
||||
PNG_EXPORT(240, int, png_image_write_to_stdio, (png_imagep image, FILE *file,
|
||||
int convert_to_8_bit, const void *buffer, png_int_32 row_stride,
|
||||
const void *colormap));
|
||||
/* Write the image to the given (FILE*). */
|
||||
/* Write the image to the given FILE object. */
|
||||
#endif /* SIMPLIFIED_WRITE_STDIO */
|
||||
|
||||
/* With all write APIs if image is in one of the linear formats with 16-bit
|
||||
@@ -3206,26 +3303,45 @@ PNG_EXPORT(245, int, png_image_write_to_memory, (png_imagep image, void *memory,
|
||||
* selected at run time.
|
||||
*/
|
||||
#ifdef PNG_SET_OPTION_SUPPORTED
|
||||
|
||||
/* HARDWARE: ARM Neon SIMD instructions supported */
|
||||
#ifdef PNG_ARM_NEON_API_SUPPORTED
|
||||
# define PNG_ARM_NEON 0 /* HARDWARE: ARM Neon SIMD instructions supported */
|
||||
#endif
|
||||
#define PNG_MAXIMUM_INFLATE_WINDOW 2 /* SOFTWARE: force maximum window */
|
||||
#define PNG_SKIP_sRGB_CHECK_PROFILE 4 /* SOFTWARE: Check ICC profile for sRGB */
|
||||
#ifdef PNG_MIPS_MSA_API_SUPPORTED
|
||||
# define PNG_MIPS_MSA 6 /* HARDWARE: MIPS Msa SIMD instructions supported */
|
||||
#endif
|
||||
#ifdef PNG_DISABLE_ADLER32_CHECK_SUPPORTED
|
||||
# define PNG_IGNORE_ADLER32 8 /* SOFTWARE: disable Adler32 check on IDAT */
|
||||
#endif
|
||||
#ifdef PNG_POWERPC_VSX_API_SUPPORTED
|
||||
# define PNG_POWERPC_VSX 10 /* HARDWARE: PowerPC VSX SIMD instructions
|
||||
* supported */
|
||||
#endif
|
||||
#ifdef PNG_MIPS_MMI_API_SUPPORTED
|
||||
# define PNG_MIPS_MMI 12 /* HARDWARE: MIPS MMI SIMD instructions supported */
|
||||
# define PNG_ARM_NEON 0
|
||||
#endif
|
||||
|
||||
#define PNG_OPTION_NEXT 14 /* Next option - numbers must be even */
|
||||
/* SOFTWARE: Force maximum window */
|
||||
#define PNG_MAXIMUM_INFLATE_WINDOW 2
|
||||
|
||||
/* SOFTWARE: Check ICC profile for sRGB */
|
||||
#define PNG_SKIP_sRGB_CHECK_PROFILE 4
|
||||
|
||||
/* HARDWARE: MIPS MSA SIMD instructions supported */
|
||||
#ifdef PNG_MIPS_MSA_API_SUPPORTED
|
||||
# define PNG_MIPS_MSA 6
|
||||
#endif
|
||||
|
||||
/* SOFTWARE: Disable Adler32 check on IDAT */
|
||||
#ifdef PNG_DISABLE_ADLER32_CHECK_SUPPORTED
|
||||
# define PNG_IGNORE_ADLER32 8
|
||||
#endif
|
||||
|
||||
/* HARDWARE: PowerPC VSX SIMD instructions supported */
|
||||
#ifdef PNG_POWERPC_VSX_API_SUPPORTED
|
||||
# define PNG_POWERPC_VSX 10
|
||||
#endif
|
||||
|
||||
/* HARDWARE: MIPS MMI SIMD instructions supported */
|
||||
#ifdef PNG_MIPS_MMI_API_SUPPORTED
|
||||
# define PNG_MIPS_MMI 12
|
||||
#endif
|
||||
|
||||
/* HARDWARE: RISC-V RVV SIMD instructions supported */
|
||||
#ifdef PNG_RISCV_RVV_API_SUPPORTED
|
||||
# define PNG_RISCV_RVV 14
|
||||
#endif
|
||||
|
||||
/* Next option - numbers must be even */
|
||||
#define PNG_OPTION_NEXT 16
|
||||
|
||||
/* Return values: NOTE: there are four values and 'off' is *not* zero */
|
||||
#define PNG_OPTION_UNSET 0 /* Unset - defaults to off */
|
||||
@@ -3249,7 +3365,7 @@ PNG_EXPORT(244, int, png_set_option, (png_structrp png_ptr, int option,
|
||||
* one to use is one more than this.)
|
||||
*/
|
||||
#ifdef PNG_EXPORT_LAST_ORDINAL
|
||||
PNG_EXPORT_LAST_ORDINAL(251);
|
||||
PNG_EXPORT_LAST_ORDINAL(259);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
Vendored
+20
-27
@@ -1,6 +1,6 @@
|
||||
/* pngconf.h - machine-configurable file for libpng
|
||||
*
|
||||
* libpng version 1.6.45
|
||||
* libpng version 1.6.51
|
||||
*
|
||||
* Copyright (c) 2018-2025 Cosmin Truta
|
||||
* Copyright (c) 1998-2002,2004,2006-2016,2018 Glenn Randers-Pehrson
|
||||
@@ -219,25 +219,13 @@
|
||||
/* NOTE: PNGCBAPI always defaults to PNGCAPI. */
|
||||
|
||||
# if defined(PNGAPI) && !defined(PNG_USER_PRIVATEBUILD)
|
||||
# error "PNG_USER_PRIVATEBUILD must be defined if PNGAPI is changed"
|
||||
# error PNG_USER_PRIVATEBUILD must be defined if PNGAPI is changed
|
||||
# endif
|
||||
|
||||
# if (defined(_MSC_VER) && _MSC_VER < 800) ||\
|
||||
(defined(__BORLANDC__) && __BORLANDC__ < 0x500)
|
||||
/* older Borland and MSC
|
||||
* compilers used '__export' and required this to be after
|
||||
* the type.
|
||||
*/
|
||||
# ifndef PNG_EXPORT_TYPE
|
||||
# define PNG_EXPORT_TYPE(type) type PNG_IMPEXP
|
||||
# endif
|
||||
# define PNG_DLL_EXPORT __export
|
||||
# else /* newer compiler */
|
||||
# define PNG_DLL_EXPORT __declspec(dllexport)
|
||||
# ifndef PNG_DLL_IMPORT
|
||||
# define PNG_DLL_IMPORT __declspec(dllimport)
|
||||
# endif
|
||||
# endif /* compiler */
|
||||
# define PNG_DLL_EXPORT __declspec(dllexport)
|
||||
# ifndef PNG_DLL_IMPORT
|
||||
# define PNG_DLL_IMPORT __declspec(dllimport)
|
||||
# endif
|
||||
|
||||
#else /* !Windows */
|
||||
# if (defined(__IBMC__) || defined(__IBMCPP__)) && defined(__OS2__)
|
||||
@@ -479,7 +467,7 @@
|
||||
#if CHAR_BIT == 8 && UCHAR_MAX == 255
|
||||
typedef unsigned char png_byte;
|
||||
#else
|
||||
# error "libpng requires 8-bit bytes"
|
||||
# error libpng requires 8-bit bytes
|
||||
#endif
|
||||
|
||||
#if INT_MIN == -32768 && INT_MAX == 32767
|
||||
@@ -487,7 +475,7 @@
|
||||
#elif SHRT_MIN == -32768 && SHRT_MAX == 32767
|
||||
typedef short png_int_16;
|
||||
#else
|
||||
# error "libpng requires a signed 16-bit type"
|
||||
# error libpng requires a signed 16-bit integer type
|
||||
#endif
|
||||
|
||||
#if UINT_MAX == 65535
|
||||
@@ -495,7 +483,7 @@
|
||||
#elif USHRT_MAX == 65535
|
||||
typedef unsigned short png_uint_16;
|
||||
#else
|
||||
# error "libpng requires an unsigned 16-bit type"
|
||||
# error libpng requires an unsigned 16-bit integer type
|
||||
#endif
|
||||
|
||||
#if INT_MIN < -2147483646 && INT_MAX > 2147483646
|
||||
@@ -503,7 +491,7 @@
|
||||
#elif LONG_MIN < -2147483646 && LONG_MAX > 2147483646
|
||||
typedef long int png_int_32;
|
||||
#else
|
||||
# error "libpng requires a signed 32-bit (or more) type"
|
||||
# error libpng requires a signed 32-bit (or longer) integer type
|
||||
#endif
|
||||
|
||||
#if UINT_MAX > 4294967294U
|
||||
@@ -511,7 +499,7 @@
|
||||
#elif ULONG_MAX > 4294967294U
|
||||
typedef unsigned long int png_uint_32;
|
||||
#else
|
||||
# error "libpng requires an unsigned 32-bit (or more) type"
|
||||
# error libpng requires an unsigned 32-bit (or longer) integer type
|
||||
#endif
|
||||
|
||||
/* Prior to 1.6.0, it was possible to disable the use of size_t and ptrdiff_t.
|
||||
@@ -592,10 +580,6 @@ typedef const png_fixed_point * png_const_fixed_point_p;
|
||||
typedef size_t * png_size_tp;
|
||||
typedef const size_t * png_const_size_tp;
|
||||
|
||||
#ifdef PNG_STDIO_SUPPORTED
|
||||
typedef FILE * png_FILE_p;
|
||||
#endif
|
||||
|
||||
#ifdef PNG_FLOATING_POINT_SUPPORTED
|
||||
typedef double * png_doublep;
|
||||
typedef const double * png_const_doublep;
|
||||
@@ -617,6 +601,15 @@ typedef double * * png_doublepp;
|
||||
/* Pointers to pointers to pointers; i.e., pointer to array */
|
||||
typedef char * * * png_charppp;
|
||||
|
||||
#ifdef PNG_STDIO_SUPPORTED
|
||||
/* With PNG_STDIO_SUPPORTED it was possible to use I/O streams that were
|
||||
* not necessarily stdio FILE streams, to allow building Windows applications
|
||||
* before Win32 and Windows CE applications before WinCE 3.0, but that kind
|
||||
* of support has long been discontinued.
|
||||
*/
|
||||
typedef FILE * png_FILE_p; /* [Deprecated] */
|
||||
#endif
|
||||
|
||||
#endif /* PNG_BUILDING_SYMBOL_TABLE */
|
||||
|
||||
#endif /* PNGCONF_H */
|
||||
|
||||
Vendored
+6
-5
@@ -1,6 +1,6 @@
|
||||
/* pngdebug.h - Debugging macros for libpng, also used in pngtest.c
|
||||
/* pngdebug.h - internal debugging macros for libpng
|
||||
*
|
||||
* Copyright (c) 2018 Cosmin Truta
|
||||
* Copyright (c) 2018-2025 Cosmin Truta
|
||||
* Copyright (c) 1998-2002,2004,2006-2013 Glenn Randers-Pehrson
|
||||
* Copyright (c) 1996-1997 Andreas Dilger
|
||||
* Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
|
||||
@@ -10,6 +10,10 @@
|
||||
* and license in png.h
|
||||
*/
|
||||
|
||||
#ifndef PNGPRIV_H
|
||||
# error This file must not be included by applications; please include <png.h>
|
||||
#endif
|
||||
|
||||
/* Define PNG_DEBUG at compile time for debugging information. Higher
|
||||
* numbers for PNG_DEBUG mean more debugging information. This has
|
||||
* only been added since version 0.95 so it is not implemented throughout
|
||||
@@ -34,9 +38,6 @@
|
||||
#define PNGDEBUG_H
|
||||
/* These settings control the formatting of messages in png.c and pngerror.c */
|
||||
/* Moved to pngdebug.h at 1.5.0 */
|
||||
# ifndef PNG_LITERAL_SHARP
|
||||
# define PNG_LITERAL_SHARP 0x23
|
||||
# endif
|
||||
# ifndef PNG_LITERAL_LEFT_SQUARE_BRACKET
|
||||
# define PNG_LITERAL_LEFT_SQUARE_BRACKET 0x5b
|
||||
# endif
|
||||
|
||||
Vendored
+28
-138
@@ -1,6 +1,6 @@
|
||||
/* pngerror.c - stub functions for i/o and memory allocation
|
||||
*
|
||||
* Copyright (c) 2018-2024 Cosmin Truta
|
||||
* Copyright (c) 2018-2025 Cosmin Truta
|
||||
* Copyright (c) 1998-2002,2004,2006-2017 Glenn Randers-Pehrson
|
||||
* Copyright (c) 1996-1997 Andreas Dilger
|
||||
* Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
|
||||
@@ -39,46 +39,6 @@ PNG_FUNCTION(void,PNGAPI
|
||||
png_error,(png_const_structrp png_ptr, png_const_charp error_message),
|
||||
PNG_NORETURN)
|
||||
{
|
||||
#ifdef PNG_ERROR_NUMBERS_SUPPORTED
|
||||
char msg[16];
|
||||
if (png_ptr != NULL)
|
||||
{
|
||||
if ((png_ptr->flags &
|
||||
(PNG_FLAG_STRIP_ERROR_NUMBERS|PNG_FLAG_STRIP_ERROR_TEXT)) != 0)
|
||||
{
|
||||
if (*error_message == PNG_LITERAL_SHARP)
|
||||
{
|
||||
/* Strip "#nnnn " from beginning of error message. */
|
||||
int offset;
|
||||
for (offset = 1; offset<15; offset++)
|
||||
if (error_message[offset] == ' ')
|
||||
break;
|
||||
|
||||
if ((png_ptr->flags & PNG_FLAG_STRIP_ERROR_TEXT) != 0)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < offset - 1; i++)
|
||||
msg[i] = error_message[i + 1];
|
||||
msg[i - 1] = '\0';
|
||||
error_message = msg;
|
||||
}
|
||||
|
||||
else
|
||||
error_message += offset;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
if ((png_ptr->flags & PNG_FLAG_STRIP_ERROR_TEXT) != 0)
|
||||
{
|
||||
msg[0] = '0';
|
||||
msg[1] = '\0';
|
||||
error_message = msg;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (png_ptr != NULL && png_ptr->error_fn != NULL)
|
||||
(*(png_ptr->error_fn))(png_constcast(png_structrp,png_ptr),
|
||||
error_message);
|
||||
@@ -216,21 +176,6 @@ void PNGAPI
|
||||
png_warning(png_const_structrp png_ptr, png_const_charp warning_message)
|
||||
{
|
||||
int offset = 0;
|
||||
if (png_ptr != NULL)
|
||||
{
|
||||
#ifdef PNG_ERROR_NUMBERS_SUPPORTED
|
||||
if ((png_ptr->flags &
|
||||
(PNG_FLAG_STRIP_ERROR_NUMBERS|PNG_FLAG_STRIP_ERROR_TEXT)) != 0)
|
||||
#endif
|
||||
{
|
||||
if (*warning_message == PNG_LITERAL_SHARP)
|
||||
{
|
||||
for (offset = 1; offset < 15; offset++)
|
||||
if (warning_message[offset] == ' ')
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (png_ptr != NULL && png_ptr->warning_fn != NULL)
|
||||
(*(png_ptr->warning_fn))(png_constcast(png_structrp,png_ptr),
|
||||
warning_message + offset);
|
||||
@@ -712,42 +657,9 @@ png_default_error,(png_const_structrp png_ptr, png_const_charp error_message),
|
||||
PNG_NORETURN)
|
||||
{
|
||||
#ifdef PNG_CONSOLE_IO_SUPPORTED
|
||||
#ifdef PNG_ERROR_NUMBERS_SUPPORTED
|
||||
/* Check on NULL only added in 1.5.4 */
|
||||
if (error_message != NULL && *error_message == PNG_LITERAL_SHARP)
|
||||
{
|
||||
/* Strip "#nnnn " from beginning of error message. */
|
||||
int offset;
|
||||
char error_number[16];
|
||||
for (offset = 0; offset<15; offset++)
|
||||
{
|
||||
error_number[offset] = error_message[offset + 1];
|
||||
if (error_message[offset] == ' ')
|
||||
break;
|
||||
}
|
||||
|
||||
if ((offset > 1) && (offset < 15))
|
||||
{
|
||||
error_number[offset - 1] = '\0';
|
||||
fprintf(stderr, "libpng error no. %s: %s",
|
||||
error_number, error_message + offset + 1);
|
||||
fprintf(stderr, PNG_STRING_NEWLINE);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "libpng error: %s, offset=%d",
|
||||
error_message, offset);
|
||||
fprintf(stderr, PNG_STRING_NEWLINE);
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
fprintf(stderr, "libpng error: %s", error_message ? error_message :
|
||||
"undefined");
|
||||
fprintf(stderr, PNG_STRING_NEWLINE);
|
||||
}
|
||||
fprintf(stderr, "libpng error: %s", error_message ? error_message :
|
||||
"undefined");
|
||||
fprintf(stderr, PNG_STRING_NEWLINE);
|
||||
#else
|
||||
PNG_UNUSED(error_message) /* Make compiler happy */
|
||||
#endif
|
||||
@@ -785,40 +697,8 @@ static void /* PRIVATE */
|
||||
png_default_warning(png_const_structrp png_ptr, png_const_charp warning_message)
|
||||
{
|
||||
#ifdef PNG_CONSOLE_IO_SUPPORTED
|
||||
# ifdef PNG_ERROR_NUMBERS_SUPPORTED
|
||||
if (*warning_message == PNG_LITERAL_SHARP)
|
||||
{
|
||||
int offset;
|
||||
char warning_number[16];
|
||||
for (offset = 0; offset < 15; offset++)
|
||||
{
|
||||
warning_number[offset] = warning_message[offset + 1];
|
||||
if (warning_message[offset] == ' ')
|
||||
break;
|
||||
}
|
||||
|
||||
if ((offset > 1) && (offset < 15))
|
||||
{
|
||||
warning_number[offset + 1] = '\0';
|
||||
fprintf(stderr, "libpng warning no. %s: %s",
|
||||
warning_number, warning_message + offset);
|
||||
fprintf(stderr, PNG_STRING_NEWLINE);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "libpng warning: %s",
|
||||
warning_message);
|
||||
fprintf(stderr, PNG_STRING_NEWLINE);
|
||||
}
|
||||
}
|
||||
else
|
||||
# endif
|
||||
|
||||
{
|
||||
fprintf(stderr, "libpng warning: %s", warning_message);
|
||||
fprintf(stderr, PNG_STRING_NEWLINE);
|
||||
}
|
||||
fprintf(stderr, "libpng warning: %s", warning_message);
|
||||
fprintf(stderr, PNG_STRING_NEWLINE);
|
||||
#else
|
||||
PNG_UNUSED(warning_message) /* Make compiler happy */
|
||||
#endif
|
||||
@@ -866,12 +746,8 @@ png_get_error_ptr(png_const_structrp png_ptr)
|
||||
void PNGAPI
|
||||
png_set_strip_error_numbers(png_structrp png_ptr, png_uint_32 strip_mode)
|
||||
{
|
||||
if (png_ptr != NULL)
|
||||
{
|
||||
png_ptr->flags &=
|
||||
((~(PNG_FLAG_STRIP_ERROR_NUMBERS |
|
||||
PNG_FLAG_STRIP_ERROR_TEXT))&strip_mode);
|
||||
}
|
||||
PNG_UNUSED(png_ptr)
|
||||
PNG_UNUSED(strip_mode)
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -935,23 +811,37 @@ png_safe_warning(png_structp png_nonconst_ptr, png_const_charp warning_message)
|
||||
int /* PRIVATE */
|
||||
png_safe_execute(png_imagep image, int (*function)(png_voidp), png_voidp arg)
|
||||
{
|
||||
png_voidp saved_error_buf = image->opaque->error_buf;
|
||||
const png_voidp saved_error_buf = image->opaque->error_buf;
|
||||
jmp_buf safe_jmpbuf;
|
||||
int result;
|
||||
|
||||
/* Safely execute function(arg), with png_error returning back here. */
|
||||
if (setjmp(safe_jmpbuf) == 0)
|
||||
{
|
||||
int result;
|
||||
|
||||
image->opaque->error_buf = safe_jmpbuf;
|
||||
result = function(arg);
|
||||
image->opaque->error_buf = saved_error_buf;
|
||||
return result;
|
||||
|
||||
if (result)
|
||||
return 1; /* success */
|
||||
}
|
||||
|
||||
/* On png_error, return via longjmp, pop the jmpbuf, and free the image. */
|
||||
/* The function failed either because of a caught png_error and a regular
|
||||
* return of false above or because of an uncaught png_error from the
|
||||
* function itself. Ensure that the error_buf is always set back to the
|
||||
* value saved above:
|
||||
*/
|
||||
image->opaque->error_buf = saved_error_buf;
|
||||
png_image_free(image);
|
||||
return 0;
|
||||
|
||||
/* On the final false return, when about to return control to the caller, the
|
||||
* image is freed (png_image_free does this check but it is duplicated here
|
||||
* for clarity:
|
||||
*/
|
||||
if (saved_error_buf == NULL)
|
||||
png_image_free(image);
|
||||
|
||||
return 0; /* failure */
|
||||
}
|
||||
#endif /* SIMPLIFIED READ || SIMPLIFIED_WRITE */
|
||||
#endif /* READ || WRITE */
|
||||
|
||||
Vendored
+184
-105
@@ -1,6 +1,6 @@
|
||||
/* pngget.c - retrieval of values from info struct
|
||||
*
|
||||
* Copyright (c) 2018-2024 Cosmin Truta
|
||||
* Copyright (c) 2018-2025 Cosmin Truta
|
||||
* Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
|
||||
* Copyright (c) 1996-1997 Andreas Dilger
|
||||
* Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
|
||||
@@ -380,7 +380,13 @@ png_fixed_inches_from_microns(png_const_structrp png_ptr, png_int_32 microns)
|
||||
* Notice that this can overflow - a warning is output and 0 is
|
||||
* returned.
|
||||
*/
|
||||
return png_muldiv_warn(png_ptr, microns, 500, 127);
|
||||
png_fixed_point result;
|
||||
|
||||
if (png_muldiv(&result, microns, 500, 127) != 0)
|
||||
return result;
|
||||
|
||||
png_warning(png_ptr, "fixed point overflow ignored");
|
||||
return 0;
|
||||
}
|
||||
|
||||
png_fixed_point PNGAPI
|
||||
@@ -390,7 +396,7 @@ png_get_x_offset_inches_fixed(png_const_structrp png_ptr,
|
||||
return png_fixed_inches_from_microns(png_ptr,
|
||||
png_get_x_offset_microns(png_ptr, info_ptr));
|
||||
}
|
||||
#endif
|
||||
#endif /* FIXED_POINT */
|
||||
|
||||
#ifdef PNG_FIXED_POINT_SUPPORTED
|
||||
png_fixed_point PNGAPI
|
||||
@@ -518,44 +524,31 @@ png_get_bKGD(png_const_structrp png_ptr, png_inforp info_ptr,
|
||||
# ifdef PNG_FLOATING_POINT_SUPPORTED
|
||||
png_uint_32 PNGAPI
|
||||
png_get_cHRM(png_const_structrp png_ptr, png_const_inforp info_ptr,
|
||||
double *white_x, double *white_y, double *red_x, double *red_y,
|
||||
double *green_x, double *green_y, double *blue_x, double *blue_y)
|
||||
double *whitex, double *whitey, double *redx, double *redy,
|
||||
double *greenx, double *greeny, double *bluex, double *bluey)
|
||||
{
|
||||
png_debug1(1, "in %s retrieval function", "cHRM");
|
||||
|
||||
/* Quiet API change: this code used to only return the end points if a cHRM
|
||||
* chunk was present, but the end points can also come from iCCP or sRGB
|
||||
* chunks, so in 1.6.0 the png_get_ APIs return the end points regardless and
|
||||
* the png_set_ APIs merely check that set end points are mutually
|
||||
* consistent.
|
||||
*/
|
||||
/* PNGv3: this just returns the values store from the cHRM, if any. */
|
||||
if (png_ptr != NULL && info_ptr != NULL &&
|
||||
(info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_ENDPOINTS) != 0)
|
||||
(info_ptr->valid & PNG_INFO_cHRM) != 0)
|
||||
{
|
||||
if (white_x != NULL)
|
||||
*white_x = png_float(png_ptr,
|
||||
info_ptr->colorspace.end_points_xy.whitex, "cHRM white X");
|
||||
if (white_y != NULL)
|
||||
*white_y = png_float(png_ptr,
|
||||
info_ptr->colorspace.end_points_xy.whitey, "cHRM white Y");
|
||||
if (red_x != NULL)
|
||||
*red_x = png_float(png_ptr, info_ptr->colorspace.end_points_xy.redx,
|
||||
"cHRM red X");
|
||||
if (red_y != NULL)
|
||||
*red_y = png_float(png_ptr, info_ptr->colorspace.end_points_xy.redy,
|
||||
"cHRM red Y");
|
||||
if (green_x != NULL)
|
||||
*green_x = png_float(png_ptr,
|
||||
info_ptr->colorspace.end_points_xy.greenx, "cHRM green X");
|
||||
if (green_y != NULL)
|
||||
*green_y = png_float(png_ptr,
|
||||
info_ptr->colorspace.end_points_xy.greeny, "cHRM green Y");
|
||||
if (blue_x != NULL)
|
||||
*blue_x = png_float(png_ptr, info_ptr->colorspace.end_points_xy.bluex,
|
||||
"cHRM blue X");
|
||||
if (blue_y != NULL)
|
||||
*blue_y = png_float(png_ptr, info_ptr->colorspace.end_points_xy.bluey,
|
||||
"cHRM blue Y");
|
||||
if (whitex != NULL)
|
||||
*whitex = png_float(png_ptr, info_ptr->cHRM.whitex, "cHRM wx");
|
||||
if (whitey != NULL)
|
||||
*whitey = png_float(png_ptr, info_ptr->cHRM.whitey, "cHRM wy");
|
||||
if (redx != NULL)
|
||||
*redx = png_float(png_ptr, info_ptr->cHRM.redx, "cHRM rx");
|
||||
if (redy != NULL)
|
||||
*redy = png_float(png_ptr, info_ptr->cHRM.redy, "cHRM ry");
|
||||
if (greenx != NULL)
|
||||
*greenx = png_float(png_ptr, info_ptr->cHRM.greenx, "cHRM gx");
|
||||
if (greeny != NULL)
|
||||
*greeny = png_float(png_ptr, info_ptr->cHRM.greeny, "cHRM gy");
|
||||
if (bluex != NULL)
|
||||
*bluex = png_float(png_ptr, info_ptr->cHRM.bluex, "cHRM bx");
|
||||
if (bluey != NULL)
|
||||
*bluey = png_float(png_ptr, info_ptr->cHRM.bluey, "cHRM by");
|
||||
return PNG_INFO_cHRM;
|
||||
}
|
||||
|
||||
@@ -568,38 +561,31 @@ png_get_cHRM_XYZ(png_const_structrp png_ptr, png_const_inforp info_ptr,
|
||||
double *green_Y, double *green_Z, double *blue_X, double *blue_Y,
|
||||
double *blue_Z)
|
||||
{
|
||||
png_XYZ XYZ;
|
||||
png_debug1(1, "in %s retrieval function", "cHRM_XYZ(float)");
|
||||
|
||||
if (png_ptr != NULL && info_ptr != NULL &&
|
||||
(info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_ENDPOINTS) != 0)
|
||||
(info_ptr->valid & PNG_INFO_cHRM) != 0 &&
|
||||
png_XYZ_from_xy(&XYZ, &info_ptr->cHRM) == 0)
|
||||
{
|
||||
if (red_X != NULL)
|
||||
*red_X = png_float(png_ptr, info_ptr->colorspace.end_points_XYZ.red_X,
|
||||
"cHRM red X");
|
||||
*red_X = png_float(png_ptr, XYZ.red_X, "cHRM red X");
|
||||
if (red_Y != NULL)
|
||||
*red_Y = png_float(png_ptr, info_ptr->colorspace.end_points_XYZ.red_Y,
|
||||
"cHRM red Y");
|
||||
*red_Y = png_float(png_ptr, XYZ.red_Y, "cHRM red Y");
|
||||
if (red_Z != NULL)
|
||||
*red_Z = png_float(png_ptr, info_ptr->colorspace.end_points_XYZ.red_Z,
|
||||
"cHRM red Z");
|
||||
*red_Z = png_float(png_ptr, XYZ.red_Z, "cHRM red Z");
|
||||
if (green_X != NULL)
|
||||
*green_X = png_float(png_ptr,
|
||||
info_ptr->colorspace.end_points_XYZ.green_X, "cHRM green X");
|
||||
*green_X = png_float(png_ptr, XYZ.green_X, "cHRM green X");
|
||||
if (green_Y != NULL)
|
||||
*green_Y = png_float(png_ptr,
|
||||
info_ptr->colorspace.end_points_XYZ.green_Y, "cHRM green Y");
|
||||
*green_Y = png_float(png_ptr, XYZ.green_Y, "cHRM green Y");
|
||||
if (green_Z != NULL)
|
||||
*green_Z = png_float(png_ptr,
|
||||
info_ptr->colorspace.end_points_XYZ.green_Z, "cHRM green Z");
|
||||
*green_Z = png_float(png_ptr, XYZ.green_Z, "cHRM green Z");
|
||||
if (blue_X != NULL)
|
||||
*blue_X = png_float(png_ptr,
|
||||
info_ptr->colorspace.end_points_XYZ.blue_X, "cHRM blue X");
|
||||
*blue_X = png_float(png_ptr, XYZ.blue_X, "cHRM blue X");
|
||||
if (blue_Y != NULL)
|
||||
*blue_Y = png_float(png_ptr,
|
||||
info_ptr->colorspace.end_points_XYZ.blue_Y, "cHRM blue Y");
|
||||
*blue_Y = png_float(png_ptr, XYZ.blue_Y, "cHRM blue Y");
|
||||
if (blue_Z != NULL)
|
||||
*blue_Z = png_float(png_ptr,
|
||||
info_ptr->colorspace.end_points_XYZ.blue_Z, "cHRM blue Z");
|
||||
*blue_Z = png_float(png_ptr, XYZ.blue_Z, "cHRM blue Z");
|
||||
return PNG_INFO_cHRM;
|
||||
}
|
||||
|
||||
@@ -616,29 +602,22 @@ png_get_cHRM_XYZ_fixed(png_const_structrp png_ptr, png_const_inforp info_ptr,
|
||||
png_fixed_point *int_blue_X, png_fixed_point *int_blue_Y,
|
||||
png_fixed_point *int_blue_Z)
|
||||
{
|
||||
png_XYZ XYZ;
|
||||
png_debug1(1, "in %s retrieval function", "cHRM_XYZ");
|
||||
|
||||
if (png_ptr != NULL && info_ptr != NULL &&
|
||||
(info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_ENDPOINTS) != 0)
|
||||
(info_ptr->valid & PNG_INFO_cHRM) != 0U &&
|
||||
png_XYZ_from_xy(&XYZ, &info_ptr->cHRM) == 0)
|
||||
{
|
||||
if (int_red_X != NULL)
|
||||
*int_red_X = info_ptr->colorspace.end_points_XYZ.red_X;
|
||||
if (int_red_Y != NULL)
|
||||
*int_red_Y = info_ptr->colorspace.end_points_XYZ.red_Y;
|
||||
if (int_red_Z != NULL)
|
||||
*int_red_Z = info_ptr->colorspace.end_points_XYZ.red_Z;
|
||||
if (int_green_X != NULL)
|
||||
*int_green_X = info_ptr->colorspace.end_points_XYZ.green_X;
|
||||
if (int_green_Y != NULL)
|
||||
*int_green_Y = info_ptr->colorspace.end_points_XYZ.green_Y;
|
||||
if (int_green_Z != NULL)
|
||||
*int_green_Z = info_ptr->colorspace.end_points_XYZ.green_Z;
|
||||
if (int_blue_X != NULL)
|
||||
*int_blue_X = info_ptr->colorspace.end_points_XYZ.blue_X;
|
||||
if (int_blue_Y != NULL)
|
||||
*int_blue_Y = info_ptr->colorspace.end_points_XYZ.blue_Y;
|
||||
if (int_blue_Z != NULL)
|
||||
*int_blue_Z = info_ptr->colorspace.end_points_XYZ.blue_Z;
|
||||
if (int_red_X != NULL) *int_red_X = XYZ.red_X;
|
||||
if (int_red_Y != NULL) *int_red_Y = XYZ.red_Y;
|
||||
if (int_red_Z != NULL) *int_red_Z = XYZ.red_Z;
|
||||
if (int_green_X != NULL) *int_green_X = XYZ.green_X;
|
||||
if (int_green_Y != NULL) *int_green_Y = XYZ.green_Y;
|
||||
if (int_green_Z != NULL) *int_green_Z = XYZ.green_Z;
|
||||
if (int_blue_X != NULL) *int_blue_X = XYZ.blue_X;
|
||||
if (int_blue_Y != NULL) *int_blue_Y = XYZ.blue_Y;
|
||||
if (int_blue_Z != NULL) *int_blue_Z = XYZ.blue_Z;
|
||||
return PNG_INFO_cHRM;
|
||||
}
|
||||
|
||||
@@ -647,31 +626,24 @@ png_get_cHRM_XYZ_fixed(png_const_structrp png_ptr, png_const_inforp info_ptr,
|
||||
|
||||
png_uint_32 PNGAPI
|
||||
png_get_cHRM_fixed(png_const_structrp png_ptr, png_const_inforp info_ptr,
|
||||
png_fixed_point *white_x, png_fixed_point *white_y, png_fixed_point *red_x,
|
||||
png_fixed_point *red_y, png_fixed_point *green_x, png_fixed_point *green_y,
|
||||
png_fixed_point *blue_x, png_fixed_point *blue_y)
|
||||
png_fixed_point *whitex, png_fixed_point *whitey, png_fixed_point *redx,
|
||||
png_fixed_point *redy, png_fixed_point *greenx, png_fixed_point *greeny,
|
||||
png_fixed_point *bluex, png_fixed_point *bluey)
|
||||
{
|
||||
png_debug1(1, "in %s retrieval function", "cHRM");
|
||||
|
||||
/* PNGv3: this just returns the values store from the cHRM, if any. */
|
||||
if (png_ptr != NULL && info_ptr != NULL &&
|
||||
(info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_ENDPOINTS) != 0)
|
||||
(info_ptr->valid & PNG_INFO_cHRM) != 0)
|
||||
{
|
||||
if (white_x != NULL)
|
||||
*white_x = info_ptr->colorspace.end_points_xy.whitex;
|
||||
if (white_y != NULL)
|
||||
*white_y = info_ptr->colorspace.end_points_xy.whitey;
|
||||
if (red_x != NULL)
|
||||
*red_x = info_ptr->colorspace.end_points_xy.redx;
|
||||
if (red_y != NULL)
|
||||
*red_y = info_ptr->colorspace.end_points_xy.redy;
|
||||
if (green_x != NULL)
|
||||
*green_x = info_ptr->colorspace.end_points_xy.greenx;
|
||||
if (green_y != NULL)
|
||||
*green_y = info_ptr->colorspace.end_points_xy.greeny;
|
||||
if (blue_x != NULL)
|
||||
*blue_x = info_ptr->colorspace.end_points_xy.bluex;
|
||||
if (blue_y != NULL)
|
||||
*blue_y = info_ptr->colorspace.end_points_xy.bluey;
|
||||
if (whitex != NULL) *whitex = info_ptr->cHRM.whitex;
|
||||
if (whitey != NULL) *whitey = info_ptr->cHRM.whitey;
|
||||
if (redx != NULL) *redx = info_ptr->cHRM.redx;
|
||||
if (redy != NULL) *redy = info_ptr->cHRM.redy;
|
||||
if (greenx != NULL) *greenx = info_ptr->cHRM.greenx;
|
||||
if (greeny != NULL) *greeny = info_ptr->cHRM.greeny;
|
||||
if (bluex != NULL) *bluex = info_ptr->cHRM.bluex;
|
||||
if (bluey != NULL) *bluey = info_ptr->cHRM.bluey;
|
||||
return PNG_INFO_cHRM;
|
||||
}
|
||||
|
||||
@@ -688,11 +660,11 @@ png_get_gAMA_fixed(png_const_structrp png_ptr, png_const_inforp info_ptr,
|
||||
{
|
||||
png_debug1(1, "in %s retrieval function", "gAMA");
|
||||
|
||||
/* PNGv3 compatibility: only report gAMA if it is really present. */
|
||||
if (png_ptr != NULL && info_ptr != NULL &&
|
||||
(info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_GAMMA) != 0 &&
|
||||
file_gamma != NULL)
|
||||
(info_ptr->valid & PNG_INFO_gAMA) != 0)
|
||||
{
|
||||
*file_gamma = info_ptr->colorspace.gamma;
|
||||
if (file_gamma != NULL) *file_gamma = info_ptr->gamma;
|
||||
return PNG_INFO_gAMA;
|
||||
}
|
||||
|
||||
@@ -707,12 +679,13 @@ png_get_gAMA(png_const_structrp png_ptr, png_const_inforp info_ptr,
|
||||
{
|
||||
png_debug1(1, "in %s retrieval function", "gAMA(float)");
|
||||
|
||||
/* PNGv3 compatibility: only report gAMA if it is really present. */
|
||||
if (png_ptr != NULL && info_ptr != NULL &&
|
||||
(info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_GAMMA) != 0 &&
|
||||
file_gamma != NULL)
|
||||
(info_ptr->valid & PNG_INFO_gAMA) != 0)
|
||||
{
|
||||
*file_gamma = png_float(png_ptr, info_ptr->colorspace.gamma,
|
||||
"png_get_gAMA");
|
||||
if (file_gamma != NULL)
|
||||
*file_gamma = png_float(png_ptr, info_ptr->gamma, "gAMA");
|
||||
|
||||
return PNG_INFO_gAMA;
|
||||
}
|
||||
|
||||
@@ -729,9 +702,10 @@ png_get_sRGB(png_const_structrp png_ptr, png_const_inforp info_ptr,
|
||||
png_debug1(1, "in %s retrieval function", "sRGB");
|
||||
|
||||
if (png_ptr != NULL && info_ptr != NULL &&
|
||||
(info_ptr->valid & PNG_INFO_sRGB) != 0 && file_srgb_intent != NULL)
|
||||
(info_ptr->valid & PNG_INFO_sRGB) != 0)
|
||||
{
|
||||
*file_srgb_intent = info_ptr->colorspace.rendering_intent;
|
||||
if (file_srgb_intent != NULL)
|
||||
*file_srgb_intent = info_ptr->rendering_intent;
|
||||
return PNG_INFO_sRGB;
|
||||
}
|
||||
|
||||
@@ -787,7 +761,7 @@ png_get_sPLT(png_const_structrp png_ptr, png_inforp info_ptr,
|
||||
#ifdef PNG_cICP_SUPPORTED
|
||||
png_uint_32 PNGAPI
|
||||
png_get_cICP(png_const_structrp png_ptr,
|
||||
png_inforp info_ptr, png_bytep colour_primaries,
|
||||
png_const_inforp info_ptr, png_bytep colour_primaries,
|
||||
png_bytep transfer_function, png_bytep matrix_coefficients,
|
||||
png_bytep video_full_range_flag)
|
||||
{
|
||||
@@ -805,10 +779,115 @@ png_get_cICP(png_const_structrp png_ptr,
|
||||
return (PNG_INFO_cICP);
|
||||
}
|
||||
|
||||
return (0);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef PNG_cLLI_SUPPORTED
|
||||
# ifdef PNG_FIXED_POINT_SUPPORTED
|
||||
png_uint_32 PNGAPI
|
||||
png_get_cLLI_fixed(png_const_structrp png_ptr, png_const_inforp info_ptr,
|
||||
png_uint_32p maxCLL,
|
||||
png_uint_32p maxFALL)
|
||||
{
|
||||
png_debug1(1, "in %s retrieval function", "cLLI");
|
||||
|
||||
if (png_ptr != NULL && info_ptr != NULL &&
|
||||
(info_ptr->valid & PNG_INFO_cLLI) != 0)
|
||||
{
|
||||
if (maxCLL != NULL) *maxCLL = info_ptr->maxCLL;
|
||||
if (maxFALL != NULL) *maxFALL = info_ptr->maxFALL;
|
||||
return PNG_INFO_cLLI;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
# endif
|
||||
|
||||
# ifdef PNG_FLOATING_POINT_SUPPORTED
|
||||
png_uint_32 PNGAPI
|
||||
png_get_cLLI(png_const_structrp png_ptr, png_const_inforp info_ptr,
|
||||
double *maxCLL, double *maxFALL)
|
||||
{
|
||||
png_debug1(1, "in %s retrieval function", "cLLI(float)");
|
||||
|
||||
if (png_ptr != NULL && info_ptr != NULL &&
|
||||
(info_ptr->valid & PNG_INFO_cLLI) != 0)
|
||||
{
|
||||
if (maxCLL != NULL) *maxCLL = info_ptr->maxCLL * .0001;
|
||||
if (maxFALL != NULL) *maxFALL = info_ptr->maxFALL * .0001;
|
||||
return PNG_INFO_cLLI;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
# endif
|
||||
#endif /* cLLI */
|
||||
|
||||
#ifdef PNG_mDCV_SUPPORTED
|
||||
# ifdef PNG_FIXED_POINT_SUPPORTED
|
||||
png_uint_32 PNGAPI
|
||||
png_get_mDCV_fixed(png_const_structrp png_ptr, png_const_inforp info_ptr,
|
||||
png_fixed_point *white_x, png_fixed_point *white_y,
|
||||
png_fixed_point *red_x, png_fixed_point *red_y,
|
||||
png_fixed_point *green_x, png_fixed_point *green_y,
|
||||
png_fixed_point *blue_x, png_fixed_point *blue_y,
|
||||
png_uint_32p mastering_maxDL, png_uint_32p mastering_minDL)
|
||||
{
|
||||
png_debug1(1, "in %s retrieval function", "mDCV");
|
||||
|
||||
if (png_ptr != NULL && info_ptr != NULL &&
|
||||
(info_ptr->valid & PNG_INFO_mDCV) != 0)
|
||||
{
|
||||
if (white_x != NULL) *white_x = info_ptr->mastering_white_x * 2;
|
||||
if (white_y != NULL) *white_y = info_ptr->mastering_white_y * 2;
|
||||
if (red_x != NULL) *red_x = info_ptr->mastering_red_x * 2;
|
||||
if (red_y != NULL) *red_y = info_ptr->mastering_red_y * 2;
|
||||
if (green_x != NULL) *green_x = info_ptr->mastering_green_x * 2;
|
||||
if (green_y != NULL) *green_y = info_ptr->mastering_green_y * 2;
|
||||
if (blue_x != NULL) *blue_x = info_ptr->mastering_blue_x * 2;
|
||||
if (blue_y != NULL) *blue_y = info_ptr->mastering_blue_y * 2;
|
||||
if (mastering_maxDL != NULL) *mastering_maxDL = info_ptr->mastering_maxDL;
|
||||
if (mastering_minDL != NULL) *mastering_minDL = info_ptr->mastering_minDL;
|
||||
return PNG_INFO_mDCV;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
# endif
|
||||
|
||||
# ifdef PNG_FLOATING_POINT_SUPPORTED
|
||||
png_uint_32 PNGAPI
|
||||
png_get_mDCV(png_const_structrp png_ptr, png_const_inforp info_ptr,
|
||||
double *white_x, double *white_y, double *red_x, double *red_y,
|
||||
double *green_x, double *green_y, double *blue_x, double *blue_y,
|
||||
double *mastering_maxDL, double *mastering_minDL)
|
||||
{
|
||||
png_debug1(1, "in %s retrieval function", "mDCV(float)");
|
||||
|
||||
if (png_ptr != NULL && info_ptr != NULL &&
|
||||
(info_ptr->valid & PNG_INFO_mDCV) != 0)
|
||||
{
|
||||
if (white_x != NULL) *white_x = info_ptr->mastering_white_x * .00002;
|
||||
if (white_y != NULL) *white_y = info_ptr->mastering_white_y * .00002;
|
||||
if (red_x != NULL) *red_x = info_ptr->mastering_red_x * .00002;
|
||||
if (red_y != NULL) *red_y = info_ptr->mastering_red_y * .00002;
|
||||
if (green_x != NULL) *green_x = info_ptr->mastering_green_x * .00002;
|
||||
if (green_y != NULL) *green_y = info_ptr->mastering_green_y * .00002;
|
||||
if (blue_x != NULL) *blue_x = info_ptr->mastering_blue_x * .00002;
|
||||
if (blue_y != NULL) *blue_y = info_ptr->mastering_blue_y * .00002;
|
||||
if (mastering_maxDL != NULL)
|
||||
*mastering_maxDL = info_ptr->mastering_maxDL * .0001;
|
||||
if (mastering_minDL != NULL)
|
||||
*mastering_minDL = info_ptr->mastering_minDL * .0001;
|
||||
return PNG_INFO_mDCV;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
# endif /* FLOATING_POINT */
|
||||
#endif /* mDCV */
|
||||
|
||||
#ifdef PNG_eXIf_SUPPORTED
|
||||
png_uint_32 PNGAPI
|
||||
png_get_eXIf(png_const_structrp png_ptr, png_inforp info_ptr,
|
||||
|
||||
Vendored
+44
-55
@@ -1,6 +1,6 @@
|
||||
/* pnginfo.h - header file for PNG reference library
|
||||
/* pnginfo.h - internal structures for libpng
|
||||
*
|
||||
* Copyright (c) 2018 Cosmin Truta
|
||||
* Copyright (c) 2018-2025 Cosmin Truta
|
||||
* Copyright (c) 1998-2002,2004,2006-2013,2018 Glenn Randers-Pehrson
|
||||
* Copyright (c) 1996-1997 Andreas Dilger
|
||||
* Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
|
||||
@@ -10,43 +10,20 @@
|
||||
* and license in png.h
|
||||
*/
|
||||
|
||||
/* png_info is a structure that holds the information in a PNG file so
|
||||
* that the application can find out the characteristics of the image.
|
||||
* If you are reading the file, this structure will tell you what is
|
||||
* in the PNG file. If you are writing the file, fill in the information
|
||||
* you want to put into the PNG file, using png_set_*() functions, then
|
||||
* call png_write_info().
|
||||
#ifndef PNGPRIV_H
|
||||
# error This file must not be included by applications; please include <png.h>
|
||||
#endif
|
||||
|
||||
/* INTERNAL, PRIVATE definition of a PNG.
|
||||
*
|
||||
* The names chosen should be very close to the PNG specification, so
|
||||
* consult that document for information about the meaning of each field.
|
||||
* png_info is a modifiable description of a PNG datastream. The fields inside
|
||||
* this structure are accessed through png_get_<CHUNK>() functions and modified
|
||||
* using png_set_<CHUNK>() functions.
|
||||
*
|
||||
* With libpng < 0.95, it was only possible to directly set and read the
|
||||
* the values in the png_info_struct, which meant that the contents and
|
||||
* order of the values had to remain fixed. With libpng 0.95 and later,
|
||||
* however, there are now functions that abstract the contents of
|
||||
* png_info_struct from the application, so this makes it easier to use
|
||||
* libpng with dynamic libraries, and even makes it possible to use
|
||||
* libraries that don't have all of the libpng ancillary chunk-handing
|
||||
* functionality. In libpng-1.5.0 this was moved into a separate private
|
||||
* file that is not visible to applications.
|
||||
*
|
||||
* The following members may have allocated storage attached that should be
|
||||
* cleaned up before the structure is discarded: palette, trans, text,
|
||||
* pcal_purpose, pcal_units, pcal_params, hist, iccp_name, iccp_profile,
|
||||
* splt_palettes, scal_unit, row_pointers, and unknowns. By default, these
|
||||
* are automatically freed when the info structure is deallocated, if they were
|
||||
* allocated internally by libpng. This behavior can be changed by means
|
||||
* of the png_data_freer() function.
|
||||
*
|
||||
* More allocation details: all the chunk-reading functions that
|
||||
* change these members go through the corresponding png_set_*
|
||||
* functions. A function to clear these members is available: see
|
||||
* png_free_data(). The png_set_* functions do not depend on being
|
||||
* able to point info structure members to any of the storage they are
|
||||
* passed (they make their own copies), EXCEPT that the png_set_text
|
||||
* functions use the same storage passed to them in the text_ptr or
|
||||
* itxt_ptr structure argument, and the png_set_rows and png_set_unknowns
|
||||
* functions do not make their own copies.
|
||||
* Some functions in libpng do directly access members of png_info. However,
|
||||
* this should be avoided. png_struct objects contain members which hold
|
||||
* caches, sometimes optimised, of the values from png_info objects, and
|
||||
* png_info is not passed to the functions which read and write image data.
|
||||
*/
|
||||
#ifndef PNGINFO_H
|
||||
#define PNGINFO_H
|
||||
@@ -86,20 +63,6 @@ struct png_info_def
|
||||
* and initialize the appropriate fields below.
|
||||
*/
|
||||
|
||||
#if defined(PNG_COLORSPACE_SUPPORTED) || defined(PNG_GAMMA_SUPPORTED)
|
||||
/* png_colorspace only contains 'flags' if neither GAMMA or COLORSPACE are
|
||||
* defined. When COLORSPACE is switched on all the colorspace-defining
|
||||
* chunks should be enabled, when GAMMA is switched on all the gamma-defining
|
||||
* chunks should be enabled. If this is not done it becomes possible to read
|
||||
* inconsistent PNG files and assign a probably incorrect interpretation to
|
||||
* the information. (In other words, by carefully choosing which chunks to
|
||||
* recognize the system configuration can select an interpretation for PNG
|
||||
* files containing ambiguous data and this will result in inconsistent
|
||||
* behavior between different libpng builds!)
|
||||
*/
|
||||
png_colorspace colorspace;
|
||||
#endif
|
||||
|
||||
#ifdef PNG_cICP_SUPPORTED
|
||||
/* cICP chunk data */
|
||||
png_byte cicp_colour_primaries;
|
||||
@@ -115,6 +78,24 @@ struct png_info_def
|
||||
png_uint_32 iccp_proflen; /* ICC profile data length */
|
||||
#endif
|
||||
|
||||
#ifdef PNG_cLLI_SUPPORTED
|
||||
png_uint_32 maxCLL; /* cd/m2 (nits) * 10,000 */
|
||||
png_uint_32 maxFALL;
|
||||
#endif
|
||||
|
||||
#ifdef PNG_mDCV_SUPPORTED
|
||||
png_uint_16 mastering_red_x; /* CIE (xy) x * 50,000 */
|
||||
png_uint_16 mastering_red_y;
|
||||
png_uint_16 mastering_green_x;
|
||||
png_uint_16 mastering_green_y;
|
||||
png_uint_16 mastering_blue_x;
|
||||
png_uint_16 mastering_blue_y;
|
||||
png_uint_16 mastering_white_x;
|
||||
png_uint_16 mastering_white_y;
|
||||
png_uint_32 mastering_maxDL; /* cd/m2 (nits) * 10,000 */
|
||||
png_uint_32 mastering_minDL;
|
||||
#endif
|
||||
|
||||
#ifdef PNG_TEXT_SUPPORTED
|
||||
/* The tEXt, and zTXt chunks contain human-readable textual data in
|
||||
* uncompressed, compressed, and optionally compressed forms, respectively.
|
||||
@@ -193,11 +174,8 @@ defined(PNG_READ_BACKGROUND_SUPPORTED)
|
||||
#endif
|
||||
|
||||
#ifdef PNG_eXIf_SUPPORTED
|
||||
int num_exif; /* Added at libpng-1.6.31 */
|
||||
png_uint_32 num_exif; /* Added at libpng-1.6.31 */
|
||||
png_bytep exif;
|
||||
# ifdef PNG_READ_eXIf_SUPPORTED
|
||||
png_bytep eXIf_buf; /* Added at libpng-1.6.32 */
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef PNG_hIST_SUPPORTED
|
||||
@@ -270,5 +248,16 @@ defined(PNG_READ_BACKGROUND_SUPPORTED)
|
||||
png_bytepp row_pointers; /* the image bits */
|
||||
#endif
|
||||
|
||||
#ifdef PNG_cHRM_SUPPORTED
|
||||
png_xy cHRM;
|
||||
#endif
|
||||
|
||||
#ifdef PNG_gAMA_SUPPORTED
|
||||
png_fixed_point gamma;
|
||||
#endif
|
||||
|
||||
#ifdef PNG_sRGB_SUPPORTED
|
||||
int rendering_intent;
|
||||
#endif
|
||||
};
|
||||
#endif /* PNGINFO_H */
|
||||
|
||||
Vendored
+13
-173
@@ -1,6 +1,6 @@
|
||||
/* pngpread.c - read a png file in push mode
|
||||
*
|
||||
* Copyright (c) 2018-2024 Cosmin Truta
|
||||
* Copyright (c) 2018-2025 Cosmin Truta
|
||||
* Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
|
||||
* Copyright (c) 1996-1997 Andreas Dilger
|
||||
* Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
|
||||
@@ -193,17 +193,8 @@ png_push_read_chunk(png_structrp png_ptr, png_inforp info_ptr)
|
||||
*/
|
||||
if ((png_ptr->mode & PNG_HAVE_CHUNK_HEADER) == 0)
|
||||
{
|
||||
png_byte chunk_length[4];
|
||||
png_byte chunk_tag[4];
|
||||
|
||||
PNG_PUSH_SAVE_BUFFER_IF_LT(8)
|
||||
png_push_fill_buffer(png_ptr, chunk_length, 4);
|
||||
png_ptr->push_length = png_get_uint_31(png_ptr, chunk_length);
|
||||
png_reset_crc(png_ptr);
|
||||
png_crc_read(png_ptr, chunk_tag, 4);
|
||||
png_ptr->chunk_name = PNG_CHUNK_FROM_STRING(chunk_tag);
|
||||
png_check_chunk_name(png_ptr, png_ptr->chunk_name);
|
||||
png_check_chunk_length(png_ptr, png_ptr->push_length);
|
||||
png_ptr->push_length = png_read_chunk_header(png_ptr);
|
||||
png_ptr->mode |= PNG_HAVE_CHUNK_HEADER;
|
||||
}
|
||||
|
||||
@@ -238,19 +229,27 @@ png_push_read_chunk(png_structrp png_ptr, png_inforp info_ptr)
|
||||
png_benign_error(png_ptr, "Too many IDATs found");
|
||||
}
|
||||
|
||||
else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0)
|
||||
{
|
||||
/* These flags must be set consistently for all non-IDAT chunks,
|
||||
* including the unknown chunks.
|
||||
*/
|
||||
png_ptr->mode |= PNG_HAVE_CHUNK_AFTER_IDAT | PNG_AFTER_IDAT;
|
||||
}
|
||||
|
||||
if (chunk_name == png_IHDR)
|
||||
{
|
||||
if (png_ptr->push_length != 13)
|
||||
png_error(png_ptr, "Invalid IHDR length");
|
||||
|
||||
PNG_PUSH_SAVE_BUFFER_IF_FULL
|
||||
png_handle_IHDR(png_ptr, info_ptr, png_ptr->push_length);
|
||||
png_handle_chunk(png_ptr, info_ptr, png_ptr->push_length);
|
||||
}
|
||||
|
||||
else if (chunk_name == png_IEND)
|
||||
{
|
||||
PNG_PUSH_SAVE_BUFFER_IF_FULL
|
||||
png_handle_IEND(png_ptr, info_ptr, png_ptr->push_length);
|
||||
png_handle_chunk(png_ptr, info_ptr, png_ptr->push_length);
|
||||
|
||||
png_ptr->process_mode = PNG_READ_DONE_MODE;
|
||||
png_push_have_end(png_ptr, info_ptr);
|
||||
@@ -267,12 +266,6 @@ png_push_read_chunk(png_structrp png_ptr, png_inforp info_ptr)
|
||||
}
|
||||
#endif
|
||||
|
||||
else if (chunk_name == png_PLTE)
|
||||
{
|
||||
PNG_PUSH_SAVE_BUFFER_IF_FULL
|
||||
png_handle_PLTE(png_ptr, info_ptr, png_ptr->push_length);
|
||||
}
|
||||
|
||||
else if (chunk_name == png_IDAT)
|
||||
{
|
||||
png_ptr->idat_size = png_ptr->push_length;
|
||||
@@ -285,163 +278,10 @@ png_push_read_chunk(png_structrp png_ptr, png_inforp info_ptr)
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef PNG_READ_gAMA_SUPPORTED
|
||||
else if (png_ptr->chunk_name == png_gAMA)
|
||||
{
|
||||
PNG_PUSH_SAVE_BUFFER_IF_FULL
|
||||
png_handle_gAMA(png_ptr, info_ptr, png_ptr->push_length);
|
||||
}
|
||||
|
||||
#endif
|
||||
#ifdef PNG_READ_sBIT_SUPPORTED
|
||||
else if (png_ptr->chunk_name == png_sBIT)
|
||||
{
|
||||
PNG_PUSH_SAVE_BUFFER_IF_FULL
|
||||
png_handle_sBIT(png_ptr, info_ptr, png_ptr->push_length);
|
||||
}
|
||||
|
||||
#endif
|
||||
#ifdef PNG_READ_cHRM_SUPPORTED
|
||||
else if (png_ptr->chunk_name == png_cHRM)
|
||||
{
|
||||
PNG_PUSH_SAVE_BUFFER_IF_FULL
|
||||
png_handle_cHRM(png_ptr, info_ptr, png_ptr->push_length);
|
||||
}
|
||||
|
||||
#endif
|
||||
#ifdef PNG_READ_cICP_SUPPORTED
|
||||
else if (png_ptr->chunk_name == png_cICP)
|
||||
{
|
||||
PNG_PUSH_SAVE_BUFFER_IF_FULL
|
||||
png_handle_cICP(png_ptr, info_ptr, png_ptr->push_length);
|
||||
}
|
||||
|
||||
#endif
|
||||
#ifdef PNG_READ_eXIf_SUPPORTED
|
||||
else if (png_ptr->chunk_name == png_eXIf)
|
||||
{
|
||||
PNG_PUSH_SAVE_BUFFER_IF_FULL
|
||||
png_handle_eXIf(png_ptr, info_ptr, png_ptr->push_length);
|
||||
}
|
||||
|
||||
#endif
|
||||
#ifdef PNG_READ_sRGB_SUPPORTED
|
||||
else if (chunk_name == png_sRGB)
|
||||
{
|
||||
PNG_PUSH_SAVE_BUFFER_IF_FULL
|
||||
png_handle_sRGB(png_ptr, info_ptr, png_ptr->push_length);
|
||||
}
|
||||
|
||||
#endif
|
||||
#ifdef PNG_READ_iCCP_SUPPORTED
|
||||
else if (png_ptr->chunk_name == png_iCCP)
|
||||
{
|
||||
PNG_PUSH_SAVE_BUFFER_IF_FULL
|
||||
png_handle_iCCP(png_ptr, info_ptr, png_ptr->push_length);
|
||||
}
|
||||
|
||||
#endif
|
||||
#ifdef PNG_READ_sPLT_SUPPORTED
|
||||
else if (chunk_name == png_sPLT)
|
||||
{
|
||||
PNG_PUSH_SAVE_BUFFER_IF_FULL
|
||||
png_handle_sPLT(png_ptr, info_ptr, png_ptr->push_length);
|
||||
}
|
||||
|
||||
#endif
|
||||
#ifdef PNG_READ_tRNS_SUPPORTED
|
||||
else if (chunk_name == png_tRNS)
|
||||
{
|
||||
PNG_PUSH_SAVE_BUFFER_IF_FULL
|
||||
png_handle_tRNS(png_ptr, info_ptr, png_ptr->push_length);
|
||||
}
|
||||
|
||||
#endif
|
||||
#ifdef PNG_READ_bKGD_SUPPORTED
|
||||
else if (chunk_name == png_bKGD)
|
||||
{
|
||||
PNG_PUSH_SAVE_BUFFER_IF_FULL
|
||||
png_handle_bKGD(png_ptr, info_ptr, png_ptr->push_length);
|
||||
}
|
||||
|
||||
#endif
|
||||
#ifdef PNG_READ_hIST_SUPPORTED
|
||||
else if (chunk_name == png_hIST)
|
||||
{
|
||||
PNG_PUSH_SAVE_BUFFER_IF_FULL
|
||||
png_handle_hIST(png_ptr, info_ptr, png_ptr->push_length);
|
||||
}
|
||||
|
||||
#endif
|
||||
#ifdef PNG_READ_pHYs_SUPPORTED
|
||||
else if (chunk_name == png_pHYs)
|
||||
{
|
||||
PNG_PUSH_SAVE_BUFFER_IF_FULL
|
||||
png_handle_pHYs(png_ptr, info_ptr, png_ptr->push_length);
|
||||
}
|
||||
|
||||
#endif
|
||||
#ifdef PNG_READ_oFFs_SUPPORTED
|
||||
else if (chunk_name == png_oFFs)
|
||||
{
|
||||
PNG_PUSH_SAVE_BUFFER_IF_FULL
|
||||
png_handle_oFFs(png_ptr, info_ptr, png_ptr->push_length);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef PNG_READ_pCAL_SUPPORTED
|
||||
else if (chunk_name == png_pCAL)
|
||||
{
|
||||
PNG_PUSH_SAVE_BUFFER_IF_FULL
|
||||
png_handle_pCAL(png_ptr, info_ptr, png_ptr->push_length);
|
||||
}
|
||||
|
||||
#endif
|
||||
#ifdef PNG_READ_sCAL_SUPPORTED
|
||||
else if (chunk_name == png_sCAL)
|
||||
{
|
||||
PNG_PUSH_SAVE_BUFFER_IF_FULL
|
||||
png_handle_sCAL(png_ptr, info_ptr, png_ptr->push_length);
|
||||
}
|
||||
|
||||
#endif
|
||||
#ifdef PNG_READ_tIME_SUPPORTED
|
||||
else if (chunk_name == png_tIME)
|
||||
{
|
||||
PNG_PUSH_SAVE_BUFFER_IF_FULL
|
||||
png_handle_tIME(png_ptr, info_ptr, png_ptr->push_length);
|
||||
}
|
||||
|
||||
#endif
|
||||
#ifdef PNG_READ_tEXt_SUPPORTED
|
||||
else if (chunk_name == png_tEXt)
|
||||
{
|
||||
PNG_PUSH_SAVE_BUFFER_IF_FULL
|
||||
png_handle_tEXt(png_ptr, info_ptr, png_ptr->push_length);
|
||||
}
|
||||
|
||||
#endif
|
||||
#ifdef PNG_READ_zTXt_SUPPORTED
|
||||
else if (chunk_name == png_zTXt)
|
||||
{
|
||||
PNG_PUSH_SAVE_BUFFER_IF_FULL
|
||||
png_handle_zTXt(png_ptr, info_ptr, png_ptr->push_length);
|
||||
}
|
||||
|
||||
#endif
|
||||
#ifdef PNG_READ_iTXt_SUPPORTED
|
||||
else if (chunk_name == png_iTXt)
|
||||
{
|
||||
PNG_PUSH_SAVE_BUFFER_IF_FULL
|
||||
png_handle_iTXt(png_ptr, info_ptr, png_ptr->push_length);
|
||||
}
|
||||
#endif
|
||||
|
||||
else
|
||||
{
|
||||
PNG_PUSH_SAVE_BUFFER_IF_FULL
|
||||
png_handle_unknown(png_ptr, info_ptr, png_ptr->push_length,
|
||||
PNG_HANDLE_CHUNK_AS_DEFAULT);
|
||||
png_handle_chunk(png_ptr, info_ptr, png_ptr->push_length);
|
||||
}
|
||||
|
||||
png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
|
||||
|
||||
Vendored
+269
-243
@@ -1,6 +1,6 @@
|
||||
/* pngpriv.h - private declarations for use inside libpng
|
||||
*
|
||||
* Copyright (c) 2018-2024 Cosmin Truta
|
||||
* Copyright (c) 2018-2025 Cosmin Truta
|
||||
* Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
|
||||
* Copyright (c) 1996-1997 Andreas Dilger
|
||||
* Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
|
||||
@@ -19,8 +19,20 @@
|
||||
* they should be well aware of the issues that may arise from doing so.
|
||||
*/
|
||||
|
||||
|
||||
/* pngpriv.h must be included first in each translation unit inside libpng.
|
||||
* On the other hand, it must not be included at all, directly or indirectly,
|
||||
* by any application code that uses the libpng API.
|
||||
*/
|
||||
#ifndef PNGPRIV_H
|
||||
#define PNGPRIV_H
|
||||
# define PNGPRIV_H
|
||||
#else
|
||||
# error Duplicate inclusion of pngpriv.h; please check the libpng source files
|
||||
#endif
|
||||
|
||||
#if defined(PNG_H) || defined(PNGCONF_H) || defined(PNGLCONF_H)
|
||||
# error This file must not be included by applications; please include <png.h>
|
||||
#endif
|
||||
|
||||
/* Feature Test Macros. The following are defined here to ensure that correctly
|
||||
* implemented libraries reveal the APIs libpng needs to build and hide those
|
||||
@@ -57,7 +69,6 @@
|
||||
*/
|
||||
#if defined(HAVE_CONFIG_H) && !defined(PNG_NO_CONFIG_H)
|
||||
# include <config.h>
|
||||
|
||||
/* Pick up the definition of 'restrict' from config.h if it was read: */
|
||||
# define PNG_RESTRICT restrict
|
||||
#endif
|
||||
@@ -67,9 +78,7 @@
|
||||
* are not internal definitions may be required. This is handled below just
|
||||
* before png.h is included, but load the configuration now if it is available.
|
||||
*/
|
||||
#ifndef PNGLCONF_H
|
||||
# include "pnglibconf.h"
|
||||
#endif
|
||||
#include "pnglibconf.h"
|
||||
|
||||
/* Local renames may change non-exported API functions from png.h */
|
||||
#if defined(PNG_PREFIX) && !defined(PNGPREFIX_H)
|
||||
@@ -134,6 +143,20 @@
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef PNG_RISCV_RVV_OPT
|
||||
/* RISCV_RVV optimizations are being controlled by the compiler settings,
|
||||
* typically the target compiler will define __riscv but the rvv extension
|
||||
* availability has to be explicitly stated. This is why if no
|
||||
* PNG_RISCV_RVV_OPT was defined then a runtime check will be executed.
|
||||
*
|
||||
* To enable RISCV_RVV optimizations unconditionally, and compile the
|
||||
* associated code, pass --enable-riscv-rvv=yes or --enable-riscv-rvv=on
|
||||
* to configure or put -DPNG_RISCV_RVV_OPT=2 in CPPFLAGS.
|
||||
*/
|
||||
|
||||
# define PNG_RISCV_RVV_OPT 0
|
||||
#endif
|
||||
|
||||
#if PNG_ARM_NEON_OPT > 0
|
||||
/* NEON optimizations are to be at least considered by libpng, so enable the
|
||||
* callbacks to do this.
|
||||
@@ -279,6 +302,16 @@
|
||||
# define PNG_LOONGARCH_LSX_IMPLEMENTATION 0
|
||||
#endif
|
||||
|
||||
#if PNG_RISCV_RVV_OPT > 0 && __riscv_v >= 1000000
|
||||
# define PNG_FILTER_OPTIMIZATIONS png_init_filter_functions_rvv
|
||||
# ifndef PNG_RISCV_RVV_IMPLEMENTATION
|
||||
/* Use the intrinsics code by default. */
|
||||
# define PNG_RISCV_RVV_IMPLEMENTATION 1
|
||||
# endif
|
||||
#else
|
||||
# define PNG_RISCV_RVV_IMPLEMENTATION 0
|
||||
#endif /* PNG_RISCV_RVV_OPT > 0 && __riscv_v >= 1000000 */
|
||||
|
||||
/* Is this a build of a DLL where compilation of the object modules requires
|
||||
* different preprocessor settings to those required for a simple library? If
|
||||
* so PNG_BUILD_DLL must be set.
|
||||
@@ -671,13 +704,13 @@
|
||||
#define PNG_FLAG_CRC_ANCILLARY_NOWARN 0x0200U
|
||||
#define PNG_FLAG_CRC_CRITICAL_USE 0x0400U
|
||||
#define PNG_FLAG_CRC_CRITICAL_IGNORE 0x0800U
|
||||
#define PNG_FLAG_ASSUME_sRGB 0x1000U /* Added to libpng-1.5.4 */
|
||||
/* PNG_FLAG_ASSUME_sRGB unused 0x1000U * Added to libpng-1.5.4 */
|
||||
#define PNG_FLAG_OPTIMIZE_ALPHA 0x2000U /* Added to libpng-1.5.4 */
|
||||
#define PNG_FLAG_DETECT_UNINITIALIZED 0x4000U /* Added to libpng-1.5.4 */
|
||||
/* #define PNG_FLAG_KEEP_UNKNOWN_CHUNKS 0x8000U */
|
||||
/* #define PNG_FLAG_KEEP_UNSAFE_CHUNKS 0x10000U */
|
||||
#define PNG_FLAG_LIBRARY_MISMATCH 0x20000U
|
||||
#define PNG_FLAG_STRIP_ERROR_NUMBERS 0x40000U
|
||||
/* 0x40000U unused */
|
||||
#define PNG_FLAG_STRIP_ERROR_TEXT 0x80000U
|
||||
#define PNG_FLAG_BENIGN_ERRORS_WARN 0x100000U /* Added to libpng-1.4.0 */
|
||||
#define PNG_FLAG_APP_WARNINGS_WARN 0x200000U /* Added to libpng-1.6.0 */
|
||||
@@ -782,6 +815,8 @@
|
||||
#ifdef PNG_FIXED_POINT_MACRO_SUPPORTED
|
||||
#define png_fixed(png_ptr, fp, s) ((fp) <= 21474 && (fp) >= -21474 ?\
|
||||
((png_fixed_point)(100000 * (fp))) : (png_fixed_error(png_ptr, s),0))
|
||||
#define png_fixed_ITU(png_ptr, fp, s) ((fp) <= 214748 && (fp) >= 0 ?\
|
||||
((png_uint_32)(10000 * (fp))) : (png_fixed_error(png_ptr, s),0))
|
||||
#endif
|
||||
/* else the corresponding function is defined below, inside the scope of the
|
||||
* cplusplus test.
|
||||
@@ -800,11 +835,31 @@
|
||||
*
|
||||
* PNG_32b correctly produces a value shifted by up to 24 bits, even on
|
||||
* architectures where (int) is only 16 bits.
|
||||
*
|
||||
* 1.6.47: PNG_32b was made into a preprocessor evaluable macro by replacing the
|
||||
* static_cast with a promoting binary operation using a guaranteed 32-bit
|
||||
* (minimum) unsigned value.
|
||||
*/
|
||||
#define PNG_32b(b,s) ((png_uint_32)(b) << (s))
|
||||
#define PNG_32b(b,s) (((0xFFFFFFFFU)&(b)) << (s))
|
||||
#define PNG_U32(b1,b2,b3,b4) \
|
||||
(PNG_32b(b1,24) | PNG_32b(b2,16) | PNG_32b(b3,8) | PNG_32b(b4,0))
|
||||
|
||||
/* Chunk name validation. When using these macros all the arguments should be
|
||||
* constants, otherwise code bloat may well occur. The macros are provided
|
||||
* primarily for use in #if checks.
|
||||
*
|
||||
* PNG_32to8 produces a byte value with the right shift; used to extract the
|
||||
* byte value from a chunk name.
|
||||
*/
|
||||
#define PNG_32to8(cn,s) (((cn) >> (s)) & 0xffU)
|
||||
#define PNG_CN_VALID_UPPER(b) ((b) >= 65 && (b) <= 90) /* upper-case ASCII */
|
||||
#define PNG_CN_VALID_ASCII(b) PNG_CN_VALID_UPPER((b) & ~32U)
|
||||
#define PNG_CHUNK_NAME_VALID(cn) (\
|
||||
PNG_CN_VALID_ASCII(PNG_32to8(cn,24)) && /* critical, !ancillary */\
|
||||
PNG_CN_VALID_ASCII(PNG_32to8(cn,16)) && /* public, !privately defined */\
|
||||
PNG_CN_VALID_UPPER(PNG_32to8(cn, 8)) && /* VALID, !reserved */\
|
||||
PNG_CN_VALID_ASCII(PNG_32to8(cn, 0)) /* data-dependent, !copy ok */)
|
||||
|
||||
/* Constants for known chunk types.
|
||||
*
|
||||
* MAINTAINERS: If you need to add a chunk, define the name here.
|
||||
@@ -832,10 +887,14 @@
|
||||
#define png_IEND PNG_U32( 73, 69, 78, 68)
|
||||
#define png_IHDR PNG_U32( 73, 72, 68, 82)
|
||||
#define png_PLTE PNG_U32( 80, 76, 84, 69)
|
||||
#define png_acTL PNG_U32( 97, 99, 84, 76) /* PNGv3: APNG */
|
||||
#define png_bKGD PNG_U32( 98, 75, 71, 68)
|
||||
#define png_cHRM PNG_U32( 99, 72, 82, 77)
|
||||
#define png_cICP PNG_U32( 99, 73, 67, 80)
|
||||
#define png_cICP PNG_U32( 99, 73, 67, 80) /* PNGv3 */
|
||||
#define png_cLLI PNG_U32( 99, 76, 76, 73) /* PNGv3 */
|
||||
#define png_eXIf PNG_U32(101, 88, 73, 102) /* registered July 2017 */
|
||||
#define png_fcTL PNG_U32(102, 99, 84, 76) /* PNGv3: APNG */
|
||||
#define png_fdAT PNG_U32(102, 100, 65, 84) /* PNGv3: APNG */
|
||||
#define png_fRAc PNG_U32(102, 82, 65, 99) /* registered, not defined */
|
||||
#define png_gAMA PNG_U32(103, 65, 77, 65)
|
||||
#define png_gIFg PNG_U32(103, 73, 70, 103)
|
||||
@@ -844,6 +903,7 @@
|
||||
#define png_hIST PNG_U32(104, 73, 83, 84)
|
||||
#define png_iCCP PNG_U32(105, 67, 67, 80)
|
||||
#define png_iTXt PNG_U32(105, 84, 88, 116)
|
||||
#define png_mDCV PNG_U32(109, 68, 67, 86) /* PNGv3 */
|
||||
#define png_oFFs PNG_U32(111, 70, 70, 115)
|
||||
#define png_pCAL PNG_U32(112, 67, 65, 76)
|
||||
#define png_pHYs PNG_U32(112, 72, 89, 115)
|
||||
@@ -884,11 +944,74 @@
|
||||
#define PNG_CHUNK_RESERVED(c) (1 & ((c) >> 13))
|
||||
#define PNG_CHUNK_SAFE_TO_COPY(c) (1 & ((c) >> 5))
|
||||
|
||||
/* Known chunks. All supported chunks must be listed here. The macro PNG_CHUNK
|
||||
* contains the four character ASCII name by which the chunk is identified. The
|
||||
* macro is implemented as required to build tables or switch statements which
|
||||
* require entries for every known chunk. The macro also contains an index
|
||||
* value which should be in order (this is checked in png.c).
|
||||
*
|
||||
* Notice that "known" does not require "SUPPORTED"; tables should be built in
|
||||
* such a way that chunks unsupported in a build require no more than the table
|
||||
* entry (which should be small.) In particular function pointers for
|
||||
* unsupported chunks should be NULL.
|
||||
*
|
||||
* At present these index values are not exported (not part of the public API)
|
||||
* so can be changed at will. For convenience the names are in lexical sort
|
||||
* order but with the critical chunks at the start in the order of occurence in
|
||||
* a PNG.
|
||||
*
|
||||
* PNG_INFO_ values do not exist for every one of these chunk handles; for
|
||||
* example PNG_INFO_{IDAT,IEND,tEXt,iTXt,zTXt} and possibly other chunks in the
|
||||
* future.
|
||||
*/
|
||||
#define PNG_KNOWN_CHUNKS\
|
||||
PNG_CHUNK(IHDR, 0)\
|
||||
PNG_CHUNK(PLTE, 1)\
|
||||
PNG_CHUNK(IDAT, 2)\
|
||||
PNG_CHUNK(IEND, 3)\
|
||||
PNG_CHUNK(acTL, 4)\
|
||||
PNG_CHUNK(bKGD, 5)\
|
||||
PNG_CHUNK(cHRM, 6)\
|
||||
PNG_CHUNK(cICP, 7)\
|
||||
PNG_CHUNK(cLLI, 8)\
|
||||
PNG_CHUNK(eXIf, 9)\
|
||||
PNG_CHUNK(fcTL, 10)\
|
||||
PNG_CHUNK(fdAT, 11)\
|
||||
PNG_CHUNK(gAMA, 12)\
|
||||
PNG_CHUNK(hIST, 13)\
|
||||
PNG_CHUNK(iCCP, 14)\
|
||||
PNG_CHUNK(iTXt, 15)\
|
||||
PNG_CHUNK(mDCV, 16)\
|
||||
PNG_CHUNK(oFFs, 17)\
|
||||
PNG_CHUNK(pCAL, 18)\
|
||||
PNG_CHUNK(pHYs, 19)\
|
||||
PNG_CHUNK(sBIT, 20)\
|
||||
PNG_CHUNK(sCAL, 21)\
|
||||
PNG_CHUNK(sPLT, 22)\
|
||||
PNG_CHUNK(sRGB, 23)\
|
||||
PNG_CHUNK(tEXt, 24)\
|
||||
PNG_CHUNK(tIME, 25)\
|
||||
PNG_CHUNK(tRNS, 26)\
|
||||
PNG_CHUNK(zTXt, 27)
|
||||
|
||||
/* Gamma values (new at libpng-1.5.4): */
|
||||
#define PNG_GAMMA_MAC_OLD 151724 /* Assume '1.8' is really 2.2/1.45! */
|
||||
#define PNG_GAMMA_MAC_INVERSE 65909
|
||||
#define PNG_GAMMA_sRGB_INVERSE 45455
|
||||
|
||||
/* gamma sanity check. libpng cannot implement gamma transforms outside a
|
||||
* certain limit because of its use of 16-bit fixed point intermediate values.
|
||||
* Gamma values that are too large or too small will zap the 16-bit values all
|
||||
* to 0 or 65535 resulting in an obvious 'bad' image.
|
||||
*
|
||||
* In libpng 1.6.0 the limits were changed from 0.07..3 to 0.01..100 to
|
||||
* accommodate the optimal 16-bit gamma of 36 and its reciprocal.
|
||||
*
|
||||
* These are png_fixed_point integral values:
|
||||
*/
|
||||
#define PNG_LIB_GAMMA_MIN 1000
|
||||
#define PNG_LIB_GAMMA_MAX 10000000
|
||||
|
||||
/* Almost everything below is C specific; the #defines above can be used in
|
||||
* non-C code (so long as it is C-preprocessed) the rest of this stuff cannot.
|
||||
*/
|
||||
@@ -901,17 +1024,15 @@
|
||||
* must match that used in the build, or we must be using pnglibconf.h.prebuilt:
|
||||
*/
|
||||
#if PNG_ZLIB_VERNUM != 0 && PNG_ZLIB_VERNUM != ZLIB_VERNUM
|
||||
# error ZLIB_VERNUM != PNG_ZLIB_VERNUM \
|
||||
"-I (include path) error: see the notes in pngpriv.h"
|
||||
/* This means that when pnglibconf.h was built the copy of zlib.h that it
|
||||
* used is not the same as the one being used here. Because the build of
|
||||
* libpng makes decisions to use inflateInit2 and inflateReset2 based on the
|
||||
* zlib version number and because this affects handling of certain broken
|
||||
* PNG files the -I directives must match.
|
||||
# error The include path of <zlib.h> is incorrect
|
||||
/* When pnglibconf.h was built, the copy of zlib.h that it used was not the
|
||||
* same as the one being used here. Considering how libpng makes decisions
|
||||
* to use the zlib API based on the zlib version number, the -I options must
|
||||
* match.
|
||||
*
|
||||
* The most likely explanation is that you passed a -I in CFLAGS. This will
|
||||
* not work; all the preprocessor directives and in particular all the -I
|
||||
* directives must be in CPPFLAGS.
|
||||
* A possible cause of this mismatch is that you passed an -I option in
|
||||
* CFLAGS, which is unlikely to work. All the preprocessor options, and all
|
||||
* the -I options in particular, should be in CPPFLAGS.
|
||||
*/
|
||||
#endif
|
||||
|
||||
@@ -952,7 +1073,6 @@ extern "C" {
|
||||
*
|
||||
* All of these functions must be declared with PNG_INTERNAL_FUNCTION.
|
||||
*/
|
||||
|
||||
/* Zlib support */
|
||||
#define PNG_UNEXPECTED_ZLIB_RETURN (-7)
|
||||
PNG_INTERNAL_FUNCTION(void, png_zstream_error,(png_structrp png_ptr, int ret),
|
||||
@@ -971,6 +1091,7 @@ PNG_INTERNAL_FUNCTION(void,png_free_buffer_list,(png_structrp png_ptr,
|
||||
!defined(PNG_FIXED_POINT_MACRO_SUPPORTED) && \
|
||||
(defined(PNG_gAMA_SUPPORTED) || defined(PNG_cHRM_SUPPORTED) || \
|
||||
defined(PNG_sCAL_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) || \
|
||||
defined(PNG_mDCV_SUPPORTED) || \
|
||||
defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)) || \
|
||||
(defined(PNG_sCAL_SUPPORTED) && \
|
||||
defined(PNG_FLOATING_ARITHMETIC_SUPPORTED))
|
||||
@@ -978,12 +1099,38 @@ PNG_INTERNAL_FUNCTION(png_fixed_point,png_fixed,(png_const_structrp png_ptr,
|
||||
double fp, png_const_charp text),PNG_EMPTY);
|
||||
#endif
|
||||
|
||||
#if defined(PNG_FLOATING_POINT_SUPPORTED) && \
|
||||
!defined(PNG_FIXED_POINT_MACRO_SUPPORTED) && \
|
||||
(defined(PNG_cLLI_SUPPORTED) || defined(PNG_mDCV_SUPPORTED))
|
||||
PNG_INTERNAL_FUNCTION(png_uint_32,png_fixed_ITU,(png_const_structrp png_ptr,
|
||||
double fp, png_const_charp text),PNG_EMPTY);
|
||||
#endif
|
||||
|
||||
/* Check the user version string for compatibility, returns false if the version
|
||||
* numbers aren't compatible.
|
||||
*/
|
||||
PNG_INTERNAL_FUNCTION(int,png_user_version_check,(png_structrp png_ptr,
|
||||
png_const_charp user_png_ver),PNG_EMPTY);
|
||||
|
||||
#ifdef PNG_READ_SUPPORTED /* should only be used on read */
|
||||
/* Security: read limits on the largest allocations while reading a PNG. This
|
||||
* avoids very large allocations caused by PNG files with damaged or altered
|
||||
* chunk 'length' fields.
|
||||
*/
|
||||
#ifdef PNG_SET_USER_LIMITS_SUPPORTED /* run-time limit */
|
||||
# define png_chunk_max(png_ptr) ((png_ptr)->user_chunk_malloc_max)
|
||||
|
||||
#elif PNG_USER_CHUNK_MALLOC_MAX > 0 /* compile-time limit */
|
||||
# define png_chunk_max(png_ptr) ((void)png_ptr, PNG_USER_CHUNK_MALLOC_MAX)
|
||||
|
||||
#elif (defined PNG_MAX_MALLOC_64K) /* legacy system limit */
|
||||
# define png_chunk_max(png_ptr) ((void)png_ptr, 65536U)
|
||||
|
||||
#else /* modern system limit SIZE_MAX (C99) */
|
||||
# define png_chunk_max(png_ptr) ((void)png_ptr, PNG_SIZE_MAX)
|
||||
#endif
|
||||
#endif /* READ */
|
||||
|
||||
/* Internal base allocator - no messages, NULL on failure to allocate. This
|
||||
* does, however, call the application provided allocator and that could call
|
||||
* png_error (although that would be a bug in the application implementation.)
|
||||
@@ -1083,9 +1230,6 @@ PNG_INTERNAL_FUNCTION(void,png_crc_read,(png_structrp png_ptr, png_bytep buf,
|
||||
PNG_INTERNAL_FUNCTION(int,png_crc_finish,(png_structrp png_ptr,
|
||||
png_uint_32 skip),PNG_EMPTY);
|
||||
|
||||
/* Read the CRC from the file and compare it to the libpng calculated CRC */
|
||||
PNG_INTERNAL_FUNCTION(int,png_crc_error,(png_structrp png_ptr),PNG_EMPTY);
|
||||
|
||||
/* Calculate the CRC over a section of data. Note that we are only
|
||||
* passing a maximum of 64K on systems that have this as a memory limit,
|
||||
* since this is the maximum buffer size we can specify.
|
||||
@@ -1137,6 +1281,20 @@ PNG_INTERNAL_FUNCTION(void,png_write_cICP,(png_structrp png_ptr,
|
||||
png_byte matrix_coefficients, png_byte video_full_range_flag), PNG_EMPTY);
|
||||
#endif
|
||||
|
||||
#ifdef PNG_WRITE_cLLI_SUPPORTED
|
||||
PNG_INTERNAL_FUNCTION(void,png_write_cLLI_fixed,(png_structrp png_ptr,
|
||||
png_uint_32 maxCLL, png_uint_32 maxFALL), PNG_EMPTY);
|
||||
#endif
|
||||
|
||||
#ifdef PNG_WRITE_mDCV_SUPPORTED
|
||||
PNG_INTERNAL_FUNCTION(void,png_write_mDCV_fixed,(png_structrp png_ptr,
|
||||
png_uint_16 red_x, png_uint_16 red_y,
|
||||
png_uint_16 green_x, png_uint_16 green_y,
|
||||
png_uint_16 blue_x, png_uint_16 blue_y,
|
||||
png_uint_16 white_x, png_uint_16 white_y,
|
||||
png_uint_32 maxDL, png_uint_32 minDL), PNG_EMPTY);
|
||||
#endif
|
||||
|
||||
#ifdef PNG_WRITE_sRGB_SUPPORTED
|
||||
PNG_INTERNAL_FUNCTION(void,png_write_sRGB,(png_structrp png_ptr,
|
||||
int intent),PNG_EMPTY);
|
||||
@@ -1149,10 +1307,10 @@ PNG_INTERNAL_FUNCTION(void,png_write_eXIf,(png_structrp png_ptr,
|
||||
|
||||
#ifdef PNG_WRITE_iCCP_SUPPORTED
|
||||
PNG_INTERNAL_FUNCTION(void,png_write_iCCP,(png_structrp png_ptr,
|
||||
png_const_charp name, png_const_bytep profile), PNG_EMPTY);
|
||||
/* The profile must have been previously validated for correctness, the
|
||||
* length comes from the first four bytes. Only the base, deflate,
|
||||
* compression is supported.
|
||||
png_const_charp name, png_const_bytep profile, png_uint_32 proflen),
|
||||
PNG_EMPTY);
|
||||
/* Writes a previously 'set' profile. The profile argument is **not**
|
||||
* compressed.
|
||||
*/
|
||||
#endif
|
||||
|
||||
@@ -1388,6 +1546,23 @@ PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth4_lsx,(png_row_infop
|
||||
row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
|
||||
#endif
|
||||
|
||||
#if PNG_RISCV_RVV_IMPLEMENTATION == 1
|
||||
PNG_INTERNAL_FUNCTION(void,png_read_filter_row_up_rvv,(png_row_infop
|
||||
row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
|
||||
PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub3_rvv,(png_row_infop
|
||||
row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
|
||||
PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub4_rvv,(png_row_infop
|
||||
row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
|
||||
PNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg3_rvv,(png_row_infop
|
||||
row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
|
||||
PNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg4_rvv,(png_row_infop
|
||||
row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
|
||||
PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth3_rvv,(png_row_infop
|
||||
row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
|
||||
PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth4_rvv,(png_row_infop
|
||||
row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
|
||||
#endif
|
||||
|
||||
/* Choose the best filter to use and filter the row data */
|
||||
PNG_INTERNAL_FUNCTION(void,png_write_find_filter,(png_structrp png_ptr,
|
||||
png_row_infop row_info),PNG_EMPTY);
|
||||
@@ -1461,124 +1636,36 @@ PNG_INTERNAL_FUNCTION(void,png_do_bgr,(png_row_infop row_info,
|
||||
/* The following decodes the appropriate chunks, and does error correction,
|
||||
* then calls the appropriate callback for the chunk if it is valid.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
/* Result of a call to png_handle_chunk made to handle the current chunk
|
||||
* png_struct::chunk_name on read. Always informational, either the stream
|
||||
* is read for the next chunk or the routine will call png_error.
|
||||
*
|
||||
* NOTE: order is important internally. handled_saved and above are regarded
|
||||
* as handling the chunk.
|
||||
*/
|
||||
handled_error = 0, /* bad crc or known and bad format or too long */
|
||||
handled_discarded, /* not saved in the unknown chunk list */
|
||||
handled_saved, /* saved in the unknown chunk list */
|
||||
handled_ok /* known, supported and handled without error */
|
||||
} png_handle_result_code;
|
||||
|
||||
/* Decode the IHDR chunk */
|
||||
PNG_INTERNAL_FUNCTION(void,png_handle_IHDR,(png_structrp png_ptr,
|
||||
png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);
|
||||
PNG_INTERNAL_FUNCTION(void,png_handle_PLTE,(png_structrp png_ptr,
|
||||
png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);
|
||||
PNG_INTERNAL_FUNCTION(void,png_handle_IEND,(png_structrp png_ptr,
|
||||
png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);
|
||||
|
||||
#ifdef PNG_READ_bKGD_SUPPORTED
|
||||
PNG_INTERNAL_FUNCTION(void,png_handle_bKGD,(png_structrp png_ptr,
|
||||
png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);
|
||||
#endif
|
||||
|
||||
#ifdef PNG_READ_cHRM_SUPPORTED
|
||||
PNG_INTERNAL_FUNCTION(void,png_handle_cHRM,(png_structrp png_ptr,
|
||||
png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);
|
||||
#endif
|
||||
|
||||
#ifdef PNG_READ_cICP_SUPPORTED
|
||||
PNG_INTERNAL_FUNCTION(void,png_handle_cICP,(png_structrp png_ptr,
|
||||
png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);
|
||||
#endif
|
||||
|
||||
#ifdef PNG_READ_eXIf_SUPPORTED
|
||||
PNG_INTERNAL_FUNCTION(void,png_handle_eXIf,(png_structrp png_ptr,
|
||||
png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);
|
||||
#endif
|
||||
|
||||
#ifdef PNG_READ_gAMA_SUPPORTED
|
||||
PNG_INTERNAL_FUNCTION(void,png_handle_gAMA,(png_structrp png_ptr,
|
||||
png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);
|
||||
#endif
|
||||
|
||||
#ifdef PNG_READ_hIST_SUPPORTED
|
||||
PNG_INTERNAL_FUNCTION(void,png_handle_hIST,(png_structrp png_ptr,
|
||||
png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);
|
||||
#endif
|
||||
|
||||
#ifdef PNG_READ_iCCP_SUPPORTED
|
||||
PNG_INTERNAL_FUNCTION(void,png_handle_iCCP,(png_structrp png_ptr,
|
||||
png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);
|
||||
#endif /* READ_iCCP */
|
||||
|
||||
#ifdef PNG_READ_iTXt_SUPPORTED
|
||||
PNG_INTERNAL_FUNCTION(void,png_handle_iTXt,(png_structrp png_ptr,
|
||||
png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);
|
||||
#endif
|
||||
|
||||
#ifdef PNG_READ_oFFs_SUPPORTED
|
||||
PNG_INTERNAL_FUNCTION(void,png_handle_oFFs,(png_structrp png_ptr,
|
||||
png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);
|
||||
#endif
|
||||
|
||||
#ifdef PNG_READ_pCAL_SUPPORTED
|
||||
PNG_INTERNAL_FUNCTION(void,png_handle_pCAL,(png_structrp png_ptr,
|
||||
png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);
|
||||
#endif
|
||||
|
||||
#ifdef PNG_READ_pHYs_SUPPORTED
|
||||
PNG_INTERNAL_FUNCTION(void,png_handle_pHYs,(png_structrp png_ptr,
|
||||
png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);
|
||||
#endif
|
||||
|
||||
#ifdef PNG_READ_sBIT_SUPPORTED
|
||||
PNG_INTERNAL_FUNCTION(void,png_handle_sBIT,(png_structrp png_ptr,
|
||||
png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);
|
||||
#endif
|
||||
|
||||
#ifdef PNG_READ_sCAL_SUPPORTED
|
||||
PNG_INTERNAL_FUNCTION(void,png_handle_sCAL,(png_structrp png_ptr,
|
||||
png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);
|
||||
#endif
|
||||
|
||||
#ifdef PNG_READ_sPLT_SUPPORTED
|
||||
PNG_INTERNAL_FUNCTION(void,png_handle_sPLT,(png_structrp png_ptr,
|
||||
png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);
|
||||
#endif /* READ_sPLT */
|
||||
|
||||
#ifdef PNG_READ_sRGB_SUPPORTED
|
||||
PNG_INTERNAL_FUNCTION(void,png_handle_sRGB,(png_structrp png_ptr,
|
||||
png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);
|
||||
#endif
|
||||
|
||||
#ifdef PNG_READ_tEXt_SUPPORTED
|
||||
PNG_INTERNAL_FUNCTION(void,png_handle_tEXt,(png_structrp png_ptr,
|
||||
png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);
|
||||
#endif
|
||||
|
||||
#ifdef PNG_READ_tIME_SUPPORTED
|
||||
PNG_INTERNAL_FUNCTION(void,png_handle_tIME,(png_structrp png_ptr,
|
||||
png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);
|
||||
#endif
|
||||
|
||||
#ifdef PNG_READ_tRNS_SUPPORTED
|
||||
PNG_INTERNAL_FUNCTION(void,png_handle_tRNS,(png_structrp png_ptr,
|
||||
png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);
|
||||
#endif
|
||||
|
||||
#ifdef PNG_READ_zTXt_SUPPORTED
|
||||
PNG_INTERNAL_FUNCTION(void,png_handle_zTXt,(png_structrp png_ptr,
|
||||
png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);
|
||||
#endif
|
||||
|
||||
PNG_INTERNAL_FUNCTION(void,png_check_chunk_name,(png_const_structrp png_ptr,
|
||||
png_uint_32 chunk_name),PNG_EMPTY);
|
||||
|
||||
PNG_INTERNAL_FUNCTION(void,png_check_chunk_length,(png_const_structrp png_ptr,
|
||||
png_uint_32 chunk_length),PNG_EMPTY);
|
||||
|
||||
PNG_INTERNAL_FUNCTION(void,png_handle_unknown,(png_structrp png_ptr,
|
||||
png_inforp info_ptr, png_uint_32 length, int keep),PNG_EMPTY);
|
||||
PNG_INTERNAL_FUNCTION(png_handle_result_code,png_handle_unknown,
|
||||
(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length, int keep),
|
||||
PNG_EMPTY);
|
||||
/* This is the function that gets called for unknown chunks. The 'keep'
|
||||
* argument is either non-zero for a known chunk that has been set to be
|
||||
* handled as unknown or zero for an unknown chunk. By default the function
|
||||
* just skips the chunk or errors out if it is critical.
|
||||
*/
|
||||
|
||||
PNG_INTERNAL_FUNCTION(png_handle_result_code,png_handle_chunk,
|
||||
(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);
|
||||
/* This handles the current chunk png_ptr->chunk_name with unread
|
||||
* data[length] and returns one of the above result codes.
|
||||
*/
|
||||
|
||||
#if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) ||\
|
||||
defined(PNG_HANDLE_AS_UNKNOWN_SUPPORTED)
|
||||
PNG_INTERNAL_FUNCTION(int,png_chunk_unknown_handling,
|
||||
@@ -1618,8 +1705,6 @@ PNG_INTERNAL_FUNCTION(void,png_process_IDAT_data,(png_structrp png_ptr,
|
||||
png_bytep buffer, size_t buffer_length),PNG_EMPTY);
|
||||
PNG_INTERNAL_FUNCTION(void,png_push_process_row,(png_structrp png_ptr),
|
||||
PNG_EMPTY);
|
||||
PNG_INTERNAL_FUNCTION(void,png_push_handle_unknown,(png_structrp png_ptr,
|
||||
png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);
|
||||
PNG_INTERNAL_FUNCTION(void,png_push_have_info,(png_structrp png_ptr,
|
||||
png_inforp info_ptr),PNG_EMPTY);
|
||||
PNG_INTERNAL_FUNCTION(void,png_push_have_end,(png_structrp png_ptr,
|
||||
@@ -1632,109 +1717,28 @@ PNG_INTERNAL_FUNCTION(void,png_process_some_data,(png_structrp png_ptr,
|
||||
png_inforp info_ptr),PNG_EMPTY);
|
||||
PNG_INTERNAL_FUNCTION(void,png_read_push_finish_row,(png_structrp png_ptr),
|
||||
PNG_EMPTY);
|
||||
# ifdef PNG_READ_tEXt_SUPPORTED
|
||||
PNG_INTERNAL_FUNCTION(void,png_push_handle_tEXt,(png_structrp png_ptr,
|
||||
png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);
|
||||
PNG_INTERNAL_FUNCTION(void,png_push_read_tEXt,(png_structrp png_ptr,
|
||||
png_inforp info_ptr),PNG_EMPTY);
|
||||
# endif
|
||||
# ifdef PNG_READ_zTXt_SUPPORTED
|
||||
PNG_INTERNAL_FUNCTION(void,png_push_handle_zTXt,(png_structrp png_ptr,
|
||||
png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);
|
||||
PNG_INTERNAL_FUNCTION(void,png_push_read_zTXt,(png_structrp png_ptr,
|
||||
png_inforp info_ptr),PNG_EMPTY);
|
||||
# endif
|
||||
# ifdef PNG_READ_iTXt_SUPPORTED
|
||||
PNG_INTERNAL_FUNCTION(void,png_push_handle_iTXt,(png_structrp png_ptr,
|
||||
png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);
|
||||
PNG_INTERNAL_FUNCTION(void,png_push_read_iTXt,(png_structrp png_ptr,
|
||||
png_inforp info_ptr),PNG_EMPTY);
|
||||
# endif
|
||||
|
||||
#endif /* PROGRESSIVE_READ */
|
||||
|
||||
/* Added at libpng version 1.6.0 */
|
||||
#ifdef PNG_GAMMA_SUPPORTED
|
||||
PNG_INTERNAL_FUNCTION(void,png_colorspace_set_gamma,(png_const_structrp png_ptr,
|
||||
png_colorspacerp colorspace, png_fixed_point gAMA), PNG_EMPTY);
|
||||
/* Set the colorspace gamma with a value provided by the application or by
|
||||
* the gAMA chunk on read. The value will override anything set by an ICC
|
||||
* profile.
|
||||
*/
|
||||
|
||||
PNG_INTERNAL_FUNCTION(void,png_colorspace_sync_info,(png_const_structrp png_ptr,
|
||||
png_inforp info_ptr), PNG_EMPTY);
|
||||
/* Synchronize the info 'valid' flags with the colorspace */
|
||||
|
||||
PNG_INTERNAL_FUNCTION(void,png_colorspace_sync,(png_const_structrp png_ptr,
|
||||
png_inforp info_ptr), PNG_EMPTY);
|
||||
/* Copy the png_struct colorspace to the info_struct and call the above to
|
||||
* synchronize the flags. Checks for NULL info_ptr and does nothing.
|
||||
*/
|
||||
#endif
|
||||
|
||||
/* Added at libpng version 1.4.0 */
|
||||
#ifdef PNG_COLORSPACE_SUPPORTED
|
||||
/* These internal functions are for maintaining the colorspace structure within
|
||||
* a png_info or png_struct (or, indeed, both).
|
||||
*/
|
||||
PNG_INTERNAL_FUNCTION(int,png_colorspace_set_chromaticities,
|
||||
(png_const_structrp png_ptr, png_colorspacerp colorspace, const png_xy *xy,
|
||||
int preferred), PNG_EMPTY);
|
||||
|
||||
PNG_INTERNAL_FUNCTION(int,png_colorspace_set_endpoints,
|
||||
(png_const_structrp png_ptr, png_colorspacerp colorspace, const png_XYZ *XYZ,
|
||||
int preferred), PNG_EMPTY);
|
||||
|
||||
#ifdef PNG_sRGB_SUPPORTED
|
||||
PNG_INTERNAL_FUNCTION(int,png_colorspace_set_sRGB,(png_const_structrp png_ptr,
|
||||
png_colorspacerp colorspace, int intent), PNG_EMPTY);
|
||||
/* This does set the colorspace gAMA and cHRM values too, but doesn't set the
|
||||
* flags to write them, if it returns false there was a problem and an error
|
||||
* message has already been output (but the colorspace may still need to be
|
||||
* synced to record the invalid flag).
|
||||
*/
|
||||
#endif /* sRGB */
|
||||
|
||||
#ifdef PNG_iCCP_SUPPORTED
|
||||
PNG_INTERNAL_FUNCTION(int,png_colorspace_set_ICC,(png_const_structrp png_ptr,
|
||||
png_colorspacerp colorspace, png_const_charp name,
|
||||
png_uint_32 profile_length, png_const_bytep profile, int color_type),
|
||||
PNG_EMPTY);
|
||||
/* The 'name' is used for information only */
|
||||
|
||||
/* Routines for checking parts of an ICC profile. */
|
||||
#ifdef PNG_READ_iCCP_SUPPORTED
|
||||
PNG_INTERNAL_FUNCTION(int,png_icc_check_length,(png_const_structrp png_ptr,
|
||||
png_colorspacerp colorspace, png_const_charp name,
|
||||
png_uint_32 profile_length), PNG_EMPTY);
|
||||
png_const_charp name, png_uint_32 profile_length), PNG_EMPTY);
|
||||
#endif /* READ_iCCP */
|
||||
PNG_INTERNAL_FUNCTION(int,png_icc_check_header,(png_const_structrp png_ptr,
|
||||
png_colorspacerp colorspace, png_const_charp name,
|
||||
png_uint_32 profile_length,
|
||||
png_const_charp name, png_uint_32 profile_length,
|
||||
png_const_bytep profile /* first 132 bytes only */, int color_type),
|
||||
PNG_EMPTY);
|
||||
PNG_INTERNAL_FUNCTION(int,png_icc_check_tag_table,(png_const_structrp png_ptr,
|
||||
png_colorspacerp colorspace, png_const_charp name,
|
||||
png_uint_32 profile_length,
|
||||
png_const_charp name, png_uint_32 profile_length,
|
||||
png_const_bytep profile /* header plus whole tag table */), PNG_EMPTY);
|
||||
#ifdef PNG_sRGB_SUPPORTED
|
||||
PNG_INTERNAL_FUNCTION(void,png_icc_set_sRGB,(
|
||||
png_const_structrp png_ptr, png_colorspacerp colorspace,
|
||||
png_const_bytep profile, uLong adler), PNG_EMPTY);
|
||||
/* 'adler' is the Adler32 checksum of the uncompressed profile data. It may
|
||||
* be zero to indicate that it is not available. It is used, if provided,
|
||||
* as a fast check on the profile when checking to see if it is sRGB.
|
||||
*/
|
||||
#endif
|
||||
#endif /* iCCP */
|
||||
|
||||
#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
|
||||
PNG_INTERNAL_FUNCTION(void,png_colorspace_set_rgb_coefficients,
|
||||
(png_structrp png_ptr), PNG_EMPTY);
|
||||
/* Set the rgb_to_gray coefficients from the colorspace Y values */
|
||||
PNG_INTERNAL_FUNCTION(void,png_set_rgb_coefficients, (png_structrp png_ptr),
|
||||
PNG_EMPTY);
|
||||
/* Set the rgb_to_gray coefficients from the cHRM Y values (if unset) */
|
||||
#endif /* READ_RGB_TO_GRAY */
|
||||
#endif /* COLORSPACE */
|
||||
|
||||
/* Added at libpng version 1.4.0 */
|
||||
PNG_INTERNAL_FUNCTION(void,png_check_IHDR,(png_const_structrp png_ptr,
|
||||
@@ -1996,8 +2000,10 @@ PNG_INTERNAL_FUNCTION(int,png_check_fp_string,(png_const_charp string,
|
||||
size_t size),PNG_EMPTY);
|
||||
#endif /* pCAL || sCAL */
|
||||
|
||||
#if defined(PNG_GAMMA_SUPPORTED) ||\
|
||||
defined(PNG_INCH_CONVERSIONS_SUPPORTED) || defined(PNG_READ_pHYs_SUPPORTED)
|
||||
#if defined(PNG_READ_GAMMA_SUPPORTED) ||\
|
||||
defined(PNG_COLORSPACE_SUPPORTED) ||\
|
||||
defined(PNG_INCH_CONVERSIONS_SUPPORTED) ||\
|
||||
defined(PNG_READ_pHYs_SUPPORTED)
|
||||
/* Added at libpng version 1.5.0 */
|
||||
/* This is a utility to provide a*times/div (rounded) and indicate
|
||||
* if there is an overflow. The result is a boolean - false (0)
|
||||
@@ -2006,22 +2012,14 @@ PNG_INTERNAL_FUNCTION(int,png_check_fp_string,(png_const_charp string,
|
||||
*/
|
||||
PNG_INTERNAL_FUNCTION(int,png_muldiv,(png_fixed_point_p res, png_fixed_point a,
|
||||
png_int_32 multiplied_by, png_int_32 divided_by),PNG_EMPTY);
|
||||
#endif
|
||||
|
||||
#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_INCH_CONVERSIONS_SUPPORTED)
|
||||
/* Same deal, but issue a warning on overflow and return 0. */
|
||||
PNG_INTERNAL_FUNCTION(png_fixed_point,png_muldiv_warn,
|
||||
(png_const_structrp png_ptr, png_fixed_point a, png_int_32 multiplied_by,
|
||||
png_int_32 divided_by),PNG_EMPTY);
|
||||
#endif
|
||||
|
||||
#ifdef PNG_GAMMA_SUPPORTED
|
||||
/* Calculate a reciprocal - used for gamma values. This returns
|
||||
* 0 if the argument is 0 in order to maintain an undefined value;
|
||||
* there are no warnings.
|
||||
*/
|
||||
PNG_INTERNAL_FUNCTION(png_fixed_point,png_reciprocal,(png_fixed_point a),
|
||||
PNG_EMPTY);
|
||||
#endif
|
||||
|
||||
#ifdef PNG_READ_GAMMA_SUPPORTED
|
||||
/* The same but gives a reciprocal of the product of two fixed point
|
||||
@@ -2030,14 +2028,22 @@ PNG_INTERNAL_FUNCTION(png_fixed_point,png_reciprocal,(png_fixed_point a),
|
||||
*/
|
||||
PNG_INTERNAL_FUNCTION(png_fixed_point,png_reciprocal2,(png_fixed_point a,
|
||||
png_fixed_point b),PNG_EMPTY);
|
||||
#endif
|
||||
|
||||
/* Return true if the gamma value is significantly different from 1.0 */
|
||||
PNG_INTERNAL_FUNCTION(int,png_gamma_significant,(png_fixed_point gamma_value),
|
||||
PNG_EMPTY);
|
||||
#endif
|
||||
|
||||
#ifdef PNG_READ_GAMMA_SUPPORTED
|
||||
/* PNGv3: 'resolve' the file gamma according to the new PNGv3 rules for colour
|
||||
* space information.
|
||||
*
|
||||
* NOTE: this uses precisely those chunks that libpng supports. For example it
|
||||
* doesn't use iCCP and it can only use cICP for known and manageable
|
||||
* transforms. For this reason a gamma specified by png_set_gamma always takes
|
||||
* precedence.
|
||||
*/
|
||||
PNG_INTERNAL_FUNCTION(png_fixed_point,png_resolve_file_gamma,
|
||||
(png_const_structrp png_ptr),PNG_EMPTY);
|
||||
|
||||
/* Internal fixed point gamma correction. These APIs are called as
|
||||
* required to convert single values - they don't need to be fast,
|
||||
* they are not used when processing image pixel values.
|
||||
@@ -2055,6 +2061,22 @@ PNG_INTERNAL_FUNCTION(void,png_destroy_gamma_table,(png_structrp png_ptr),
|
||||
PNG_EMPTY);
|
||||
PNG_INTERNAL_FUNCTION(void,png_build_gamma_table,(png_structrp png_ptr,
|
||||
int bit_depth),PNG_EMPTY);
|
||||
#endif /* READ_GAMMA */
|
||||
|
||||
#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
|
||||
/* Set the RGB coefficients if not already set by png_set_rgb_to_gray */
|
||||
PNG_INTERNAL_FUNCTION(void,png_set_rgb_coefficients,(png_structrp png_ptr),
|
||||
PNG_EMPTY);
|
||||
#endif
|
||||
|
||||
#if defined(PNG_cHRM_SUPPORTED) || defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
|
||||
PNG_INTERNAL_FUNCTION(int,png_XYZ_from_xy,(png_XYZ *XYZ, const png_xy *xy),
|
||||
PNG_EMPTY);
|
||||
#endif /* cHRM || READ_RGB_TO_GRAY */
|
||||
|
||||
#ifdef PNG_COLORSPACE_SUPPORTED
|
||||
PNG_INTERNAL_FUNCTION(int,png_xy_from_XYZ,(png_xy *xy, const png_XYZ *XYZ),
|
||||
PNG_EMPTY);
|
||||
#endif
|
||||
|
||||
/* SIMPLIFIED READ/WRITE SUPPORT */
|
||||
@@ -2153,6 +2175,11 @@ PNG_INTERNAL_FUNCTION(void, png_init_filter_functions_lsx,
|
||||
(png_structp png_ptr, unsigned int bpp), PNG_EMPTY);
|
||||
#endif
|
||||
|
||||
# if PNG_RISCV_RVV_IMPLEMENTATION == 1
|
||||
PNG_INTERNAL_FUNCTION(void, png_init_filter_functions_rvv,
|
||||
(png_structp png_ptr, unsigned int bpp), PNG_EMPTY);
|
||||
#endif
|
||||
|
||||
PNG_INTERNAL_FUNCTION(png_uint_32, png_check_keyword, (png_structrp png_ptr,
|
||||
png_const_charp key, png_bytep new_key), PNG_EMPTY);
|
||||
|
||||
@@ -2188,4 +2215,3 @@ PNG_INTERNAL_FUNCTION(int,
|
||||
#endif
|
||||
|
||||
#endif /* PNG_VERSION_INFO_ONLY */
|
||||
#endif /* PNGPRIV_H */
|
||||
|
||||
Vendored
+191
-255
@@ -131,14 +131,11 @@ png_read_info(png_structrp png_ptr, png_inforp info_ptr)
|
||||
png_ptr->mode |= PNG_AFTER_IDAT;
|
||||
}
|
||||
|
||||
/* This should be a binary subdivision search or a hash for
|
||||
* matching the chunk name rather than a linear search.
|
||||
*/
|
||||
if (chunk_name == png_IHDR)
|
||||
png_handle_IHDR(png_ptr, info_ptr, length);
|
||||
png_handle_chunk(png_ptr, info_ptr, length);
|
||||
|
||||
else if (chunk_name == png_IEND)
|
||||
png_handle_IEND(png_ptr, info_ptr, length);
|
||||
png_handle_chunk(png_ptr, info_ptr, length);
|
||||
|
||||
#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
|
||||
else if ((keep = png_chunk_unknown_handling(png_ptr, chunk_name)) != 0)
|
||||
@@ -155,8 +152,6 @@ png_read_info(png_structrp png_ptr, png_inforp info_ptr)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
else if (chunk_name == png_PLTE)
|
||||
png_handle_PLTE(png_ptr, info_ptr, length);
|
||||
|
||||
else if (chunk_name == png_IDAT)
|
||||
{
|
||||
@@ -164,104 +159,8 @@ png_read_info(png_structrp png_ptr, png_inforp info_ptr)
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef PNG_READ_bKGD_SUPPORTED
|
||||
else if (chunk_name == png_bKGD)
|
||||
png_handle_bKGD(png_ptr, info_ptr, length);
|
||||
#endif
|
||||
|
||||
#ifdef PNG_READ_cHRM_SUPPORTED
|
||||
else if (chunk_name == png_cHRM)
|
||||
png_handle_cHRM(png_ptr, info_ptr, length);
|
||||
#endif
|
||||
|
||||
#ifdef PNG_READ_cICP_SUPPORTED
|
||||
else if (chunk_name == png_cICP)
|
||||
png_handle_cICP(png_ptr, info_ptr, length);
|
||||
#endif
|
||||
|
||||
#ifdef PNG_READ_eXIf_SUPPORTED
|
||||
else if (chunk_name == png_eXIf)
|
||||
png_handle_eXIf(png_ptr, info_ptr, length);
|
||||
#endif
|
||||
|
||||
#ifdef PNG_READ_gAMA_SUPPORTED
|
||||
else if (chunk_name == png_gAMA)
|
||||
png_handle_gAMA(png_ptr, info_ptr, length);
|
||||
#endif
|
||||
|
||||
#ifdef PNG_READ_hIST_SUPPORTED
|
||||
else if (chunk_name == png_hIST)
|
||||
png_handle_hIST(png_ptr, info_ptr, length);
|
||||
#endif
|
||||
|
||||
#ifdef PNG_READ_oFFs_SUPPORTED
|
||||
else if (chunk_name == png_oFFs)
|
||||
png_handle_oFFs(png_ptr, info_ptr, length);
|
||||
#endif
|
||||
|
||||
#ifdef PNG_READ_pCAL_SUPPORTED
|
||||
else if (chunk_name == png_pCAL)
|
||||
png_handle_pCAL(png_ptr, info_ptr, length);
|
||||
#endif
|
||||
|
||||
#ifdef PNG_READ_sCAL_SUPPORTED
|
||||
else if (chunk_name == png_sCAL)
|
||||
png_handle_sCAL(png_ptr, info_ptr, length);
|
||||
#endif
|
||||
|
||||
#ifdef PNG_READ_pHYs_SUPPORTED
|
||||
else if (chunk_name == png_pHYs)
|
||||
png_handle_pHYs(png_ptr, info_ptr, length);
|
||||
#endif
|
||||
|
||||
#ifdef PNG_READ_sBIT_SUPPORTED
|
||||
else if (chunk_name == png_sBIT)
|
||||
png_handle_sBIT(png_ptr, info_ptr, length);
|
||||
#endif
|
||||
|
||||
#ifdef PNG_READ_sRGB_SUPPORTED
|
||||
else if (chunk_name == png_sRGB)
|
||||
png_handle_sRGB(png_ptr, info_ptr, length);
|
||||
#endif
|
||||
|
||||
#ifdef PNG_READ_iCCP_SUPPORTED
|
||||
else if (chunk_name == png_iCCP)
|
||||
png_handle_iCCP(png_ptr, info_ptr, length);
|
||||
#endif
|
||||
|
||||
#ifdef PNG_READ_sPLT_SUPPORTED
|
||||
else if (chunk_name == png_sPLT)
|
||||
png_handle_sPLT(png_ptr, info_ptr, length);
|
||||
#endif
|
||||
|
||||
#ifdef PNG_READ_tEXt_SUPPORTED
|
||||
else if (chunk_name == png_tEXt)
|
||||
png_handle_tEXt(png_ptr, info_ptr, length);
|
||||
#endif
|
||||
|
||||
#ifdef PNG_READ_tIME_SUPPORTED
|
||||
else if (chunk_name == png_tIME)
|
||||
png_handle_tIME(png_ptr, info_ptr, length);
|
||||
#endif
|
||||
|
||||
#ifdef PNG_READ_tRNS_SUPPORTED
|
||||
else if (chunk_name == png_tRNS)
|
||||
png_handle_tRNS(png_ptr, info_ptr, length);
|
||||
#endif
|
||||
|
||||
#ifdef PNG_READ_zTXt_SUPPORTED
|
||||
else if (chunk_name == png_zTXt)
|
||||
png_handle_zTXt(png_ptr, info_ptr, length);
|
||||
#endif
|
||||
|
||||
#ifdef PNG_READ_iTXt_SUPPORTED
|
||||
else if (chunk_name == png_iTXt)
|
||||
png_handle_iTXt(png_ptr, info_ptr, length);
|
||||
#endif
|
||||
|
||||
else
|
||||
png_handle_unknown(png_ptr, info_ptr, length,
|
||||
PNG_HANDLE_CHUNK_AS_DEFAULT);
|
||||
png_handle_chunk(png_ptr, info_ptr, length);
|
||||
}
|
||||
}
|
||||
#endif /* SEQUENTIAL_READ */
|
||||
@@ -803,13 +702,18 @@ png_read_end(png_structrp png_ptr, png_inforp info_ptr)
|
||||
png_uint_32 chunk_name = png_ptr->chunk_name;
|
||||
|
||||
if (chunk_name != png_IDAT)
|
||||
png_ptr->mode |= PNG_HAVE_CHUNK_AFTER_IDAT;
|
||||
{
|
||||
/* These flags must be set consistently for all non-IDAT chunks,
|
||||
* including the unknown chunks.
|
||||
*/
|
||||
png_ptr->mode |= PNG_HAVE_CHUNK_AFTER_IDAT | PNG_AFTER_IDAT;
|
||||
}
|
||||
|
||||
if (chunk_name == png_IEND)
|
||||
png_handle_IEND(png_ptr, info_ptr, length);
|
||||
png_handle_chunk(png_ptr, info_ptr, length);
|
||||
|
||||
else if (chunk_name == png_IHDR)
|
||||
png_handle_IHDR(png_ptr, info_ptr, length);
|
||||
png_handle_chunk(png_ptr, info_ptr, length);
|
||||
|
||||
else if (info_ptr == NULL)
|
||||
png_crc_finish(png_ptr, length);
|
||||
@@ -843,107 +747,9 @@ png_read_end(png_structrp png_ptr, png_inforp info_ptr)
|
||||
|
||||
png_crc_finish(png_ptr, length);
|
||||
}
|
||||
else if (chunk_name == png_PLTE)
|
||||
png_handle_PLTE(png_ptr, info_ptr, length);
|
||||
|
||||
#ifdef PNG_READ_bKGD_SUPPORTED
|
||||
else if (chunk_name == png_bKGD)
|
||||
png_handle_bKGD(png_ptr, info_ptr, length);
|
||||
#endif
|
||||
|
||||
#ifdef PNG_READ_cHRM_SUPPORTED
|
||||
else if (chunk_name == png_cHRM)
|
||||
png_handle_cHRM(png_ptr, info_ptr, length);
|
||||
#endif
|
||||
|
||||
#ifdef PNG_READ_cICP_SUPPORTED
|
||||
else if (chunk_name == png_cICP)
|
||||
png_handle_cICP(png_ptr, info_ptr, length);
|
||||
#endif
|
||||
|
||||
#ifdef PNG_READ_eXIf_SUPPORTED
|
||||
else if (chunk_name == png_eXIf)
|
||||
png_handle_eXIf(png_ptr, info_ptr, length);
|
||||
#endif
|
||||
|
||||
#ifdef PNG_READ_gAMA_SUPPORTED
|
||||
else if (chunk_name == png_gAMA)
|
||||
png_handle_gAMA(png_ptr, info_ptr, length);
|
||||
#endif
|
||||
|
||||
#ifdef PNG_READ_hIST_SUPPORTED
|
||||
else if (chunk_name == png_hIST)
|
||||
png_handle_hIST(png_ptr, info_ptr, length);
|
||||
#endif
|
||||
|
||||
#ifdef PNG_READ_oFFs_SUPPORTED
|
||||
else if (chunk_name == png_oFFs)
|
||||
png_handle_oFFs(png_ptr, info_ptr, length);
|
||||
#endif
|
||||
|
||||
#ifdef PNG_READ_pCAL_SUPPORTED
|
||||
else if (chunk_name == png_pCAL)
|
||||
png_handle_pCAL(png_ptr, info_ptr, length);
|
||||
#endif
|
||||
|
||||
#ifdef PNG_READ_sCAL_SUPPORTED
|
||||
else if (chunk_name == png_sCAL)
|
||||
png_handle_sCAL(png_ptr, info_ptr, length);
|
||||
#endif
|
||||
|
||||
#ifdef PNG_READ_pHYs_SUPPORTED
|
||||
else if (chunk_name == png_pHYs)
|
||||
png_handle_pHYs(png_ptr, info_ptr, length);
|
||||
#endif
|
||||
|
||||
#ifdef PNG_READ_sBIT_SUPPORTED
|
||||
else if (chunk_name == png_sBIT)
|
||||
png_handle_sBIT(png_ptr, info_ptr, length);
|
||||
#endif
|
||||
|
||||
#ifdef PNG_READ_sRGB_SUPPORTED
|
||||
else if (chunk_name == png_sRGB)
|
||||
png_handle_sRGB(png_ptr, info_ptr, length);
|
||||
#endif
|
||||
|
||||
#ifdef PNG_READ_iCCP_SUPPORTED
|
||||
else if (chunk_name == png_iCCP)
|
||||
png_handle_iCCP(png_ptr, info_ptr, length);
|
||||
#endif
|
||||
|
||||
#ifdef PNG_READ_sPLT_SUPPORTED
|
||||
else if (chunk_name == png_sPLT)
|
||||
png_handle_sPLT(png_ptr, info_ptr, length);
|
||||
#endif
|
||||
|
||||
#ifdef PNG_READ_tEXt_SUPPORTED
|
||||
else if (chunk_name == png_tEXt)
|
||||
png_handle_tEXt(png_ptr, info_ptr, length);
|
||||
#endif
|
||||
|
||||
#ifdef PNG_READ_tIME_SUPPORTED
|
||||
else if (chunk_name == png_tIME)
|
||||
png_handle_tIME(png_ptr, info_ptr, length);
|
||||
#endif
|
||||
|
||||
#ifdef PNG_READ_tRNS_SUPPORTED
|
||||
else if (chunk_name == png_tRNS)
|
||||
png_handle_tRNS(png_ptr, info_ptr, length);
|
||||
#endif
|
||||
|
||||
#ifdef PNG_READ_zTXt_SUPPORTED
|
||||
else if (chunk_name == png_zTXt)
|
||||
png_handle_zTXt(png_ptr, info_ptr, length);
|
||||
#endif
|
||||
|
||||
#ifdef PNG_READ_iTXt_SUPPORTED
|
||||
else if (chunk_name == png_iTXt)
|
||||
png_handle_iTXt(png_ptr, info_ptr, length);
|
||||
#endif
|
||||
|
||||
else
|
||||
png_handle_unknown(png_ptr, info_ptr, length,
|
||||
PNG_HANDLE_CHUNK_AS_DEFAULT);
|
||||
png_handle_chunk(png_ptr, info_ptr, length);
|
||||
} while ((png_ptr->mode & PNG_HAVE_IEND) == 0);
|
||||
}
|
||||
#endif /* SEQUENTIAL_READ */
|
||||
@@ -1008,7 +814,8 @@ png_read_destroy(png_structrp png_ptr)
|
||||
#endif
|
||||
|
||||
#if defined(PNG_READ_EXPAND_SUPPORTED) && \
|
||||
defined(PNG_ARM_NEON_IMPLEMENTATION)
|
||||
(defined(PNG_ARM_NEON_IMPLEMENTATION) || \
|
||||
defined(PNG_RISCV_RVV_IMPLEMENTATION))
|
||||
png_free(png_ptr, png_ptr->riffled_palette);
|
||||
png_ptr->riffled_palette = NULL;
|
||||
#endif
|
||||
@@ -1394,6 +1201,31 @@ png_image_format(png_structrp png_ptr)
|
||||
return format;
|
||||
}
|
||||
|
||||
static int
|
||||
chromaticities_match_sRGB(const png_xy *xy)
|
||||
{
|
||||
# define sRGB_TOLERANCE 1000
|
||||
static const png_xy sRGB_xy = /* From ITU-R BT.709-3 */
|
||||
{
|
||||
/* color x y */
|
||||
/* red */ 64000, 33000,
|
||||
/* green */ 30000, 60000,
|
||||
/* blue */ 15000, 6000,
|
||||
/* white */ 31270, 32900
|
||||
};
|
||||
|
||||
if (PNG_OUT_OF_RANGE(xy->whitex, sRGB_xy.whitex,sRGB_TOLERANCE) ||
|
||||
PNG_OUT_OF_RANGE(xy->whitey, sRGB_xy.whitey,sRGB_TOLERANCE) ||
|
||||
PNG_OUT_OF_RANGE(xy->redx, sRGB_xy.redx, sRGB_TOLERANCE) ||
|
||||
PNG_OUT_OF_RANGE(xy->redy, sRGB_xy.redy, sRGB_TOLERANCE) ||
|
||||
PNG_OUT_OF_RANGE(xy->greenx, sRGB_xy.greenx,sRGB_TOLERANCE) ||
|
||||
PNG_OUT_OF_RANGE(xy->greeny, sRGB_xy.greeny,sRGB_TOLERANCE) ||
|
||||
PNG_OUT_OF_RANGE(xy->bluex, sRGB_xy.bluex, sRGB_TOLERANCE) ||
|
||||
PNG_OUT_OF_RANGE(xy->bluey, sRGB_xy.bluey, sRGB_TOLERANCE))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Is the given gamma significantly different from sRGB? The test is the same
|
||||
* one used in pngrtran.c when deciding whether to do gamma correction. The
|
||||
* arithmetic optimizes the division by using the fact that the inverse of the
|
||||
@@ -1402,22 +1234,44 @@ png_image_format(png_structrp png_ptr)
|
||||
static int
|
||||
png_gamma_not_sRGB(png_fixed_point g)
|
||||
{
|
||||
if (g < PNG_FP_1)
|
||||
{
|
||||
/* An uninitialized gamma is assumed to be sRGB for the simplified API. */
|
||||
if (g == 0)
|
||||
return 0;
|
||||
/* 1.6.47: use the same sanity checks as used in pngrtran.c */
|
||||
if (g < PNG_LIB_GAMMA_MIN || g > PNG_LIB_GAMMA_MAX)
|
||||
return 0; /* Includes the uninitialized value 0 */
|
||||
|
||||
return png_gamma_significant((g * 11 + 2)/5 /* i.e. *2.2, rounded */);
|
||||
}
|
||||
|
||||
return 1;
|
||||
return png_gamma_significant((g * 11 + 2)/5 /* i.e. *2.2, rounded */);
|
||||
}
|
||||
|
||||
/* Do the main body of a 'png_image_begin_read' function; read the PNG file
|
||||
* header and fill in all the information. This is executed in a safe context,
|
||||
* unlike the init routine above.
|
||||
*/
|
||||
static int
|
||||
png_image_is_not_sRGB(png_const_structrp png_ptr)
|
||||
{
|
||||
/* Does the colorspace **not** match sRGB? The flag is only set if the
|
||||
* answer can be determined reliably.
|
||||
*
|
||||
* png_struct::chromaticities always exists since the simplified API
|
||||
* requires rgb-to-gray. The mDCV, cICP and cHRM chunks may all set it to
|
||||
* a non-sRGB value, so it needs to be checked but **only** if one of
|
||||
* those chunks occured in the file.
|
||||
*/
|
||||
/* Highest priority: check to be safe. */
|
||||
if (png_has_chunk(png_ptr, cICP) || png_has_chunk(png_ptr, mDCV))
|
||||
return !chromaticities_match_sRGB(&png_ptr->chromaticities);
|
||||
|
||||
/* If the image is marked as sRGB then it is... */
|
||||
if (png_has_chunk(png_ptr, sRGB))
|
||||
return 0;
|
||||
|
||||
/* Last stop: cHRM, must check: */
|
||||
if (png_has_chunk(png_ptr, cHRM))
|
||||
return !chromaticities_match_sRGB(&png_ptr->chromaticities);
|
||||
|
||||
/* Else default to sRGB */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
png_image_read_header(png_voidp argument)
|
||||
{
|
||||
@@ -1439,17 +1293,13 @@ png_image_read_header(png_voidp argument)
|
||||
|
||||
image->format = format;
|
||||
|
||||
#ifdef PNG_COLORSPACE_SUPPORTED
|
||||
/* Does the colorspace match sRGB? If there is no color endpoint
|
||||
* (colorant) information assume yes, otherwise require the
|
||||
* 'ENDPOINTS_MATCHP_sRGB' colorspace flag to have been set. If the
|
||||
* colorspace has been determined to be invalid ignore it.
|
||||
/* Greyscale images don't (typically) have colour space information and
|
||||
* using it is pretty much impossible, so use sRGB for grayscale (it
|
||||
* doesn't matter r==g==b so the transform is irrelevant.)
|
||||
*/
|
||||
if ((format & PNG_FORMAT_FLAG_COLOR) != 0 && ((png_ptr->colorspace.flags
|
||||
& (PNG_COLORSPACE_HAVE_ENDPOINTS|PNG_COLORSPACE_ENDPOINTS_MATCH_sRGB|
|
||||
PNG_COLORSPACE_INVALID)) == PNG_COLORSPACE_HAVE_ENDPOINTS))
|
||||
if ((format & PNG_FORMAT_FLAG_COLOR) != 0 &&
|
||||
png_image_is_not_sRGB(png_ptr))
|
||||
image->flags |= PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* We need the maximum number of entries regardless of the format the
|
||||
@@ -1484,7 +1334,7 @@ png_image_read_header(png_voidp argument)
|
||||
|
||||
#ifdef PNG_STDIO_SUPPORTED
|
||||
int PNGAPI
|
||||
png_image_begin_read_from_stdio(png_imagep image, FILE* file)
|
||||
png_image_begin_read_from_stdio(png_imagep image, FILE *file)
|
||||
{
|
||||
if (image != NULL && image->version == PNG_IMAGE_VERSION)
|
||||
{
|
||||
@@ -1637,21 +1487,18 @@ png_image_skip_unused_chunks(png_structrp png_ptr)
|
||||
* potential vulnerability to security problems in the unused chunks.
|
||||
*
|
||||
* At present the iCCP chunk data isn't used, so iCCP chunk can be ignored
|
||||
* too. This allows the simplified API to be compiled without iCCP support,
|
||||
* however if the support is there the chunk is still checked to detect
|
||||
* errors (which are unfortunately quite common.)
|
||||
* too. This allows the simplified API to be compiled without iCCP support.
|
||||
*/
|
||||
{
|
||||
static const png_byte chunks_to_process[] = {
|
||||
98, 75, 71, 68, '\0', /* bKGD */
|
||||
99, 72, 82, 77, '\0', /* cHRM */
|
||||
99, 73, 67, 80, '\0', /* cICP */
|
||||
103, 65, 77, 65, '\0', /* gAMA */
|
||||
# ifdef PNG_READ_iCCP_SUPPORTED
|
||||
105, 67, 67, 80, '\0', /* iCCP */
|
||||
# endif
|
||||
109, 68, 67, 86, '\0', /* mDCV */
|
||||
115, 66, 73, 84, '\0', /* sBIT */
|
||||
115, 82, 71, 66, '\0', /* sRGB */
|
||||
};
|
||||
};
|
||||
|
||||
/* Ignore unknown chunks and all other chunks except for the
|
||||
* IHDR, PLTE, tRNS, IDAT, and IEND chunks.
|
||||
@@ -1680,7 +1527,15 @@ png_image_skip_unused_chunks(png_structrp png_ptr)
|
||||
static void
|
||||
set_file_encoding(png_image_read_control *display)
|
||||
{
|
||||
png_fixed_point g = display->image->opaque->png_ptr->colorspace.gamma;
|
||||
png_structrp png_ptr = display->image->opaque->png_ptr;
|
||||
png_fixed_point g = png_resolve_file_gamma(png_ptr);
|
||||
|
||||
/* PNGv3: the result may be 0 however the 'default_gamma' should have been
|
||||
* set before this is called so zero is an error:
|
||||
*/
|
||||
if (g == 0)
|
||||
png_error(png_ptr, "internal: default gamma not set");
|
||||
|
||||
if (png_gamma_significant(g) != 0)
|
||||
{
|
||||
if (png_gamma_not_sRGB(g) != 0)
|
||||
@@ -2168,24 +2023,18 @@ png_image_read_colormap(png_voidp argument)
|
||||
/* Default the input file gamma if required - this is necessary because
|
||||
* libpng assumes that if no gamma information is present the data is in the
|
||||
* output format, but the simplified API deduces the gamma from the input
|
||||
* format.
|
||||
* format. The 'default' gamma value is also set by png_set_alpha_mode, but
|
||||
* this is happening before any such call, so:
|
||||
*
|
||||
* TODO: should be an internal API and all this code should be copied into a
|
||||
* single common gamma+colorspace file.
|
||||
*/
|
||||
if ((png_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_GAMMA) == 0)
|
||||
{
|
||||
/* Do this directly, not using the png_colorspace functions, to ensure
|
||||
* that it happens even if the colorspace is invalid (though probably if
|
||||
* it is the setting will be ignored) Note that the same thing can be
|
||||
* achieved at the application interface with png_set_gAMA.
|
||||
*/
|
||||
if (png_ptr->bit_depth == 16 &&
|
||||
(image->flags & PNG_IMAGE_FLAG_16BIT_sRGB) == 0)
|
||||
png_ptr->colorspace.gamma = PNG_GAMMA_LINEAR;
|
||||
if (png_ptr->bit_depth == 16 &&
|
||||
(image->flags & PNG_IMAGE_FLAG_16BIT_sRGB) == 0)
|
||||
png_ptr->default_gamma = PNG_GAMMA_LINEAR;
|
||||
|
||||
else
|
||||
png_ptr->colorspace.gamma = PNG_GAMMA_sRGB_INVERSE;
|
||||
|
||||
png_ptr->colorspace.flags |= PNG_COLORSPACE_HAVE_GAMMA;
|
||||
}
|
||||
else
|
||||
png_ptr->default_gamma = PNG_GAMMA_sRGB_INVERSE;
|
||||
|
||||
/* Decide what to do based on the PNG color type of the input data. The
|
||||
* utility function png_create_colormap_entry deals with most aspects of the
|
||||
@@ -2563,6 +2412,8 @@ png_image_read_colormap(png_voidp argument)
|
||||
|
||||
else
|
||||
{
|
||||
const png_fixed_point gamma = png_resolve_file_gamma(png_ptr);
|
||||
|
||||
/* Either the input or the output has no alpha channel, so there
|
||||
* will be no non-opaque pixels in the color-map; it will just be
|
||||
* grayscale.
|
||||
@@ -2577,10 +2428,13 @@ png_image_read_colormap(png_voidp argument)
|
||||
* this case and doing it in the palette; this will result in
|
||||
* duplicate palette entries, but that's better than the
|
||||
* alternative of double gamma correction.
|
||||
*
|
||||
* NOTE: PNGv3: check the resolved result of all the potentially
|
||||
* different colour space chunks.
|
||||
*/
|
||||
if ((png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA ||
|
||||
png_ptr->num_trans > 0) &&
|
||||
png_gamma_not_sRGB(png_ptr->colorspace.gamma) != 0)
|
||||
png_gamma_not_sRGB(gamma) != 0)
|
||||
{
|
||||
cmap_entries = (unsigned int)make_gray_file_colormap(display);
|
||||
data_encoding = P_FILE;
|
||||
@@ -2612,8 +2466,8 @@ png_image_read_colormap(png_voidp argument)
|
||||
if (output_encoding == P_sRGB)
|
||||
gray = png_sRGB_table[gray]; /* now P_LINEAR */
|
||||
|
||||
gray = PNG_DIV257(png_gamma_16bit_correct(gray,
|
||||
png_ptr->colorspace.gamma)); /* now P_FILE */
|
||||
gray = PNG_DIV257(png_gamma_16bit_correct(gray, gamma));
|
||||
/* now P_FILE */
|
||||
|
||||
/* And make sure the corresponding palette entry contains
|
||||
* exactly the required sRGB value.
|
||||
@@ -3275,6 +3129,54 @@ png_image_read_colormapped(png_voidp argument)
|
||||
}
|
||||
}
|
||||
|
||||
/* Row reading for interlaced 16-to-8 bit depth conversion with local buffer. */
|
||||
static int
|
||||
png_image_read_direct_scaled(png_voidp argument)
|
||||
{
|
||||
png_image_read_control *display = png_voidcast(png_image_read_control*,
|
||||
argument);
|
||||
png_imagep image = display->image;
|
||||
png_structrp png_ptr = image->opaque->png_ptr;
|
||||
png_bytep local_row = png_voidcast(png_bytep, display->local_row);
|
||||
png_bytep first_row = png_voidcast(png_bytep, display->first_row);
|
||||
ptrdiff_t row_bytes = display->row_bytes;
|
||||
int passes;
|
||||
|
||||
/* Handle interlacing. */
|
||||
switch (png_ptr->interlaced)
|
||||
{
|
||||
case PNG_INTERLACE_NONE:
|
||||
passes = 1;
|
||||
break;
|
||||
|
||||
case PNG_INTERLACE_ADAM7:
|
||||
passes = PNG_INTERLACE_ADAM7_PASSES;
|
||||
break;
|
||||
|
||||
default:
|
||||
png_error(png_ptr, "unknown interlace type");
|
||||
}
|
||||
|
||||
/* Read each pass using local_row as intermediate buffer. */
|
||||
while (--passes >= 0)
|
||||
{
|
||||
png_uint_32 y = image->height;
|
||||
png_bytep output_row = first_row;
|
||||
|
||||
for (; y > 0; --y)
|
||||
{
|
||||
/* Read into local_row (gets transformed 8-bit data). */
|
||||
png_read_row(png_ptr, local_row, NULL);
|
||||
|
||||
/* Copy from local_row to user buffer. */
|
||||
memcpy(output_row, local_row, (size_t)row_bytes);
|
||||
output_row += row_bytes;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Just the row reading part of png_image_read. */
|
||||
static int
|
||||
png_image_read_composite(png_voidp argument)
|
||||
@@ -3693,6 +3595,7 @@ png_image_read_direct(png_voidp argument)
|
||||
int linear = (format & PNG_FORMAT_FLAG_LINEAR) != 0;
|
||||
int do_local_compose = 0;
|
||||
int do_local_background = 0; /* to avoid double gamma correction bug */
|
||||
int do_local_scale = 0; /* for interlaced 16-to-8 bit conversion */
|
||||
int passes = 0;
|
||||
|
||||
/* Add transforms to ensure the correct output format is produced then check
|
||||
@@ -3744,6 +3647,12 @@ png_image_read_direct(png_voidp argument)
|
||||
/* Set the gamma appropriately, linear for 16-bit input, sRGB otherwise.
|
||||
*/
|
||||
{
|
||||
/* This is safe but should no longer be necessary as
|
||||
* png_ptr->default_gamma should have been set after the
|
||||
* info-before-IDAT was read in png_image_read_header.
|
||||
*
|
||||
* TODO: 1.8: remove this and see what happens.
|
||||
*/
|
||||
png_fixed_point input_gamma_default;
|
||||
|
||||
if ((base_format & PNG_FORMAT_FLAG_LINEAR) != 0 &&
|
||||
@@ -3799,8 +3708,9 @@ png_image_read_direct(png_voidp argument)
|
||||
* yet; it's set below. png_struct::gamma, however, is set to the
|
||||
* final value.
|
||||
*/
|
||||
if (png_muldiv(>est, output_gamma, png_ptr->colorspace.gamma,
|
||||
PNG_FP_1) != 0 && png_gamma_significant(gtest) == 0)
|
||||
if (png_muldiv(>est, output_gamma,
|
||||
png_resolve_file_gamma(png_ptr), PNG_FP_1) != 0 &&
|
||||
png_gamma_significant(gtest) == 0)
|
||||
do_local_background = 0;
|
||||
|
||||
else if (mode == PNG_ALPHA_STANDARD)
|
||||
@@ -3819,8 +3729,16 @@ png_image_read_direct(png_voidp argument)
|
||||
png_set_expand_16(png_ptr);
|
||||
|
||||
else /* 8-bit output */
|
||||
{
|
||||
png_set_scale_16(png_ptr);
|
||||
|
||||
/* For interlaced images, use local_row buffer to avoid overflow
|
||||
* in png_combine_row() which writes using IHDR bit-depth.
|
||||
*/
|
||||
if (png_ptr->interlaced != 0)
|
||||
do_local_scale = 1;
|
||||
}
|
||||
|
||||
change &= ~PNG_FORMAT_FLAG_LINEAR;
|
||||
}
|
||||
|
||||
@@ -4096,6 +4014,24 @@ png_image_read_direct(png_voidp argument)
|
||||
return result;
|
||||
}
|
||||
|
||||
else if (do_local_scale != 0)
|
||||
{
|
||||
/* For interlaced 16-to-8 conversion, use an intermediate row buffer
|
||||
* to avoid buffer overflows in png_combine_row. The local_row is sized
|
||||
* for the transformed (8-bit) output, preventing the overflow that would
|
||||
* occur if png_combine_row wrote 16-bit data directly to the user buffer.
|
||||
*/
|
||||
int result;
|
||||
png_voidp row = png_malloc(png_ptr, png_get_rowbytes(png_ptr, info_ptr));
|
||||
|
||||
display->local_row = row;
|
||||
result = png_safe_execute(image, png_image_read_direct_scaled, display);
|
||||
display->local_row = NULL;
|
||||
png_free(png_ptr, row);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
png_alloc_size_t row_bytes = (png_alloc_size_t)display->row_bytes;
|
||||
|
||||
Vendored
+2
-2
@@ -1,6 +1,6 @@
|
||||
/* pngrio.c - functions for data input
|
||||
*
|
||||
* Copyright (c) 2018 Cosmin Truta
|
||||
* Copyright (c) 2018-2025 Cosmin Truta
|
||||
* Copyright (c) 1998-2002,2004,2006-2016,2018 Glenn Randers-Pehrson
|
||||
* Copyright (c) 1996-1997 Andreas Dilger
|
||||
* Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
|
||||
@@ -56,7 +56,7 @@ png_default_read_data(png_structp png_ptr, png_bytep data, size_t length)
|
||||
/* fread() returns 0 on error, so it is OK to store this in a size_t
|
||||
* instead of an int, which is what fread() actually returns.
|
||||
*/
|
||||
check = fread(data, 1, length, png_voidcast(png_FILE_p, png_ptr->io_ptr));
|
||||
check = fread(data, 1, length, png_voidcast(FILE *, png_ptr->io_ptr));
|
||||
|
||||
if (check != length)
|
||||
png_error(png_ptr, "Read Error");
|
||||
|
||||
Vendored
+286
-167
@@ -1,6 +1,6 @@
|
||||
/* pngrtran.c - transforms the data in a row for PNG readers
|
||||
*
|
||||
* Copyright (c) 2018-2024 Cosmin Truta
|
||||
* Copyright (c) 2018-2025 Cosmin Truta
|
||||
* Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
|
||||
* Copyright (c) 1996-1997 Andreas Dilger
|
||||
* Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
|
||||
@@ -28,6 +28,12 @@
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef PNG_RISCV_RVV_IMPLEMENTATION
|
||||
# if PNG_RISCV_RVV_IMPLEMENTATION == 1
|
||||
# define PNG_RISCV_RVV_INTRINSICS_AVAILABLE
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef PNG_READ_SUPPORTED
|
||||
|
||||
/* Set the action on getting a CRC error for an ancillary or critical chunk. */
|
||||
@@ -218,9 +224,59 @@ png_set_strip_alpha(png_structrp png_ptr)
|
||||
#endif
|
||||
|
||||
#if defined(PNG_READ_ALPHA_MODE_SUPPORTED) || defined(PNG_READ_GAMMA_SUPPORTED)
|
||||
/* PNGv3 conformance: this private API exists to resolve the now mandatory error
|
||||
* resolution when multiple conflicting sources of gamma or colour space
|
||||
* information are available.
|
||||
*
|
||||
* Terminology (assuming power law, "gamma", encodings):
|
||||
* "screen" gamma: a power law imposed by the output device when digital
|
||||
* samples are converted to visible light output. The EOTF - volage to
|
||||
* luminance on output.
|
||||
*
|
||||
* "file" gamma: a power law used to encode luminance levels from the input
|
||||
* data (the scene or the mastering display system) into digital voltages.
|
||||
* The OETF - luminance to voltage on input.
|
||||
*
|
||||
* gamma "correction": a power law matching the **inverse** of the overall
|
||||
* transfer function from input luminance levels to output levels. The
|
||||
* **inverse** of the OOTF; the correction "corrects" for the OOTF by aiming
|
||||
* to make the overall OOTF (including the correction) linear.
|
||||
*
|
||||
* It is important to understand this terminology because the defined terms are
|
||||
* scattered throughout the libpng code and it is very easy to end up with the
|
||||
* inverse of the power law required.
|
||||
*
|
||||
* Variable and struct::member names:
|
||||
* file_gamma OETF how the PNG data was encoded
|
||||
*
|
||||
* screen_gamma EOTF how the screen will decode digital levels
|
||||
*
|
||||
* -- not used -- OOTF the net effect OETF x EOTF
|
||||
* gamma_correction the inverse of OOTF to make the result linear
|
||||
*
|
||||
* All versions of libpng require a call to "png_set_gamma" to establish the
|
||||
* "screen" gamma, the power law representing the EOTF. png_set_gamma may also
|
||||
* set or default the "file" gamma; the OETF. gamma_correction is calculated
|
||||
* internally.
|
||||
*
|
||||
* The earliest libpng versions required file_gamma to be supplied to set_gamma.
|
||||
* Later versions started allowing png_set_gamma and, later, png_set_alpha_mode,
|
||||
* to cause defaulting from the file data.
|
||||
*
|
||||
* PNGv3 mandated a particular form for this defaulting, one that is compatible
|
||||
* with what libpng did except that if libpng detected inconsistencies it marked
|
||||
* all the chunks as "invalid". PNGv3 effectively invalidates this prior code.
|
||||
*
|
||||
* Behaviour implemented below:
|
||||
* translate_gamma_flags(gamma, is_screen)
|
||||
* The libpng-1.6 API for the gamma parameters to libpng APIs
|
||||
* (png_set_gamma and png_set_alpha_mode at present). This allows the
|
||||
* 'gamma' value to be passed as a png_fixed_point number or as one of a
|
||||
* set of integral values for specific "well known" examples of transfer
|
||||
* functions. This is compatible with PNGv3.
|
||||
*/
|
||||
static png_fixed_point
|
||||
translate_gamma_flags(png_structrp png_ptr, png_fixed_point output_gamma,
|
||||
int is_screen)
|
||||
translate_gamma_flags(png_fixed_point output_gamma, int is_screen)
|
||||
{
|
||||
/* Check for flag values. The main reason for having the old Mac value as a
|
||||
* flag is that it is pretty near impossible to work out what the correct
|
||||
@@ -230,14 +286,6 @@ translate_gamma_flags(png_structrp png_ptr, png_fixed_point output_gamma,
|
||||
if (output_gamma == PNG_DEFAULT_sRGB ||
|
||||
output_gamma == PNG_FP_1 / PNG_DEFAULT_sRGB)
|
||||
{
|
||||
/* If there is no sRGB support this just sets the gamma to the standard
|
||||
* sRGB value. (This is a side effect of using this function!)
|
||||
*/
|
||||
# ifdef PNG_READ_sRGB_SUPPORTED
|
||||
png_ptr->flags |= PNG_FLAG_ASSUME_sRGB;
|
||||
# else
|
||||
PNG_UNUSED(png_ptr)
|
||||
# endif
|
||||
if (is_screen != 0)
|
||||
output_gamma = PNG_GAMMA_sRGB;
|
||||
else
|
||||
@@ -279,6 +327,33 @@ convert_gamma_value(png_structrp png_ptr, double output_gamma)
|
||||
return (png_fixed_point)output_gamma;
|
||||
}
|
||||
# endif
|
||||
|
||||
static int
|
||||
unsupported_gamma(png_structrp png_ptr, png_fixed_point gamma, int warn)
|
||||
{
|
||||
/* Validate a gamma value to ensure it is in a reasonable range. The value
|
||||
* is expected to be 1 or greater, but this range test allows for some
|
||||
* viewing correction values. The intent is to weed out the API users
|
||||
* who might use the inverse of the gamma value accidentally!
|
||||
*
|
||||
* 1.6.47: apply the test in png_set_gamma as well but only warn and return
|
||||
* false if it fires.
|
||||
*
|
||||
* TODO: 1.8: make this an app_error in png_set_gamma as well.
|
||||
*/
|
||||
if (gamma < PNG_LIB_GAMMA_MIN || gamma > PNG_LIB_GAMMA_MAX)
|
||||
{
|
||||
# define msg "gamma out of supported range"
|
||||
if (warn)
|
||||
png_app_warning(png_ptr, msg);
|
||||
else
|
||||
png_app_error(png_ptr, msg);
|
||||
return 1;
|
||||
# undef msg
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* READ_ALPHA_MODE || READ_GAMMA */
|
||||
|
||||
#ifdef PNG_READ_ALPHA_MODE_SUPPORTED
|
||||
@@ -286,31 +361,29 @@ void PNGFAPI
|
||||
png_set_alpha_mode_fixed(png_structrp png_ptr, int mode,
|
||||
png_fixed_point output_gamma)
|
||||
{
|
||||
int compose = 0;
|
||||
png_fixed_point file_gamma;
|
||||
int compose = 0;
|
||||
|
||||
png_debug(1, "in png_set_alpha_mode_fixed");
|
||||
|
||||
if (png_rtran_ok(png_ptr, 0) == 0)
|
||||
return;
|
||||
|
||||
output_gamma = translate_gamma_flags(png_ptr, output_gamma, 1/*screen*/);
|
||||
|
||||
/* Validate the value to ensure it is in a reasonable range. The value
|
||||
* is expected to be 1 or greater, but this range test allows for some
|
||||
* viewing correction values. The intent is to weed out the API users
|
||||
* who might use the inverse of the gamma value accidentally!
|
||||
*
|
||||
* In libpng 1.6.0, we changed from 0.07..3 to 0.01..100, to accommodate
|
||||
* the optimal 16-bit gamma of 36 and its reciprocal.
|
||||
*/
|
||||
if (output_gamma < 1000 || output_gamma > 10000000)
|
||||
png_error(png_ptr, "output gamma out of expected range");
|
||||
output_gamma = translate_gamma_flags(output_gamma, 1/*screen*/);
|
||||
if (unsupported_gamma(png_ptr, output_gamma, 0/*error*/))
|
||||
return;
|
||||
|
||||
/* The default file gamma is the inverse of the output gamma; the output
|
||||
* gamma may be changed below so get the file value first:
|
||||
* gamma may be changed below so get the file value first. The default_gamma
|
||||
* is set here and from the simplified API (which uses a different algorithm)
|
||||
* so don't overwrite a set value:
|
||||
*/
|
||||
file_gamma = png_reciprocal(output_gamma);
|
||||
file_gamma = png_ptr->default_gamma;
|
||||
if (file_gamma == 0)
|
||||
{
|
||||
file_gamma = png_reciprocal(output_gamma);
|
||||
png_ptr->default_gamma = file_gamma;
|
||||
}
|
||||
|
||||
/* There are really 8 possibilities here, composed of any combination
|
||||
* of:
|
||||
@@ -361,17 +434,7 @@ png_set_alpha_mode_fixed(png_structrp png_ptr, int mode,
|
||||
png_error(png_ptr, "invalid alpha mode");
|
||||
}
|
||||
|
||||
/* Only set the default gamma if the file gamma has not been set (this has
|
||||
* the side effect that the gamma in a second call to png_set_alpha_mode will
|
||||
* be ignored.)
|
||||
*/
|
||||
if (png_ptr->colorspace.gamma == 0)
|
||||
{
|
||||
png_ptr->colorspace.gamma = file_gamma;
|
||||
png_ptr->colorspace.flags |= PNG_COLORSPACE_HAVE_GAMMA;
|
||||
}
|
||||
|
||||
/* But always set the output gamma: */
|
||||
/* Set the screen gamma values: */
|
||||
png_ptr->screen_gamma = output_gamma;
|
||||
|
||||
/* Finally, if pre-multiplying, set the background fields to achieve the
|
||||
@@ -381,7 +444,7 @@ png_set_alpha_mode_fixed(png_structrp png_ptr, int mode,
|
||||
{
|
||||
/* And obtain alpha pre-multiplication by composing on black: */
|
||||
memset(&png_ptr->background, 0, (sizeof png_ptr->background));
|
||||
png_ptr->background_gamma = png_ptr->colorspace.gamma; /* just in case */
|
||||
png_ptr->background_gamma = file_gamma; /* just in case */
|
||||
png_ptr->background_gamma_type = PNG_BACKGROUND_GAMMA_FILE;
|
||||
png_ptr->transformations &= ~PNG_BACKGROUND_EXPAND;
|
||||
|
||||
@@ -438,9 +501,19 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette,
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Initialize the array to index colors.
|
||||
*
|
||||
* Ensure quantize_index can fit 256 elements (PNG_MAX_PALETTE_LENGTH)
|
||||
* rather than num_palette elements. This is to prevent buffer overflows
|
||||
* caused by malformed PNG files with out-of-range palette indices.
|
||||
*
|
||||
* Be careful to avoid leaking memory. Applications are allowed to call
|
||||
* this function more than once per png_struct.
|
||||
*/
|
||||
png_free(png_ptr, png_ptr->quantize_index);
|
||||
png_ptr->quantize_index = (png_bytep)png_malloc(png_ptr,
|
||||
(png_alloc_size_t)num_palette);
|
||||
for (i = 0; i < num_palette; i++)
|
||||
PNG_MAX_PALETTE_LENGTH);
|
||||
for (i = 0; i < PNG_MAX_PALETTE_LENGTH; i++)
|
||||
png_ptr->quantize_index[i] = (png_byte)i;
|
||||
}
|
||||
|
||||
@@ -452,15 +525,14 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette,
|
||||
* Perhaps not the best solution, but good enough.
|
||||
*/
|
||||
|
||||
int i;
|
||||
png_bytep quantize_sort;
|
||||
int i, j;
|
||||
|
||||
/* Initialize an array to sort colors */
|
||||
png_ptr->quantize_sort = (png_bytep)png_malloc(png_ptr,
|
||||
/* Initialize the local array to sort colors. */
|
||||
quantize_sort = (png_bytep)png_malloc(png_ptr,
|
||||
(png_alloc_size_t)num_palette);
|
||||
|
||||
/* Initialize the quantize_sort array */
|
||||
for (i = 0; i < num_palette; i++)
|
||||
png_ptr->quantize_sort[i] = (png_byte)i;
|
||||
quantize_sort[i] = (png_byte)i;
|
||||
|
||||
/* Find the least used palette entries by starting a
|
||||
* bubble sort, and running it until we have sorted
|
||||
@@ -472,19 +544,18 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette,
|
||||
for (i = num_palette - 1; i >= maximum_colors; i--)
|
||||
{
|
||||
int done; /* To stop early if the list is pre-sorted */
|
||||
int j;
|
||||
|
||||
done = 1;
|
||||
for (j = 0; j < i; j++)
|
||||
{
|
||||
if (histogram[png_ptr->quantize_sort[j]]
|
||||
< histogram[png_ptr->quantize_sort[j + 1]])
|
||||
if (histogram[quantize_sort[j]]
|
||||
< histogram[quantize_sort[j + 1]])
|
||||
{
|
||||
png_byte t;
|
||||
|
||||
t = png_ptr->quantize_sort[j];
|
||||
png_ptr->quantize_sort[j] = png_ptr->quantize_sort[j + 1];
|
||||
png_ptr->quantize_sort[j + 1] = t;
|
||||
t = quantize_sort[j];
|
||||
quantize_sort[j] = quantize_sort[j + 1];
|
||||
quantize_sort[j + 1] = t;
|
||||
done = 0;
|
||||
}
|
||||
}
|
||||
@@ -496,18 +567,18 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette,
|
||||
/* Swap the palette around, and set up a table, if necessary */
|
||||
if (full_quantize != 0)
|
||||
{
|
||||
int j = num_palette;
|
||||
j = num_palette;
|
||||
|
||||
/* Put all the useful colors within the max, but don't
|
||||
* move the others.
|
||||
*/
|
||||
for (i = 0; i < maximum_colors; i++)
|
||||
{
|
||||
if ((int)png_ptr->quantize_sort[i] >= maximum_colors)
|
||||
if ((int)quantize_sort[i] >= maximum_colors)
|
||||
{
|
||||
do
|
||||
j--;
|
||||
while ((int)png_ptr->quantize_sort[j] >= maximum_colors);
|
||||
while ((int)quantize_sort[j] >= maximum_colors);
|
||||
|
||||
palette[i] = palette[j];
|
||||
}
|
||||
@@ -515,7 +586,7 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette,
|
||||
}
|
||||
else
|
||||
{
|
||||
int j = num_palette;
|
||||
j = num_palette;
|
||||
|
||||
/* Move all the used colors inside the max limit, and
|
||||
* develop a translation table.
|
||||
@@ -523,13 +594,13 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette,
|
||||
for (i = 0; i < maximum_colors; i++)
|
||||
{
|
||||
/* Only move the colors we need to */
|
||||
if ((int)png_ptr->quantize_sort[i] >= maximum_colors)
|
||||
if ((int)quantize_sort[i] >= maximum_colors)
|
||||
{
|
||||
png_color tmp_color;
|
||||
|
||||
do
|
||||
j--;
|
||||
while ((int)png_ptr->quantize_sort[j] >= maximum_colors);
|
||||
while ((int)quantize_sort[j] >= maximum_colors);
|
||||
|
||||
tmp_color = palette[j];
|
||||
palette[j] = palette[i];
|
||||
@@ -567,8 +638,7 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette,
|
||||
}
|
||||
}
|
||||
}
|
||||
png_free(png_ptr, png_ptr->quantize_sort);
|
||||
png_ptr->quantize_sort = NULL;
|
||||
png_free(png_ptr, quantize_sort);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -819,8 +889,8 @@ png_set_gamma_fixed(png_structrp png_ptr, png_fixed_point scrn_gamma,
|
||||
return;
|
||||
|
||||
/* New in libpng-1.5.4 - reserve particular negative values as flags. */
|
||||
scrn_gamma = translate_gamma_flags(png_ptr, scrn_gamma, 1/*screen*/);
|
||||
file_gamma = translate_gamma_flags(png_ptr, file_gamma, 0/*file*/);
|
||||
scrn_gamma = translate_gamma_flags(scrn_gamma, 1/*screen*/);
|
||||
file_gamma = translate_gamma_flags(file_gamma, 0/*file*/);
|
||||
|
||||
/* Checking the gamma values for being >0 was added in 1.5.4 along with the
|
||||
* premultiplied alpha support; this actually hides an undocumented feature
|
||||
@@ -834,17 +904,19 @@ png_set_gamma_fixed(png_structrp png_ptr, png_fixed_point scrn_gamma,
|
||||
* libpng-1.6.0.
|
||||
*/
|
||||
if (file_gamma <= 0)
|
||||
png_error(png_ptr, "invalid file gamma in png_set_gamma");
|
||||
|
||||
png_app_error(png_ptr, "invalid file gamma in png_set_gamma");
|
||||
if (scrn_gamma <= 0)
|
||||
png_error(png_ptr, "invalid screen gamma in png_set_gamma");
|
||||
png_app_error(png_ptr, "invalid screen gamma in png_set_gamma");
|
||||
|
||||
/* Set the gamma values unconditionally - this overrides the value in the PNG
|
||||
* file if a gAMA chunk was present. png_set_alpha_mode provides a
|
||||
* different, easier, way to default the file gamma.
|
||||
if (unsupported_gamma(png_ptr, file_gamma, 1/*warn*/) ||
|
||||
unsupported_gamma(png_ptr, scrn_gamma, 1/*warn*/))
|
||||
return;
|
||||
|
||||
/* 1.6.47: png_struct::file_gamma and png_struct::screen_gamma are now only
|
||||
* written by this API. This removes dependencies on the order of API calls
|
||||
* and allows the complex gamma checks to be delayed until needed.
|
||||
*/
|
||||
png_ptr->colorspace.gamma = file_gamma;
|
||||
png_ptr->colorspace.flags |= PNG_COLORSPACE_HAVE_GAMMA;
|
||||
png_ptr->file_gamma = file_gamma;
|
||||
png_ptr->screen_gamma = scrn_gamma;
|
||||
}
|
||||
|
||||
@@ -1022,26 +1094,9 @@ png_set_rgb_to_gray_fixed(png_structrp png_ptr, int error_action,
|
||||
png_ptr->rgb_to_gray_coefficients_set = 1;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
if (red >= 0 && green >= 0)
|
||||
png_app_warning(png_ptr,
|
||||
"ignoring out of range rgb_to_gray coefficients");
|
||||
|
||||
/* Use the defaults, from the cHRM chunk if set, else the historical
|
||||
* values which are close to the sRGB/HDTV/ITU-Rec 709 values. See
|
||||
* png_do_rgb_to_gray for more discussion of the values. In this case
|
||||
* the coefficients are not marked as 'set' and are not overwritten if
|
||||
* something has already provided a default.
|
||||
*/
|
||||
if (png_ptr->rgb_to_gray_red_coeff == 0 &&
|
||||
png_ptr->rgb_to_gray_green_coeff == 0)
|
||||
{
|
||||
png_ptr->rgb_to_gray_red_coeff = 6968;
|
||||
png_ptr->rgb_to_gray_green_coeff = 23434;
|
||||
/* png_ptr->rgb_to_gray_blue_coeff = 2366; */
|
||||
}
|
||||
}
|
||||
else if (red >= 0 && green >= 0)
|
||||
png_app_warning(png_ptr,
|
||||
"ignoring out of range rgb_to_gray coefficients");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1282,6 +1337,80 @@ png_init_rgb_transformations(png_structrp png_ptr)
|
||||
#endif /* READ_EXPAND && READ_BACKGROUND */
|
||||
}
|
||||
|
||||
#ifdef PNG_READ_GAMMA_SUPPORTED
|
||||
png_fixed_point /* PRIVATE */
|
||||
png_resolve_file_gamma(png_const_structrp png_ptr)
|
||||
{
|
||||
png_fixed_point file_gamma;
|
||||
|
||||
/* The file gamma is determined by these precedence rules, in this order
|
||||
* (i.e. use the first value found):
|
||||
*
|
||||
* png_set_gamma; png_struct::file_gammma if not zero, then:
|
||||
* png_struct::chunk_gamma if not 0 (determined the PNGv3 rules), then:
|
||||
* png_set_gamma; 1/png_struct::screen_gamma if not zero
|
||||
*
|
||||
* 0 (i.e. do no gamma handling)
|
||||
*/
|
||||
file_gamma = png_ptr->file_gamma;
|
||||
if (file_gamma != 0)
|
||||
return file_gamma;
|
||||
|
||||
file_gamma = png_ptr->chunk_gamma;
|
||||
if (file_gamma != 0)
|
||||
return file_gamma;
|
||||
|
||||
file_gamma = png_ptr->default_gamma;
|
||||
if (file_gamma != 0)
|
||||
return file_gamma;
|
||||
|
||||
/* If png_reciprocal oveflows it returns 0 which indicates to the caller that
|
||||
* there is no usable file gamma. (The checks added to png_set_gamma and
|
||||
* png_set_alpha_mode should prevent a screen_gamma which would overflow.)
|
||||
*/
|
||||
if (png_ptr->screen_gamma != 0)
|
||||
file_gamma = png_reciprocal(png_ptr->screen_gamma);
|
||||
|
||||
return file_gamma;
|
||||
}
|
||||
|
||||
static int
|
||||
png_init_gamma_values(png_structrp png_ptr)
|
||||
{
|
||||
/* The following temporary indicates if overall gamma correction is
|
||||
* required.
|
||||
*/
|
||||
int gamma_correction = 0;
|
||||
png_fixed_point file_gamma, screen_gamma;
|
||||
|
||||
/* Resolve the file_gamma. See above: if png_ptr::screen_gamma is set
|
||||
* file_gamma will always be set here:
|
||||
*/
|
||||
file_gamma = png_resolve_file_gamma(png_ptr);
|
||||
screen_gamma = png_ptr->screen_gamma;
|
||||
|
||||
if (file_gamma > 0) /* file has been set */
|
||||
{
|
||||
if (screen_gamma > 0) /* screen set too */
|
||||
gamma_correction = png_gamma_threshold(file_gamma, screen_gamma);
|
||||
|
||||
else
|
||||
/* Assume the output matches the input; a long time default behavior
|
||||
* of libpng, although the standard has nothing to say about this.
|
||||
*/
|
||||
screen_gamma = png_reciprocal(file_gamma);
|
||||
}
|
||||
|
||||
else /* both unset, prevent corrections: */
|
||||
file_gamma = screen_gamma = PNG_FP_1;
|
||||
|
||||
png_ptr->file_gamma = file_gamma;
|
||||
png_ptr->screen_gamma = screen_gamma;
|
||||
return gamma_correction;
|
||||
|
||||
}
|
||||
#endif /* READ_GAMMA */
|
||||
|
||||
void /* PRIVATE */
|
||||
png_init_read_transformations(png_structrp png_ptr)
|
||||
{
|
||||
@@ -1301,59 +1430,22 @@ png_init_read_transformations(png_structrp png_ptr)
|
||||
* the test needs to be performed later - here. In addition prior to 1.5.4
|
||||
* the tests were repeated for the PALETTE color type here - this is no
|
||||
* longer necessary (and doesn't seem to have been necessary before.)
|
||||
*
|
||||
* PNGv3: the new mandatory precedence/priority rules for colour space chunks
|
||||
* are handled here (by calling the above function).
|
||||
*
|
||||
* Turn the gamma transformation on or off as appropriate. Notice that
|
||||
* PNG_GAMMA just refers to the file->screen correction. Alpha composition
|
||||
* may independently cause gamma correction because it needs linear data
|
||||
* (e.g. if the file has a gAMA chunk but the screen gamma hasn't been
|
||||
* specified.) In any case this flag may get turned off in the code
|
||||
* immediately below if the transform can be handled outside the row loop.
|
||||
*/
|
||||
{
|
||||
/* The following temporary indicates if overall gamma correction is
|
||||
* required.
|
||||
*/
|
||||
int gamma_correction = 0;
|
||||
if (png_init_gamma_values(png_ptr) != 0)
|
||||
png_ptr->transformations |= PNG_GAMMA;
|
||||
|
||||
if (png_ptr->colorspace.gamma != 0) /* has been set */
|
||||
{
|
||||
if (png_ptr->screen_gamma != 0) /* screen set too */
|
||||
gamma_correction = png_gamma_threshold(png_ptr->colorspace.gamma,
|
||||
png_ptr->screen_gamma);
|
||||
|
||||
else
|
||||
/* Assume the output matches the input; a long time default behavior
|
||||
* of libpng, although the standard has nothing to say about this.
|
||||
*/
|
||||
png_ptr->screen_gamma = png_reciprocal(png_ptr->colorspace.gamma);
|
||||
}
|
||||
|
||||
else if (png_ptr->screen_gamma != 0)
|
||||
/* The converse - assume the file matches the screen, note that this
|
||||
* perhaps undesirable default can (from 1.5.4) be changed by calling
|
||||
* png_set_alpha_mode (even if the alpha handling mode isn't required
|
||||
* or isn't changed from the default.)
|
||||
*/
|
||||
png_ptr->colorspace.gamma = png_reciprocal(png_ptr->screen_gamma);
|
||||
|
||||
else /* neither are set */
|
||||
/* Just in case the following prevents any processing - file and screen
|
||||
* are both assumed to be linear and there is no way to introduce a
|
||||
* third gamma value other than png_set_background with 'UNIQUE', and,
|
||||
* prior to 1.5.4
|
||||
*/
|
||||
png_ptr->screen_gamma = png_ptr->colorspace.gamma = PNG_FP_1;
|
||||
|
||||
/* We have a gamma value now. */
|
||||
png_ptr->colorspace.flags |= PNG_COLORSPACE_HAVE_GAMMA;
|
||||
|
||||
/* Now turn the gamma transformation on or off as appropriate. Notice
|
||||
* that PNG_GAMMA just refers to the file->screen correction. Alpha
|
||||
* composition may independently cause gamma correction because it needs
|
||||
* linear data (e.g. if the file has a gAMA chunk but the screen gamma
|
||||
* hasn't been specified.) In any case this flag may get turned off in
|
||||
* the code immediately below if the transform can be handled outside the
|
||||
* row loop.
|
||||
*/
|
||||
if (gamma_correction != 0)
|
||||
png_ptr->transformations |= PNG_GAMMA;
|
||||
|
||||
else
|
||||
png_ptr->transformations &= ~PNG_GAMMA;
|
||||
}
|
||||
else
|
||||
png_ptr->transformations &= ~PNG_GAMMA;
|
||||
#endif
|
||||
|
||||
/* Certain transformations have the effect of preventing other
|
||||
@@ -1425,7 +1517,7 @@ png_init_read_transformations(png_structrp png_ptr)
|
||||
* appropriately.
|
||||
*/
|
||||
if ((png_ptr->transformations & PNG_RGB_TO_GRAY) != 0)
|
||||
png_colorspace_set_rgb_coefficients(png_ptr);
|
||||
png_set_rgb_coefficients(png_ptr);
|
||||
#endif
|
||||
|
||||
#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED
|
||||
@@ -1568,10 +1660,10 @@ png_init_read_transformations(png_structrp png_ptr)
|
||||
*/
|
||||
if ((png_ptr->transformations & PNG_GAMMA) != 0 ||
|
||||
((png_ptr->transformations & PNG_RGB_TO_GRAY) != 0 &&
|
||||
(png_gamma_significant(png_ptr->colorspace.gamma) != 0 ||
|
||||
(png_gamma_significant(png_ptr->file_gamma) != 0 ||
|
||||
png_gamma_significant(png_ptr->screen_gamma) != 0)) ||
|
||||
((png_ptr->transformations & PNG_COMPOSE) != 0 &&
|
||||
(png_gamma_significant(png_ptr->colorspace.gamma) != 0 ||
|
||||
(png_gamma_significant(png_ptr->file_gamma) != 0 ||
|
||||
png_gamma_significant(png_ptr->screen_gamma) != 0
|
||||
# ifdef PNG_READ_BACKGROUND_SUPPORTED
|
||||
|| (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_UNIQUE &&
|
||||
@@ -1627,8 +1719,8 @@ png_init_read_transformations(png_structrp png_ptr)
|
||||
break;
|
||||
|
||||
case PNG_BACKGROUND_GAMMA_FILE:
|
||||
g = png_reciprocal(png_ptr->colorspace.gamma);
|
||||
gs = png_reciprocal2(png_ptr->colorspace.gamma,
|
||||
g = png_reciprocal(png_ptr->file_gamma);
|
||||
gs = png_reciprocal2(png_ptr->file_gamma,
|
||||
png_ptr->screen_gamma);
|
||||
break;
|
||||
|
||||
@@ -1689,19 +1781,51 @@ png_init_read_transformations(png_structrp png_ptr)
|
||||
}
|
||||
else /* if (png_ptr->trans_alpha[i] != 0xff) */
|
||||
{
|
||||
png_byte v, w;
|
||||
if ((png_ptr->flags & PNG_FLAG_OPTIMIZE_ALPHA) != 0)
|
||||
{
|
||||
/* Premultiply only:
|
||||
* component = round((component * alpha) / 255)
|
||||
*/
|
||||
png_uint_32 component;
|
||||
|
||||
v = png_ptr->gamma_to_1[palette[i].red];
|
||||
png_composite(w, v, png_ptr->trans_alpha[i], back_1.red);
|
||||
palette[i].red = png_ptr->gamma_from_1[w];
|
||||
component = png_ptr->gamma_to_1[palette[i].red];
|
||||
component =
|
||||
(component * png_ptr->trans_alpha[i] + 128) / 255;
|
||||
palette[i].red = png_ptr->gamma_from_1[component];
|
||||
|
||||
v = png_ptr->gamma_to_1[palette[i].green];
|
||||
png_composite(w, v, png_ptr->trans_alpha[i], back_1.green);
|
||||
palette[i].green = png_ptr->gamma_from_1[w];
|
||||
component = png_ptr->gamma_to_1[palette[i].green];
|
||||
component =
|
||||
(component * png_ptr->trans_alpha[i] + 128) / 255;
|
||||
palette[i].green = png_ptr->gamma_from_1[component];
|
||||
|
||||
v = png_ptr->gamma_to_1[palette[i].blue];
|
||||
png_composite(w, v, png_ptr->trans_alpha[i], back_1.blue);
|
||||
palette[i].blue = png_ptr->gamma_from_1[w];
|
||||
component = png_ptr->gamma_to_1[palette[i].blue];
|
||||
component =
|
||||
(component * png_ptr->trans_alpha[i] + 128) / 255;
|
||||
palette[i].blue = png_ptr->gamma_from_1[component];
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Composite with background color:
|
||||
* component =
|
||||
* alpha * component + (1 - alpha) * background
|
||||
*/
|
||||
png_byte v, w;
|
||||
|
||||
v = png_ptr->gamma_to_1[palette[i].red];
|
||||
png_composite(w, v,
|
||||
png_ptr->trans_alpha[i], back_1.red);
|
||||
palette[i].red = png_ptr->gamma_from_1[w];
|
||||
|
||||
v = png_ptr->gamma_to_1[palette[i].green];
|
||||
png_composite(w, v,
|
||||
png_ptr->trans_alpha[i], back_1.green);
|
||||
palette[i].green = png_ptr->gamma_from_1[w];
|
||||
|
||||
v = png_ptr->gamma_to_1[palette[i].blue];
|
||||
png_composite(w, v,
|
||||
png_ptr->trans_alpha[i], back_1.blue);
|
||||
palette[i].blue = png_ptr->gamma_from_1[w];
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -1736,8 +1860,8 @@ png_init_read_transformations(png_structrp png_ptr)
|
||||
break;
|
||||
|
||||
case PNG_BACKGROUND_GAMMA_FILE:
|
||||
g = png_reciprocal(png_ptr->colorspace.gamma);
|
||||
gs = png_reciprocal2(png_ptr->colorspace.gamma,
|
||||
g = png_reciprocal(png_ptr->file_gamma);
|
||||
gs = png_reciprocal2(png_ptr->file_gamma,
|
||||
png_ptr->screen_gamma);
|
||||
break;
|
||||
|
||||
@@ -1987,11 +2111,11 @@ png_read_transform_info(png_structrp png_ptr, png_inforp info_ptr)
|
||||
* been called before this from png_read_update_info->png_read_start_row
|
||||
* sometimes does the gamma transform and cancels the flag.
|
||||
*
|
||||
* TODO: this looks wrong; the info_ptr should end up with a gamma equal to
|
||||
* the screen_gamma value. The following probably results in weirdness if
|
||||
* the info_ptr is used by the app after the rows have been read.
|
||||
* TODO: this is confusing. It only changes the result of png_get_gAMA and,
|
||||
* yes, it does return the value that the transformed data effectively has
|
||||
* but does any app really understand this?
|
||||
*/
|
||||
info_ptr->colorspace.gamma = png_ptr->colorspace.gamma;
|
||||
info_ptr->gamma = png_ptr->file_gamma;
|
||||
#endif
|
||||
|
||||
if (info_ptr->bit_depth == 16)
|
||||
@@ -4924,13 +5048,8 @@ png_do_read_transformations(png_structrp png_ptr, png_row_infop row_info)
|
||||
|
||||
#ifdef PNG_READ_QUANTIZE_SUPPORTED
|
||||
if ((png_ptr->transformations & PNG_QUANTIZE) != 0)
|
||||
{
|
||||
png_do_quantize(row_info, png_ptr->row_buf + 1,
|
||||
png_ptr->palette_lookup, png_ptr->quantize_index);
|
||||
|
||||
if (row_info->rowbytes == 0)
|
||||
png_error(png_ptr, "png_do_quantize returned rowbytes=0");
|
||||
}
|
||||
#endif /* READ_QUANTIZE */
|
||||
|
||||
#ifdef PNG_READ_EXPAND_16_SUPPORTED
|
||||
|
||||
Vendored
+928
-936
@@ -1,6 +1,6 @@
|
||||
/* pngrutil.c - utilities to read a PNG file
|
||||
*
|
||||
* Copyright (c) 2018-2024 Cosmin Truta
|
||||
* Copyright (c) 2018-2025 Cosmin Truta
|
||||
* Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
|
||||
* Copyright (c) 1996-1997 Andreas Dilger
|
||||
* Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
|
||||
@@ -17,6 +17,11 @@
|
||||
|
||||
#ifdef PNG_READ_SUPPORTED
|
||||
|
||||
/* The minimum 'zlib' stream is assumed to be just the 2 byte header, 5 bytes
|
||||
* minimum 'deflate' stream, and the 4 byte checksum.
|
||||
*/
|
||||
#define LZ77Min (2U+5U+4U)
|
||||
|
||||
#ifdef PNG_READ_INTERLACING_SUPPORTED
|
||||
/* Arrays to facilitate interlacing - use pass (0 - 6) as index. */
|
||||
|
||||
@@ -43,30 +48,6 @@ png_get_uint_31(png_const_structrp png_ptr, png_const_bytep buf)
|
||||
return uval;
|
||||
}
|
||||
|
||||
#if defined(PNG_READ_gAMA_SUPPORTED) || defined(PNG_READ_cHRM_SUPPORTED)
|
||||
/* The following is a variation on the above for use with the fixed
|
||||
* point values used for gAMA and cHRM. Instead of png_error it
|
||||
* issues a warning and returns (-1) - an invalid value because both
|
||||
* gAMA and cHRM use *unsigned* integers for fixed point values.
|
||||
*/
|
||||
#define PNG_FIXED_ERROR (-1)
|
||||
|
||||
static png_fixed_point /* PRIVATE */
|
||||
png_get_fixed_point(png_structrp png_ptr, png_const_bytep buf)
|
||||
{
|
||||
png_uint_32 uval = png_get_uint_32(buf);
|
||||
|
||||
if (uval <= PNG_UINT_31_MAX)
|
||||
return (png_fixed_point)uval; /* known to be in range */
|
||||
|
||||
/* The caller can turn off the warning by passing NULL. */
|
||||
if (png_ptr != NULL)
|
||||
png_warning(png_ptr, "PNG fixed point integer out of range");
|
||||
|
||||
return PNG_FIXED_ERROR;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef PNG_READ_INT_FUNCTIONS_SUPPORTED
|
||||
/* NOTE: the read macros will obscure these definitions, so that if
|
||||
* PNG_USE_READ_MACROS is set the library will not use them internally,
|
||||
@@ -163,6 +144,38 @@ png_read_sig(png_structrp png_ptr, png_inforp info_ptr)
|
||||
png_ptr->mode |= PNG_HAVE_PNG_SIGNATURE;
|
||||
}
|
||||
|
||||
/* This function is called to verify that a chunk name is valid.
|
||||
* Do this using the bit-whacking approach from contrib/tools/pngfix.c
|
||||
*
|
||||
* Copied from libpng 1.7.
|
||||
*/
|
||||
static int
|
||||
check_chunk_name(png_uint_32 name)
|
||||
{
|
||||
png_uint_32 t;
|
||||
|
||||
/* Remove bit 5 from all but the reserved byte; this means
|
||||
* every 8-bit unit must be in the range 65-90 to be valid.
|
||||
* So bit 5 must be zero, bit 6 must be set and bit 7 zero.
|
||||
*/
|
||||
name &= ~PNG_U32(32,32,0,32);
|
||||
t = (name & ~0x1f1f1f1fU) ^ 0x40404040U;
|
||||
|
||||
/* Subtract 65 for each 8-bit quantity, this must not
|
||||
* overflow and each byte must then be in the range 0-25.
|
||||
*/
|
||||
name -= PNG_U32(65,65,65,65);
|
||||
t |= name;
|
||||
|
||||
/* Subtract 26, handling the overflow which should set the
|
||||
* top three bits of each byte.
|
||||
*/
|
||||
name -= PNG_U32(25,25,25,26);
|
||||
t |= ~name;
|
||||
|
||||
return (t & 0xe0e0e0e0U) == 0U;
|
||||
}
|
||||
|
||||
/* Read the chunk header (length + type name).
|
||||
* Put the type name into png_ptr->chunk_name, and return the length.
|
||||
*/
|
||||
@@ -170,33 +183,36 @@ png_uint_32 /* PRIVATE */
|
||||
png_read_chunk_header(png_structrp png_ptr)
|
||||
{
|
||||
png_byte buf[8];
|
||||
png_uint_32 length;
|
||||
png_uint_32 chunk_name, length;
|
||||
|
||||
#ifdef PNG_IO_STATE_SUPPORTED
|
||||
png_ptr->io_state = PNG_IO_READING | PNG_IO_CHUNK_HDR;
|
||||
#endif
|
||||
|
||||
/* Read the length and the chunk name.
|
||||
* This must be performed in a single I/O call.
|
||||
/* Read the length and the chunk name. png_struct::chunk_name is immediately
|
||||
* updated even if they are detectably wrong. This aids error message
|
||||
* handling by allowing png_chunk_error to be used.
|
||||
*/
|
||||
png_read_data(png_ptr, buf, 8);
|
||||
length = png_get_uint_31(png_ptr, buf);
|
||||
|
||||
/* Put the chunk name into png_ptr->chunk_name. */
|
||||
png_ptr->chunk_name = PNG_CHUNK_FROM_STRING(buf+4);
|
||||
|
||||
png_debug2(0, "Reading chunk typeid = 0x%lx, length = %lu",
|
||||
(unsigned long)png_ptr->chunk_name, (unsigned long)length);
|
||||
png_ptr->chunk_name = chunk_name = PNG_CHUNK_FROM_STRING(buf+4);
|
||||
|
||||
/* Reset the crc and run it over the chunk name. */
|
||||
png_reset_crc(png_ptr);
|
||||
png_calculate_crc(png_ptr, buf + 4, 4);
|
||||
|
||||
/* Check to see if chunk name is valid. */
|
||||
png_check_chunk_name(png_ptr, png_ptr->chunk_name);
|
||||
png_debug2(0, "Reading chunk typeid = 0x%lx, length = %lu",
|
||||
(unsigned long)png_ptr->chunk_name, (unsigned long)length);
|
||||
|
||||
/* Check for too-large chunk length */
|
||||
png_check_chunk_length(png_ptr, length);
|
||||
/* Sanity check the length (first by <= 0x80) and the chunk name. An error
|
||||
* here indicates a broken stream and libpng has no recovery from this.
|
||||
*/
|
||||
if (buf[0] >= 0x80U)
|
||||
png_chunk_error(png_ptr, "bad header (invalid length)");
|
||||
|
||||
/* Check to see if chunk name is valid. */
|
||||
if (!check_chunk_name(chunk_name))
|
||||
png_chunk_error(png_ptr, "bad header (invalid type)");
|
||||
|
||||
#ifdef PNG_IO_STATE_SUPPORTED
|
||||
png_ptr->io_state = PNG_IO_READING | PNG_IO_CHUNK_DATA;
|
||||
@@ -216,59 +232,43 @@ png_crc_read(png_structrp png_ptr, png_bytep buf, png_uint_32 length)
|
||||
png_calculate_crc(png_ptr, buf, length);
|
||||
}
|
||||
|
||||
/* Optionally skip data and then check the CRC. Depending on whether we
|
||||
* are reading an 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 /* PRIVATE */
|
||||
png_crc_finish(png_structrp png_ptr, png_uint_32 skip)
|
||||
{
|
||||
/* The size of the local buffer for inflate is a good guess as to a
|
||||
* reasonable size to use for buffering reads from the application.
|
||||
*/
|
||||
while (skip > 0)
|
||||
{
|
||||
png_uint_32 len;
|
||||
png_byte tmpbuf[PNG_INFLATE_BUF_SIZE];
|
||||
|
||||
len = (sizeof tmpbuf);
|
||||
if (len > skip)
|
||||
len = skip;
|
||||
skip -= len;
|
||||
|
||||
png_crc_read(png_ptr, tmpbuf, len);
|
||||
}
|
||||
|
||||
if (png_crc_error(png_ptr) != 0)
|
||||
{
|
||||
if (PNG_CHUNK_ANCILLARY(png_ptr->chunk_name) != 0 ?
|
||||
(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN) == 0 :
|
||||
(png_ptr->flags & PNG_FLAG_CRC_CRITICAL_USE) != 0)
|
||||
{
|
||||
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 /* PRIVATE */
|
||||
png_crc_error(png_structrp png_ptr)
|
||||
static int
|
||||
png_crc_error(png_structrp png_ptr, int handle_as_ancillary)
|
||||
{
|
||||
png_byte crc_bytes[4];
|
||||
png_uint_32 crc;
|
||||
int need_crc = 1;
|
||||
|
||||
if (PNG_CHUNK_ANCILLARY(png_ptr->chunk_name) != 0)
|
||||
/* There are four flags two for ancillary and two for critical chunks. The
|
||||
* default setting of these flags is all zero.
|
||||
*
|
||||
* PNG_FLAG_CRC_ANCILLARY_USE
|
||||
* PNG_FLAG_CRC_ANCILLARY_NOWARN
|
||||
* USE+NOWARN: no CRC calculation (implemented here), else;
|
||||
* NOWARN: png_chunk_error on error (implemented in png_crc_finish)
|
||||
* else: png_chunk_warning on error (implemented in png_crc_finish)
|
||||
* This is the default.
|
||||
*
|
||||
* I.e. NOWARN without USE produces png_chunk_error. The default setting
|
||||
* where neither are set does the same thing.
|
||||
*
|
||||
* PNG_FLAG_CRC_CRITICAL_USE
|
||||
* PNG_FLAG_CRC_CRITICAL_IGNORE
|
||||
* IGNORE: no CRC calculation (implemented here), else;
|
||||
* USE: png_chunk_warning on error (implemented in png_crc_finish)
|
||||
* else: png_chunk_error on error (implemented in png_crc_finish)
|
||||
* This is the default.
|
||||
*
|
||||
* This arose because of original mis-implementation and has persisted for
|
||||
* compatibility reasons.
|
||||
*
|
||||
* TODO: the flag names are internal so maybe this can be changed to
|
||||
* something comprehensible.
|
||||
*/
|
||||
if (handle_as_ancillary || PNG_CHUNK_ANCILLARY(png_ptr->chunk_name) != 0)
|
||||
{
|
||||
if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_MASK) ==
|
||||
(PNG_FLAG_CRC_ANCILLARY_USE | PNG_FLAG_CRC_ANCILLARY_NOWARN))
|
||||
@@ -298,21 +298,87 @@ png_crc_error(png_structrp png_ptr)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Optionally skip data and then check the CRC. Depending on whether we
|
||||
* are reading an 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.
|
||||
*
|
||||
* There is one public version which is used in most places and another which
|
||||
* takes the value for the 'critical' flag to check. This allows PLTE and IEND
|
||||
* handling code to ignore the CRC error and removes some confusing code
|
||||
* duplication.
|
||||
*/
|
||||
static int
|
||||
png_crc_finish_critical(png_structrp png_ptr, png_uint_32 skip,
|
||||
int handle_as_ancillary)
|
||||
{
|
||||
/* The size of the local buffer for inflate is a good guess as to a
|
||||
* reasonable size to use for buffering reads from the application.
|
||||
*/
|
||||
while (skip > 0)
|
||||
{
|
||||
png_uint_32 len;
|
||||
png_byte tmpbuf[PNG_INFLATE_BUF_SIZE];
|
||||
|
||||
len = (sizeof tmpbuf);
|
||||
if (len > skip)
|
||||
len = skip;
|
||||
skip -= len;
|
||||
|
||||
png_crc_read(png_ptr, tmpbuf, len);
|
||||
}
|
||||
|
||||
/* If 'handle_as_ancillary' has been requested and this is a critical chunk
|
||||
* but PNG_FLAG_CRC_CRITICAL_IGNORE was set then png_read_crc did not, in
|
||||
* fact, calculate the CRC so the ANCILLARY settings should not be used
|
||||
* instead.
|
||||
*/
|
||||
if (handle_as_ancillary &&
|
||||
(png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE) != 0)
|
||||
handle_as_ancillary = 0;
|
||||
|
||||
/* TODO: this might be more comprehensible if png_crc_error was inlined here.
|
||||
*/
|
||||
if (png_crc_error(png_ptr, handle_as_ancillary) != 0)
|
||||
{
|
||||
/* See above for the explanation of how the flags work. */
|
||||
if (handle_as_ancillary || PNG_CHUNK_ANCILLARY(png_ptr->chunk_name) != 0 ?
|
||||
(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN) == 0 :
|
||||
(png_ptr->flags & PNG_FLAG_CRC_CRITICAL_USE) != 0)
|
||||
png_chunk_warning(png_ptr, "CRC error");
|
||||
|
||||
else
|
||||
png_chunk_error(png_ptr, "CRC error");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int /* PRIVATE */
|
||||
png_crc_finish(png_structrp png_ptr, png_uint_32 skip)
|
||||
{
|
||||
return png_crc_finish_critical(png_ptr, skip, 0/*critical handling*/);
|
||||
}
|
||||
|
||||
#if defined(PNG_READ_iCCP_SUPPORTED) || defined(PNG_READ_iTXt_SUPPORTED) ||\
|
||||
defined(PNG_READ_pCAL_SUPPORTED) || defined(PNG_READ_sCAL_SUPPORTED) ||\
|
||||
defined(PNG_READ_sPLT_SUPPORTED) || defined(PNG_READ_tEXt_SUPPORTED) ||\
|
||||
defined(PNG_READ_zTXt_SUPPORTED) || defined(PNG_SEQUENTIAL_READ_SUPPORTED)
|
||||
defined(PNG_READ_zTXt_SUPPORTED) || defined(PNG_READ_eXIf_SUPPORTED) ||\
|
||||
defined(PNG_SEQUENTIAL_READ_SUPPORTED)
|
||||
/* Manage the read buffer; this simply reallocates the buffer if it is not small
|
||||
* enough (or if it is not allocated). The routine returns a pointer to the
|
||||
* buffer; if an error occurs and 'warn' is set the routine returns NULL, else
|
||||
* it will call png_error (via png_malloc) on failure. (warn == 2 means
|
||||
* 'silent').
|
||||
* it will call png_error on failure.
|
||||
*/
|
||||
static png_bytep
|
||||
png_read_buffer(png_structrp png_ptr, png_alloc_size_t new_size, int warn)
|
||||
png_read_buffer(png_structrp png_ptr, png_alloc_size_t new_size)
|
||||
{
|
||||
png_bytep buffer = png_ptr->read_buffer;
|
||||
|
||||
if (new_size > png_chunk_max(png_ptr)) return NULL;
|
||||
|
||||
if (buffer != NULL && new_size > png_ptr->read_buffer_size)
|
||||
{
|
||||
png_ptr->read_buffer = NULL;
|
||||
@@ -327,24 +393,17 @@ png_read_buffer(png_structrp png_ptr, png_alloc_size_t new_size, int warn)
|
||||
|
||||
if (buffer != NULL)
|
||||
{
|
||||
memset(buffer, 0, new_size); /* just in case */
|
||||
# ifndef PNG_NO_MEMZERO /* for detecting UIM bugs **only** */
|
||||
memset(buffer, 0, new_size); /* just in case */
|
||||
# endif
|
||||
png_ptr->read_buffer = buffer;
|
||||
png_ptr->read_buffer_size = new_size;
|
||||
}
|
||||
|
||||
else if (warn < 2) /* else silent */
|
||||
{
|
||||
if (warn != 0)
|
||||
png_chunk_warning(png_ptr, "insufficient memory to read chunk");
|
||||
|
||||
else
|
||||
png_chunk_error(png_ptr, "insufficient memory to read chunk");
|
||||
}
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
#endif /* READ_iCCP|iTXt|pCAL|sCAL|sPLT|tEXt|zTXt|SEQUENTIAL_READ */
|
||||
#endif /* READ_iCCP|iTXt|pCAL|sCAL|sPLT|tEXt|zTXt|eXIf|SEQUENTIAL_READ */
|
||||
|
||||
/* png_inflate_claim: claim the zstream for some nefarious purpose that involves
|
||||
* decompression. Returns Z_OK on success, else a zlib error code. It checks
|
||||
@@ -631,16 +690,7 @@ png_decompress_chunk(png_structrp png_ptr,
|
||||
* maybe a '\0' terminator too. We have to assume that 'prefix_size' is
|
||||
* limited only by the maximum chunk size.
|
||||
*/
|
||||
png_alloc_size_t limit = PNG_SIZE_MAX;
|
||||
|
||||
# ifdef PNG_SET_USER_LIMITS_SUPPORTED
|
||||
if (png_ptr->user_chunk_malloc_max > 0 &&
|
||||
png_ptr->user_chunk_malloc_max < limit)
|
||||
limit = png_ptr->user_chunk_malloc_max;
|
||||
# elif PNG_USER_CHUNK_MALLOC_MAX > 0
|
||||
if (PNG_USER_CHUNK_MALLOC_MAX < limit)
|
||||
limit = PNG_USER_CHUNK_MALLOC_MAX;
|
||||
# endif
|
||||
png_alloc_size_t limit = png_chunk_max(png_ptr);
|
||||
|
||||
if (limit >= prefix_size + (terminate != 0))
|
||||
{
|
||||
@@ -845,9 +895,9 @@ png_inflate_read(png_structrp png_ptr, png_bytep read_buffer, uInt read_size,
|
||||
}
|
||||
#endif /* READ_iCCP */
|
||||
|
||||
/* CHUNK HANDLING */
|
||||
/* Read and check the IDHR chunk */
|
||||
|
||||
void /* PRIVATE */
|
||||
static png_handle_result_code
|
||||
png_handle_IHDR(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
|
||||
{
|
||||
png_byte buf[13];
|
||||
@@ -857,12 +907,7 @@ png_handle_IHDR(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
|
||||
|
||||
png_debug(1, "in png_handle_IHDR");
|
||||
|
||||
if ((png_ptr->mode & PNG_HAVE_IHDR) != 0)
|
||||
png_chunk_error(png_ptr, "out of place");
|
||||
|
||||
/* Check the length */
|
||||
if (length != 13)
|
||||
png_chunk_error(png_ptr, "invalid");
|
||||
/* Length and position are checked by the caller. */
|
||||
|
||||
png_ptr->mode |= PNG_HAVE_IHDR;
|
||||
|
||||
@@ -916,257 +961,196 @@ png_handle_IHDR(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
|
||||
png_debug1(3, "bit_depth = %d", png_ptr->bit_depth);
|
||||
png_debug1(3, "channels = %d", png_ptr->channels);
|
||||
png_debug1(3, "rowbytes = %lu", (unsigned long)png_ptr->rowbytes);
|
||||
|
||||
/* Rely on png_set_IHDR to completely validate the data and call png_error if
|
||||
* it's wrong.
|
||||
*/
|
||||
png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth,
|
||||
color_type, interlace_type, compression_type, filter_type);
|
||||
|
||||
return handled_ok;
|
||||
PNG_UNUSED(length)
|
||||
}
|
||||
|
||||
/* Read and check the palette */
|
||||
void /* PRIVATE */
|
||||
/* TODO: there are several obvious errors in this code when handling
|
||||
* out-of-place chunks and there is much over-complexity caused by trying to
|
||||
* patch up the problems.
|
||||
*/
|
||||
static png_handle_result_code
|
||||
png_handle_PLTE(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
|
||||
{
|
||||
png_color palette[PNG_MAX_PALETTE_LENGTH];
|
||||
int max_palette_length, num, i;
|
||||
#ifdef PNG_POINTER_INDEXING_SUPPORTED
|
||||
png_colorp pal_ptr;
|
||||
#endif
|
||||
png_const_charp errmsg = NULL;
|
||||
|
||||
png_debug(1, "in png_handle_PLTE");
|
||||
|
||||
if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)
|
||||
png_chunk_error(png_ptr, "missing IHDR");
|
||||
|
||||
/* Moved to before the 'after IDAT' check below because otherwise duplicate
|
||||
* PLTE chunks are potentially ignored (the spec says there shall not be more
|
||||
* than one PLTE, the error is not treated as benign, so this check trumps
|
||||
* the requirement that PLTE appears before IDAT.)
|
||||
/* 1.6.47: consistency. This used to be especially treated as a critical
|
||||
* error even in an image which is not colour mapped, there isn't a good
|
||||
* justification for treating some errors here one way and others another so
|
||||
* everything uses the same logic.
|
||||
*/
|
||||
else if ((png_ptr->mode & PNG_HAVE_PLTE) != 0)
|
||||
png_chunk_error(png_ptr, "duplicate");
|
||||
if ((png_ptr->mode & PNG_HAVE_PLTE) != 0)
|
||||
errmsg = "duplicate";
|
||||
|
||||
else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0)
|
||||
{
|
||||
/* This is benign because the non-benign error happened before, when an
|
||||
* IDAT was encountered in a color-mapped image with no PLTE.
|
||||
*/
|
||||
png_crc_finish(png_ptr, length);
|
||||
png_chunk_benign_error(png_ptr, "out of place");
|
||||
return;
|
||||
}
|
||||
errmsg = "out of place";
|
||||
|
||||
png_ptr->mode |= PNG_HAVE_PLTE;
|
||||
else if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) == 0)
|
||||
errmsg = "ignored in grayscale PNG";
|
||||
|
||||
if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) == 0)
|
||||
{
|
||||
png_crc_finish(png_ptr, length);
|
||||
png_chunk_benign_error(png_ptr, "ignored in grayscale PNG");
|
||||
return;
|
||||
}
|
||||
else if (length > 3*PNG_MAX_PALETTE_LENGTH || (length % 3) != 0)
|
||||
errmsg = "invalid";
|
||||
|
||||
#ifndef 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*PNG_MAX_PALETTE_LENGTH || length % 3)
|
||||
{
|
||||
png_crc_finish(png_ptr, length);
|
||||
|
||||
if (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE)
|
||||
png_chunk_benign_error(png_ptr, "invalid");
|
||||
|
||||
else
|
||||
png_chunk_error(png_ptr, "invalid");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* The cast is safe because 'length' is less than 3*PNG_MAX_PALETTE_LENGTH */
|
||||
num = (int)length / 3;
|
||||
|
||||
/* If the palette has 256 or fewer entries but is too large for the bit
|
||||
* depth, we don't issue an error, to preserve the behavior of previous
|
||||
* libpng versions. We silently truncate the unused extra palette entries
|
||||
* here.
|
||||
/* This drops PLTE in favour of tRNS or bKGD because both of those chunks
|
||||
* can have an effect on the rendering of the image whereas PLTE only matters
|
||||
* in the case of an 8-bit display with a decoder which controls the palette.
|
||||
*
|
||||
* The alternative here is to ignore the error and store the palette anyway;
|
||||
* destroying the tRNS will definately cause problems.
|
||||
*
|
||||
* NOTE: the case of PNG_COLOR_TYPE_PALETTE need not be considered because
|
||||
* the png_handle_ routines for the three 'after PLTE' chunks tRNS, bKGD and
|
||||
* hIST all check for a preceding PLTE in these cases.
|
||||
*/
|
||||
if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
|
||||
max_palette_length = (1 << png_ptr->bit_depth);
|
||||
else if (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE &&
|
||||
(png_has_chunk(png_ptr, tRNS) || png_has_chunk(png_ptr, bKGD)))
|
||||
errmsg = "out of place";
|
||||
|
||||
else
|
||||
max_palette_length = PNG_MAX_PALETTE_LENGTH;
|
||||
|
||||
if (num > max_palette_length)
|
||||
num = max_palette_length;
|
||||
|
||||
#ifdef PNG_POINTER_INDEXING_SUPPORTED
|
||||
for (i = 0, pal_ptr = palette; i < num; i++, pal_ptr++)
|
||||
{
|
||||
png_byte buf[3];
|
||||
|
||||
png_crc_read(png_ptr, buf, 3);
|
||||
pal_ptr->red = buf[0];
|
||||
pal_ptr->green = buf[1];
|
||||
pal_ptr->blue = buf[2];
|
||||
}
|
||||
#else
|
||||
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];
|
||||
}
|
||||
#endif
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
#ifndef PNG_READ_OPT_PLTE_SUPPORTED
|
||||
if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
|
||||
#endif
|
||||
{
|
||||
png_crc_finish(png_ptr, (png_uint_32) (length - (unsigned int)num * 3));
|
||||
}
|
||||
|
||||
#ifndef PNG_READ_OPT_PLTE_SUPPORTED
|
||||
else if (png_crc_error(png_ptr) != 0) /* 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).
|
||||
*
|
||||
* IMPLEMENTATION NOTE: this is only here because png_crc_finish uses the
|
||||
* chunk type to determine whether to check the ancillary or the critical
|
||||
* flags.
|
||||
/* If the palette has 256 or fewer entries but is too large for the bit
|
||||
* depth we don't issue an error to preserve the behavior of previous
|
||||
* libpng versions. We silently truncate the unused extra palette entries
|
||||
* here.
|
||||
*/
|
||||
if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_USE) == 0)
|
||||
{
|
||||
if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN) != 0)
|
||||
return;
|
||||
const unsigned max_palette_length =
|
||||
(png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) ?
|
||||
1U << png_ptr->bit_depth : PNG_MAX_PALETTE_LENGTH;
|
||||
|
||||
else
|
||||
png_chunk_error(png_ptr, "CRC error");
|
||||
/* The cast is safe because 'length' is less than
|
||||
* 3*PNG_MAX_PALETTE_LENGTH
|
||||
*/
|
||||
const unsigned num = (length > 3U*max_palette_length) ?
|
||||
max_palette_length : (unsigned)length / 3U;
|
||||
|
||||
unsigned i, j;
|
||||
png_byte buf[3*PNG_MAX_PALETTE_LENGTH];
|
||||
png_color palette[PNG_MAX_PALETTE_LENGTH];
|
||||
|
||||
/* Read the chunk into the buffer then read to the end of the chunk. */
|
||||
png_crc_read(png_ptr, buf, num*3U);
|
||||
png_crc_finish_critical(png_ptr, length - 3U*num,
|
||||
/* Handle as ancillary if PLTE is optional: */
|
||||
png_ptr->color_type != PNG_COLOR_TYPE_PALETTE);
|
||||
|
||||
for (i = 0U, j = 0U; i < num; i++)
|
||||
{
|
||||
palette[i].red = buf[j++];
|
||||
palette[i].green = buf[j++];
|
||||
palette[i].blue = buf[j++];
|
||||
}
|
||||
|
||||
/* Otherwise, we (optionally) emit a warning and use the chunk. */
|
||||
else if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN) == 0)
|
||||
png_chunk_warning(png_ptr, "CRC error");
|
||||
}
|
||||
#endif
|
||||
/* A valid PLTE chunk has been read */
|
||||
png_ptr->mode |= PNG_HAVE_PLTE;
|
||||
|
||||
/* TODO: png_set_PLTE has the side effect of setting png_ptr->palette to its
|
||||
* own copy of the palette. This has the side effect that when png_start_row
|
||||
* is called (this happens after any call to png_read_update_info) the
|
||||
* info_ptr palette gets changed. This is extremely unexpected and
|
||||
* confusing.
|
||||
*
|
||||
* Fix this by not sharing the palette in this way.
|
||||
*/
|
||||
png_set_PLTE(png_ptr, info_ptr, palette, num);
|
||||
|
||||
/* The three chunks, bKGD, hIST and tRNS *must* appear after PLTE and before
|
||||
* IDAT. Prior to 1.6.0 this was not checked; instead the code merely
|
||||
* checked the apparent validity of a tRNS chunk inserted before PLTE on a
|
||||
* palette PNG. 1.6.0 attempts to rigorously follow the standard and
|
||||
* therefore does a benign error if the erroneous condition is detected *and*
|
||||
* cancels the tRNS if the benign error returns. The alternative is to
|
||||
* amend the standard since it would be rather hypocritical of the standards
|
||||
* maintainers to ignore it.
|
||||
*/
|
||||
#ifdef PNG_READ_tRNS_SUPPORTED
|
||||
if (png_ptr->num_trans > 0 ||
|
||||
(info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS) != 0))
|
||||
{
|
||||
/* Cancel this because otherwise it would be used if the transforms
|
||||
* require it. Don't cancel the 'valid' flag because this would prevent
|
||||
* detection of duplicate chunks.
|
||||
/* TODO: png_set_PLTE has the side effect of setting png_ptr->palette to
|
||||
* its own copy of the palette. This has the side effect that when
|
||||
* png_start_row is called (this happens after any call to
|
||||
* png_read_update_info) the info_ptr palette gets changed. This is
|
||||
* extremely unexpected and confusing.
|
||||
*
|
||||
* REVIEW: there have been consistent bugs in the past about gamma and
|
||||
* similar transforms to colour mapped images being useless because the
|
||||
* modified palette cannot be accessed because of the above.
|
||||
*
|
||||
* CONSIDER: Fix this by not sharing the palette in this way. But does
|
||||
* this completely fix the problem?
|
||||
*/
|
||||
png_ptr->num_trans = 0;
|
||||
|
||||
if (info_ptr != NULL)
|
||||
info_ptr->num_trans = 0;
|
||||
|
||||
png_chunk_benign_error(png_ptr, "tRNS must be after");
|
||||
png_set_PLTE(png_ptr, info_ptr, palette, num);
|
||||
return handled_ok;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef PNG_READ_hIST_SUPPORTED
|
||||
if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_hIST) != 0)
|
||||
png_chunk_benign_error(png_ptr, "hIST must be after");
|
||||
#endif
|
||||
/* Here on error: errmsg is non NULL. */
|
||||
if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
|
||||
{
|
||||
png_crc_finish(png_ptr, length);
|
||||
png_chunk_error(png_ptr, errmsg);
|
||||
}
|
||||
|
||||
#ifdef PNG_READ_bKGD_SUPPORTED
|
||||
if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_bKGD) != 0)
|
||||
png_chunk_benign_error(png_ptr, "bKGD must be after");
|
||||
#endif
|
||||
else /* not critical to this image */
|
||||
{
|
||||
png_crc_finish_critical(png_ptr, length, 1/*handle as ancillary*/);
|
||||
png_chunk_benign_error(png_ptr, errmsg);
|
||||
}
|
||||
|
||||
/* Because PNG_UNUSED(errmsg) does not work if all the uses are compiled out
|
||||
* (this does happen).
|
||||
*/
|
||||
return errmsg != NULL ? handled_error : handled_error;
|
||||
}
|
||||
|
||||
void /* PRIVATE */
|
||||
/* On read the IDAT chunk is always handled specially, even if marked for
|
||||
* unknown handling (this is allowed), so:
|
||||
*/
|
||||
#define png_handle_IDAT NULL
|
||||
|
||||
static png_handle_result_code
|
||||
png_handle_IEND(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
|
||||
{
|
||||
png_debug(1, "in png_handle_IEND");
|
||||
|
||||
if ((png_ptr->mode & PNG_HAVE_IHDR) == 0 ||
|
||||
(png_ptr->mode & PNG_HAVE_IDAT) == 0)
|
||||
png_chunk_error(png_ptr, "out of place");
|
||||
|
||||
png_ptr->mode |= (PNG_AFTER_IDAT | PNG_HAVE_IEND);
|
||||
|
||||
png_crc_finish(png_ptr, length);
|
||||
|
||||
if (length != 0)
|
||||
png_chunk_benign_error(png_ptr, "invalid");
|
||||
|
||||
png_crc_finish_critical(png_ptr, length, 1/*handle as ancillary*/);
|
||||
|
||||
return handled_ok;
|
||||
PNG_UNUSED(info_ptr)
|
||||
}
|
||||
|
||||
#ifdef PNG_READ_gAMA_SUPPORTED
|
||||
void /* PRIVATE */
|
||||
static png_handle_result_code
|
||||
png_handle_gAMA(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
|
||||
{
|
||||
png_fixed_point igamma;
|
||||
png_uint_32 ugamma;
|
||||
png_byte buf[4];
|
||||
|
||||
png_debug(1, "in png_handle_gAMA");
|
||||
|
||||
if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)
|
||||
png_chunk_error(png_ptr, "missing IHDR");
|
||||
|
||||
else if ((png_ptr->mode & (PNG_HAVE_IDAT|PNG_HAVE_PLTE)) != 0)
|
||||
{
|
||||
png_crc_finish(png_ptr, length);
|
||||
png_chunk_benign_error(png_ptr, "out of place");
|
||||
return;
|
||||
}
|
||||
|
||||
if (length != 4)
|
||||
{
|
||||
png_crc_finish(png_ptr, length);
|
||||
png_chunk_benign_error(png_ptr, "invalid");
|
||||
return;
|
||||
}
|
||||
|
||||
png_crc_read(png_ptr, buf, 4);
|
||||
|
||||
if (png_crc_finish(png_ptr, 0) != 0)
|
||||
return;
|
||||
return handled_error;
|
||||
|
||||
igamma = png_get_fixed_point(NULL, buf);
|
||||
ugamma = png_get_uint_32(buf);
|
||||
|
||||
png_colorspace_set_gamma(png_ptr, &png_ptr->colorspace, igamma);
|
||||
png_colorspace_sync(png_ptr, info_ptr);
|
||||
if (ugamma > PNG_UINT_31_MAX)
|
||||
{
|
||||
png_chunk_benign_error(png_ptr, "invalid");
|
||||
return handled_error;
|
||||
}
|
||||
|
||||
png_set_gAMA_fixed(png_ptr, info_ptr, (png_fixed_point)/*SAFE*/ugamma);
|
||||
|
||||
#ifdef PNG_READ_GAMMA_SUPPORTED
|
||||
/* PNGv3: chunk precedence for gamma is cICP, [iCCP], sRGB, gAMA. gAMA is
|
||||
* at the end of the chain so simply check for an unset value.
|
||||
*/
|
||||
if (png_ptr->chunk_gamma == 0)
|
||||
png_ptr->chunk_gamma = (png_fixed_point)/*SAFE*/ugamma;
|
||||
#endif /*READ_GAMMA*/
|
||||
|
||||
return handled_ok;
|
||||
PNG_UNUSED(length)
|
||||
}
|
||||
#else
|
||||
# define png_handle_gAMA NULL
|
||||
#endif
|
||||
|
||||
#ifdef PNG_READ_sBIT_SUPPORTED
|
||||
void /* PRIVATE */
|
||||
static png_handle_result_code /* PRIVATE */
|
||||
png_handle_sBIT(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
|
||||
{
|
||||
unsigned int truelen, i;
|
||||
@@ -1175,23 +1159,6 @@ png_handle_sBIT(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
|
||||
|
||||
png_debug(1, "in png_handle_sBIT");
|
||||
|
||||
if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)
|
||||
png_chunk_error(png_ptr, "missing IHDR");
|
||||
|
||||
else if ((png_ptr->mode & (PNG_HAVE_IDAT|PNG_HAVE_PLTE)) != 0)
|
||||
{
|
||||
png_crc_finish(png_ptr, length);
|
||||
png_chunk_benign_error(png_ptr, "out of place");
|
||||
return;
|
||||
}
|
||||
|
||||
if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sBIT) != 0)
|
||||
{
|
||||
png_crc_finish(png_ptr, length);
|
||||
png_chunk_benign_error(png_ptr, "duplicate");
|
||||
return;
|
||||
}
|
||||
|
||||
if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
|
||||
{
|
||||
truelen = 3;
|
||||
@@ -1204,25 +1171,25 @@ png_handle_sBIT(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
|
||||
sample_depth = png_ptr->bit_depth;
|
||||
}
|
||||
|
||||
if (length != truelen || length > 4)
|
||||
if (length != truelen)
|
||||
{
|
||||
png_chunk_benign_error(png_ptr, "invalid");
|
||||
png_crc_finish(png_ptr, length);
|
||||
return;
|
||||
png_chunk_benign_error(png_ptr, "bad length");
|
||||
return handled_error;
|
||||
}
|
||||
|
||||
buf[0] = buf[1] = buf[2] = buf[3] = sample_depth;
|
||||
png_crc_read(png_ptr, buf, truelen);
|
||||
|
||||
if (png_crc_finish(png_ptr, 0) != 0)
|
||||
return;
|
||||
return handled_error;
|
||||
|
||||
for (i=0; i<truelen; ++i)
|
||||
{
|
||||
if (buf[i] == 0 || buf[i] > sample_depth)
|
||||
{
|
||||
png_chunk_benign_error(png_ptr, "invalid");
|
||||
return;
|
||||
return handled_error;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1234,7 +1201,7 @@ png_handle_sBIT(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
|
||||
png_ptr->sig_bit.alpha = buf[3];
|
||||
}
|
||||
|
||||
else
|
||||
else /* grayscale */
|
||||
{
|
||||
png_ptr->sig_bit.gray = buf[0];
|
||||
png_ptr->sig_bit.red = buf[0];
|
||||
@@ -1244,133 +1211,132 @@ png_handle_sBIT(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
|
||||
}
|
||||
|
||||
png_set_sBIT(png_ptr, info_ptr, &(png_ptr->sig_bit));
|
||||
return handled_ok;
|
||||
}
|
||||
#else
|
||||
# define png_handle_sBIT NULL
|
||||
#endif
|
||||
|
||||
#ifdef PNG_READ_cHRM_SUPPORTED
|
||||
void /* PRIVATE */
|
||||
static png_int_32
|
||||
png_get_int_32_checked(png_const_bytep buf, int *error)
|
||||
{
|
||||
png_uint_32 uval = png_get_uint_32(buf);
|
||||
if ((uval & 0x80000000) == 0) /* non-negative */
|
||||
return (png_int_32)uval;
|
||||
|
||||
uval = (uval ^ 0xffffffff) + 1; /* 2's complement: -x = ~x+1 */
|
||||
if ((uval & 0x80000000) == 0) /* no overflow */
|
||||
return -(png_int_32)uval;
|
||||
|
||||
/* This version of png_get_int_32 has a way of returning the error to the
|
||||
* caller, so:
|
||||
*/
|
||||
*error = 1;
|
||||
return 0; /* Safe */
|
||||
}
|
||||
|
||||
static png_handle_result_code /* PRIVATE */
|
||||
png_handle_cHRM(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
|
||||
{
|
||||
png_byte buf[32];
|
||||
int error = 0;
|
||||
png_xy xy;
|
||||
png_byte buf[32];
|
||||
|
||||
png_debug(1, "in png_handle_cHRM");
|
||||
|
||||
if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)
|
||||
png_chunk_error(png_ptr, "missing IHDR");
|
||||
|
||||
else if ((png_ptr->mode & (PNG_HAVE_IDAT|PNG_HAVE_PLTE)) != 0)
|
||||
{
|
||||
png_crc_finish(png_ptr, length);
|
||||
png_chunk_benign_error(png_ptr, "out of place");
|
||||
return;
|
||||
}
|
||||
|
||||
if (length != 32)
|
||||
{
|
||||
png_crc_finish(png_ptr, length);
|
||||
png_chunk_benign_error(png_ptr, "invalid");
|
||||
return;
|
||||
}
|
||||
|
||||
png_crc_read(png_ptr, buf, 32);
|
||||
|
||||
if (png_crc_finish(png_ptr, 0) != 0)
|
||||
return;
|
||||
return handled_error;
|
||||
|
||||
xy.whitex = png_get_fixed_point(NULL, buf);
|
||||
xy.whitey = png_get_fixed_point(NULL, buf + 4);
|
||||
xy.redx = png_get_fixed_point(NULL, buf + 8);
|
||||
xy.redy = png_get_fixed_point(NULL, buf + 12);
|
||||
xy.greenx = png_get_fixed_point(NULL, buf + 16);
|
||||
xy.greeny = png_get_fixed_point(NULL, buf + 20);
|
||||
xy.bluex = png_get_fixed_point(NULL, buf + 24);
|
||||
xy.bluey = png_get_fixed_point(NULL, buf + 28);
|
||||
xy.whitex = png_get_int_32_checked(buf + 0, &error);
|
||||
xy.whitey = png_get_int_32_checked(buf + 4, &error);
|
||||
xy.redx = png_get_int_32_checked(buf + 8, &error);
|
||||
xy.redy = png_get_int_32_checked(buf + 12, &error);
|
||||
xy.greenx = png_get_int_32_checked(buf + 16, &error);
|
||||
xy.greeny = png_get_int_32_checked(buf + 20, &error);
|
||||
xy.bluex = png_get_int_32_checked(buf + 24, &error);
|
||||
xy.bluey = png_get_int_32_checked(buf + 28, &error);
|
||||
|
||||
if (xy.whitex == PNG_FIXED_ERROR ||
|
||||
xy.whitey == PNG_FIXED_ERROR ||
|
||||
xy.redx == PNG_FIXED_ERROR ||
|
||||
xy.redy == PNG_FIXED_ERROR ||
|
||||
xy.greenx == PNG_FIXED_ERROR ||
|
||||
xy.greeny == PNG_FIXED_ERROR ||
|
||||
xy.bluex == PNG_FIXED_ERROR ||
|
||||
xy.bluey == PNG_FIXED_ERROR)
|
||||
if (error)
|
||||
{
|
||||
png_chunk_benign_error(png_ptr, "invalid values");
|
||||
return;
|
||||
png_chunk_benign_error(png_ptr, "invalid");
|
||||
return handled_error;
|
||||
}
|
||||
|
||||
/* If a colorspace error has already been output skip this chunk */
|
||||
if ((png_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) != 0)
|
||||
return;
|
||||
/* png_set_cHRM may complain about some of the values but this doesn't matter
|
||||
* because it was a cHRM and it did have vaguely (if, perhaps, ridiculous)
|
||||
* values. Ridiculousity will be checked if the values are used later.
|
||||
*/
|
||||
png_set_cHRM_fixed(png_ptr, info_ptr, xy.whitex, xy.whitey, xy.redx, xy.redy,
|
||||
xy.greenx, xy.greeny, xy.bluex, xy.bluey);
|
||||
|
||||
if ((png_ptr->colorspace.flags & PNG_COLORSPACE_FROM_cHRM) != 0)
|
||||
{
|
||||
png_ptr->colorspace.flags |= PNG_COLORSPACE_INVALID;
|
||||
png_colorspace_sync(png_ptr, info_ptr);
|
||||
png_chunk_benign_error(png_ptr, "duplicate");
|
||||
return;
|
||||
}
|
||||
/* We only use 'chromaticities' for RGB to gray */
|
||||
# ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
|
||||
/* There is no need to check sRGB here, cICP is NYI and iCCP is not
|
||||
* supported so just check mDCV.
|
||||
*/
|
||||
if (!png_has_chunk(png_ptr, mDCV))
|
||||
{
|
||||
png_ptr->chromaticities = xy;
|
||||
}
|
||||
# endif /* READ_RGB_TO_GRAY */
|
||||
|
||||
png_ptr->colorspace.flags |= PNG_COLORSPACE_FROM_cHRM;
|
||||
(void)png_colorspace_set_chromaticities(png_ptr, &png_ptr->colorspace, &xy,
|
||||
1/*prefer cHRM values*/);
|
||||
png_colorspace_sync(png_ptr, info_ptr);
|
||||
return handled_ok;
|
||||
PNG_UNUSED(length)
|
||||
}
|
||||
#else
|
||||
# define png_handle_cHRM NULL
|
||||
#endif
|
||||
|
||||
#ifdef PNG_READ_sRGB_SUPPORTED
|
||||
void /* PRIVATE */
|
||||
static png_handle_result_code /* PRIVATE */
|
||||
png_handle_sRGB(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
|
||||
{
|
||||
png_byte intent;
|
||||
|
||||
png_debug(1, "in png_handle_sRGB");
|
||||
|
||||
if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)
|
||||
png_chunk_error(png_ptr, "missing IHDR");
|
||||
|
||||
else if ((png_ptr->mode & (PNG_HAVE_IDAT|PNG_HAVE_PLTE)) != 0)
|
||||
{
|
||||
png_crc_finish(png_ptr, length);
|
||||
png_chunk_benign_error(png_ptr, "out of place");
|
||||
return;
|
||||
}
|
||||
|
||||
if (length != 1)
|
||||
{
|
||||
png_crc_finish(png_ptr, length);
|
||||
png_chunk_benign_error(png_ptr, "invalid");
|
||||
return;
|
||||
}
|
||||
|
||||
png_crc_read(png_ptr, &intent, 1);
|
||||
|
||||
if (png_crc_finish(png_ptr, 0) != 0)
|
||||
return;
|
||||
return handled_error;
|
||||
|
||||
/* If a colorspace error has already been output skip this chunk */
|
||||
if ((png_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) != 0)
|
||||
return;
|
||||
|
||||
/* Only one sRGB or iCCP chunk is allowed, use the HAVE_INTENT flag to detect
|
||||
* this.
|
||||
/* This checks the range of the "rendering intent" because it is specified in
|
||||
* the PNG spec itself; the "reserved" values will result in the chunk not
|
||||
* being accepted, just as they do with the various "reserved" values in
|
||||
* IHDR.
|
||||
*/
|
||||
if ((png_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_INTENT) != 0)
|
||||
if (intent > 3/*PNGv3 spec*/)
|
||||
{
|
||||
png_ptr->colorspace.flags |= PNG_COLORSPACE_INVALID;
|
||||
png_colorspace_sync(png_ptr, info_ptr);
|
||||
png_chunk_benign_error(png_ptr, "too many profiles");
|
||||
return;
|
||||
png_chunk_benign_error(png_ptr, "invalid");
|
||||
return handled_error;
|
||||
}
|
||||
|
||||
(void)png_colorspace_set_sRGB(png_ptr, &png_ptr->colorspace, intent);
|
||||
png_colorspace_sync(png_ptr, info_ptr);
|
||||
png_set_sRGB(png_ptr, info_ptr, intent);
|
||||
/* NOTE: png_struct::chromaticities is not set here because the RGB to gray
|
||||
* coefficients are known without a need for the chromaticities.
|
||||
*/
|
||||
|
||||
#ifdef PNG_READ_GAMMA_SUPPORTED
|
||||
/* PNGv3: chunk precedence for gamma is cICP, [iCCP], sRGB, gAMA. iCCP is
|
||||
* not supported by libpng so the only requirement is to check for cICP
|
||||
* setting the gamma (this is NYI, but this check is safe.)
|
||||
*/
|
||||
if (!png_has_chunk(png_ptr, cICP) || png_ptr->chunk_gamma == 0)
|
||||
png_ptr->chunk_gamma = PNG_GAMMA_sRGB_INVERSE;
|
||||
#endif /*READ_GAMMA*/
|
||||
|
||||
return handled_ok;
|
||||
PNG_UNUSED(length)
|
||||
}
|
||||
#else
|
||||
# define png_handle_sRGB NULL
|
||||
#endif /* READ_sRGB */
|
||||
|
||||
#ifdef PNG_READ_iCCP_SUPPORTED
|
||||
void /* PRIVATE */
|
||||
static png_handle_result_code /* PRIVATE */
|
||||
png_handle_iCCP(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
|
||||
/* Note: this does not properly handle profiles that are > 64K under DOS */
|
||||
{
|
||||
@@ -1379,44 +1345,10 @@ png_handle_iCCP(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
|
||||
|
||||
png_debug(1, "in png_handle_iCCP");
|
||||
|
||||
if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)
|
||||
png_chunk_error(png_ptr, "missing IHDR");
|
||||
|
||||
else if ((png_ptr->mode & (PNG_HAVE_IDAT|PNG_HAVE_PLTE)) != 0)
|
||||
{
|
||||
png_crc_finish(png_ptr, length);
|
||||
png_chunk_benign_error(png_ptr, "out of place");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Consistent with all the above colorspace handling an obviously *invalid*
|
||||
* chunk is just ignored, so does not invalidate the color space. An
|
||||
* alternative is to set the 'invalid' flags at the start of this routine
|
||||
* and only clear them in they were not set before and all the tests pass.
|
||||
/* PNGv3: allow PNG files with both sRGB and iCCP because the PNG spec only
|
||||
* ever said that there "should" be only one, not "shall" and the PNGv3
|
||||
* colour chunk precedence rules give a handling for this case anyway.
|
||||
*/
|
||||
|
||||
/* The keyword must be at least one character and there is a
|
||||
* terminator (0) byte and the compression method byte, and the
|
||||
* 'zlib' datastream is at least 11 bytes.
|
||||
*/
|
||||
if (length < 14)
|
||||
{
|
||||
png_crc_finish(png_ptr, length);
|
||||
png_chunk_benign_error(png_ptr, "too short");
|
||||
return;
|
||||
}
|
||||
|
||||
/* If a colorspace error has already been output skip this chunk */
|
||||
if ((png_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) != 0)
|
||||
{
|
||||
png_crc_finish(png_ptr, length);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Only one sRGB or iCCP chunk is allowed, use the HAVE_INTENT flag to detect
|
||||
* this.
|
||||
*/
|
||||
if ((png_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_INTENT) == 0)
|
||||
{
|
||||
uInt read_length, keyword_length;
|
||||
char keyword[81];
|
||||
@@ -1426,19 +1358,16 @@ png_handle_iCCP(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
|
||||
*/
|
||||
read_length = 81; /* maximum */
|
||||
if (read_length > length)
|
||||
read_length = (uInt)length;
|
||||
read_length = (uInt)/*SAFE*/length;
|
||||
|
||||
png_crc_read(png_ptr, (png_bytep)keyword, read_length);
|
||||
length -= read_length;
|
||||
|
||||
/* The minimum 'zlib' stream is assumed to be just the 2 byte header,
|
||||
* 5 bytes minimum 'deflate' stream, and the 4 byte checksum.
|
||||
*/
|
||||
if (length < 11)
|
||||
if (length < LZ77Min)
|
||||
{
|
||||
png_crc_finish(png_ptr, length);
|
||||
png_chunk_benign_error(png_ptr, "too short");
|
||||
return;
|
||||
return handled_error;
|
||||
}
|
||||
|
||||
keyword_length = 0;
|
||||
@@ -1475,15 +1404,14 @@ png_handle_iCCP(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
|
||||
*/
|
||||
png_uint_32 profile_length = png_get_uint_32(profile_header);
|
||||
|
||||
if (png_icc_check_length(png_ptr, &png_ptr->colorspace,
|
||||
keyword, profile_length) != 0)
|
||||
if (png_icc_check_length(png_ptr, keyword, profile_length) !=
|
||||
0)
|
||||
{
|
||||
/* The length is apparently ok, so we can check the 132
|
||||
* byte header.
|
||||
*/
|
||||
if (png_icc_check_header(png_ptr, &png_ptr->colorspace,
|
||||
keyword, profile_length, profile_header,
|
||||
png_ptr->color_type) != 0)
|
||||
if (png_icc_check_header(png_ptr, keyword, profile_length,
|
||||
profile_header, png_ptr->color_type) != 0)
|
||||
{
|
||||
/* Now read the tag table; a variable size buffer is
|
||||
* needed at this point, allocate one for the whole
|
||||
@@ -1493,7 +1421,7 @@ png_handle_iCCP(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
|
||||
png_uint_32 tag_count =
|
||||
png_get_uint_32(profile_header + 128);
|
||||
png_bytep profile = png_read_buffer(png_ptr,
|
||||
profile_length, 2/*silent*/);
|
||||
profile_length);
|
||||
|
||||
if (profile != NULL)
|
||||
{
|
||||
@@ -1512,8 +1440,7 @@ png_handle_iCCP(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
|
||||
if (size == 0)
|
||||
{
|
||||
if (png_icc_check_tag_table(png_ptr,
|
||||
&png_ptr->colorspace, keyword, profile_length,
|
||||
profile) != 0)
|
||||
keyword, profile_length, profile) != 0)
|
||||
{
|
||||
/* The profile has been validated for basic
|
||||
* security issues, so read the whole thing in.
|
||||
@@ -1545,13 +1472,6 @@ png_handle_iCCP(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
|
||||
png_crc_finish(png_ptr, length);
|
||||
finished = 1;
|
||||
|
||||
# if defined(PNG_sRGB_SUPPORTED) && PNG_sRGB_PROFILE_CHECKS >= 0
|
||||
/* Check for a match against sRGB */
|
||||
png_icc_set_sRGB(png_ptr,
|
||||
&png_ptr->colorspace, profile,
|
||||
png_ptr->zstream.adler);
|
||||
# endif
|
||||
|
||||
/* Steal the profile for info_ptr. */
|
||||
if (info_ptr != NULL)
|
||||
{
|
||||
@@ -1574,11 +1494,7 @@ png_handle_iCCP(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
png_ptr->colorspace.flags |=
|
||||
PNG_COLORSPACE_INVALID;
|
||||
errmsg = "out of memory";
|
||||
}
|
||||
}
|
||||
|
||||
/* else the profile remains in the read
|
||||
@@ -1586,13 +1502,10 @@ png_handle_iCCP(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
|
||||
* chunks.
|
||||
*/
|
||||
|
||||
if (info_ptr != NULL)
|
||||
png_colorspace_sync(png_ptr, info_ptr);
|
||||
|
||||
if (errmsg == NULL)
|
||||
{
|
||||
png_ptr->zowner = 0;
|
||||
return;
|
||||
return handled_ok;
|
||||
}
|
||||
}
|
||||
if (errmsg == NULL)
|
||||
@@ -1633,22 +1546,21 @@ png_handle_iCCP(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
|
||||
errmsg = "bad keyword";
|
||||
}
|
||||
|
||||
else
|
||||
errmsg = "too many profiles";
|
||||
|
||||
/* Failure: the reason is in 'errmsg' */
|
||||
if (finished == 0)
|
||||
png_crc_finish(png_ptr, length);
|
||||
|
||||
png_ptr->colorspace.flags |= PNG_COLORSPACE_INVALID;
|
||||
png_colorspace_sync(png_ptr, info_ptr);
|
||||
if (errmsg != NULL) /* else already output */
|
||||
png_chunk_benign_error(png_ptr, errmsg);
|
||||
|
||||
return handled_error;
|
||||
}
|
||||
#else
|
||||
# define png_handle_iCCP NULL
|
||||
#endif /* READ_iCCP */
|
||||
|
||||
#ifdef PNG_READ_sPLT_SUPPORTED
|
||||
void /* PRIVATE */
|
||||
static png_handle_result_code /* PRIVATE */
|
||||
png_handle_sPLT(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
|
||||
/* Note: this does not properly handle chunks that are > 64K under DOS */
|
||||
{
|
||||
@@ -1669,43 +1581,24 @@ png_handle_sPLT(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
|
||||
if (png_ptr->user_chunk_cache_max == 1)
|
||||
{
|
||||
png_crc_finish(png_ptr, length);
|
||||
return;
|
||||
return handled_error;
|
||||
}
|
||||
|
||||
if (--png_ptr->user_chunk_cache_max == 1)
|
||||
{
|
||||
png_warning(png_ptr, "No space in chunk cache for sPLT");
|
||||
png_crc_finish(png_ptr, length);
|
||||
return;
|
||||
return handled_error;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)
|
||||
png_chunk_error(png_ptr, "missing IHDR");
|
||||
|
||||
else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0)
|
||||
{
|
||||
png_crc_finish(png_ptr, length);
|
||||
png_chunk_benign_error(png_ptr, "out of place");
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef PNG_MAX_MALLOC_64K
|
||||
if (length > 65535U)
|
||||
{
|
||||
png_crc_finish(png_ptr, length);
|
||||
png_chunk_benign_error(png_ptr, "too large to fit in memory");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
buffer = png_read_buffer(png_ptr, length+1, 2/*silent*/);
|
||||
buffer = png_read_buffer(png_ptr, length+1);
|
||||
if (buffer == NULL)
|
||||
{
|
||||
png_crc_finish(png_ptr, length);
|
||||
png_chunk_benign_error(png_ptr, "out of memory");
|
||||
return;
|
||||
return handled_error;
|
||||
}
|
||||
|
||||
|
||||
@@ -1716,7 +1609,7 @@ png_handle_sPLT(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
|
||||
png_crc_read(png_ptr, buffer, length);
|
||||
|
||||
if (png_crc_finish(png_ptr, skip) != 0)
|
||||
return;
|
||||
return handled_error;
|
||||
|
||||
buffer[length] = 0;
|
||||
|
||||
@@ -1729,7 +1622,7 @@ png_handle_sPLT(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
|
||||
if (length < 2U || entry_start > buffer + (length - 2U))
|
||||
{
|
||||
png_warning(png_ptr, "malformed sPLT chunk");
|
||||
return;
|
||||
return handled_error;
|
||||
}
|
||||
|
||||
new_palette.depth = *entry_start++;
|
||||
@@ -1743,7 +1636,7 @@ png_handle_sPLT(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
|
||||
if ((data_length % (unsigned int)entry_size) != 0)
|
||||
{
|
||||
png_warning(png_ptr, "sPLT chunk has bad length");
|
||||
return;
|
||||
return handled_error;
|
||||
}
|
||||
|
||||
dl = (png_uint_32)(data_length / (unsigned int)entry_size);
|
||||
@@ -1752,7 +1645,7 @@ png_handle_sPLT(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
|
||||
if (dl > max_dl)
|
||||
{
|
||||
png_warning(png_ptr, "sPLT chunk too long");
|
||||
return;
|
||||
return handled_error;
|
||||
}
|
||||
|
||||
new_palette.nentries = (png_int_32)(data_length / (unsigned int)entry_size);
|
||||
@@ -1763,10 +1656,9 @@ png_handle_sPLT(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
|
||||
if (new_palette.entries == NULL)
|
||||
{
|
||||
png_warning(png_ptr, "sPLT chunk requires too much memory");
|
||||
return;
|
||||
return handled_error;
|
||||
}
|
||||
|
||||
#ifdef PNG_POINTER_INDEXING_SUPPORTED
|
||||
for (i = 0; i < new_palette.nentries; i++)
|
||||
{
|
||||
pp = new_palette.entries + i;
|
||||
@@ -1789,31 +1681,6 @@ png_handle_sPLT(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
|
||||
|
||||
pp->frequency = png_get_uint_16(entry_start); entry_start += 2;
|
||||
}
|
||||
#else
|
||||
pp = new_palette.entries;
|
||||
|
||||
for (i = 0; i < new_palette.nentries; i++)
|
||||
{
|
||||
|
||||
if (new_palette.depth == 8)
|
||||
{
|
||||
pp[i].red = *entry_start++;
|
||||
pp[i].green = *entry_start++;
|
||||
pp[i].blue = *entry_start++;
|
||||
pp[i].alpha = *entry_start++;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
pp[i].red = png_get_uint_16(entry_start); entry_start += 2;
|
||||
pp[i].green = png_get_uint_16(entry_start); entry_start += 2;
|
||||
pp[i].blue = png_get_uint_16(entry_start); entry_start += 2;
|
||||
pp[i].alpha = png_get_uint_16(entry_start); entry_start += 2;
|
||||
}
|
||||
|
||||
pp[i].frequency = png_get_uint_16(entry_start); entry_start += 2;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Discard all chunk data except the name and stash that */
|
||||
new_palette.name = (png_charp)buffer;
|
||||
@@ -1821,34 +1688,20 @@ png_handle_sPLT(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
|
||||
png_set_sPLT(png_ptr, info_ptr, &new_palette, 1);
|
||||
|
||||
png_free(png_ptr, new_palette.entries);
|
||||
return handled_ok;
|
||||
}
|
||||
#else
|
||||
# define png_handle_sPLT NULL
|
||||
#endif /* READ_sPLT */
|
||||
|
||||
#ifdef PNG_READ_tRNS_SUPPORTED
|
||||
void /* PRIVATE */
|
||||
static png_handle_result_code /* PRIVATE */
|
||||
png_handle_tRNS(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
|
||||
{
|
||||
png_byte readbuf[PNG_MAX_PALETTE_LENGTH];
|
||||
|
||||
png_debug(1, "in png_handle_tRNS");
|
||||
|
||||
if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)
|
||||
png_chunk_error(png_ptr, "missing IHDR");
|
||||
|
||||
else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0)
|
||||
{
|
||||
png_crc_finish(png_ptr, length);
|
||||
png_chunk_benign_error(png_ptr, "out of place");
|
||||
return;
|
||||
}
|
||||
|
||||
else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS) != 0)
|
||||
{
|
||||
png_crc_finish(png_ptr, length);
|
||||
png_chunk_benign_error(png_ptr, "duplicate");
|
||||
return;
|
||||
}
|
||||
|
||||
if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY)
|
||||
{
|
||||
png_byte buf[2];
|
||||
@@ -1857,7 +1710,7 @@ png_handle_tRNS(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
|
||||
{
|
||||
png_crc_finish(png_ptr, length);
|
||||
png_chunk_benign_error(png_ptr, "invalid");
|
||||
return;
|
||||
return handled_error;
|
||||
}
|
||||
|
||||
png_crc_read(png_ptr, buf, 2);
|
||||
@@ -1873,7 +1726,7 @@ png_handle_tRNS(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
|
||||
{
|
||||
png_crc_finish(png_ptr, length);
|
||||
png_chunk_benign_error(png_ptr, "invalid");
|
||||
return;
|
||||
return handled_error;
|
||||
}
|
||||
|
||||
png_crc_read(png_ptr, buf, length);
|
||||
@@ -1887,10 +1740,9 @@ png_handle_tRNS(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
|
||||
{
|
||||
if ((png_ptr->mode & PNG_HAVE_PLTE) == 0)
|
||||
{
|
||||
/* TODO: is this actually an error in the ISO spec? */
|
||||
png_crc_finish(png_ptr, length);
|
||||
png_chunk_benign_error(png_ptr, "out of place");
|
||||
return;
|
||||
return handled_error;
|
||||
}
|
||||
|
||||
if (length > (unsigned int) png_ptr->num_palette ||
|
||||
@@ -1899,7 +1751,7 @@ png_handle_tRNS(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
|
||||
{
|
||||
png_crc_finish(png_ptr, length);
|
||||
png_chunk_benign_error(png_ptr, "invalid");
|
||||
return;
|
||||
return handled_error;
|
||||
}
|
||||
|
||||
png_crc_read(png_ptr, readbuf, length);
|
||||
@@ -1910,13 +1762,13 @@ png_handle_tRNS(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
|
||||
{
|
||||
png_crc_finish(png_ptr, length);
|
||||
png_chunk_benign_error(png_ptr, "invalid with alpha channel");
|
||||
return;
|
||||
return handled_error;
|
||||
}
|
||||
|
||||
if (png_crc_finish(png_ptr, 0) != 0)
|
||||
{
|
||||
png_ptr->num_trans = 0;
|
||||
return;
|
||||
return handled_error;
|
||||
}
|
||||
|
||||
/* TODO: this is a horrible side effect in the palette case because the
|
||||
@@ -1925,11 +1777,14 @@ png_handle_tRNS(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
|
||||
*/
|
||||
png_set_tRNS(png_ptr, info_ptr, readbuf, png_ptr->num_trans,
|
||||
&(png_ptr->trans_color));
|
||||
return handled_ok;
|
||||
}
|
||||
#else
|
||||
# define png_handle_tRNS NULL
|
||||
#endif
|
||||
|
||||
#ifdef PNG_READ_bKGD_SUPPORTED
|
||||
void /* PRIVATE */
|
||||
static png_handle_result_code /* PRIVATE */
|
||||
png_handle_bKGD(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
|
||||
{
|
||||
unsigned int truelen;
|
||||
@@ -1938,27 +1793,17 @@ png_handle_bKGD(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
|
||||
|
||||
png_debug(1, "in png_handle_bKGD");
|
||||
|
||||
if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)
|
||||
png_chunk_error(png_ptr, "missing IHDR");
|
||||
|
||||
else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0 ||
|
||||
(png_ptr->color_type == PNG_COLOR_TYPE_PALETTE &&
|
||||
(png_ptr->mode & PNG_HAVE_PLTE) == 0))
|
||||
{
|
||||
png_crc_finish(png_ptr, length);
|
||||
png_chunk_benign_error(png_ptr, "out of place");
|
||||
return;
|
||||
}
|
||||
|
||||
else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_bKGD) != 0)
|
||||
{
|
||||
png_crc_finish(png_ptr, length);
|
||||
png_chunk_benign_error(png_ptr, "duplicate");
|
||||
return;
|
||||
}
|
||||
|
||||
if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
|
||||
{
|
||||
if ((png_ptr->mode & PNG_HAVE_PLTE) == 0)
|
||||
{
|
||||
png_crc_finish(png_ptr, length);
|
||||
png_chunk_benign_error(png_ptr, "out of place");
|
||||
return handled_error;
|
||||
}
|
||||
|
||||
truelen = 1;
|
||||
}
|
||||
|
||||
else if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0)
|
||||
truelen = 6;
|
||||
@@ -1970,13 +1815,13 @@ png_handle_bKGD(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
|
||||
{
|
||||
png_crc_finish(png_ptr, length);
|
||||
png_chunk_benign_error(png_ptr, "invalid");
|
||||
return;
|
||||
return handled_error;
|
||||
}
|
||||
|
||||
png_crc_read(png_ptr, buf, truelen);
|
||||
|
||||
if (png_crc_finish(png_ptr, 0) != 0)
|
||||
return;
|
||||
return handled_error;
|
||||
|
||||
/* We convert the index value into RGB components so that we can allow
|
||||
* arbitrary RGB values for background when we have transparency, and
|
||||
@@ -1992,7 +1837,7 @@ png_handle_bKGD(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
|
||||
if (buf[0] >= info_ptr->num_palette)
|
||||
{
|
||||
png_chunk_benign_error(png_ptr, "invalid index");
|
||||
return;
|
||||
return handled_error;
|
||||
}
|
||||
|
||||
background.red = (png_uint_16)png_ptr->palette[buf[0]].red;
|
||||
@@ -2013,7 +1858,7 @@ png_handle_bKGD(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
|
||||
if (buf[0] != 0 || buf[1] >= (unsigned int)(1 << png_ptr->bit_depth))
|
||||
{
|
||||
png_chunk_benign_error(png_ptr, "invalid gray level");
|
||||
return;
|
||||
return handled_error;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2031,7 +1876,7 @@ png_handle_bKGD(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
|
||||
if (buf[0] != 0 || buf[2] != 0 || buf[4] != 0)
|
||||
{
|
||||
png_chunk_benign_error(png_ptr, "invalid color");
|
||||
return;
|
||||
return handled_error;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2043,116 +1888,174 @@ png_handle_bKGD(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
|
||||
}
|
||||
|
||||
png_set_bKGD(png_ptr, info_ptr, &background);
|
||||
return handled_ok;
|
||||
}
|
||||
#else
|
||||
# define png_handle_bKGD NULL
|
||||
#endif
|
||||
|
||||
#ifdef PNG_READ_cICP_SUPPORTED
|
||||
void /* PRIVATE */
|
||||
static png_handle_result_code /* PRIVATE */
|
||||
png_handle_cICP(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
|
||||
{
|
||||
png_byte buf[4];
|
||||
|
||||
png_debug(1, "in png_handle_cICP");
|
||||
|
||||
if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)
|
||||
png_chunk_error(png_ptr, "missing IHDR");
|
||||
|
||||
else if ((png_ptr->mode & (PNG_HAVE_IDAT|PNG_HAVE_PLTE)) != 0)
|
||||
{
|
||||
png_crc_finish(png_ptr, length);
|
||||
png_chunk_benign_error(png_ptr, "out of place");
|
||||
return;
|
||||
}
|
||||
|
||||
else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_cICP) != 0)
|
||||
{
|
||||
png_crc_finish(png_ptr, length);
|
||||
png_chunk_benign_error(png_ptr, "duplicate");
|
||||
return;
|
||||
}
|
||||
|
||||
else if (length != 4)
|
||||
{
|
||||
png_crc_finish(png_ptr, length);
|
||||
png_chunk_benign_error(png_ptr, "invalid");
|
||||
return;
|
||||
}
|
||||
|
||||
png_crc_read(png_ptr, buf, 4);
|
||||
|
||||
if (png_crc_finish(png_ptr, 0) != 0)
|
||||
return;
|
||||
return handled_error;
|
||||
|
||||
png_set_cICP(png_ptr, info_ptr, buf[0], buf[1], buf[2], buf[3]);
|
||||
|
||||
/* We only use 'chromaticities' for RGB to gray */
|
||||
# ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
|
||||
if (!png_has_chunk(png_ptr, mDCV))
|
||||
{
|
||||
/* TODO: png_ptr->chromaticities = chromaticities; */
|
||||
}
|
||||
# endif /* READ_RGB_TO_GRAY */
|
||||
|
||||
#ifdef PNG_READ_GAMMA_SUPPORTED
|
||||
/* PNGv3: chunk precedence for gamma is cICP, [iCCP], sRGB, gAMA. cICP is
|
||||
* at the head so simply set the gamma if it can be determined. If not
|
||||
* chunk_gamma remains unchanged; sRGB and gAMA handling check it for
|
||||
* being zero.
|
||||
*/
|
||||
/* TODO: set png_struct::chunk_gamma when possible */
|
||||
#endif /*READ_GAMMA*/
|
||||
|
||||
return handled_ok;
|
||||
PNG_UNUSED(length)
|
||||
}
|
||||
#else
|
||||
# define png_handle_cICP NULL
|
||||
#endif
|
||||
|
||||
#ifdef PNG_READ_cLLI_SUPPORTED
|
||||
static png_handle_result_code /* PRIVATE */
|
||||
png_handle_cLLI(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
|
||||
{
|
||||
png_byte buf[8];
|
||||
|
||||
png_debug(1, "in png_handle_cLLI");
|
||||
|
||||
png_crc_read(png_ptr, buf, 8);
|
||||
|
||||
if (png_crc_finish(png_ptr, 0) != 0)
|
||||
return handled_error;
|
||||
|
||||
/* The error checking happens here, this puts it in just one place: */
|
||||
png_set_cLLI_fixed(png_ptr, info_ptr, png_get_uint_32(buf),
|
||||
png_get_uint_32(buf+4));
|
||||
return handled_ok;
|
||||
PNG_UNUSED(length)
|
||||
}
|
||||
#else
|
||||
# define png_handle_cLLI NULL
|
||||
#endif
|
||||
|
||||
#ifdef PNG_READ_mDCV_SUPPORTED
|
||||
static png_handle_result_code /* PRIVATE */
|
||||
png_handle_mDCV(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
|
||||
{
|
||||
png_xy chromaticities;
|
||||
png_byte buf[24];
|
||||
|
||||
png_debug(1, "in png_handle_mDCV");
|
||||
|
||||
png_crc_read(png_ptr, buf, 24);
|
||||
|
||||
if (png_crc_finish(png_ptr, 0) != 0)
|
||||
return handled_error;
|
||||
|
||||
/* The error checking happens here, this puts it in just one place. The
|
||||
* odd /50000 scaling factor makes it more difficult but the (x.y) values are
|
||||
* only two bytes so a <<1 is safe.
|
||||
*
|
||||
* WARNING: the PNG specification defines the cHRM chunk to **start** with
|
||||
* the white point (x,y). The W3C PNG v3 specification puts the white point
|
||||
* **after* R,G,B. The x,y values in mDCV are also scaled by 50,000 and
|
||||
* stored in just two bytes, whereas those in cHRM are scaled by 100,000 and
|
||||
* stored in four bytes. This is very, very confusing. These APIs remove
|
||||
* the confusion by copying the existing, well established, API.
|
||||
*/
|
||||
chromaticities.redx = png_get_uint_16(buf+ 0U) << 1; /* red x */
|
||||
chromaticities.redy = png_get_uint_16(buf+ 2U) << 1; /* red y */
|
||||
chromaticities.greenx = png_get_uint_16(buf+ 4U) << 1; /* green x */
|
||||
chromaticities.greeny = png_get_uint_16(buf+ 6U) << 1; /* green y */
|
||||
chromaticities.bluex = png_get_uint_16(buf+ 8U) << 1; /* blue x */
|
||||
chromaticities.bluey = png_get_uint_16(buf+10U) << 1; /* blue y */
|
||||
chromaticities.whitex = png_get_uint_16(buf+12U) << 1; /* white x */
|
||||
chromaticities.whitey = png_get_uint_16(buf+14U) << 1; /* white y */
|
||||
|
||||
png_set_mDCV_fixed(png_ptr, info_ptr,
|
||||
chromaticities.whitex, chromaticities.whitey,
|
||||
chromaticities.redx, chromaticities.redy,
|
||||
chromaticities.greenx, chromaticities.greeny,
|
||||
chromaticities.bluex, chromaticities.bluey,
|
||||
png_get_uint_32(buf+16U), /* peak luminance */
|
||||
png_get_uint_32(buf+20U));/* minimum perceivable luminance */
|
||||
|
||||
/* We only use 'chromaticities' for RGB to gray */
|
||||
# ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
|
||||
png_ptr->chromaticities = chromaticities;
|
||||
# endif /* READ_RGB_TO_GRAY */
|
||||
|
||||
return handled_ok;
|
||||
PNG_UNUSED(length)
|
||||
}
|
||||
#else
|
||||
# define png_handle_mDCV NULL
|
||||
#endif
|
||||
|
||||
#ifdef PNG_READ_eXIf_SUPPORTED
|
||||
void /* PRIVATE */
|
||||
static png_handle_result_code /* PRIVATE */
|
||||
png_handle_eXIf(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
|
||||
{
|
||||
unsigned int i;
|
||||
png_bytep buffer = NULL;
|
||||
|
||||
png_debug(1, "in png_handle_eXIf");
|
||||
|
||||
if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)
|
||||
png_chunk_error(png_ptr, "missing IHDR");
|
||||
buffer = png_read_buffer(png_ptr, length);
|
||||
|
||||
if (length < 2)
|
||||
{
|
||||
png_crc_finish(png_ptr, length);
|
||||
png_chunk_benign_error(png_ptr, "too short");
|
||||
return;
|
||||
}
|
||||
|
||||
else if (info_ptr == NULL || (info_ptr->valid & PNG_INFO_eXIf) != 0)
|
||||
{
|
||||
png_crc_finish(png_ptr, length);
|
||||
png_chunk_benign_error(png_ptr, "duplicate");
|
||||
return;
|
||||
}
|
||||
|
||||
info_ptr->free_me |= PNG_FREE_EXIF;
|
||||
|
||||
info_ptr->eXIf_buf = png_voidcast(png_bytep,
|
||||
png_malloc_warn(png_ptr, length));
|
||||
|
||||
if (info_ptr->eXIf_buf == NULL)
|
||||
if (buffer == NULL)
|
||||
{
|
||||
png_crc_finish(png_ptr, length);
|
||||
png_chunk_benign_error(png_ptr, "out of memory");
|
||||
return;
|
||||
return handled_error;
|
||||
}
|
||||
|
||||
for (i = 0; i < length; i++)
|
||||
png_crc_read(png_ptr, buffer, length);
|
||||
|
||||
if (png_crc_finish(png_ptr, 0) != 0)
|
||||
return handled_error;
|
||||
|
||||
/* PNGv3: the code used to check the byte order mark at the start for MM or
|
||||
* II, however PNGv3 states that the the first 4 bytes should be checked.
|
||||
* The caller ensures that there are four bytes available.
|
||||
*/
|
||||
{
|
||||
png_byte buf[1];
|
||||
png_crc_read(png_ptr, buf, 1);
|
||||
info_ptr->eXIf_buf[i] = buf[0];
|
||||
if (i == 1)
|
||||
png_uint_32 header = png_get_uint_32(buffer);
|
||||
|
||||
/* These numbers are copied from the PNGv3 spec: */
|
||||
if (header != 0x49492A00 && header != 0x4D4D002A)
|
||||
{
|
||||
if ((buf[0] != 'M' && buf[0] != 'I') ||
|
||||
(info_ptr->eXIf_buf[0] != buf[0]))
|
||||
{
|
||||
png_crc_finish(png_ptr, length - 2);
|
||||
png_chunk_benign_error(png_ptr, "incorrect byte-order specifier");
|
||||
png_free(png_ptr, info_ptr->eXIf_buf);
|
||||
info_ptr->eXIf_buf = NULL;
|
||||
return;
|
||||
}
|
||||
png_chunk_benign_error(png_ptr, "invalid");
|
||||
return handled_error;
|
||||
}
|
||||
}
|
||||
|
||||
if (png_crc_finish(png_ptr, 0) == 0)
|
||||
png_set_eXIf_1(png_ptr, info_ptr, length, info_ptr->eXIf_buf);
|
||||
|
||||
png_free(png_ptr, info_ptr->eXIf_buf);
|
||||
info_ptr->eXIf_buf = NULL;
|
||||
png_set_eXIf_1(png_ptr, info_ptr, length, buffer);
|
||||
return handled_ok;
|
||||
}
|
||||
#else
|
||||
# define png_handle_eXIf NULL
|
||||
#endif
|
||||
|
||||
#ifdef PNG_READ_hIST_SUPPORTED
|
||||
void /* PRIVATE */
|
||||
static png_handle_result_code /* PRIVATE */
|
||||
png_handle_hIST(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
|
||||
{
|
||||
unsigned int num, i;
|
||||
@@ -2160,25 +2063,13 @@ png_handle_hIST(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
|
||||
|
||||
png_debug(1, "in png_handle_hIST");
|
||||
|
||||
if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)
|
||||
png_chunk_error(png_ptr, "missing IHDR");
|
||||
|
||||
else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0 ||
|
||||
(png_ptr->mode & PNG_HAVE_PLTE) == 0)
|
||||
{
|
||||
png_crc_finish(png_ptr, length);
|
||||
png_chunk_benign_error(png_ptr, "out of place");
|
||||
return;
|
||||
}
|
||||
|
||||
else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_hIST) != 0)
|
||||
{
|
||||
png_crc_finish(png_ptr, length);
|
||||
png_chunk_benign_error(png_ptr, "duplicate");
|
||||
return;
|
||||
}
|
||||
|
||||
num = length / 2 ;
|
||||
/* This cast is safe because the chunk definition limits the length to a
|
||||
* maximum of 1024 bytes.
|
||||
*
|
||||
* TODO: maybe use png_uint_32 anyway, not unsigned int, to reduce the
|
||||
* casts.
|
||||
*/
|
||||
num = (unsigned int)length / 2 ;
|
||||
|
||||
if (length != num * 2 ||
|
||||
num != (unsigned int)png_ptr->num_palette ||
|
||||
@@ -2186,7 +2077,7 @@ png_handle_hIST(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
|
||||
{
|
||||
png_crc_finish(png_ptr, length);
|
||||
png_chunk_benign_error(png_ptr, "invalid");
|
||||
return;
|
||||
return handled_error;
|
||||
}
|
||||
|
||||
for (i = 0; i < num; i++)
|
||||
@@ -2198,14 +2089,17 @@ png_handle_hIST(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
|
||||
}
|
||||
|
||||
if (png_crc_finish(png_ptr, 0) != 0)
|
||||
return;
|
||||
return handled_error;
|
||||
|
||||
png_set_hIST(png_ptr, info_ptr, readbuf);
|
||||
return handled_ok;
|
||||
}
|
||||
#else
|
||||
# define png_handle_hIST NULL
|
||||
#endif
|
||||
|
||||
#ifdef PNG_READ_pHYs_SUPPORTED
|
||||
void /* PRIVATE */
|
||||
static png_handle_result_code /* PRIVATE */
|
||||
png_handle_pHYs(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
|
||||
{
|
||||
png_byte buf[9];
|
||||
@@ -2214,44 +2108,24 @@ png_handle_pHYs(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
|
||||
|
||||
png_debug(1, "in png_handle_pHYs");
|
||||
|
||||
if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)
|
||||
png_chunk_error(png_ptr, "missing IHDR");
|
||||
|
||||
else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0)
|
||||
{
|
||||
png_crc_finish(png_ptr, length);
|
||||
png_chunk_benign_error(png_ptr, "out of place");
|
||||
return;
|
||||
}
|
||||
|
||||
else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs) != 0)
|
||||
{
|
||||
png_crc_finish(png_ptr, length);
|
||||
png_chunk_benign_error(png_ptr, "duplicate");
|
||||
return;
|
||||
}
|
||||
|
||||
if (length != 9)
|
||||
{
|
||||
png_crc_finish(png_ptr, length);
|
||||
png_chunk_benign_error(png_ptr, "invalid");
|
||||
return;
|
||||
}
|
||||
|
||||
png_crc_read(png_ptr, buf, 9);
|
||||
|
||||
if (png_crc_finish(png_ptr, 0) != 0)
|
||||
return;
|
||||
return handled_error;
|
||||
|
||||
res_x = png_get_uint_32(buf);
|
||||
res_y = png_get_uint_32(buf + 4);
|
||||
unit_type = buf[8];
|
||||
png_set_pHYs(png_ptr, info_ptr, res_x, res_y, unit_type);
|
||||
return handled_ok;
|
||||
PNG_UNUSED(length)
|
||||
}
|
||||
#else
|
||||
# define png_handle_pHYs NULL
|
||||
#endif
|
||||
|
||||
#ifdef PNG_READ_oFFs_SUPPORTED
|
||||
void /* PRIVATE */
|
||||
static png_handle_result_code /* PRIVATE */
|
||||
png_handle_oFFs(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
|
||||
{
|
||||
png_byte buf[9];
|
||||
@@ -2260,45 +2134,25 @@ png_handle_oFFs(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
|
||||
|
||||
png_debug(1, "in png_handle_oFFs");
|
||||
|
||||
if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)
|
||||
png_chunk_error(png_ptr, "missing IHDR");
|
||||
|
||||
else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0)
|
||||
{
|
||||
png_crc_finish(png_ptr, length);
|
||||
png_chunk_benign_error(png_ptr, "out of place");
|
||||
return;
|
||||
}
|
||||
|
||||
else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_oFFs) != 0)
|
||||
{
|
||||
png_crc_finish(png_ptr, length);
|
||||
png_chunk_benign_error(png_ptr, "duplicate");
|
||||
return;
|
||||
}
|
||||
|
||||
if (length != 9)
|
||||
{
|
||||
png_crc_finish(png_ptr, length);
|
||||
png_chunk_benign_error(png_ptr, "invalid");
|
||||
return;
|
||||
}
|
||||
|
||||
png_crc_read(png_ptr, buf, 9);
|
||||
|
||||
if (png_crc_finish(png_ptr, 0) != 0)
|
||||
return;
|
||||
return handled_error;
|
||||
|
||||
offset_x = png_get_int_32(buf);
|
||||
offset_y = png_get_int_32(buf + 4);
|
||||
unit_type = buf[8];
|
||||
png_set_oFFs(png_ptr, info_ptr, offset_x, offset_y, unit_type);
|
||||
return handled_ok;
|
||||
PNG_UNUSED(length)
|
||||
}
|
||||
#else
|
||||
# define png_handle_oFFs NULL
|
||||
#endif
|
||||
|
||||
#ifdef PNG_READ_pCAL_SUPPORTED
|
||||
/* Read the pCAL chunk (described in the PNG Extensions document) */
|
||||
void /* PRIVATE */
|
||||
static png_handle_result_code /* PRIVATE */
|
||||
png_handle_pCAL(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
|
||||
{
|
||||
png_int_32 X0, X1;
|
||||
@@ -2308,40 +2162,22 @@ png_handle_pCAL(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
|
||||
int i;
|
||||
|
||||
png_debug(1, "in png_handle_pCAL");
|
||||
|
||||
if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)
|
||||
png_chunk_error(png_ptr, "missing IHDR");
|
||||
|
||||
else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0)
|
||||
{
|
||||
png_crc_finish(png_ptr, length);
|
||||
png_chunk_benign_error(png_ptr, "out of place");
|
||||
return;
|
||||
}
|
||||
|
||||
else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_pCAL) != 0)
|
||||
{
|
||||
png_crc_finish(png_ptr, length);
|
||||
png_chunk_benign_error(png_ptr, "duplicate");
|
||||
return;
|
||||
}
|
||||
|
||||
png_debug1(2, "Allocating and reading pCAL chunk data (%u bytes)",
|
||||
length + 1);
|
||||
|
||||
buffer = png_read_buffer(png_ptr, length+1, 2/*silent*/);
|
||||
buffer = png_read_buffer(png_ptr, length+1);
|
||||
|
||||
if (buffer == NULL)
|
||||
{
|
||||
png_crc_finish(png_ptr, length);
|
||||
png_chunk_benign_error(png_ptr, "out of memory");
|
||||
return;
|
||||
return handled_error;
|
||||
}
|
||||
|
||||
png_crc_read(png_ptr, buffer, length);
|
||||
|
||||
if (png_crc_finish(png_ptr, 0) != 0)
|
||||
return;
|
||||
return handled_error;
|
||||
|
||||
buffer[length] = 0; /* Null terminate the last string */
|
||||
|
||||
@@ -2357,7 +2193,7 @@ png_handle_pCAL(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
|
||||
if (endptr - buf <= 12)
|
||||
{
|
||||
png_chunk_benign_error(png_ptr, "invalid");
|
||||
return;
|
||||
return handled_error;
|
||||
}
|
||||
|
||||
png_debug(3, "Reading pCAL X0, X1, type, nparams, and units");
|
||||
@@ -2377,7 +2213,7 @@ png_handle_pCAL(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
|
||||
(type == PNG_EQUATION_HYPERBOLIC && nparams != 4))
|
||||
{
|
||||
png_chunk_benign_error(png_ptr, "invalid parameter count");
|
||||
return;
|
||||
return handled_error;
|
||||
}
|
||||
|
||||
else if (type >= PNG_EQUATION_LAST)
|
||||
@@ -2396,7 +2232,7 @@ png_handle_pCAL(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
|
||||
if (params == NULL)
|
||||
{
|
||||
png_chunk_benign_error(png_ptr, "out of memory");
|
||||
return;
|
||||
return handled_error;
|
||||
}
|
||||
|
||||
/* Get pointers to the start of each parameter string. */
|
||||
@@ -2414,20 +2250,29 @@ png_handle_pCAL(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
|
||||
{
|
||||
png_free(png_ptr, params);
|
||||
png_chunk_benign_error(png_ptr, "invalid data");
|
||||
return;
|
||||
return handled_error;
|
||||
}
|
||||
}
|
||||
|
||||
png_set_pCAL(png_ptr, info_ptr, (png_charp)buffer, X0, X1, type, nparams,
|
||||
(png_charp)units, params);
|
||||
|
||||
/* TODO: BUG: png_set_pCAL calls png_chunk_report which, in this case, calls
|
||||
* png_benign_error and that can error out.
|
||||
*
|
||||
* png_read_buffer needs to be allocated with space for both nparams and the
|
||||
* parameter strings. Not hard to do.
|
||||
*/
|
||||
png_free(png_ptr, params);
|
||||
return handled_ok;
|
||||
}
|
||||
#else
|
||||
# define png_handle_pCAL NULL
|
||||
#endif
|
||||
|
||||
#ifdef PNG_READ_sCAL_SUPPORTED
|
||||
/* Read the sCAL chunk */
|
||||
void /* PRIVATE */
|
||||
static png_handle_result_code /* PRIVATE */
|
||||
png_handle_sCAL(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
|
||||
{
|
||||
png_bytep buffer;
|
||||
@@ -2435,55 +2280,29 @@ png_handle_sCAL(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
|
||||
int state;
|
||||
|
||||
png_debug(1, "in png_handle_sCAL");
|
||||
|
||||
if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)
|
||||
png_chunk_error(png_ptr, "missing IHDR");
|
||||
|
||||
else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0)
|
||||
{
|
||||
png_crc_finish(png_ptr, length);
|
||||
png_chunk_benign_error(png_ptr, "out of place");
|
||||
return;
|
||||
}
|
||||
|
||||
else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sCAL) != 0)
|
||||
{
|
||||
png_crc_finish(png_ptr, length);
|
||||
png_chunk_benign_error(png_ptr, "duplicate");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Need unit type, width, \0, height: minimum 4 bytes */
|
||||
else if (length < 4)
|
||||
{
|
||||
png_crc_finish(png_ptr, length);
|
||||
png_chunk_benign_error(png_ptr, "invalid");
|
||||
return;
|
||||
}
|
||||
|
||||
png_debug1(2, "Allocating and reading sCAL chunk data (%u bytes)",
|
||||
length + 1);
|
||||
|
||||
buffer = png_read_buffer(png_ptr, length+1, 2/*silent*/);
|
||||
buffer = png_read_buffer(png_ptr, length+1);
|
||||
|
||||
if (buffer == NULL)
|
||||
{
|
||||
png_chunk_benign_error(png_ptr, "out of memory");
|
||||
png_crc_finish(png_ptr, length);
|
||||
return;
|
||||
png_chunk_benign_error(png_ptr, "out of memory");
|
||||
return handled_error;
|
||||
}
|
||||
|
||||
png_crc_read(png_ptr, buffer, length);
|
||||
buffer[length] = 0; /* Null terminate the last string */
|
||||
|
||||
if (png_crc_finish(png_ptr, 0) != 0)
|
||||
return;
|
||||
return handled_error;
|
||||
|
||||
/* Validate the unit. */
|
||||
if (buffer[0] != 1 && buffer[0] != 2)
|
||||
{
|
||||
png_chunk_benign_error(png_ptr, "invalid unit");
|
||||
return;
|
||||
return handled_error;
|
||||
}
|
||||
|
||||
/* Validate the ASCII numbers, need two ASCII numbers separated by
|
||||
@@ -2512,15 +2331,22 @@ png_handle_sCAL(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
|
||||
png_chunk_benign_error(png_ptr, "non-positive height");
|
||||
|
||||
else
|
||||
{
|
||||
/* This is the (only) success case. */
|
||||
png_set_sCAL_s(png_ptr, info_ptr, buffer[0],
|
||||
(png_charp)buffer+1, (png_charp)buffer+heighti);
|
||||
return handled_ok;
|
||||
}
|
||||
}
|
||||
|
||||
return handled_error;
|
||||
}
|
||||
#else
|
||||
# define png_handle_sCAL NULL
|
||||
#endif
|
||||
|
||||
#ifdef PNG_READ_tIME_SUPPORTED
|
||||
void /* PRIVATE */
|
||||
static png_handle_result_code /* PRIVATE */
|
||||
png_handle_tIME(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
|
||||
{
|
||||
png_byte buf[7];
|
||||
@@ -2528,30 +2354,17 @@ png_handle_tIME(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
|
||||
|
||||
png_debug(1, "in png_handle_tIME");
|
||||
|
||||
if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)
|
||||
png_chunk_error(png_ptr, "missing IHDR");
|
||||
|
||||
else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tIME) != 0)
|
||||
{
|
||||
png_crc_finish(png_ptr, length);
|
||||
png_chunk_benign_error(png_ptr, "duplicate");
|
||||
return;
|
||||
}
|
||||
|
||||
/* TODO: what is this doing here? It should be happened in pngread.c and
|
||||
* pngpread.c, although it could be moved to png_handle_chunk below and
|
||||
* thereby avoid some code duplication.
|
||||
*/
|
||||
if ((png_ptr->mode & PNG_HAVE_IDAT) != 0)
|
||||
png_ptr->mode |= PNG_AFTER_IDAT;
|
||||
|
||||
if (length != 7)
|
||||
{
|
||||
png_crc_finish(png_ptr, length);
|
||||
png_chunk_benign_error(png_ptr, "invalid");
|
||||
return;
|
||||
}
|
||||
|
||||
png_crc_read(png_ptr, buf, 7);
|
||||
|
||||
if (png_crc_finish(png_ptr, 0) != 0)
|
||||
return;
|
||||
return handled_error;
|
||||
|
||||
mod_time.second = buf[6];
|
||||
mod_time.minute = buf[5];
|
||||
@@ -2561,12 +2374,16 @@ png_handle_tIME(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
|
||||
mod_time.year = png_get_uint_16(buf);
|
||||
|
||||
png_set_tIME(png_ptr, info_ptr, &mod_time);
|
||||
return handled_ok;
|
||||
PNG_UNUSED(length)
|
||||
}
|
||||
#else
|
||||
# define png_handle_tIME NULL
|
||||
#endif
|
||||
|
||||
#ifdef PNG_READ_tEXt_SUPPORTED
|
||||
/* Note: this does not properly handle chunks that are > 64K under DOS */
|
||||
void /* PRIVATE */
|
||||
static png_handle_result_code /* PRIVATE */
|
||||
png_handle_tEXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
|
||||
{
|
||||
png_text text_info;
|
||||
@@ -2583,45 +2400,31 @@ png_handle_tEXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
|
||||
if (png_ptr->user_chunk_cache_max == 1)
|
||||
{
|
||||
png_crc_finish(png_ptr, length);
|
||||
return;
|
||||
return handled_error;
|
||||
}
|
||||
|
||||
if (--png_ptr->user_chunk_cache_max == 1)
|
||||
{
|
||||
png_crc_finish(png_ptr, length);
|
||||
png_chunk_benign_error(png_ptr, "no space in chunk cache");
|
||||
return;
|
||||
return handled_error;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)
|
||||
png_chunk_error(png_ptr, "missing IHDR");
|
||||
|
||||
if ((png_ptr->mode & PNG_HAVE_IDAT) != 0)
|
||||
png_ptr->mode |= PNG_AFTER_IDAT;
|
||||
|
||||
#ifdef PNG_MAX_MALLOC_64K
|
||||
if (length > 65535U)
|
||||
{
|
||||
png_crc_finish(png_ptr, length);
|
||||
png_chunk_benign_error(png_ptr, "too large to fit in memory");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
buffer = png_read_buffer(png_ptr, length+1, 1/*warn*/);
|
||||
buffer = png_read_buffer(png_ptr, length+1);
|
||||
|
||||
if (buffer == NULL)
|
||||
{
|
||||
png_crc_finish(png_ptr, length);
|
||||
png_chunk_benign_error(png_ptr, "out of memory");
|
||||
return;
|
||||
return handled_error;
|
||||
}
|
||||
|
||||
png_crc_read(png_ptr, buffer, length);
|
||||
|
||||
if (png_crc_finish(png_ptr, skip) != 0)
|
||||
return;
|
||||
return handled_error;
|
||||
|
||||
key = (png_charp)buffer;
|
||||
key[length] = 0;
|
||||
@@ -2640,14 +2443,19 @@ png_handle_tEXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
|
||||
text_info.text = text;
|
||||
text_info.text_length = strlen(text);
|
||||
|
||||
if (png_set_text_2(png_ptr, info_ptr, &text_info, 1) != 0)
|
||||
png_warning(png_ptr, "Insufficient memory to process text chunk");
|
||||
if (png_set_text_2(png_ptr, info_ptr, &text_info, 1) == 0)
|
||||
return handled_ok;
|
||||
|
||||
png_chunk_benign_error(png_ptr, "out of memory");
|
||||
return handled_error;
|
||||
}
|
||||
#else
|
||||
# define png_handle_tEXt NULL
|
||||
#endif
|
||||
|
||||
#ifdef PNG_READ_zTXt_SUPPORTED
|
||||
/* Note: this does not correctly handle chunks that are > 64K under DOS */
|
||||
void /* PRIVATE */
|
||||
static png_handle_result_code /* PRIVATE */
|
||||
png_handle_zTXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
|
||||
{
|
||||
png_const_charp errmsg = NULL;
|
||||
@@ -2662,40 +2470,35 @@ png_handle_zTXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
|
||||
if (png_ptr->user_chunk_cache_max == 1)
|
||||
{
|
||||
png_crc_finish(png_ptr, length);
|
||||
return;
|
||||
return handled_error;
|
||||
}
|
||||
|
||||
if (--png_ptr->user_chunk_cache_max == 1)
|
||||
{
|
||||
png_crc_finish(png_ptr, length);
|
||||
png_chunk_benign_error(png_ptr, "no space in chunk cache");
|
||||
return;
|
||||
return handled_error;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)
|
||||
png_chunk_error(png_ptr, "missing IHDR");
|
||||
|
||||
if ((png_ptr->mode & PNG_HAVE_IDAT) != 0)
|
||||
png_ptr->mode |= PNG_AFTER_IDAT;
|
||||
|
||||
/* Note, "length" is sufficient here; we won't be adding
|
||||
* a null terminator later.
|
||||
* a null terminator later. The limit check in png_handle_chunk should be
|
||||
* sufficient.
|
||||
*/
|
||||
buffer = png_read_buffer(png_ptr, length, 2/*silent*/);
|
||||
buffer = png_read_buffer(png_ptr, length);
|
||||
|
||||
if (buffer == NULL)
|
||||
{
|
||||
png_crc_finish(png_ptr, length);
|
||||
png_chunk_benign_error(png_ptr, "out of memory");
|
||||
return;
|
||||
return handled_error;
|
||||
}
|
||||
|
||||
png_crc_read(png_ptr, buffer, length);
|
||||
|
||||
if (png_crc_finish(png_ptr, 0) != 0)
|
||||
return;
|
||||
return handled_error;
|
||||
|
||||
/* TODO: also check that the keyword contents match the spec! */
|
||||
for (keyword_length = 0;
|
||||
@@ -2748,8 +2551,10 @@ png_handle_zTXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
|
||||
text.lang = NULL;
|
||||
text.lang_key = NULL;
|
||||
|
||||
if (png_set_text_2(png_ptr, info_ptr, &text, 1) != 0)
|
||||
errmsg = "insufficient memory";
|
||||
if (png_set_text_2(png_ptr, info_ptr, &text, 1) == 0)
|
||||
return handled_ok;
|
||||
|
||||
errmsg = "out of memory";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2757,14 +2562,16 @@ png_handle_zTXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
|
||||
errmsg = png_ptr->zstream.msg;
|
||||
}
|
||||
|
||||
if (errmsg != NULL)
|
||||
png_chunk_benign_error(png_ptr, errmsg);
|
||||
png_chunk_benign_error(png_ptr, errmsg);
|
||||
return handled_error;
|
||||
}
|
||||
#else
|
||||
# define png_handle_zTXt NULL
|
||||
#endif
|
||||
|
||||
#ifdef PNG_READ_iTXt_SUPPORTED
|
||||
/* Note: this does not correctly handle chunks that are > 64K under DOS */
|
||||
void /* PRIVATE */
|
||||
static png_handle_result_code /* PRIVATE */
|
||||
png_handle_iTXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
|
||||
{
|
||||
png_const_charp errmsg = NULL;
|
||||
@@ -2779,37 +2586,31 @@ png_handle_iTXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
|
||||
if (png_ptr->user_chunk_cache_max == 1)
|
||||
{
|
||||
png_crc_finish(png_ptr, length);
|
||||
return;
|
||||
return handled_error;
|
||||
}
|
||||
|
||||
if (--png_ptr->user_chunk_cache_max == 1)
|
||||
{
|
||||
png_crc_finish(png_ptr, length);
|
||||
png_chunk_benign_error(png_ptr, "no space in chunk cache");
|
||||
return;
|
||||
return handled_error;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)
|
||||
png_chunk_error(png_ptr, "missing IHDR");
|
||||
|
||||
if ((png_ptr->mode & PNG_HAVE_IDAT) != 0)
|
||||
png_ptr->mode |= PNG_AFTER_IDAT;
|
||||
|
||||
buffer = png_read_buffer(png_ptr, length+1, 1/*warn*/);
|
||||
buffer = png_read_buffer(png_ptr, length+1);
|
||||
|
||||
if (buffer == NULL)
|
||||
{
|
||||
png_crc_finish(png_ptr, length);
|
||||
png_chunk_benign_error(png_ptr, "out of memory");
|
||||
return;
|
||||
return handled_error;
|
||||
}
|
||||
|
||||
png_crc_read(png_ptr, buffer, length);
|
||||
|
||||
if (png_crc_finish(png_ptr, 0) != 0)
|
||||
return;
|
||||
return handled_error;
|
||||
|
||||
/* First the keyword. */
|
||||
for (prefix_length=0;
|
||||
@@ -2899,8 +2700,10 @@ png_handle_iTXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
|
||||
text.text_length = 0;
|
||||
text.itxt_length = uncompressed_length;
|
||||
|
||||
if (png_set_text_2(png_ptr, info_ptr, &text, 1) != 0)
|
||||
errmsg = "insufficient memory";
|
||||
if (png_set_text_2(png_ptr, info_ptr, &text, 1) == 0)
|
||||
return handled_ok;
|
||||
|
||||
errmsg = "out of memory";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2909,7 +2712,10 @@ png_handle_iTXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
|
||||
|
||||
if (errmsg != NULL)
|
||||
png_chunk_benign_error(png_ptr, errmsg);
|
||||
return handled_error;
|
||||
}
|
||||
#else
|
||||
# define png_handle_iTXt NULL
|
||||
#endif
|
||||
|
||||
#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
|
||||
@@ -2917,7 +2723,7 @@ png_handle_iTXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
|
||||
static int
|
||||
png_cache_unknown_chunk(png_structrp png_ptr, png_uint_32 length)
|
||||
{
|
||||
png_alloc_size_t limit = PNG_SIZE_MAX;
|
||||
const png_alloc_size_t limit = png_chunk_max(png_ptr);
|
||||
|
||||
if (png_ptr->unknown_chunk.data != NULL)
|
||||
{
|
||||
@@ -2925,16 +2731,6 @@ png_cache_unknown_chunk(png_structrp png_ptr, png_uint_32 length)
|
||||
png_ptr->unknown_chunk.data = NULL;
|
||||
}
|
||||
|
||||
# ifdef PNG_SET_USER_LIMITS_SUPPORTED
|
||||
if (png_ptr->user_chunk_malloc_max > 0 &&
|
||||
png_ptr->user_chunk_malloc_max < limit)
|
||||
limit = png_ptr->user_chunk_malloc_max;
|
||||
|
||||
# elif PNG_USER_CHUNK_MALLOC_MAX > 0
|
||||
if (PNG_USER_CHUNK_MALLOC_MAX < limit)
|
||||
limit = PNG_USER_CHUNK_MALLOC_MAX;
|
||||
# endif
|
||||
|
||||
if (length <= limit)
|
||||
{
|
||||
PNG_CSTRING_FROM_CHUNK(png_ptr->unknown_chunk.name, png_ptr->chunk_name);
|
||||
@@ -2973,11 +2769,11 @@ png_cache_unknown_chunk(png_structrp png_ptr, png_uint_32 length)
|
||||
#endif /* READ_UNKNOWN_CHUNKS */
|
||||
|
||||
/* Handle an unknown, or known but disabled, chunk */
|
||||
void /* PRIVATE */
|
||||
png_handle_result_code /*PRIVATE*/
|
||||
png_handle_unknown(png_structrp png_ptr, png_inforp info_ptr,
|
||||
png_uint_32 length, int keep)
|
||||
{
|
||||
int handled = 0; /* the chunk was handled */
|
||||
png_handle_result_code handled = handled_discarded; /* the default */
|
||||
|
||||
png_debug(1, "in png_handle_unknown");
|
||||
|
||||
@@ -3024,7 +2820,7 @@ png_handle_unknown(png_structrp png_ptr, png_inforp info_ptr,
|
||||
* error at this point unless it is to be saved.
|
||||
* positive: The chunk was handled, libpng will ignore/discard it.
|
||||
*/
|
||||
if (ret < 0)
|
||||
if (ret < 0) /* handled_error */
|
||||
png_chunk_error(png_ptr, "error in user chunk");
|
||||
|
||||
else if (ret == 0)
|
||||
@@ -3058,7 +2854,7 @@ png_handle_unknown(png_structrp png_ptr, png_inforp info_ptr,
|
||||
|
||||
else /* chunk was handled */
|
||||
{
|
||||
handled = 1;
|
||||
handled = handled_ok;
|
||||
/* Critical chunks can be safely discarded at this point. */
|
||||
keep = PNG_HANDLE_CHUNK_NEVER;
|
||||
}
|
||||
@@ -3143,7 +2939,7 @@ png_handle_unknown(png_structrp png_ptr, png_inforp info_ptr,
|
||||
*/
|
||||
png_set_unknown_chunks(png_ptr, info_ptr,
|
||||
&png_ptr->unknown_chunk, 1);
|
||||
handled = 1;
|
||||
handled = handled_saved;
|
||||
# ifdef PNG_USER_LIMITS_SUPPORTED
|
||||
break;
|
||||
}
|
||||
@@ -3169,79 +2965,267 @@ png_handle_unknown(png_structrp png_ptr, png_inforp info_ptr,
|
||||
#endif /* !READ_UNKNOWN_CHUNKS */
|
||||
|
||||
/* Check for unhandled critical chunks */
|
||||
if (handled == 0 && PNG_CHUNK_CRITICAL(png_ptr->chunk_name))
|
||||
if (handled < handled_saved && PNG_CHUNK_CRITICAL(png_ptr->chunk_name))
|
||||
png_chunk_error(png_ptr, "unhandled critical chunk");
|
||||
|
||||
return handled;
|
||||
}
|
||||
|
||||
/* This function is called to verify that a chunk name is valid.
|
||||
* This function can't have the "critical chunk check" incorporated
|
||||
* into it, since in the future we will need to be able to call user
|
||||
* functions to handle unknown critical chunks after we check that
|
||||
* the chunk name itself is valid.
|
||||
*/
|
||||
|
||||
/* Bit hacking: the test for an invalid byte in the 4 byte chunk name is:
|
||||
/* APNG handling: the minimal implementation of APNG handling in libpng 1.6
|
||||
* requires that those significant applications which already handle APNG not
|
||||
* get hosed. To do this ensure the code here will have to ensure than APNG
|
||||
* data by default (at least in 1.6) gets stored in the unknown chunk list.
|
||||
* Maybe this can be relaxed in a few years but at present it's just the only
|
||||
* safe way.
|
||||
*
|
||||
* ((c) < 65 || (c) > 122 || ((c) > 90 && (c) < 97))
|
||||
* ATM just cause unknown handling for all three chunks:
|
||||
*/
|
||||
#define png_handle_acTL NULL
|
||||
#define png_handle_fcTL NULL
|
||||
#define png_handle_fdAT NULL
|
||||
|
||||
void /* PRIVATE */
|
||||
png_check_chunk_name(png_const_structrp png_ptr, png_uint_32 chunk_name)
|
||||
/*
|
||||
* 1.6.47: This is the new table driven interface to all the chunk handling.
|
||||
*
|
||||
* The table describes the PNG standard rules for **reading** known chunks -
|
||||
* every chunk which has an entry in PNG_KNOWN_CHUNKS. The table contains an
|
||||
* entry for each PNG_INDEX_cHNK describing the rules.
|
||||
*
|
||||
* In this initial version the only information in the entry is the
|
||||
* png_handle_cHNK function for the chunk in question. When chunk support is
|
||||
* compiled out the entry will be NULL.
|
||||
*/
|
||||
static const struct
|
||||
{
|
||||
int i;
|
||||
png_uint_32 cn=chunk_name;
|
||||
png_handle_result_code (*handler)(
|
||||
png_structrp, png_inforp, png_uint_32 length);
|
||||
/* A chunk-specific 'handler', NULL if the chunk is not supported in this
|
||||
* build.
|
||||
*/
|
||||
|
||||
png_debug(1, "in png_check_chunk_name");
|
||||
/* Crushing these values helps on modern 32-bit architectures because the
|
||||
* pointer and the following bit fields both end up requiring 32 bits.
|
||||
* Typically this will halve the table size. On 64-bit architectures the
|
||||
* table entries will typically be 8 bytes.
|
||||
*/
|
||||
png_uint_32 max_length :12; /* Length min, max in bytes */
|
||||
png_uint_32 min_length :8;
|
||||
/* Length errors on critical chunks have special handling to preserve the
|
||||
* existing behaviour in libpng 1.6. Anciallary chunks are checked below
|
||||
* and produce a 'benign' error.
|
||||
*/
|
||||
png_uint_32 pos_before :4; /* PNG_HAVE_ values chunk must precede */
|
||||
png_uint_32 pos_after :4; /* PNG_HAVE_ values chunk must follow */
|
||||
/* NOTE: PLTE, tRNS and bKGD require special handling which depends on
|
||||
* the colour type of the base image.
|
||||
*/
|
||||
png_uint_32 multiple :1; /* Multiple occurences permitted */
|
||||
/* This is enabled for PLTE because PLTE may, in practice, be optional */
|
||||
}
|
||||
read_chunks[PNG_INDEX_unknown] =
|
||||
{
|
||||
/* Definitions as above but done indirectly by #define so that
|
||||
* PNG_KNOWN_CHUNKS can be used safely to build the table in order.
|
||||
*
|
||||
* Each CDcHNK definition lists the values for the parameters **after**
|
||||
* the first, 'handler', function. 'handler' is NULL when the chunk has no
|
||||
* compiled in support.
|
||||
*/
|
||||
# define NoCheck 0x801U /* Do not check the maximum length */
|
||||
# define Limit 0x802U /* Limit to png_chunk_max bytes */
|
||||
# define LKMin 3U+LZ77Min /* Minimum length of keyword+LZ77 */
|
||||
|
||||
for (i=1; i<=4; ++i)
|
||||
#define hIHDR PNG_HAVE_IHDR
|
||||
#define hPLTE PNG_HAVE_PLTE
|
||||
#define hIDAT PNG_HAVE_IDAT
|
||||
/* For the two chunks, tRNS and bKGD which can occur in PNGs without a PLTE
|
||||
* but must occur after the PLTE use this and put the check in the handler
|
||||
* routine for colour mapped images were PLTE is required. Also put a check
|
||||
* in PLTE for other image types to drop the PLTE if tRNS or bKGD have been
|
||||
* seen.
|
||||
*/
|
||||
#define hCOL (PNG_HAVE_PLTE|PNG_HAVE_IDAT)
|
||||
/* Used for the decoding chunks which must be before PLTE. */
|
||||
#define aIDAT PNG_AFTER_IDAT
|
||||
|
||||
/* Chunks from W3C PNG v3: */
|
||||
/* cHNK max_len, min, before, after, multiple */
|
||||
# define CDIHDR 13U, 13U, hIHDR, 0, 0
|
||||
# define CDPLTE NoCheck, 0U, 0, hIHDR, 1
|
||||
/* PLTE errors are only critical for colour-map images, consequently the
|
||||
* hander does all the checks.
|
||||
*/
|
||||
# define CDIDAT NoCheck, 0U, aIDAT, hIHDR, 1
|
||||
# define CDIEND NoCheck, 0U, 0, aIDAT, 0
|
||||
/* Historically data was allowed in IEND */
|
||||
# define CDtRNS 256U, 0U, hIDAT, hIHDR, 0
|
||||
# define CDcHRM 32U, 32U, hCOL, hIHDR, 0
|
||||
# define CDgAMA 4U, 4U, hCOL, hIHDR, 0
|
||||
# define CDiCCP NoCheck, LKMin, hCOL, hIHDR, 0
|
||||
# define CDsBIT 4U, 1U, hCOL, hIHDR, 0
|
||||
# define CDsRGB 1U, 1U, hCOL, hIHDR, 0
|
||||
# define CDcICP 4U, 4U, hCOL, hIHDR, 0
|
||||
# define CDmDCV 24U, 24U, hCOL, hIHDR, 0
|
||||
# define CDeXIf Limit, 4U, 0, hIHDR, 0
|
||||
# define CDcLLI 8U, 8U, hCOL, hIHDR, 0
|
||||
# define CDtEXt NoCheck, 2U, 0, hIHDR, 1
|
||||
/* Allocates 'length+1'; checked in the handler */
|
||||
# define CDzTXt Limit, LKMin, 0, hIHDR, 1
|
||||
# define CDiTXt NoCheck, 6U, 0, hIHDR, 1
|
||||
/* Allocates 'length+1'; checked in the handler */
|
||||
# define CDbKGD 6U, 1U, hIDAT, hIHDR, 0
|
||||
# define CDhIST 1024U, 0U, hPLTE, hIHDR, 0
|
||||
# define CDpHYs 9U, 9U, hIDAT, hIHDR, 0
|
||||
# define CDsPLT NoCheck, 3U, hIDAT, hIHDR, 1
|
||||
/* Allocates 'length+1'; checked in the handler */
|
||||
# define CDtIME 7U, 7U, 0, hIHDR, 0
|
||||
# define CDacTL 8U, 8U, hIDAT, hIHDR, 0
|
||||
# define CDfcTL 25U, 26U, 0, hIHDR, 1
|
||||
# define CDfdAT Limit, 4U, hIDAT, hIHDR, 1
|
||||
/* Supported chunks from PNG extensions 1.5.0, NYI so limit */
|
||||
# define CDoFFs 9U, 9U, hIDAT, hIHDR, 0
|
||||
# define CDpCAL NoCheck, 14U, hIDAT, hIHDR, 0
|
||||
/* Allocates 'length+1'; checked in the handler */
|
||||
# define CDsCAL Limit, 4U, hIDAT, hIHDR, 0
|
||||
/* Allocates 'length+1'; checked in the handler */
|
||||
|
||||
# define PNG_CHUNK(cHNK, index) { png_handle_ ## cHNK, CD ## cHNK },
|
||||
PNG_KNOWN_CHUNKS
|
||||
# undef PNG_CHUNK
|
||||
};
|
||||
|
||||
|
||||
static png_index
|
||||
png_chunk_index_from_name(png_uint_32 chunk_name)
|
||||
{
|
||||
/* For chunk png_cHNK return PNG_INDEX_cHNK. Return PNG_INDEX_unknown if
|
||||
* chunk_name is not known. Notice that in a particular build "known" does
|
||||
* not necessarily mean "supported", although the inverse applies.
|
||||
*/
|
||||
switch (chunk_name)
|
||||
{
|
||||
int c = cn & 0xff;
|
||||
# define PNG_CHUNK(cHNK, index)\
|
||||
case png_ ## cHNK: return PNG_INDEX_ ## cHNK; /* == index */
|
||||
|
||||
if (c < 65 || c > 122 || (c > 90 && c < 97))
|
||||
png_chunk_error(png_ptr, "invalid chunk type");
|
||||
PNG_KNOWN_CHUNKS
|
||||
|
||||
cn >>= 8;
|
||||
# undef PNG_CHUNK
|
||||
|
||||
default: return PNG_INDEX_unknown;
|
||||
}
|
||||
}
|
||||
|
||||
void /* PRIVATE */
|
||||
png_check_chunk_length(png_const_structrp png_ptr, png_uint_32 length)
|
||||
png_handle_result_code /*PRIVATE*/
|
||||
png_handle_chunk(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
|
||||
{
|
||||
png_alloc_size_t limit = PNG_UINT_31_MAX;
|
||||
/* CSE: these things don't change, these autos are just to save typing and
|
||||
* make the code more clear.
|
||||
*/
|
||||
const png_uint_32 chunk_name = png_ptr->chunk_name;
|
||||
const png_index chunk_index = png_chunk_index_from_name(chunk_name);
|
||||
|
||||
# ifdef PNG_SET_USER_LIMITS_SUPPORTED
|
||||
if (png_ptr->user_chunk_malloc_max > 0 &&
|
||||
png_ptr->user_chunk_malloc_max < limit)
|
||||
limit = png_ptr->user_chunk_malloc_max;
|
||||
# elif PNG_USER_CHUNK_MALLOC_MAX > 0
|
||||
if (PNG_USER_CHUNK_MALLOC_MAX < limit)
|
||||
limit = PNG_USER_CHUNK_MALLOC_MAX;
|
||||
# endif
|
||||
if (png_ptr->chunk_name == png_IDAT)
|
||||
png_handle_result_code handled = handled_error;
|
||||
png_const_charp errmsg = NULL;
|
||||
|
||||
/* Is this a known chunk? If not there are no checks performed here;
|
||||
* png_handle_unknown does the correct checks. This means that the values
|
||||
* for known but unsupported chunks in the above table are not used here
|
||||
* however the chunks_seen fields in png_struct are still set.
|
||||
*/
|
||||
if (chunk_index == PNG_INDEX_unknown ||
|
||||
read_chunks[chunk_index].handler == NULL)
|
||||
{
|
||||
png_alloc_size_t idat_limit = PNG_UINT_31_MAX;
|
||||
size_t row_factor =
|
||||
(size_t)png_ptr->width
|
||||
* (size_t)png_ptr->channels
|
||||
* (png_ptr->bit_depth > 8? 2: 1)
|
||||
+ 1
|
||||
+ (png_ptr->interlaced? 6: 0);
|
||||
if (png_ptr->height > PNG_UINT_32_MAX/row_factor)
|
||||
idat_limit = PNG_UINT_31_MAX;
|
||||
else
|
||||
idat_limit = png_ptr->height * row_factor;
|
||||
row_factor = row_factor > 32566? 32566 : row_factor;
|
||||
idat_limit += 6 + 5*(idat_limit/row_factor+1); /* zlib+deflate overhead */
|
||||
idat_limit=idat_limit < PNG_UINT_31_MAX? idat_limit : PNG_UINT_31_MAX;
|
||||
limit = limit < idat_limit? idat_limit : limit;
|
||||
handled = png_handle_unknown(
|
||||
png_ptr, info_ptr, length, PNG_HANDLE_CHUNK_AS_DEFAULT);
|
||||
}
|
||||
|
||||
if (length > limit)
|
||||
/* First check the position. The first check is historical; the stream must
|
||||
* start with IHDR and anything else causes libpng to give up immediately.
|
||||
*/
|
||||
else if (chunk_index != PNG_INDEX_IHDR &&
|
||||
(png_ptr->mode & PNG_HAVE_IHDR) == 0)
|
||||
png_chunk_error(png_ptr, "missing IHDR"); /* NORETURN */
|
||||
|
||||
/* Before all the pos_before chunks, after all the pos_after chunks. */
|
||||
else if (((png_ptr->mode & read_chunks[chunk_index].pos_before) != 0) ||
|
||||
((png_ptr->mode & read_chunks[chunk_index].pos_after) !=
|
||||
read_chunks[chunk_index].pos_after))
|
||||
{
|
||||
png_debug2(0," length = %lu, limit = %lu",
|
||||
(unsigned long)length,(unsigned long)limit);
|
||||
png_benign_error(png_ptr, "chunk data is too large");
|
||||
errmsg = "out of place";
|
||||
}
|
||||
|
||||
/* Now check for duplicates: duplicated critical chunks also produce a
|
||||
* full error.
|
||||
*/
|
||||
else if (read_chunks[chunk_index].multiple == 0 &&
|
||||
png_file_has_chunk(png_ptr, chunk_index))
|
||||
{
|
||||
errmsg = "duplicate";
|
||||
}
|
||||
|
||||
else if (length < read_chunks[chunk_index].min_length)
|
||||
errmsg = "too short";
|
||||
else
|
||||
{
|
||||
/* NOTE: apart from IHDR the critical chunks (PLTE, IDAT and IEND) are set
|
||||
* up above not to do any length checks.
|
||||
*
|
||||
* The png_chunk_max check ensures that the variable length chunks are
|
||||
* always checked at this point for being within the system allocation
|
||||
* limits.
|
||||
*/
|
||||
unsigned max_length = read_chunks[chunk_index].max_length;
|
||||
|
||||
switch (max_length)
|
||||
{
|
||||
case Limit:
|
||||
/* png_read_chunk_header has already png_error'ed chunks with a
|
||||
* length exceeding the 31-bit PNG limit, so just check the memory
|
||||
* limit:
|
||||
*/
|
||||
if (length <= png_chunk_max(png_ptr))
|
||||
goto MeetsLimit;
|
||||
|
||||
errmsg = "length exceeds libpng limit";
|
||||
break;
|
||||
|
||||
default:
|
||||
if (length <= max_length)
|
||||
goto MeetsLimit;
|
||||
|
||||
errmsg = "too long";
|
||||
break;
|
||||
|
||||
case NoCheck:
|
||||
MeetsLimit:
|
||||
handled = read_chunks[chunk_index].handler(
|
||||
png_ptr, info_ptr, length);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* If there was an error or the chunk was simply skipped it is not counted as
|
||||
* 'seen'.
|
||||
*/
|
||||
if (errmsg != NULL)
|
||||
{
|
||||
if (PNG_CHUNK_CRITICAL(chunk_name)) /* stop immediately */
|
||||
png_chunk_error(png_ptr, errmsg);
|
||||
else /* ancillary chunk */
|
||||
{
|
||||
/* The chunk data is skipped: */
|
||||
png_crc_finish(png_ptr, length);
|
||||
png_chunk_benign_error(png_ptr, errmsg);
|
||||
}
|
||||
}
|
||||
|
||||
else if (handled >= handled_saved)
|
||||
{
|
||||
if (chunk_index != PNG_INDEX_unknown)
|
||||
png_file_add_chunk(png_ptr, chunk_index);
|
||||
}
|
||||
|
||||
return handled;
|
||||
}
|
||||
|
||||
/* Combines the row recently read in with the existing pixels in the row. This
|
||||
@@ -4231,6 +4215,9 @@ png_read_IDAT_data(png_structrp png_ptr, png_bytep output,
|
||||
|
||||
avail_in = png_ptr->IDAT_read_size;
|
||||
|
||||
if (avail_in > png_chunk_max(png_ptr))
|
||||
avail_in = (uInt)/*SAFE*/png_chunk_max(png_ptr);
|
||||
|
||||
if (avail_in > png_ptr->idat_size)
|
||||
avail_in = (uInt)png_ptr->idat_size;
|
||||
|
||||
@@ -4238,8 +4225,13 @@ png_read_IDAT_data(png_structrp png_ptr, png_bytep output,
|
||||
* to minimize memory usage by causing lots of re-allocs, but
|
||||
* realistically doing IDAT_read_size re-allocs is not likely to be a
|
||||
* big problem.
|
||||
*
|
||||
* An error here corresponds to the system being out of memory.
|
||||
*/
|
||||
buffer = png_read_buffer(png_ptr, avail_in, 0/*error*/);
|
||||
buffer = png_read_buffer(png_ptr, avail_in);
|
||||
|
||||
if (buffer == NULL)
|
||||
png_chunk_error(png_ptr, "out of memory");
|
||||
|
||||
png_crc_read(png_ptr, buffer, avail_in);
|
||||
png_ptr->idat_size -= avail_in;
|
||||
|
||||
Vendored
+210
-53
@@ -41,27 +41,21 @@ png_set_cHRM_fixed(png_const_structrp png_ptr, png_inforp info_ptr,
|
||||
png_fixed_point red_y, png_fixed_point green_x, png_fixed_point green_y,
|
||||
png_fixed_point blue_x, png_fixed_point blue_y)
|
||||
{
|
||||
png_xy xy;
|
||||
|
||||
png_debug1(1, "in %s storage function", "cHRM fixed");
|
||||
|
||||
if (png_ptr == NULL || info_ptr == NULL)
|
||||
return;
|
||||
|
||||
xy.redx = red_x;
|
||||
xy.redy = red_y;
|
||||
xy.greenx = green_x;
|
||||
xy.greeny = green_y;
|
||||
xy.bluex = blue_x;
|
||||
xy.bluey = blue_y;
|
||||
xy.whitex = white_x;
|
||||
xy.whitey = white_y;
|
||||
info_ptr->cHRM.redx = red_x;
|
||||
info_ptr->cHRM.redy = red_y;
|
||||
info_ptr->cHRM.greenx = green_x;
|
||||
info_ptr->cHRM.greeny = green_y;
|
||||
info_ptr->cHRM.bluex = blue_x;
|
||||
info_ptr->cHRM.bluey = blue_y;
|
||||
info_ptr->cHRM.whitex = white_x;
|
||||
info_ptr->cHRM.whitey = white_y;
|
||||
|
||||
if (png_colorspace_set_chromaticities(png_ptr, &info_ptr->colorspace, &xy,
|
||||
2/* override with app values*/) != 0)
|
||||
info_ptr->colorspace.flags |= PNG_COLORSPACE_FROM_cHRM;
|
||||
|
||||
png_colorspace_sync_info(png_ptr, info_ptr);
|
||||
info_ptr->valid |= PNG_INFO_cHRM;
|
||||
}
|
||||
|
||||
void PNGFAPI
|
||||
@@ -73,6 +67,7 @@ png_set_cHRM_XYZ_fixed(png_const_structrp png_ptr, png_inforp info_ptr,
|
||||
png_fixed_point int_blue_Z)
|
||||
{
|
||||
png_XYZ XYZ;
|
||||
png_xy xy;
|
||||
|
||||
png_debug1(1, "in %s storage function", "cHRM XYZ fixed");
|
||||
|
||||
@@ -89,11 +84,14 @@ png_set_cHRM_XYZ_fixed(png_const_structrp png_ptr, png_inforp info_ptr,
|
||||
XYZ.blue_Y = int_blue_Y;
|
||||
XYZ.blue_Z = int_blue_Z;
|
||||
|
||||
if (png_colorspace_set_endpoints(png_ptr, &info_ptr->colorspace,
|
||||
&XYZ, 2) != 0)
|
||||
info_ptr->colorspace.flags |= PNG_COLORSPACE_FROM_cHRM;
|
||||
if (png_xy_from_XYZ(&xy, &XYZ) == 0)
|
||||
{
|
||||
info_ptr->cHRM = xy;
|
||||
info_ptr->valid |= PNG_INFO_cHRM;
|
||||
}
|
||||
|
||||
png_colorspace_sync_info(png_ptr, info_ptr);
|
||||
else
|
||||
png_app_error(png_ptr, "invalid cHRM XYZ");
|
||||
}
|
||||
|
||||
# ifdef PNG_FLOATING_POINT_SUPPORTED
|
||||
@@ -159,6 +157,163 @@ png_set_cICP(png_const_structrp png_ptr, png_inforp info_ptr,
|
||||
}
|
||||
#endif /* cICP */
|
||||
|
||||
#ifdef PNG_cLLI_SUPPORTED
|
||||
void PNGFAPI
|
||||
png_set_cLLI_fixed(png_const_structrp png_ptr, png_inforp info_ptr,
|
||||
/* The values below are in cd/m2 (nits) and are scaled by 10,000; not
|
||||
* 100,000 as in the case of png_fixed_point.
|
||||
*/
|
||||
png_uint_32 maxCLL, png_uint_32 maxFALL)
|
||||
{
|
||||
png_debug1(1, "in %s storage function", "cLLI");
|
||||
|
||||
if (png_ptr == NULL || info_ptr == NULL)
|
||||
return;
|
||||
|
||||
/* Check the light level range: */
|
||||
if (maxCLL > 0x7FFFFFFFU || maxFALL > 0x7FFFFFFFU)
|
||||
{
|
||||
/* The limit is 200kcd/m2; somewhat bright but not inconceivable because
|
||||
* human vision is said to run up to 100Mcd/m2. The sun is about 2Gcd/m2.
|
||||
*
|
||||
* The reference sRGB monitor is 80cd/m2 and the limit of PQ encoding is
|
||||
* 2kcd/m2.
|
||||
*/
|
||||
png_chunk_report(png_ptr, "cLLI light level exceeds PNG limit",
|
||||
PNG_CHUNK_WRITE_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
info_ptr->maxCLL = maxCLL;
|
||||
info_ptr->maxFALL = maxFALL;
|
||||
info_ptr->valid |= PNG_INFO_cLLI;
|
||||
}
|
||||
|
||||
# ifdef PNG_FLOATING_POINT_SUPPORTED
|
||||
void PNGAPI
|
||||
png_set_cLLI(png_const_structrp png_ptr, png_inforp info_ptr,
|
||||
double maxCLL, double maxFALL)
|
||||
{
|
||||
png_set_cLLI_fixed(png_ptr, info_ptr,
|
||||
png_fixed_ITU(png_ptr, maxCLL, "png_set_cLLI(maxCLL)"),
|
||||
png_fixed_ITU(png_ptr, maxFALL, "png_set_cLLI(maxFALL)"));
|
||||
}
|
||||
# endif /* FLOATING_POINT */
|
||||
#endif /* cLLI */
|
||||
|
||||
#ifdef PNG_mDCV_SUPPORTED
|
||||
static png_uint_16
|
||||
png_ITU_fixed_16(int *error, png_fixed_point v)
|
||||
{
|
||||
/* Return a safe uint16_t value scaled according to the ITU H273 rules for
|
||||
* 16-bit display chromaticities. Functions like the corresponding
|
||||
* png_fixed() internal function with regard to errors: it's an error on
|
||||
* write, a chunk_benign_error on read: See the definition of
|
||||
* png_chunk_report in pngpriv.h.
|
||||
*/
|
||||
v /= 2; /* rounds to 0 in C: avoids insignificant arithmetic errors */
|
||||
if (v > 65535 || v < 0)
|
||||
{
|
||||
*error = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (png_uint_16)/*SAFE*/v;
|
||||
}
|
||||
|
||||
void PNGAPI
|
||||
png_set_mDCV_fixed(png_const_structrp png_ptr, png_inforp info_ptr,
|
||||
png_fixed_point white_x, png_fixed_point white_y,
|
||||
png_fixed_point red_x, png_fixed_point red_y,
|
||||
png_fixed_point green_x, png_fixed_point green_y,
|
||||
png_fixed_point blue_x, png_fixed_point blue_y,
|
||||
png_uint_32 maxDL,
|
||||
png_uint_32 minDL)
|
||||
{
|
||||
png_uint_16 rx, ry, gx, gy, bx, by, wx, wy;
|
||||
int error;
|
||||
|
||||
png_debug1(1, "in %s storage function", "mDCV");
|
||||
|
||||
if (png_ptr == NULL || info_ptr == NULL)
|
||||
return;
|
||||
|
||||
/* Check the input values to ensure they are in the expected range: */
|
||||
error = 0;
|
||||
rx = png_ITU_fixed_16(&error, red_x);
|
||||
ry = png_ITU_fixed_16(&error, red_y);
|
||||
gx = png_ITU_fixed_16(&error, green_x);
|
||||
gy = png_ITU_fixed_16(&error, green_y);
|
||||
bx = png_ITU_fixed_16(&error, blue_x);
|
||||
by = png_ITU_fixed_16(&error, blue_y);
|
||||
wx = png_ITU_fixed_16(&error, white_x);
|
||||
wy = png_ITU_fixed_16(&error, white_y);
|
||||
|
||||
if (error)
|
||||
{
|
||||
png_chunk_report(png_ptr,
|
||||
"mDCV chromaticities outside representable range",
|
||||
PNG_CHUNK_WRITE_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check the light level range: */
|
||||
if (maxDL > 0x7FFFFFFFU || minDL > 0x7FFFFFFFU)
|
||||
{
|
||||
/* The limit is 200kcd/m2; somewhat bright but not inconceivable because
|
||||
* human vision is said to run up to 100Mcd/m2. The sun is about 2Gcd/m2.
|
||||
*
|
||||
* The reference sRGB monitor is 80cd/m2 and the limit of PQ encoding is
|
||||
* 2kcd/m2.
|
||||
*/
|
||||
png_chunk_report(png_ptr, "mDCV display light level exceeds PNG limit",
|
||||
PNG_CHUNK_WRITE_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
/* All values are safe, the settings are accepted.
|
||||
*
|
||||
* IMPLEMENTATION NOTE: in practice the values can be checked and assigned
|
||||
* but the result is confusing if a writing app calls png_set_mDCV more than
|
||||
* once, the second time with an invalid value. This approach is more
|
||||
* obviously correct at the cost of typing and a very slight machine
|
||||
* overhead.
|
||||
*/
|
||||
info_ptr->mastering_red_x = rx;
|
||||
info_ptr->mastering_red_y = ry;
|
||||
info_ptr->mastering_green_x = gx;
|
||||
info_ptr->mastering_green_y = gy;
|
||||
info_ptr->mastering_blue_x = bx;
|
||||
info_ptr->mastering_blue_y = by;
|
||||
info_ptr->mastering_white_x = wx;
|
||||
info_ptr->mastering_white_y = wy;
|
||||
info_ptr->mastering_maxDL = maxDL;
|
||||
info_ptr->mastering_minDL = minDL;
|
||||
info_ptr->valid |= PNG_INFO_mDCV;
|
||||
}
|
||||
|
||||
# ifdef PNG_FLOATING_POINT_SUPPORTED
|
||||
void PNGAPI
|
||||
png_set_mDCV(png_const_structrp png_ptr, png_inforp info_ptr,
|
||||
double white_x, double white_y, double red_x, double red_y, double green_x,
|
||||
double green_y, double blue_x, double blue_y,
|
||||
double maxDL, double minDL)
|
||||
{
|
||||
png_set_mDCV_fixed(png_ptr, info_ptr,
|
||||
png_fixed(png_ptr, white_x, "png_set_mDCV(white(x))"),
|
||||
png_fixed(png_ptr, white_y, "png_set_mDCV(white(y))"),
|
||||
png_fixed(png_ptr, red_x, "png_set_mDCV(red(x))"),
|
||||
png_fixed(png_ptr, red_y, "png_set_mDCV(red(y))"),
|
||||
png_fixed(png_ptr, green_x, "png_set_mDCV(green(x))"),
|
||||
png_fixed(png_ptr, green_y, "png_set_mDCV(green(y))"),
|
||||
png_fixed(png_ptr, blue_x, "png_set_mDCV(blue(x))"),
|
||||
png_fixed(png_ptr, blue_y, "png_set_mDCV(blue(y))"),
|
||||
png_fixed_ITU(png_ptr, maxDL, "png_set_mDCV(maxDL)"),
|
||||
png_fixed_ITU(png_ptr, minDL, "png_set_mDCV(minDL)"));
|
||||
}
|
||||
# endif /* FLOATING_POINT */
|
||||
#endif /* mDCV */
|
||||
|
||||
#ifdef PNG_eXIf_SUPPORTED
|
||||
void PNGAPI
|
||||
png_set_eXIf(png_const_structrp png_ptr, png_inforp info_ptr,
|
||||
@@ -210,8 +365,8 @@ png_set_gAMA_fixed(png_const_structrp png_ptr, png_inforp info_ptr,
|
||||
if (png_ptr == NULL || info_ptr == NULL)
|
||||
return;
|
||||
|
||||
png_colorspace_set_gamma(png_ptr, &info_ptr->colorspace, file_gamma);
|
||||
png_colorspace_sync_info(png_ptr, info_ptr);
|
||||
info_ptr->gamma = file_gamma;
|
||||
info_ptr->valid |= PNG_INFO_gAMA;
|
||||
}
|
||||
|
||||
# ifdef PNG_FLOATING_POINT_SUPPORTED
|
||||
@@ -670,8 +825,8 @@ png_set_sRGB(png_const_structrp png_ptr, png_inforp info_ptr, int srgb_intent)
|
||||
if (png_ptr == NULL || info_ptr == NULL)
|
||||
return;
|
||||
|
||||
(void)png_colorspace_set_sRGB(png_ptr, &info_ptr->colorspace, srgb_intent);
|
||||
png_colorspace_sync_info(png_ptr, info_ptr);
|
||||
info_ptr->rendering_intent = srgb_intent;
|
||||
info_ptr->valid |= PNG_INFO_sRGB;
|
||||
}
|
||||
|
||||
void PNGAPI
|
||||
@@ -683,15 +838,20 @@ png_set_sRGB_gAMA_and_cHRM(png_const_structrp png_ptr, png_inforp info_ptr,
|
||||
if (png_ptr == NULL || info_ptr == NULL)
|
||||
return;
|
||||
|
||||
if (png_colorspace_set_sRGB(png_ptr, &info_ptr->colorspace,
|
||||
srgb_intent) != 0)
|
||||
{
|
||||
/* This causes the gAMA and cHRM to be written too */
|
||||
info_ptr->colorspace.flags |=
|
||||
PNG_COLORSPACE_FROM_gAMA|PNG_COLORSPACE_FROM_cHRM;
|
||||
}
|
||||
png_set_sRGB(png_ptr, info_ptr, srgb_intent);
|
||||
|
||||
png_colorspace_sync_info(png_ptr, info_ptr);
|
||||
# ifdef PNG_gAMA_SUPPORTED
|
||||
png_set_gAMA_fixed(png_ptr, info_ptr, PNG_GAMMA_sRGB_INVERSE);
|
||||
# endif /* gAMA */
|
||||
|
||||
# ifdef PNG_cHRM_SUPPORTED
|
||||
png_set_cHRM_fixed(png_ptr, info_ptr,
|
||||
/* color x y */
|
||||
/* white */ 31270, 32900,
|
||||
/* red */ 64000, 33000,
|
||||
/* green */ 30000, 60000,
|
||||
/* blue */ 15000, 6000);
|
||||
# endif /* cHRM */
|
||||
}
|
||||
#endif /* sRGB */
|
||||
|
||||
@@ -714,27 +874,6 @@ png_set_iCCP(png_const_structrp png_ptr, png_inforp info_ptr,
|
||||
if (compression_type != PNG_COMPRESSION_TYPE_BASE)
|
||||
png_app_error(png_ptr, "Invalid iCCP compression method");
|
||||
|
||||
/* Set the colorspace first because this validates the profile; do not
|
||||
* override previously set app cHRM or gAMA here (because likely as not the
|
||||
* application knows better than libpng what the correct values are.) Pass
|
||||
* the info_ptr color_type field to png_colorspace_set_ICC because in the
|
||||
* write case it has not yet been stored in png_ptr.
|
||||
*/
|
||||
{
|
||||
int result = png_colorspace_set_ICC(png_ptr, &info_ptr->colorspace, name,
|
||||
proflen, profile, info_ptr->color_type);
|
||||
|
||||
png_colorspace_sync_info(png_ptr, info_ptr);
|
||||
|
||||
/* Don't do any of the copying if the profile was bad, or inconsistent. */
|
||||
if (result == 0)
|
||||
return;
|
||||
|
||||
/* But do write the gAMA and cHRM chunks from the profile. */
|
||||
info_ptr->colorspace.flags |=
|
||||
PNG_COLORSPACE_FROM_gAMA|PNG_COLORSPACE_FROM_cHRM;
|
||||
}
|
||||
|
||||
length = strlen(name)+1;
|
||||
new_iccp_name = png_voidcast(png_charp, png_malloc_warn(png_ptr, length));
|
||||
|
||||
@@ -1421,11 +1560,13 @@ png_set_keep_unknown_chunks(png_structrp png_ptr, int keep,
|
||||
98, 75, 71, 68, '\0', /* bKGD */
|
||||
99, 72, 82, 77, '\0', /* cHRM */
|
||||
99, 73, 67, 80, '\0', /* cICP */
|
||||
99, 76, 76, 73, '\0', /* cLLI */
|
||||
101, 88, 73, 102, '\0', /* eXIf */
|
||||
103, 65, 77, 65, '\0', /* gAMA */
|
||||
104, 73, 83, 84, '\0', /* hIST */
|
||||
105, 67, 67, 80, '\0', /* iCCP */
|
||||
105, 84, 88, 116, '\0', /* iTXt */
|
||||
109, 68, 67, 86, '\0', /* mDCV */
|
||||
111, 70, 70, 115, '\0', /* oFFs */
|
||||
112, 67, 65, 76, '\0', /* pCAL */
|
||||
112, 72, 89, 115, '\0', /* pHYs */
|
||||
@@ -1687,8 +1828,24 @@ png_set_chunk_malloc_max(png_structrp png_ptr,
|
||||
{
|
||||
png_debug(1, "in png_set_chunk_malloc_max");
|
||||
|
||||
/* pngstruct::user_chunk_malloc_max is initialized to a non-zero value in
|
||||
* png.c. This API supports '0' for unlimited, make sure the correct
|
||||
* (unlimited) value is set here to avoid a need to check for 0 everywhere
|
||||
* the parameter is used.
|
||||
*/
|
||||
if (png_ptr != NULL)
|
||||
png_ptr->user_chunk_malloc_max = user_chunk_malloc_max;
|
||||
{
|
||||
if (user_chunk_malloc_max == 0U) /* unlimited */
|
||||
{
|
||||
# ifdef PNG_MAX_MALLOC_64K
|
||||
png_ptr->user_chunk_malloc_max = 65536U;
|
||||
# else
|
||||
png_ptr->user_chunk_malloc_max = PNG_SIZE_MAX;
|
||||
# endif
|
||||
}
|
||||
else
|
||||
png_ptr->user_chunk_malloc_max = user_chunk_malloc_max;
|
||||
}
|
||||
}
|
||||
#endif /* ?SET_USER_LIMITS */
|
||||
|
||||
|
||||
Vendored
+49
-63
@@ -1,6 +1,6 @@
|
||||
/* pngstruct.h - header file for PNG reference library
|
||||
/* pngstruct.h - internal structures for libpng
|
||||
*
|
||||
* Copyright (c) 2018-2022 Cosmin Truta
|
||||
* Copyright (c) 2018-2025 Cosmin Truta
|
||||
* Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
|
||||
* Copyright (c) 1996-1997 Andreas Dilger
|
||||
* Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
|
||||
@@ -10,11 +10,9 @@
|
||||
* and license in png.h
|
||||
*/
|
||||
|
||||
/* The structure that holds the information to read and write PNG files.
|
||||
* The only people who need to care about what is inside of this are the
|
||||
* people who will be modifying the library for their own special needs.
|
||||
* It should NOT be accessed directly by an application.
|
||||
*/
|
||||
#ifndef PNGPRIV_H
|
||||
# error This file must not be included by applications; please include <png.h>
|
||||
#endif
|
||||
|
||||
#ifndef PNGSTRUCT_H
|
||||
#define PNGSTRUCT_H
|
||||
@@ -69,13 +67,7 @@ typedef struct png_compression_buffer
|
||||
|
||||
/* Colorspace support; structures used in png_struct, png_info and in internal
|
||||
* functions to hold and communicate information about the color space.
|
||||
*
|
||||
* PNG_COLORSPACE_SUPPORTED is only required if the application will perform
|
||||
* colorspace corrections, otherwise all the colorspace information can be
|
||||
* skipped and the size of libpng can be reduced (significantly) by compiling
|
||||
* out the colorspace support.
|
||||
*/
|
||||
#ifdef PNG_COLORSPACE_SUPPORTED
|
||||
/* The chromaticities of the red, green and blue colorants and the chromaticity
|
||||
* of the corresponding white point (i.e. of rgb(1.0,1.0,1.0)).
|
||||
*/
|
||||
@@ -96,48 +88,36 @@ typedef struct png_XYZ
|
||||
png_fixed_point green_X, green_Y, green_Z;
|
||||
png_fixed_point blue_X, blue_Y, blue_Z;
|
||||
} png_XYZ;
|
||||
#endif /* COLORSPACE */
|
||||
|
||||
#if defined(PNG_COLORSPACE_SUPPORTED) || defined(PNG_GAMMA_SUPPORTED)
|
||||
/* A colorspace is all the above plus, potentially, profile information;
|
||||
* however at present libpng does not use the profile internally so it is only
|
||||
* stored in the png_info struct (if iCCP is supported.) The rendering intent
|
||||
* is retained here and is checked.
|
||||
*
|
||||
* The file gamma encoding information is also stored here and gamma correction
|
||||
* is done by libpng, whereas color correction must currently be done by the
|
||||
* application.
|
||||
/* Chunk index values as an enum, PNG_INDEX_unknown is also a count of the
|
||||
* number of chunks.
|
||||
*/
|
||||
typedef struct png_colorspace
|
||||
#define PNG_CHUNK(cHNK, i) PNG_INDEX_ ## cHNK = (i),
|
||||
typedef enum
|
||||
{
|
||||
#ifdef PNG_GAMMA_SUPPORTED
|
||||
png_fixed_point gamma; /* File gamma */
|
||||
#endif
|
||||
PNG_KNOWN_CHUNKS
|
||||
PNG_INDEX_unknown
|
||||
} png_index;
|
||||
#undef PNG_CHUNK
|
||||
|
||||
#ifdef PNG_COLORSPACE_SUPPORTED
|
||||
png_xy end_points_xy; /* End points as chromaticities */
|
||||
png_XYZ end_points_XYZ; /* End points as CIE XYZ colorant values */
|
||||
png_uint_16 rendering_intent; /* Rendering intent of a profile */
|
||||
#endif
|
||||
/* Chunk flag values. These are (png_uint_32 values) with exactly one bit set
|
||||
* and can be combined into a flag set with bitwise 'or'.
|
||||
*
|
||||
* TODO: C23: convert these macros to C23 inlines (which are static).
|
||||
*/
|
||||
#define png_chunk_flag_from_index(i) (0x80000000U >> (31 - (i)))
|
||||
/* The flag coresponding to the given png_index enum value. This is defined
|
||||
* for png_unknown as well (until it reaches the value 32) but this should
|
||||
* not be relied on.
|
||||
*/
|
||||
|
||||
/* Flags are always defined to simplify the code. */
|
||||
png_uint_16 flags; /* As defined below */
|
||||
} png_colorspace, * PNG_RESTRICT png_colorspacerp;
|
||||
#define png_file_has_chunk(png_ptr, i)\
|
||||
(((png_ptr)->chunks & png_chunk_flag_from_index(i)) != 0)
|
||||
/* The chunk has been recorded in png_struct */
|
||||
|
||||
typedef const png_colorspace * PNG_RESTRICT png_const_colorspacerp;
|
||||
|
||||
/* General flags for the 'flags' field */
|
||||
#define PNG_COLORSPACE_HAVE_GAMMA 0x0001
|
||||
#define PNG_COLORSPACE_HAVE_ENDPOINTS 0x0002
|
||||
#define PNG_COLORSPACE_HAVE_INTENT 0x0004
|
||||
#define PNG_COLORSPACE_FROM_gAMA 0x0008
|
||||
#define PNG_COLORSPACE_FROM_cHRM 0x0010
|
||||
#define PNG_COLORSPACE_FROM_sRGB 0x0020
|
||||
#define PNG_COLORSPACE_ENDPOINTS_MATCH_sRGB 0x0040
|
||||
#define PNG_COLORSPACE_MATCHES_sRGB 0x0080 /* exact match on profile */
|
||||
#define PNG_COLORSPACE_INVALID 0x8000
|
||||
#define PNG_COLORSPACE_CANCEL(flags) (0xffff ^ (flags))
|
||||
#endif /* COLORSPACE || GAMMA */
|
||||
#define png_file_add_chunk(pnt_ptr, i)\
|
||||
((void)((png_ptr)->chunks |= png_chunk_flag_from_index(i)))
|
||||
/* Record the chunk in the png_struct */
|
||||
|
||||
struct png_struct_def
|
||||
{
|
||||
@@ -209,6 +189,11 @@ struct png_struct_def
|
||||
int zlib_set_strategy;
|
||||
#endif
|
||||
|
||||
png_uint_32 chunks; /* PNG_CF_ for every chunk read or (NYI) written */
|
||||
# define png_has_chunk(png_ptr, cHNK)\
|
||||
png_file_has_chunk(png_ptr, PNG_INDEX_ ## cHNK)
|
||||
/* Convenience accessor - use this to check for a known chunk by name */
|
||||
|
||||
png_uint_32 width; /* width of image in pixels */
|
||||
png_uint_32 height; /* height of image in pixels */
|
||||
png_uint_32 num_rows; /* number of rows in current pass */
|
||||
@@ -285,9 +270,16 @@ struct png_struct_def
|
||||
png_uint_32 flush_rows; /* number of rows written since last flush */
|
||||
#endif
|
||||
|
||||
#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
|
||||
png_xy chromaticities; /* From mDVC, cICP, [iCCP], sRGB or cHRM */
|
||||
#endif
|
||||
|
||||
#ifdef PNG_READ_GAMMA_SUPPORTED
|
||||
int gamma_shift; /* number of "insignificant" bits in 16-bit gamma */
|
||||
png_fixed_point screen_gamma; /* screen gamma value (display_exponent) */
|
||||
png_fixed_point screen_gamma; /* screen gamma value (display exponent) */
|
||||
png_fixed_point file_gamma; /* file gamma value (encoding exponent) */
|
||||
png_fixed_point chunk_gamma; /* from cICP, iCCP, sRGB or gAMA */
|
||||
png_fixed_point default_gamma;/* from png_set_alpha_mode */
|
||||
|
||||
png_bytep gamma_table; /* gamma table for 8-bit depth files */
|
||||
png_uint_16pp gamma_16_table; /* gamma table for 16-bit depth files */
|
||||
@@ -299,7 +291,7 @@ struct png_struct_def
|
||||
png_uint_16pp gamma_16_from_1; /* converts from 1.0 to screen */
|
||||
png_uint_16pp gamma_16_to_1; /* converts from file to 1.0 */
|
||||
#endif /* READ_BACKGROUND || READ_ALPHA_MODE || RGB_TO_GRAY */
|
||||
#endif
|
||||
#endif /* READ_GAMMA */
|
||||
|
||||
#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_sBIT_SUPPORTED)
|
||||
png_color_8 sig_bit; /* significant bits in each available channel */
|
||||
@@ -349,8 +341,8 @@ struct png_struct_def
|
||||
/* To do: remove this from libpng-1.7 */
|
||||
#ifdef PNG_TIME_RFC1123_SUPPORTED
|
||||
char time_buffer[29]; /* String to hold RFC 1123 time text */
|
||||
#endif
|
||||
#endif
|
||||
#endif /* TIME_RFC1123 */
|
||||
#endif /* LIBPNG_VER < 10700 */
|
||||
|
||||
/* New members added in libpng-1.0.6 */
|
||||
|
||||
@@ -360,8 +352,8 @@ struct png_struct_def
|
||||
png_voidp user_chunk_ptr;
|
||||
#ifdef PNG_READ_USER_CHUNKS_SUPPORTED
|
||||
png_user_chunk_ptr read_user_chunk_fn; /* user read chunk handler */
|
||||
#endif
|
||||
#endif
|
||||
#endif /* READ_USER_CHUNKS */
|
||||
#endif /* USER_CHUNKS */
|
||||
|
||||
#ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED
|
||||
int unknown_default; /* As PNG_HANDLE_* */
|
||||
@@ -383,7 +375,8 @@ struct png_struct_def
|
||||
|
||||
/* New member added in libpng-1.6.36 */
|
||||
#if defined(PNG_READ_EXPAND_SUPPORTED) && \
|
||||
defined(PNG_ARM_NEON_IMPLEMENTATION)
|
||||
(defined(PNG_ARM_NEON_IMPLEMENTATION) || \
|
||||
defined(PNG_RISCV_RVV_IMPLEMENTATION))
|
||||
png_bytep riffled_palette; /* buffer for accelerated palette expansion */
|
||||
#endif
|
||||
|
||||
@@ -412,7 +405,6 @@ struct png_struct_def
|
||||
|
||||
#ifdef PNG_READ_QUANTIZE_SUPPORTED
|
||||
/* The following three members were added at version 1.0.14 and 1.2.4 */
|
||||
png_bytep quantize_sort; /* working sort array */
|
||||
png_bytep index_to_palette; /* where the original index currently is
|
||||
in the palette */
|
||||
png_bytep palette_to_index; /* which original index points to this
|
||||
@@ -468,11 +460,5 @@ struct png_struct_def
|
||||
/* New member added in libpng-1.5.7 */
|
||||
void (*read_filter[PNG_FILTER_VALUE_LAST-1])(png_row_infop row_info,
|
||||
png_bytep row, png_const_bytep prev_row);
|
||||
|
||||
#ifdef PNG_READ_SUPPORTED
|
||||
#if defined(PNG_COLORSPACE_SUPPORTED) || defined(PNG_GAMMA_SUPPORTED)
|
||||
png_colorspace colorspace;
|
||||
#endif
|
||||
#endif
|
||||
};
|
||||
#endif /* PNGSTRUCT_H */
|
||||
|
||||
Vendored
+4
-4
@@ -1,6 +1,6 @@
|
||||
/* pngwio.c - functions for data output
|
||||
*
|
||||
* Copyright (c) 2018 Cosmin Truta
|
||||
* Copyright (c) 2018-2025 Cosmin Truta
|
||||
* Copyright (c) 1998-2002,2004,2006-2014,2016,2018 Glenn Randers-Pehrson
|
||||
* Copyright (c) 1996-1997 Andreas Dilger
|
||||
* Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
|
||||
@@ -54,7 +54,7 @@ png_default_write_data(png_structp png_ptr, png_bytep data, size_t length)
|
||||
if (png_ptr == NULL)
|
||||
return;
|
||||
|
||||
check = fwrite(data, 1, length, (png_FILE_p)(png_ptr->io_ptr));
|
||||
check = fwrite(data, 1, length, (FILE *)png_ptr->io_ptr);
|
||||
|
||||
if (check != length)
|
||||
png_error(png_ptr, "Write Error");
|
||||
@@ -77,12 +77,12 @@ png_flush(png_structrp png_ptr)
|
||||
void PNGCBAPI
|
||||
png_default_flush(png_structp png_ptr)
|
||||
{
|
||||
png_FILE_p io_ptr;
|
||||
FILE *io_ptr;
|
||||
|
||||
if (png_ptr == NULL)
|
||||
return;
|
||||
|
||||
io_ptr = png_voidcast(png_FILE_p, (png_ptr->io_ptr));
|
||||
io_ptr = png_voidcast(FILE *, png_ptr->io_ptr);
|
||||
fflush(io_ptr);
|
||||
}
|
||||
# endif
|
||||
|
||||
Vendored
+33
-34
@@ -157,8 +157,30 @@ png_write_info_before_PLTE(png_structrp png_ptr, png_const_inforp info_ptr)
|
||||
* space priority. As above it therefore behooves libpng to write the colour
|
||||
* space chunks in the priority order so that a streaming app need not buffer
|
||||
* them.
|
||||
*
|
||||
* PNG v3: Chunks mDCV and cLLI provide ancillary information for the
|
||||
* interpretation of the colourspace chunkgs but do not require support for
|
||||
* those chunks so are outside the "COLORSPACE" check but before the write of
|
||||
* the colourspace chunks themselves.
|
||||
*/
|
||||
#ifdef PNG_COLORSPACE_SUPPORTED
|
||||
#ifdef PNG_WRITE_cLLI_SUPPORTED
|
||||
if ((info_ptr->valid & PNG_INFO_cLLI) != 0)
|
||||
{
|
||||
png_write_cLLI_fixed(png_ptr, info_ptr->maxCLL, info_ptr->maxFALL);
|
||||
}
|
||||
#endif
|
||||
#ifdef PNG_WRITE_mDCV_SUPPORTED
|
||||
if ((info_ptr->valid & PNG_INFO_mDCV) != 0)
|
||||
{
|
||||
png_write_mDCV_fixed(png_ptr,
|
||||
info_ptr->mastering_red_x, info_ptr->mastering_red_y,
|
||||
info_ptr->mastering_green_x, info_ptr->mastering_green_y,
|
||||
info_ptr->mastering_blue_x, info_ptr->mastering_blue_y,
|
||||
info_ptr->mastering_white_x, info_ptr->mastering_white_y,
|
||||
info_ptr->mastering_maxDL, info_ptr->mastering_minDL);
|
||||
}
|
||||
#endif
|
||||
|
||||
# ifdef PNG_WRITE_cICP_SUPPORTED /* Priority 4 */
|
||||
if ((info_ptr->valid & PNG_INFO_cICP) != 0)
|
||||
{
|
||||
@@ -170,50 +192,28 @@ png_write_info_before_PLTE(png_structrp png_ptr, png_const_inforp info_ptr)
|
||||
}
|
||||
# endif
|
||||
|
||||
/* PNG v3 change: it is now permitted to write both sRGB and ICC profiles,
|
||||
* however because the libpng code auto-generates an sRGB for the
|
||||
* corresponding ICC profiles and because PNG v2 disallowed this we need
|
||||
* to only write one.
|
||||
*
|
||||
* Remove the PNG v2 warning about writing an sRGB ICC profile as well
|
||||
* because it's invalid with PNG v3.
|
||||
*/
|
||||
# ifdef PNG_WRITE_iCCP_SUPPORTED /* Priority 3 */
|
||||
if ((info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) == 0 &&
|
||||
(info_ptr->valid & PNG_INFO_iCCP) != 0)
|
||||
if ((info_ptr->valid & PNG_INFO_iCCP) != 0)
|
||||
{
|
||||
png_write_iCCP(png_ptr, info_ptr->iccp_name,
|
||||
info_ptr->iccp_profile);
|
||||
info_ptr->iccp_profile, info_ptr->iccp_proflen);
|
||||
}
|
||||
# ifdef PNG_WRITE_sRGB_SUPPORTED
|
||||
else
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# ifdef PNG_WRITE_sRGB_SUPPORTED /* Priority 2 */
|
||||
if ((info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) == 0 &&
|
||||
(info_ptr->valid & PNG_INFO_sRGB) != 0)
|
||||
png_write_sRGB(png_ptr, info_ptr->colorspace.rendering_intent);
|
||||
if ((info_ptr->valid & PNG_INFO_sRGB) != 0)
|
||||
png_write_sRGB(png_ptr, info_ptr->rendering_intent);
|
||||
# endif /* WRITE_sRGB */
|
||||
#endif /* COLORSPACE */
|
||||
|
||||
#ifdef PNG_GAMMA_SUPPORTED
|
||||
# ifdef PNG_WRITE_gAMA_SUPPORTED /* Priority 1 */
|
||||
if ((info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) == 0 &&
|
||||
(info_ptr->colorspace.flags & PNG_COLORSPACE_FROM_gAMA) != 0 &&
|
||||
(info_ptr->valid & PNG_INFO_gAMA) != 0)
|
||||
png_write_gAMA_fixed(png_ptr, info_ptr->colorspace.gamma);
|
||||
if ((info_ptr->valid & PNG_INFO_gAMA) != 0)
|
||||
png_write_gAMA_fixed(png_ptr, info_ptr->gamma);
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef PNG_COLORSPACE_SUPPORTED
|
||||
# ifdef PNG_WRITE_cHRM_SUPPORTED /* Also priority 1 */
|
||||
if ((info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) == 0 &&
|
||||
(info_ptr->colorspace.flags & PNG_COLORSPACE_FROM_cHRM) != 0 &&
|
||||
(info_ptr->valid & PNG_INFO_cHRM) != 0)
|
||||
png_write_cHRM_fixed(png_ptr, &info_ptr->colorspace.end_points_xy);
|
||||
if ((info_ptr->valid & PNG_INFO_cHRM) != 0)
|
||||
png_write_cHRM_fixed(png_ptr, &info_ptr->cHRM);
|
||||
# endif
|
||||
#endif
|
||||
|
||||
png_ptr->mode |= PNG_WROTE_INFO_BEFORE_PLTE;
|
||||
}
|
||||
@@ -2173,8 +2173,7 @@ png_image_write_main(png_voidp argument)
|
||||
* before it is written. This only applies when the input is 16-bit and
|
||||
* either there is an alpha channel or it is converted to 8-bit.
|
||||
*/
|
||||
if ((linear != 0 && alpha != 0 ) ||
|
||||
(colormap == 0 && display->convert_to_8bit != 0))
|
||||
if (linear != 0 && (alpha != 0 || display->convert_to_8bit != 0))
|
||||
{
|
||||
png_bytep row = png_voidcast(png_bytep, png_malloc(png_ptr,
|
||||
png_get_rowbytes(png_ptr, info_ptr)));
|
||||
@@ -2333,7 +2332,7 @@ int PNGAPI
|
||||
png_image_write_to_stdio(png_imagep image, FILE *file, int convert_to_8bit,
|
||||
const void *buffer, png_int_32 row_stride, const void *colormap)
|
||||
{
|
||||
/* Write the image to the given (FILE*). */
|
||||
/* Write the image to the given FILE object. */
|
||||
if (image != NULL && image->version == PNG_IMAGE_VERSION)
|
||||
{
|
||||
if (file != NULL && buffer != NULL)
|
||||
|
||||
Vendored
+49
-5
@@ -1,6 +1,6 @@
|
||||
/* pngwutil.c - utilities to write a PNG file
|
||||
*
|
||||
* Copyright (c) 2018-2024 Cosmin Truta
|
||||
* Copyright (c) 2018-2025 Cosmin Truta
|
||||
* Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
|
||||
* Copyright (c) 1996-1997 Andreas Dilger
|
||||
* Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
|
||||
@@ -1132,10 +1132,9 @@ png_write_sRGB(png_structrp png_ptr, int srgb_intent)
|
||||
/* Write an iCCP chunk */
|
||||
void /* PRIVATE */
|
||||
png_write_iCCP(png_structrp png_ptr, png_const_charp name,
|
||||
png_const_bytep profile)
|
||||
png_const_bytep profile, png_uint_32 profile_len)
|
||||
{
|
||||
png_uint_32 name_len;
|
||||
png_uint_32 profile_len;
|
||||
png_byte new_name[81]; /* 1 byte for the compression byte */
|
||||
compression_state comp;
|
||||
png_uint_32 temp;
|
||||
@@ -1148,11 +1147,12 @@ png_write_iCCP(png_structrp png_ptr, png_const_charp name,
|
||||
if (profile == NULL)
|
||||
png_error(png_ptr, "No profile for iCCP chunk"); /* internal error */
|
||||
|
||||
profile_len = png_get_uint_32(profile);
|
||||
|
||||
if (profile_len < 132)
|
||||
png_error(png_ptr, "ICC profile too short");
|
||||
|
||||
if (png_get_uint_32(profile) != profile_len)
|
||||
png_error(png_ptr, "Incorrect data in iCCP");
|
||||
|
||||
temp = (png_uint_32) (*(profile+8));
|
||||
if (temp > 3 && (profile_len & 0x03))
|
||||
png_error(png_ptr, "ICC profile length invalid (not a multiple of 4)");
|
||||
@@ -1511,6 +1511,50 @@ png_write_cICP(png_structrp png_ptr,
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef PNG_WRITE_cLLI_SUPPORTED
|
||||
void /* PRIVATE */
|
||||
png_write_cLLI_fixed(png_structrp png_ptr, png_uint_32 maxCLL,
|
||||
png_uint_32 maxFALL)
|
||||
{
|
||||
png_byte buf[8];
|
||||
|
||||
png_debug(1, "in png_write_cLLI_fixed");
|
||||
|
||||
png_save_uint_32(buf, maxCLL);
|
||||
png_save_uint_32(buf + 4, maxFALL);
|
||||
|
||||
png_write_complete_chunk(png_ptr, png_cLLI, buf, 8);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef PNG_WRITE_mDCV_SUPPORTED
|
||||
void /* PRIVATE */
|
||||
png_write_mDCV_fixed(png_structrp png_ptr,
|
||||
png_uint_16 red_x, png_uint_16 red_y,
|
||||
png_uint_16 green_x, png_uint_16 green_y,
|
||||
png_uint_16 blue_x, png_uint_16 blue_y,
|
||||
png_uint_16 white_x, png_uint_16 white_y,
|
||||
png_uint_32 maxDL, png_uint_32 minDL)
|
||||
{
|
||||
png_byte buf[24];
|
||||
|
||||
png_debug(1, "in png_write_mDCV_fixed");
|
||||
|
||||
png_save_uint_16(buf + 0, red_x);
|
||||
png_save_uint_16(buf + 2, red_y);
|
||||
png_save_uint_16(buf + 4, green_x);
|
||||
png_save_uint_16(buf + 6, green_y);
|
||||
png_save_uint_16(buf + 8, blue_x);
|
||||
png_save_uint_16(buf + 10, blue_y);
|
||||
png_save_uint_16(buf + 12, white_x);
|
||||
png_save_uint_16(buf + 14, white_y);
|
||||
png_save_uint_32(buf + 16, maxDL);
|
||||
png_save_uint_32(buf + 20, minDL);
|
||||
|
||||
png_write_complete_chunk(png_ptr, png_mDCV, buf, 24);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef PNG_WRITE_eXIf_SUPPORTED
|
||||
/* Write the Exif data */
|
||||
void /* PRIVATE */
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@
|
||||
#if PNG_POWERPC_VSX_OPT > 0
|
||||
|
||||
#ifndef __VSX__
|
||||
# error "This code requires VSX support (POWER7 and later). Please provide -mvsx compiler flag."
|
||||
# error This code requires VSX support (POWER7 and later); please compile with -mvsx
|
||||
#endif
|
||||
|
||||
#define vec_ld_unaligned(vec,data) vec = vec_vsx_ld(0,data)
|
||||
|
||||
+1
-1
@@ -46,7 +46,7 @@ static int png_have_vsx(png_structp png_ptr);
|
||||
#include PNG_POWERPC_VSX_FILE
|
||||
|
||||
#else /* PNG_POWERPC_VSX_FILE */
|
||||
# error "PNG_POWERPC_VSX_FILE undefined: no support for run-time POWERPC VSX checks"
|
||||
# error PNG_POWERPC_VSX_FILE undefined: no support for run-time POWERPC VSX checks
|
||||
#endif /* PNG_POWERPC_VSX_FILE */
|
||||
#endif /* PNG_POWERPC_VSX_CHECK_SUPPORTED */
|
||||
|
||||
|
||||
+350
@@ -0,0 +1,350 @@
|
||||
/* filter_rvv_intrinsics.c - RISC-V Vector optimized filter functions
|
||||
*
|
||||
* Copyright (c) 2023 Google LLC
|
||||
* Written by Manfred SCHLAEGL, 2022
|
||||
* Dragoș Tiselice <dtiselice@google.com>, May 2023.
|
||||
* Filip Wasil <f.wasil@samsung.com>, March 2025.
|
||||
*
|
||||
* This code is released under the libpng license.
|
||||
* For conditions of distribution and use, see the disclaimer
|
||||
* and license in png.h
|
||||
*/
|
||||
|
||||
#include "../pngpriv.h"
|
||||
|
||||
#ifdef PNG_READ_SUPPORTED
|
||||
|
||||
#if PNG_RISCV_RVV_IMPLEMENTATION == 1 /* intrinsics code from pngpriv.h */
|
||||
|
||||
#include <riscv_vector.h>
|
||||
|
||||
void
|
||||
png_read_filter_row_up_rvv(png_row_infop row_info, png_bytep row,
|
||||
png_const_bytep prev_row)
|
||||
{
|
||||
size_t len = row_info->rowbytes;
|
||||
|
||||
for (size_t vl; len > 0; len -= vl, row += vl, prev_row += vl)
|
||||
{
|
||||
vl = __riscv_vsetvl_e8m8(len);
|
||||
|
||||
vuint8m8_t prev_vals = __riscv_vle8_v_u8m8(prev_row, vl);
|
||||
vuint8m8_t row_vals = __riscv_vle8_v_u8m8(row, vl);
|
||||
|
||||
row_vals = __riscv_vadd_vv_u8m8(row_vals, prev_vals, vl);
|
||||
|
||||
__riscv_vse8_v_u8m8(row, row_vals, vl);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
png_read_filter_row_sub_rvv(size_t len, size_t bpp, unsigned char* row)
|
||||
{
|
||||
png_bytep rp_end = row + len;
|
||||
|
||||
/*
|
||||
* row: | a | x |
|
||||
*
|
||||
* a = a + x
|
||||
*
|
||||
* a .. [v0](e8)
|
||||
* x .. [v8](e8)
|
||||
*/
|
||||
|
||||
size_t vl = __riscv_vsetvl_e8m1(bpp);
|
||||
|
||||
/* a = *row */
|
||||
vuint8m1_t a = __riscv_vle8_v_u8m1(row, vl);
|
||||
row += bpp;
|
||||
|
||||
while (row < rp_end)
|
||||
{
|
||||
/* x = *row */
|
||||
vuint8m1_t x = __riscv_vle8_v_u8m1(row, vl);
|
||||
|
||||
/* a = a + x */
|
||||
a = __riscv_vadd_vv_u8m1(a, x, vl);
|
||||
|
||||
/* *row = a */
|
||||
__riscv_vse8_v_u8m1(row, a, vl);
|
||||
row += bpp;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
png_read_filter_row_sub3_rvv(png_row_infop row_info, png_bytep row,
|
||||
png_const_bytep prev_row)
|
||||
{
|
||||
size_t len = row_info->rowbytes;
|
||||
|
||||
png_read_filter_row_sub_rvv(len, 3, row);
|
||||
|
||||
PNG_UNUSED(prev_row)
|
||||
}
|
||||
|
||||
void
|
||||
png_read_filter_row_sub4_rvv(png_row_infop row_info, png_bytep row,
|
||||
png_const_bytep prev_row)
|
||||
{
|
||||
size_t len = row_info->rowbytes;
|
||||
|
||||
png_read_filter_row_sub_rvv(len, 4, row);
|
||||
|
||||
PNG_UNUSED(prev_row)
|
||||
}
|
||||
|
||||
static inline void
|
||||
png_read_filter_row_avg_rvv(size_t len, size_t bpp, unsigned char* row,
|
||||
const unsigned char* prev_row)
|
||||
{
|
||||
png_bytep rp_end = row + len;
|
||||
|
||||
/*
|
||||
* row: | a | x |
|
||||
* prev_row: | | b |
|
||||
*
|
||||
* a .. [v2](e8)
|
||||
* b .. [v4](e8)
|
||||
* x .. [v8](e8)
|
||||
* tmp .. [v12-v13](e16)
|
||||
*/
|
||||
|
||||
/* first pixel */
|
||||
|
||||
size_t vl = __riscv_vsetvl_e8m1(bpp);
|
||||
|
||||
/* b = *prev_row */
|
||||
vuint8m1_t b = __riscv_vle8_v_u8m1(prev_row, vl);
|
||||
prev_row += bpp;
|
||||
|
||||
/* x = *row */
|
||||
vuint8m1_t x = __riscv_vle8_v_u8m1(row, vl);
|
||||
|
||||
/* b = b / 2 */
|
||||
b = __riscv_vsrl_vx_u8m1(b, 1, vl);
|
||||
|
||||
/* a = x + b */
|
||||
vuint8m1_t a = __riscv_vadd_vv_u8m1(b, x, vl);
|
||||
|
||||
/* *row = a */
|
||||
__riscv_vse8_v_u8m1(row, a, vl);
|
||||
row += bpp;
|
||||
|
||||
/* remaining pixels */
|
||||
while (row < rp_end)
|
||||
{
|
||||
/* b = *prev_row */
|
||||
b = __riscv_vle8_v_u8m1(prev_row, vl);
|
||||
prev_row += bpp;
|
||||
|
||||
/* x = *row */
|
||||
x = __riscv_vle8_v_u8m1(row, vl);
|
||||
|
||||
/* tmp = a + b */
|
||||
vuint16m2_t tmp = __riscv_vwaddu_vv_u16m2(a, b, vl);
|
||||
|
||||
/* a = tmp/2 */
|
||||
a = __riscv_vnsrl_wx_u8m1(tmp, 1, vl);
|
||||
|
||||
/* a += x */
|
||||
a = __riscv_vadd_vv_u8m1(a, x, vl);
|
||||
|
||||
/* *row = a */
|
||||
__riscv_vse8_v_u8m1(row, a, vl);
|
||||
row += bpp;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
png_read_filter_row_avg3_rvv(png_row_infop row_info, png_bytep row,
|
||||
png_const_bytep prev_row)
|
||||
{
|
||||
size_t len = row_info->rowbytes;
|
||||
|
||||
png_read_filter_row_avg_rvv(len, 3, row, prev_row);
|
||||
|
||||
PNG_UNUSED(prev_row)
|
||||
}
|
||||
|
||||
void
|
||||
png_read_filter_row_avg4_rvv(png_row_infop row_info, png_bytep row,
|
||||
png_const_bytep prev_row)
|
||||
{
|
||||
size_t len = row_info->rowbytes;
|
||||
|
||||
png_read_filter_row_avg_rvv(len, 4, row, prev_row);
|
||||
|
||||
PNG_UNUSED(prev_row)
|
||||
}
|
||||
|
||||
#define MIN_CHUNK_LEN 256
|
||||
#define MAX_CHUNK_LEN 2048
|
||||
|
||||
static inline vuint8m1_t
|
||||
prefix_sum(vuint8m1_t chunk, unsigned char* carry, size_t vl,
|
||||
size_t max_chunk_len)
|
||||
{
|
||||
size_t r;
|
||||
|
||||
for (r = 1; r < MIN_CHUNK_LEN; r <<= 1)
|
||||
{
|
||||
vbool8_t shift_mask = __riscv_vmsgeu_vx_u8m1_b8(__riscv_vid_v_u8m1(vl), r, vl);
|
||||
chunk = __riscv_vadd_vv_u8m1_mu(shift_mask, chunk, chunk, __riscv_vslideup_vx_u8m1(__riscv_vundefined_u8m1(), chunk, r, vl), vl);
|
||||
}
|
||||
|
||||
for (r = MIN_CHUNK_LEN; r < MAX_CHUNK_LEN && r < max_chunk_len; r <<= 1)
|
||||
{
|
||||
vbool8_t shift_mask = __riscv_vmsgeu_vx_u8m1_b8(__riscv_vid_v_u8m1(vl), r, vl);
|
||||
chunk = __riscv_vadd_vv_u8m1_mu(shift_mask, chunk, chunk, __riscv_vslideup_vx_u8m1(__riscv_vundefined_u8m1(), chunk, r, vl), vl);
|
||||
}
|
||||
|
||||
chunk = __riscv_vadd_vx_u8m1(chunk, *carry, vl);
|
||||
*carry = __riscv_vmv_x_s_u8m1_u8(__riscv_vslidedown_vx_u8m1(chunk, vl - 1, vl));
|
||||
|
||||
return chunk;
|
||||
}
|
||||
|
||||
static inline vint16m1_t
|
||||
abs_diff(vuint16m1_t a, vuint16m1_t b, size_t vl)
|
||||
{
|
||||
vint16m1_t diff = __riscv_vreinterpret_v_u16m1_i16m1(__riscv_vsub_vv_u16m1(a, b, vl));
|
||||
vbool16_t mask = __riscv_vmslt_vx_i16m1_b16(diff, 0, vl);
|
||||
return __riscv_vrsub_vx_i16m1_m(mask, diff, 0, vl);
|
||||
}
|
||||
|
||||
static inline vint16m1_t
|
||||
abs_sum(vint16m1_t a, vint16m1_t b, size_t vl)
|
||||
{
|
||||
return __riscv_vadd_vv_i16m1(a, b, vl);
|
||||
}
|
||||
|
||||
static inline void
|
||||
png_read_filter_row_paeth_rvv(size_t len, size_t bpp, unsigned char* row,
|
||||
const unsigned char* prev)
|
||||
{
|
||||
png_bytep rp_end = row + len;
|
||||
|
||||
/*
|
||||
* row: | a | x |
|
||||
* prev: | c | b |
|
||||
*
|
||||
* a .. [v2](e8)
|
||||
* b .. [v4](e8)
|
||||
* c .. [v6](e8)
|
||||
* x .. [v8](e8)
|
||||
* p .. [v12-v13](e16)
|
||||
* pa, pb, pc .. [v16-v17, v20-v21, v24-v25](e16)
|
||||
*/
|
||||
|
||||
/* first pixel */
|
||||
|
||||
size_t vl = __riscv_vsetvl_e8m1(bpp);
|
||||
|
||||
/* a = *row */
|
||||
vuint8m1_t a = __riscv_vle8_v_u8m1(row, vl);
|
||||
|
||||
/* c = *prev */
|
||||
vuint8m1_t c = __riscv_vle8_v_u8m1(prev, vl);
|
||||
|
||||
/* a += c */
|
||||
a = __riscv_vadd_vv_u8m1(a, c, vl);
|
||||
|
||||
/* *row = a */
|
||||
__riscv_vse8_v_u8m1(row, a, vl);
|
||||
row += bpp;
|
||||
prev += bpp;
|
||||
|
||||
/* remaining pixels */
|
||||
|
||||
while (row < rp_end)
|
||||
{
|
||||
/* b = *prev */
|
||||
vuint8m1_t b = __riscv_vle8_v_u8m1(prev, vl);
|
||||
prev += bpp;
|
||||
|
||||
/* x = *row */
|
||||
vuint8m1_t x = __riscv_vle8_v_u8m1(row, vl);
|
||||
|
||||
/* Calculate p = b - c and pc = a - c using widening subtraction */
|
||||
vuint16m2_t p_wide = __riscv_vwsubu_vv_u16m2(b, c, vl);
|
||||
vuint16m2_t pc_wide = __riscv_vwsubu_vv_u16m2(a, c, vl);
|
||||
|
||||
/* Convert to signed for easier manipulation */
|
||||
size_t vl16 = __riscv_vsetvl_e16m2(bpp);
|
||||
vint16m2_t p = __riscv_vreinterpret_v_u16m2_i16m2(p_wide);
|
||||
vint16m2_t pc = __riscv_vreinterpret_v_u16m2_i16m2(pc_wide);
|
||||
|
||||
/* pa = |p| */
|
||||
vbool8_t p_neg_mask = __riscv_vmslt_vx_i16m2_b8(p, 0, vl16);
|
||||
vint16m2_t pa = __riscv_vrsub_vx_i16m2_m(p_neg_mask, p, 0, vl16);
|
||||
|
||||
/* pb = |pc| */
|
||||
vbool8_t pc_neg_mask = __riscv_vmslt_vx_i16m2_b8(pc, 0, vl16);
|
||||
vint16m2_t pb = __riscv_vrsub_vx_i16m2_m(pc_neg_mask, pc, 0, vl16);
|
||||
|
||||
/* pc = |p + pc| */
|
||||
vint16m2_t p_plus_pc = __riscv_vadd_vv_i16m2(p, pc, vl16);
|
||||
vbool8_t p_plus_pc_neg_mask = __riscv_vmslt_vx_i16m2_b8(p_plus_pc, 0, vl16);
|
||||
pc = __riscv_vrsub_vx_i16m2_m(p_plus_pc_neg_mask, p_plus_pc, 0, vl16);
|
||||
|
||||
/*
|
||||
* The key insight is that we want the minimum of pa, pb, pc.
|
||||
* - If pa <= pb and pa <= pc, use a
|
||||
* - Else if pb <= pc, use b
|
||||
* - Else use c
|
||||
*/
|
||||
|
||||
/* Find which predictor to use based on minimum absolute difference */
|
||||
vbool8_t pa_le_pb = __riscv_vmsle_vv_i16m2_b8(pa, pb, vl16);
|
||||
vbool8_t pa_le_pc = __riscv_vmsle_vv_i16m2_b8(pa, pc, vl16);
|
||||
vbool8_t pb_le_pc = __riscv_vmsle_vv_i16m2_b8(pb, pc, vl16);
|
||||
|
||||
/* use_a = pa <= pb && pa <= pc */
|
||||
vbool8_t use_a = __riscv_vmand_mm_b8(pa_le_pb, pa_le_pc, vl16);
|
||||
|
||||
/* use_b = !use_a && pb <= pc */
|
||||
vbool8_t not_use_a = __riscv_vmnot_m_b8(use_a, vl16);
|
||||
vbool8_t use_b = __riscv_vmand_mm_b8(not_use_a, pb_le_pc, vl16);
|
||||
|
||||
/* Switch back to e8m1 for final operations */
|
||||
vl = __riscv_vsetvl_e8m1(bpp);
|
||||
|
||||
/* Start with a, then conditionally replace with b or c */
|
||||
vuint8m1_t result = a;
|
||||
result = __riscv_vmerge_vvm_u8m1(result, b, use_b, vl);
|
||||
|
||||
/* use_c = !use_a && !use_b */
|
||||
vbool8_t use_c = __riscv_vmnand_mm_b8(__riscv_vmor_mm_b8(use_a, use_b, vl), __riscv_vmor_mm_b8(use_a, use_b, vl), vl);
|
||||
result = __riscv_vmerge_vvm_u8m1(result, c, use_c, vl);
|
||||
|
||||
/* a = result + x */
|
||||
a = __riscv_vadd_vv_u8m1(result, x, vl);
|
||||
|
||||
/* *row = a */
|
||||
__riscv_vse8_v_u8m1(row, a, vl);
|
||||
row += bpp;
|
||||
|
||||
/* c = b for next iteration */
|
||||
c = b;
|
||||
}
|
||||
}
|
||||
void
|
||||
png_read_filter_row_paeth3_rvv(png_row_infop row_info, png_bytep row,
|
||||
png_const_bytep prev_row)
|
||||
{
|
||||
size_t len = row_info->rowbytes;
|
||||
|
||||
png_read_filter_row_paeth_rvv(len, 3, row, prev_row);
|
||||
}
|
||||
|
||||
void
|
||||
png_read_filter_row_paeth4_rvv(png_row_infop row_info, png_bytep row,
|
||||
png_const_bytep prev_row)
|
||||
{
|
||||
size_t len = row_info->rowbytes;
|
||||
|
||||
png_read_filter_row_paeth_rvv(len, 4, row, prev_row);
|
||||
}
|
||||
|
||||
#endif /* PNG_RISCV_RVV_IMPLEMENTATION == 1 */
|
||||
#endif /* PNG_READ_SUPPORTED */
|
||||
Vendored
+45
@@ -0,0 +1,45 @@
|
||||
/* riscv_init.c - RISC-V Vector optimized filter functions
|
||||
*
|
||||
* Copyright (c) 2023 Google LLC
|
||||
* Written by Dragoș Tiselice <dtiselice@google.com>, May 2023.
|
||||
* Filip Wasil <f.wasil@samsung.com>, March 2025.
|
||||
* This code is released under the libpng license.
|
||||
* For conditions of distribution and use, see the disclaimer
|
||||
* and license in png.h
|
||||
*/
|
||||
|
||||
#include "../pngpriv.h"
|
||||
|
||||
#ifdef PNG_READ_SUPPORTED
|
||||
|
||||
#if PNG_RISCV_RVV_IMPLEMENTATION == 1
|
||||
|
||||
#include <riscv_vector.h>
|
||||
|
||||
#ifndef PNG_ALIGNED_MEMORY_SUPPORTED
|
||||
# error "ALIGNED_MEMORY is required; set: -DPNG_ALIGNED_MEMORY_SUPPORTED"
|
||||
#endif
|
||||
|
||||
void
|
||||
png_init_filter_functions_rvv(png_structp pp, unsigned int bpp)
|
||||
{
|
||||
png_debug(1, "in png_init_filter_functions_rvv");
|
||||
|
||||
pp->read_filter[PNG_FILTER_VALUE_UP-1] = png_read_filter_row_up_rvv;
|
||||
|
||||
if (bpp == 3)
|
||||
{
|
||||
pp->read_filter[PNG_FILTER_VALUE_AVG-1] = png_read_filter_row_avg3_rvv;
|
||||
pp->read_filter[PNG_FILTER_VALUE_PAETH-1] = png_read_filter_row_paeth3_rvv;
|
||||
pp->read_filter[PNG_FILTER_VALUE_SUB-1] = png_read_filter_row_sub3_rvv;
|
||||
}
|
||||
else if (bpp == 4)
|
||||
{
|
||||
pp->read_filter[PNG_FILTER_VALUE_AVG-1] = png_read_filter_row_avg4_rvv;
|
||||
pp->read_filter[PNG_FILTER_VALUE_PAETH-1] = png_read_filter_row_paeth4_rvv;
|
||||
pp->read_filter[PNG_FILTER_VALUE_SUB-1] = png_read_filter_row_sub4_rvv;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* PNG_RISCV_RVV_IMPLEMENTATION == 1 */
|
||||
#endif /* PNG_READ_SUPPORTED */
|
||||
Reference in New Issue
Block a user