Commit 11101b6f authored by Adrià Arrufat's avatar Adrià Arrufat Committed by Davis E. King
Browse files

update libpng to version 1.6.37

parent 23e50632
/* pngwrite.c - general routines to write a PNG file /* pngwrite.c - general routines to write a PNG file
* *
* Last changed in libpng 1.6.2 [April 25, 2013] * Copyright (c) 2018-2019 Cosmin Truta
* Copyright (c) 1998-2013 Glenn Randers-Pehrson * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
* (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * Copyright (c) 1996-1997 Andreas Dilger
* (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
* *
* This code is released under the libpng license. * This code is released under the libpng license.
* For conditions of distribution and use, see the disclaimer * For conditions of distribution and use, see the disclaimer
...@@ -12,9 +12,9 @@ ...@@ -12,9 +12,9 @@
*/ */
#include "pngpriv.h" #include "pngpriv.h"
#if defined(PNG_SIMPLIFIED_WRITE_SUPPORTED) && defined(PNG_STDIO_SUPPORTED) #ifdef PNG_SIMPLIFIED_WRITE_STDIO_SUPPORTED
# include <errno.h> # include <errno.h>
#endif #endif /* SIMPLIFIED_WRITE_STDIO */
#ifdef PNG_WRITE_SUPPORTED #ifdef PNG_WRITE_SUPPORTED
...@@ -22,9 +22,9 @@ ...@@ -22,9 +22,9 @@
/* Write out all the unknown chunks for the current given location */ /* Write out all the unknown chunks for the current given location */
static void static void
write_unknown_chunks(png_structrp png_ptr, png_const_inforp info_ptr, write_unknown_chunks(png_structrp png_ptr, png_const_inforp info_ptr,
unsigned int where) unsigned int where)
{ {
if (info_ptr->unknown_chunks_num) if (info_ptr->unknown_chunks_num != 0)
{ {
png_const_unknown_chunkp up; png_const_unknown_chunkp up;
...@@ -33,7 +33,7 @@ write_unknown_chunks(png_structrp png_ptr, png_const_inforp info_ptr, ...@@ -33,7 +33,7 @@ write_unknown_chunks(png_structrp png_ptr, png_const_inforp info_ptr,
for (up = info_ptr->unknown_chunks; for (up = info_ptr->unknown_chunks;
up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num; up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num;
++up) ++up)
if (up->location & where) if ((up->location & where) != 0)
{ {
/* If per-chunk unknown chunk handling is enabled use it, otherwise /* If per-chunk unknown chunk handling is enabled use it, otherwise
* just write the chunks the application has set. * just write the chunks the application has set.
...@@ -69,7 +69,7 @@ write_unknown_chunks(png_structrp png_ptr, png_const_inforp info_ptr, ...@@ -69,7 +69,7 @@ write_unknown_chunks(png_structrp png_ptr, png_const_inforp info_ptr,
} }
} }
} }
#endif /* PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED */ #endif /* WRITE_UNKNOWN_CHUNKS */
/* Writes all the PNG information. This is the suggested way to use the /* Writes all the PNG information. This is the suggested way to use the
* library. If you have a new chunk to add, make a function to write it, * library. If you have a new chunk to add, make a function to write it,
...@@ -88,99 +88,100 @@ png_write_info_before_PLTE(png_structrp png_ptr, png_const_inforp info_ptr) ...@@ -88,99 +88,100 @@ png_write_info_before_PLTE(png_structrp png_ptr, png_const_inforp info_ptr)
if (png_ptr == NULL || info_ptr == NULL) if (png_ptr == NULL || info_ptr == NULL)
return; return;
if (!(png_ptr->mode & PNG_WROTE_INFO_BEFORE_PLTE)) if ((png_ptr->mode & PNG_WROTE_INFO_BEFORE_PLTE) == 0)
{ {
/* Write PNG signature */ /* Write PNG signature */
png_write_sig(png_ptr); png_write_sig(png_ptr);
#ifdef PNG_MNG_FEATURES_SUPPORTED #ifdef PNG_MNG_FEATURES_SUPPORTED
if ((png_ptr->mode&PNG_HAVE_PNG_SIGNATURE) && \ if ((png_ptr->mode & PNG_HAVE_PNG_SIGNATURE) != 0 && \
(png_ptr->mng_features_permitted)) png_ptr->mng_features_permitted != 0)
{ {
png_warning(png_ptr, "MNG features are not allowed in a PNG datastream"); png_warning(png_ptr,
png_ptr->mng_features_permitted = 0; "MNG features are not allowed in a PNG datastream");
} png_ptr->mng_features_permitted = 0;
}
#endif #endif
/* Write IHDR information. */ /* Write IHDR information. */
png_write_IHDR(png_ptr, info_ptr->width, info_ptr->height, png_write_IHDR(png_ptr, info_ptr->width, info_ptr->height,
info_ptr->bit_depth, info_ptr->color_type, info_ptr->compression_type, info_ptr->bit_depth, info_ptr->color_type, info_ptr->compression_type,
info_ptr->filter_type, info_ptr->filter_type,
#ifdef PNG_WRITE_INTERLACING_SUPPORTED #ifdef PNG_WRITE_INTERLACING_SUPPORTED
info_ptr->interlace_type info_ptr->interlace_type
#else #else
0 0
#endif #endif
); );
/* The rest of these check to see if the valid field has the appropriate /* The rest of these check to see if the valid field has the appropriate
* flag set, and if it does, writes the chunk. * flag set, and if it does, writes the chunk.
* *
* 1.6.0: COLORSPACE support controls the writing of these chunks too, and * 1.6.0: COLORSPACE support controls the writing of these chunks too, and
* the chunks will be written if the WRITE routine is there and information * the chunks will be written if the WRITE routine is there and
* is available in the COLORSPACE. (See png_colorspace_sync_info in png.c * information * is available in the COLORSPACE. (See
* for where the valid flags get set.) * png_colorspace_sync_info in png.c for where the valid flags get set.)
* *
* Under certain circumstances the colorspace can be invalidated without * Under certain circumstances the colorspace can be invalidated without
* syncing the info_struct 'valid' flags; this happens if libpng detects and * syncing the info_struct 'valid' flags; this happens if libpng detects
* error and calls png_error while the color space is being set, yet the * an error and calls png_error while the color space is being set, yet
* application continues writing the PNG. So check the 'invalid' flag here * the application continues writing the PNG. So check the 'invalid'
* too. * flag here too.
*/ */
#ifdef PNG_GAMMA_SUPPORTED #ifdef PNG_GAMMA_SUPPORTED
# ifdef PNG_WRITE_gAMA_SUPPORTED # ifdef PNG_WRITE_gAMA_SUPPORTED
if (!(info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) && if ((info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) == 0 &&
(info_ptr->colorspace.flags & PNG_COLORSPACE_FROM_gAMA) && (info_ptr->colorspace.flags & PNG_COLORSPACE_FROM_gAMA) != 0 &&
(info_ptr->valid & PNG_INFO_gAMA)) (info_ptr->valid & PNG_INFO_gAMA) != 0)
png_write_gAMA_fixed(png_ptr, info_ptr->colorspace.gamma); png_write_gAMA_fixed(png_ptr, info_ptr->colorspace.gamma);
# endif # endif
#endif #endif
#ifdef PNG_COLORSPACE_SUPPORTED #ifdef PNG_COLORSPACE_SUPPORTED
/* Write only one of sRGB or an ICC profile. If a profile was supplied /* Write only one of sRGB or an ICC profile. If a profile was supplied
* and it matches one of the known sRGB ones issue a warning. * and it matches one of the known sRGB ones issue a warning.
*/ */
# ifdef PNG_WRITE_iCCP_SUPPORTED # ifdef PNG_WRITE_iCCP_SUPPORTED
if (!(info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) && if ((info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) == 0 &&
(info_ptr->valid & PNG_INFO_iCCP)) (info_ptr->valid & PNG_INFO_iCCP) != 0)
{ {
# ifdef PNG_WRITE_sRGB_SUPPORTED # ifdef PNG_WRITE_sRGB_SUPPORTED
if (info_ptr->valid & PNG_INFO_sRGB) if ((info_ptr->valid & PNG_INFO_sRGB) != 0)
png_app_warning(png_ptr, png_app_warning(png_ptr,
"profile matches sRGB but writing iCCP instead"); "profile matches sRGB but writing iCCP instead");
# endif # endif
png_write_iCCP(png_ptr, info_ptr->iccp_name, png_write_iCCP(png_ptr, info_ptr->iccp_name,
info_ptr->iccp_profile); info_ptr->iccp_profile);
} }
# ifdef PNG_WRITE_sRGB_SUPPORTED # ifdef PNG_WRITE_sRGB_SUPPORTED
else else
# endif # endif
# endif # endif
# ifdef PNG_WRITE_sRGB_SUPPORTED # ifdef PNG_WRITE_sRGB_SUPPORTED
if (!(info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) && if ((info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) == 0 &&
(info_ptr->valid & PNG_INFO_sRGB)) (info_ptr->valid & PNG_INFO_sRGB) != 0)
png_write_sRGB(png_ptr, info_ptr->colorspace.rendering_intent); png_write_sRGB(png_ptr, info_ptr->colorspace.rendering_intent);
# endif /* WRITE_sRGB */ # endif /* WRITE_sRGB */
#endif /* COLORSPACE */ #endif /* COLORSPACE */
#ifdef PNG_WRITE_sBIT_SUPPORTED #ifdef PNG_WRITE_sBIT_SUPPORTED
if (info_ptr->valid & PNG_INFO_sBIT) if ((info_ptr->valid & PNG_INFO_sBIT) != 0)
png_write_sBIT(png_ptr, &(info_ptr->sig_bit), info_ptr->color_type); png_write_sBIT(png_ptr, &(info_ptr->sig_bit), info_ptr->color_type);
#endif #endif
#ifdef PNG_COLORSPACE_SUPPORTED #ifdef PNG_COLORSPACE_SUPPORTED
# ifdef PNG_WRITE_cHRM_SUPPORTED # ifdef PNG_WRITE_cHRM_SUPPORTED
if (!(info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) && if ((info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) == 0 &&
(info_ptr->colorspace.flags & PNG_COLORSPACE_FROM_cHRM) && (info_ptr->colorspace.flags & PNG_COLORSPACE_FROM_cHRM) != 0 &&
(info_ptr->valid & PNG_INFO_cHRM)) (info_ptr->valid & PNG_INFO_cHRM) != 0)
png_write_cHRM_fixed(png_ptr, &info_ptr->colorspace.end_points_xy); png_write_cHRM_fixed(png_ptr, &info_ptr->colorspace.end_points_xy);
# endif # endif
#endif #endif
#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED #ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
write_unknown_chunks(png_ptr, info_ptr, PNG_HAVE_IHDR); write_unknown_chunks(png_ptr, info_ptr, PNG_HAVE_IHDR);
#endif #endif
png_ptr->mode |= PNG_WROTE_INFO_BEFORE_PLTE; png_ptr->mode |= PNG_WROTE_INFO_BEFORE_PLTE;
...@@ -201,7 +202,7 @@ png_write_info(png_structrp png_ptr, png_const_inforp info_ptr) ...@@ -201,7 +202,7 @@ png_write_info(png_structrp png_ptr, png_const_inforp info_ptr)
png_write_info_before_PLTE(png_ptr, info_ptr); png_write_info_before_PLTE(png_ptr, info_ptr);
if (info_ptr->valid & PNG_INFO_PLTE) if ((info_ptr->valid & PNG_INFO_PLTE) != 0)
png_write_PLTE(png_ptr, info_ptr->palette, png_write_PLTE(png_ptr, info_ptr->palette,
(png_uint_32)info_ptr->num_palette); (png_uint_32)info_ptr->num_palette);
...@@ -209,15 +210,20 @@ png_write_info(png_structrp png_ptr, png_const_inforp info_ptr) ...@@ -209,15 +210,20 @@ png_write_info(png_structrp png_ptr, png_const_inforp info_ptr)
png_error(png_ptr, "Valid palette required for paletted images"); png_error(png_ptr, "Valid palette required for paletted images");
#ifdef PNG_WRITE_tRNS_SUPPORTED #ifdef PNG_WRITE_tRNS_SUPPORTED
if (info_ptr->valid & PNG_INFO_tRNS) if ((info_ptr->valid & PNG_INFO_tRNS) !=0)
{ {
#ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED #ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED
/* Invert the alpha channel (in tRNS) */ /* Invert the alpha channel (in tRNS) */
if ((png_ptr->transformations & PNG_INVERT_ALPHA) && if ((png_ptr->transformations & PNG_INVERT_ALPHA) != 0 &&
info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
{ {
int j; int j, jend;
for (j = 0; j<(int)info_ptr->num_trans; j++)
jend = info_ptr->num_trans;
if (jend > PNG_MAX_PALETTE_LENGTH)
jend = PNG_MAX_PALETTE_LENGTH;
for (j = 0; j<jend; ++j)
info_ptr->trans_alpha[j] = info_ptr->trans_alpha[j] =
(png_byte)(255 - info_ptr->trans_alpha[j]); (png_byte)(255 - info_ptr->trans_alpha[j]);
} }
...@@ -227,42 +233,47 @@ png_write_info(png_structrp png_ptr, png_const_inforp info_ptr) ...@@ -227,42 +233,47 @@ png_write_info(png_structrp png_ptr, png_const_inforp info_ptr)
} }
#endif #endif
#ifdef PNG_WRITE_bKGD_SUPPORTED #ifdef PNG_WRITE_bKGD_SUPPORTED
if (info_ptr->valid & PNG_INFO_bKGD) if ((info_ptr->valid & PNG_INFO_bKGD) != 0)
png_write_bKGD(png_ptr, &(info_ptr->background), info_ptr->color_type); png_write_bKGD(png_ptr, &(info_ptr->background), info_ptr->color_type);
#endif #endif
#ifdef PNG_WRITE_eXIf_SUPPORTED
if ((info_ptr->valid & PNG_INFO_eXIf) != 0)
png_write_eXIf(png_ptr, info_ptr->exif, info_ptr->num_exif);
#endif
#ifdef PNG_WRITE_hIST_SUPPORTED #ifdef PNG_WRITE_hIST_SUPPORTED
if (info_ptr->valid & PNG_INFO_hIST) if ((info_ptr->valid & PNG_INFO_hIST) != 0)
png_write_hIST(png_ptr, info_ptr->hist, info_ptr->num_palette); png_write_hIST(png_ptr, info_ptr->hist, info_ptr->num_palette);
#endif #endif
#ifdef PNG_WRITE_oFFs_SUPPORTED #ifdef PNG_WRITE_oFFs_SUPPORTED
if (info_ptr->valid & PNG_INFO_oFFs) if ((info_ptr->valid & PNG_INFO_oFFs) != 0)
png_write_oFFs(png_ptr, info_ptr->x_offset, info_ptr->y_offset, png_write_oFFs(png_ptr, info_ptr->x_offset, info_ptr->y_offset,
info_ptr->offset_unit_type); info_ptr->offset_unit_type);
#endif #endif
#ifdef PNG_WRITE_pCAL_SUPPORTED #ifdef PNG_WRITE_pCAL_SUPPORTED
if (info_ptr->valid & PNG_INFO_pCAL) if ((info_ptr->valid & PNG_INFO_pCAL) != 0)
png_write_pCAL(png_ptr, info_ptr->pcal_purpose, info_ptr->pcal_X0, png_write_pCAL(png_ptr, info_ptr->pcal_purpose, info_ptr->pcal_X0,
info_ptr->pcal_X1, info_ptr->pcal_type, info_ptr->pcal_nparams, info_ptr->pcal_X1, info_ptr->pcal_type, info_ptr->pcal_nparams,
info_ptr->pcal_units, info_ptr->pcal_params); info_ptr->pcal_units, info_ptr->pcal_params);
#endif #endif
#ifdef PNG_WRITE_sCAL_SUPPORTED #ifdef PNG_WRITE_sCAL_SUPPORTED
if (info_ptr->valid & PNG_INFO_sCAL) if ((info_ptr->valid & PNG_INFO_sCAL) != 0)
png_write_sCAL_s(png_ptr, (int)info_ptr->scal_unit, png_write_sCAL_s(png_ptr, (int)info_ptr->scal_unit,
info_ptr->scal_s_width, info_ptr->scal_s_height); info_ptr->scal_s_width, info_ptr->scal_s_height);
#endif /* sCAL */ #endif /* sCAL */
#ifdef PNG_WRITE_pHYs_SUPPORTED #ifdef PNG_WRITE_pHYs_SUPPORTED
if (info_ptr->valid & PNG_INFO_pHYs) if ((info_ptr->valid & PNG_INFO_pHYs) != 0)
png_write_pHYs(png_ptr, info_ptr->x_pixels_per_unit, png_write_pHYs(png_ptr, info_ptr->x_pixels_per_unit,
info_ptr->y_pixels_per_unit, info_ptr->phys_unit_type); info_ptr->y_pixels_per_unit, info_ptr->phys_unit_type);
#endif /* pHYs */ #endif /* pHYs */
#ifdef PNG_WRITE_tIME_SUPPORTED #ifdef PNG_WRITE_tIME_SUPPORTED
if (info_ptr->valid & PNG_INFO_tIME) if ((info_ptr->valid & PNG_INFO_tIME) != 0)
{ {
png_write_tIME(png_ptr, &(info_ptr->mod_time)); png_write_tIME(png_ptr, &(info_ptr->mod_time));
png_ptr->mode |= PNG_WROTE_tIME; png_ptr->mode |= PNG_WROTE_tIME;
...@@ -270,7 +281,7 @@ png_write_info(png_structrp png_ptr, png_const_inforp info_ptr) ...@@ -270,7 +281,7 @@ png_write_info(png_structrp png_ptr, png_const_inforp info_ptr)
#endif /* tIME */ #endif /* tIME */
#ifdef PNG_WRITE_sPLT_SUPPORTED #ifdef PNG_WRITE_sPLT_SUPPORTED
if (info_ptr->valid & PNG_INFO_sPLT) if ((info_ptr->valid & PNG_INFO_sPLT) != 0)
for (i = 0; i < (int)info_ptr->splt_palettes_num; i++) for (i = 0; i < (int)info_ptr->splt_palettes_num; i++)
png_write_sPLT(png_ptr, info_ptr->splt_palettes + i); png_write_sPLT(png_ptr, info_ptr->splt_palettes + i);
#endif /* sPLT */ #endif /* sPLT */
...@@ -292,11 +303,14 @@ png_write_info(png_structrp png_ptr, png_const_inforp info_ptr) ...@@ -292,11 +303,14 @@ png_write_info(png_structrp png_ptr, png_const_inforp info_ptr)
info_ptr->text[i].lang, info_ptr->text[i].lang,
info_ptr->text[i].lang_key, info_ptr->text[i].lang_key,
info_ptr->text[i].text); info_ptr->text[i].text);
/* Mark this chunk as written */
if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE)
info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;
else
info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR;
#else #else
png_warning(png_ptr, "Unable to write international text"); png_warning(png_ptr, "Unable to write international text");
#endif #endif
/* Mark this chunk as written */
info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;
} }
/* If we want a compressed text chunk */ /* If we want a compressed text chunk */
...@@ -305,13 +319,12 @@ png_write_info(png_structrp png_ptr, png_const_inforp info_ptr) ...@@ -305,13 +319,12 @@ png_write_info(png_structrp png_ptr, png_const_inforp info_ptr)
#ifdef PNG_WRITE_zTXt_SUPPORTED #ifdef PNG_WRITE_zTXt_SUPPORTED
/* Write compressed chunk */ /* Write compressed chunk */
png_write_zTXt(png_ptr, info_ptr->text[i].key, png_write_zTXt(png_ptr, info_ptr->text[i].key,
info_ptr->text[i].text, 0, info_ptr->text[i].text, info_ptr->text[i].compression);
info_ptr->text[i].compression); /* Mark this chunk as written */
info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR;
#else #else
png_warning(png_ptr, "Unable to write compressed text"); png_warning(png_ptr, "Unable to write compressed text");
#endif #endif
/* Mark this chunk as written */
info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR;
} }
else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE) else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE)
...@@ -349,7 +362,7 @@ png_write_end(png_structrp png_ptr, png_inforp info_ptr) ...@@ -349,7 +362,7 @@ png_write_end(png_structrp png_ptr, png_inforp info_ptr)
if (png_ptr == NULL) if (png_ptr == NULL)
return; return;
if (!(png_ptr->mode & PNG_HAVE_IDAT)) if ((png_ptr->mode & PNG_HAVE_IDAT) == 0)
png_error(png_ptr, "No IDATs written into file"); png_error(png_ptr, "No IDATs written into file");
#ifdef PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED #ifdef PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED
...@@ -365,8 +378,8 @@ png_write_end(png_structrp png_ptr, png_inforp info_ptr) ...@@ -365,8 +378,8 @@ png_write_end(png_structrp png_ptr, png_inforp info_ptr)
#endif #endif
#ifdef PNG_WRITE_tIME_SUPPORTED #ifdef PNG_WRITE_tIME_SUPPORTED
/* Check to see if user has supplied a time chunk */ /* Check to see if user has supplied a time chunk */
if ((info_ptr->valid & PNG_INFO_tIME) && if ((info_ptr->valid & PNG_INFO_tIME) != 0 &&
!(png_ptr->mode & PNG_WROTE_tIME)) (png_ptr->mode & PNG_WROTE_tIME) == 0)
png_write_tIME(png_ptr, &(info_ptr->mod_time)); png_write_tIME(png_ptr, &(info_ptr->mod_time));
#endif #endif
...@@ -375,7 +388,7 @@ png_write_end(png_structrp png_ptr, png_inforp info_ptr) ...@@ -375,7 +388,7 @@ png_write_end(png_structrp png_ptr, png_inforp info_ptr)
for (i = 0; i < info_ptr->num_text; i++) for (i = 0; i < info_ptr->num_text; i++)
{ {
png_debug2(2, "Writing trailer text chunk %d, type %d", i, png_debug2(2, "Writing trailer text chunk %d, type %d", i,
info_ptr->text[i].compression); info_ptr->text[i].compression);
/* An internationalized chunk? */ /* An internationalized chunk? */
if (info_ptr->text[i].compression > 0) if (info_ptr->text[i].compression > 0)
{ {
...@@ -387,11 +400,14 @@ png_write_end(png_structrp png_ptr, png_inforp info_ptr) ...@@ -387,11 +400,14 @@ png_write_end(png_structrp png_ptr, png_inforp info_ptr)
info_ptr->text[i].lang, info_ptr->text[i].lang,
info_ptr->text[i].lang_key, info_ptr->text[i].lang_key,
info_ptr->text[i].text); info_ptr->text[i].text);
/* Mark this chunk as written */
if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE)
info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;
else
info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR;
#else #else
png_warning(png_ptr, "Unable to write international text"); png_warning(png_ptr, "Unable to write international text");
#endif #endif
/* Mark this chunk as written */
info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;
} }
else if (info_ptr->text[i].compression >= PNG_TEXT_COMPRESSION_zTXt) else if (info_ptr->text[i].compression >= PNG_TEXT_COMPRESSION_zTXt)
...@@ -399,13 +415,12 @@ png_write_end(png_structrp png_ptr, png_inforp info_ptr) ...@@ -399,13 +415,12 @@ png_write_end(png_structrp png_ptr, png_inforp info_ptr)
#ifdef PNG_WRITE_zTXt_SUPPORTED #ifdef PNG_WRITE_zTXt_SUPPORTED
/* Write compressed chunk */ /* Write compressed chunk */
png_write_zTXt(png_ptr, info_ptr->text[i].key, png_write_zTXt(png_ptr, info_ptr->text[i].key,
info_ptr->text[i].text, 0, info_ptr->text[i].text, info_ptr->text[i].compression);
info_ptr->text[i].compression); /* Mark this chunk as written */
info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR;
#else #else
png_warning(png_ptr, "Unable to write compressed text"); png_warning(png_ptr, "Unable to write compressed text");
#endif #endif
/* Mark this chunk as written */
info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR;
} }
else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE) else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE)
...@@ -414,15 +429,20 @@ png_write_end(png_structrp png_ptr, png_inforp info_ptr) ...@@ -414,15 +429,20 @@ png_write_end(png_structrp png_ptr, png_inforp info_ptr)
/* Write uncompressed chunk */ /* Write uncompressed chunk */
png_write_tEXt(png_ptr, info_ptr->text[i].key, png_write_tEXt(png_ptr, info_ptr->text[i].key,
info_ptr->text[i].text, 0); info_ptr->text[i].text, 0);
/* Mark this chunk as written */
info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;
#else #else
png_warning(png_ptr, "Unable to write uncompressed text"); png_warning(png_ptr, "Unable to write uncompressed text");
#endif #endif
/* Mark this chunk as written */
info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;
} }
} }
#endif #endif
#ifdef PNG_WRITE_eXIf_SUPPORTED
if ((info_ptr->valid & PNG_INFO_eXIf) != 0)
png_write_eXIf(png_ptr, info_ptr->exif, info_ptr->num_exif);
#endif
#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED #ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
write_unknown_chunks(png_ptr, info_ptr, PNG_AFTER_IDAT); write_unknown_chunks(png_ptr, info_ptr, PNG_AFTER_IDAT);
#endif #endif
...@@ -432,6 +452,7 @@ png_write_end(png_structrp png_ptr, png_inforp info_ptr) ...@@ -432,6 +452,7 @@ png_write_end(png_structrp png_ptr, png_inforp info_ptr)
/* Write end of PNG file */ /* Write end of PNG file */
png_write_IEND(png_ptr); png_write_IEND(png_ptr);
/* This flush, added in libpng-1.0.8, removed from libpng-1.0.9beta03, /* This flush, added in libpng-1.0.8, removed from libpng-1.0.9beta03,
* and restored again in libpng-1.2.30, may cause some applications that * and restored again in libpng-1.2.30, may cause some applications that
* do not set png_ptr->output_flush_fn to crash. If your application * do not set png_ptr->output_flush_fn to crash. If your application
...@@ -448,7 +469,7 @@ png_write_end(png_structrp png_ptr, png_inforp info_ptr) ...@@ -448,7 +469,7 @@ png_write_end(png_structrp png_ptr, png_inforp info_ptr)
#ifdef PNG_CONVERT_tIME_SUPPORTED #ifdef PNG_CONVERT_tIME_SUPPORTED
void PNGAPI void PNGAPI
png_convert_from_struct_tm(png_timep ptime, PNG_CONST struct tm * ttime) png_convert_from_struct_tm(png_timep ptime, const struct tm * ttime)
{ {
png_debug(1, "in png_convert_from_struct_tm"); png_debug(1, "in png_convert_from_struct_tm");
...@@ -479,7 +500,7 @@ png_create_write_struct,(png_const_charp user_png_ver, png_voidp error_ptr, ...@@ -479,7 +500,7 @@ png_create_write_struct,(png_const_charp user_png_ver, png_voidp error_ptr,
{ {
#ifndef PNG_USER_MEM_SUPPORTED #ifndef PNG_USER_MEM_SUPPORTED
png_structrp png_ptr = png_create_png_struct(user_png_ver, error_ptr, png_structrp png_ptr = png_create_png_struct(user_png_ver, error_ptr,
error_fn, warn_fn, NULL, NULL, NULL); error_fn, warn_fn, NULL, NULL, NULL);
#else #else
return png_create_write_struct_2(user_png_ver, error_ptr, error_fn, return png_create_write_struct_2(user_png_ver, error_ptr, error_fn,
warn_fn, NULL, NULL, NULL); warn_fn, NULL, NULL, NULL);
...@@ -492,8 +513,8 @@ png_create_write_struct_2,(png_const_charp user_png_ver, png_voidp error_ptr, ...@@ -492,8 +513,8 @@ png_create_write_struct_2,(png_const_charp user_png_ver, png_voidp error_ptr,
png_malloc_ptr malloc_fn, png_free_ptr free_fn),PNG_ALLOCATED) png_malloc_ptr malloc_fn, png_free_ptr free_fn),PNG_ALLOCATED)
{ {
png_structrp png_ptr = png_create_png_struct(user_png_ver, error_ptr, png_structrp png_ptr = png_create_png_struct(user_png_ver, error_ptr,
error_fn, warn_fn, mem_ptr, malloc_fn, free_fn); error_fn, warn_fn, mem_ptr, malloc_fn, free_fn);
#endif /* PNG_USER_MEM_SUPPORTED */ #endif /* USER_MEM */
if (png_ptr != NULL) if (png_ptr != NULL)
{ {
/* Set the zlib control values to defaults; they can be overridden by the /* Set the zlib control values to defaults; they can be overridden by the
...@@ -517,7 +538,7 @@ png_create_write_struct_2,(png_const_charp user_png_ver, png_voidp error_ptr, ...@@ -517,7 +538,7 @@ png_create_write_struct_2,(png_const_charp user_png_ver, png_voidp error_ptr,
png_ptr->zlib_text_mem_level = 8; png_ptr->zlib_text_mem_level = 8;
png_ptr->zlib_text_window_bits = 15; png_ptr->zlib_text_window_bits = 15;
png_ptr->zlib_text_method = 8; png_ptr->zlib_text_method = 8;
#endif /* PNG_WRITE_COMPRESSED_TEXT_SUPPORTED */ #endif /* WRITE_COMPRESSED_TEXT */
/* This is a highly dubious configuration option; by default it is off, /* This is a highly dubious configuration option; by default it is off,
* but it may be appropriate for private builds that are testing * but it may be appropriate for private builds that are testing
...@@ -525,16 +546,16 @@ png_create_write_struct_2,(png_const_charp user_png_ver, png_voidp error_ptr, ...@@ -525,16 +546,16 @@ png_create_write_struct_2,(png_const_charp user_png_ver, png_voidp error_ptr,
* applications that must not fail to write at all costs! * applications that must not fail to write at all costs!
*/ */
#ifdef PNG_BENIGN_WRITE_ERRORS_SUPPORTED #ifdef PNG_BENIGN_WRITE_ERRORS_SUPPORTED
png_ptr->flags |= PNG_FLAG_BENIGN_ERRORS_WARN;
/* In stable builds only warn if an application error can be completely /* In stable builds only warn if an application error can be completely
* handled. * handled.
*/ */
png_ptr->flags |= PNG_FLAG_BENIGN_ERRORS_WARN;
#endif #endif
/* App warnings are warnings in release (or release candidate) builds but /* App warnings are warnings in release (or release candidate) builds but
* are errors during development. * are errors during development.
*/ */
#if PNG_LIBPNG_BUILD_BASE_TYPE >= PNG_LIBPNG_BUILD_RC #if PNG_RELEASE_BUILD
png_ptr->flags |= PNG_FLAG_APP_WARNINGS_WARN; png_ptr->flags |= PNG_FLAG_APP_WARNINGS_WARN;
#endif #endif
...@@ -607,6 +628,71 @@ png_write_image(png_structrp png_ptr, png_bytepp image) ...@@ -607,6 +628,71 @@ png_write_image(png_structrp png_ptr, png_bytepp image)
} }
} }
#ifdef PNG_MNG_FEATURES_SUPPORTED
/* Performs intrapixel differencing */
static void
png_do_write_intrapixel(png_row_infop row_info, png_bytep row)
{
png_debug(1, "in png_do_write_intrapixel");
if ((row_info->color_type & PNG_COLOR_MASK_COLOR) != 0)
{
int bytes_per_pixel;
png_uint_32 row_width = row_info->width;
if (row_info->bit_depth == 8)
{
png_bytep rp;
png_uint_32 i;
if (row_info->color_type == PNG_COLOR_TYPE_RGB)
bytes_per_pixel = 3;
else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
bytes_per_pixel = 4;
else
return;
for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel)
{
*(rp) = (png_byte)(*rp - *(rp + 1));
*(rp + 2) = (png_byte)(*(rp + 2) - *(rp + 1));
}
}
#ifdef PNG_WRITE_16BIT_SUPPORTED
else if (row_info->bit_depth == 16)
{
png_bytep rp;
png_uint_32 i;
if (row_info->color_type == PNG_COLOR_TYPE_RGB)
bytes_per_pixel = 6;
else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
bytes_per_pixel = 8;
else
return;
for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel)
{
png_uint_32 s0 = (png_uint_32)(*(rp ) << 8) | *(rp + 1);
png_uint_32 s1 = (png_uint_32)(*(rp + 2) << 8) | *(rp + 3);
png_uint_32 s2 = (png_uint_32)(*(rp + 4) << 8) | *(rp + 5);
png_uint_32 red = (png_uint_32)((s0 - s1) & 0xffffL);
png_uint_32 blue = (png_uint_32)((s2 - s1) & 0xffffL);
*(rp ) = (png_byte)(red >> 8);
*(rp + 1) = (png_byte)red;
*(rp + 4) = (png_byte)(blue >> 8);
*(rp + 5) = (png_byte)blue;
}
}
#endif /* WRITE_16BIT */
}
}
#endif /* MNG_FEATURES */
/* Called by user to write a row of image data */ /* Called by user to write a row of image data */
void PNGAPI void PNGAPI
png_write_row(png_structrp png_ptr, png_const_bytep row) png_write_row(png_structrp png_ptr, png_const_bytep row)
...@@ -618,50 +704,50 @@ png_write_row(png_structrp png_ptr, png_const_bytep row) ...@@ -618,50 +704,50 @@ png_write_row(png_structrp png_ptr, png_const_bytep row)
return; return;
png_debug2(1, "in png_write_row (row %u, pass %d)", png_debug2(1, "in png_write_row (row %u, pass %d)",
png_ptr->row_number, png_ptr->pass); png_ptr->row_number, png_ptr->pass);
/* Initialize transformations and other stuff if first time */ /* Initialize transformations and other stuff if first time */
if (png_ptr->row_number == 0 && png_ptr->pass == 0) if (png_ptr->row_number == 0 && png_ptr->pass == 0)
{ {
/* Make sure we wrote the header info */ /* Make sure we wrote the header info */
if (!(png_ptr->mode & PNG_WROTE_INFO_BEFORE_PLTE)) if ((png_ptr->mode & PNG_WROTE_INFO_BEFORE_PLTE) == 0)
png_error(png_ptr, png_error(png_ptr,
"png_write_info was never called before png_write_row"); "png_write_info was never called before png_write_row");
/* Check for transforms that have been set but were defined out */ /* Check for transforms that have been set but were defined out */
#if !defined(PNG_WRITE_INVERT_SUPPORTED) && defined(PNG_READ_INVERT_SUPPORTED) #if !defined(PNG_WRITE_INVERT_SUPPORTED) && defined(PNG_READ_INVERT_SUPPORTED)
if (png_ptr->transformations & PNG_INVERT_MONO) if ((png_ptr->transformations & PNG_INVERT_MONO) != 0)
png_warning(png_ptr, "PNG_WRITE_INVERT_SUPPORTED is not defined"); png_warning(png_ptr, "PNG_WRITE_INVERT_SUPPORTED is not defined");
#endif #endif
#if !defined(PNG_WRITE_FILLER_SUPPORTED) && defined(PNG_READ_FILLER_SUPPORTED) #if !defined(PNG_WRITE_FILLER_SUPPORTED) && defined(PNG_READ_FILLER_SUPPORTED)
if (png_ptr->transformations & PNG_FILLER) if ((png_ptr->transformations & PNG_FILLER) != 0)
png_warning(png_ptr, "PNG_WRITE_FILLER_SUPPORTED is not defined"); png_warning(png_ptr, "PNG_WRITE_FILLER_SUPPORTED is not defined");
#endif #endif
#if !defined(PNG_WRITE_PACKSWAP_SUPPORTED) && \ #if !defined(PNG_WRITE_PACKSWAP_SUPPORTED) && \
defined(PNG_READ_PACKSWAP_SUPPORTED) defined(PNG_READ_PACKSWAP_SUPPORTED)
if (png_ptr->transformations & PNG_PACKSWAP) if ((png_ptr->transformations & PNG_PACKSWAP) != 0)
png_warning(png_ptr, png_warning(png_ptr,
"PNG_WRITE_PACKSWAP_SUPPORTED is not defined"); "PNG_WRITE_PACKSWAP_SUPPORTED is not defined");
#endif #endif
#if !defined(PNG_WRITE_PACK_SUPPORTED) && defined(PNG_READ_PACK_SUPPORTED) #if !defined(PNG_WRITE_PACK_SUPPORTED) && defined(PNG_READ_PACK_SUPPORTED)
if (png_ptr->transformations & PNG_PACK) if ((png_ptr->transformations & PNG_PACK) != 0)
png_warning(png_ptr, "PNG_WRITE_PACK_SUPPORTED is not defined"); png_warning(png_ptr, "PNG_WRITE_PACK_SUPPORTED is not defined");
#endif #endif
#if !defined(PNG_WRITE_SHIFT_SUPPORTED) && defined(PNG_READ_SHIFT_SUPPORTED) #if !defined(PNG_WRITE_SHIFT_SUPPORTED) && defined(PNG_READ_SHIFT_SUPPORTED)
if (png_ptr->transformations & PNG_SHIFT) if ((png_ptr->transformations & PNG_SHIFT) != 0)
png_warning(png_ptr, "PNG_WRITE_SHIFT_SUPPORTED is not defined"); png_warning(png_ptr, "PNG_WRITE_SHIFT_SUPPORTED is not defined");
#endif #endif
#if !defined(PNG_WRITE_BGR_SUPPORTED) && defined(PNG_READ_BGR_SUPPORTED) #if !defined(PNG_WRITE_BGR_SUPPORTED) && defined(PNG_READ_BGR_SUPPORTED)
if (png_ptr->transformations & PNG_BGR) if ((png_ptr->transformations & PNG_BGR) != 0)
png_warning(png_ptr, "PNG_WRITE_BGR_SUPPORTED is not defined"); png_warning(png_ptr, "PNG_WRITE_BGR_SUPPORTED is not defined");
#endif #endif
#if !defined(PNG_WRITE_SWAP_SUPPORTED) && defined(PNG_READ_SWAP_SUPPORTED) #if !defined(PNG_WRITE_SWAP_SUPPORTED) && defined(PNG_READ_SWAP_SUPPORTED)
if (png_ptr->transformations & PNG_SWAP_BYTES) if ((png_ptr->transformations & PNG_SWAP_BYTES) != 0)
png_warning(png_ptr, "PNG_WRITE_SWAP_SUPPORTED is not defined"); png_warning(png_ptr, "PNG_WRITE_SWAP_SUPPORTED is not defined");
#endif #endif
...@@ -670,12 +756,13 @@ png_write_row(png_structrp png_ptr, png_const_bytep row) ...@@ -670,12 +756,13 @@ png_write_row(png_structrp png_ptr, png_const_bytep row)
#ifdef PNG_WRITE_INTERLACING_SUPPORTED #ifdef PNG_WRITE_INTERLACING_SUPPORTED
/* If interlaced and not interested in row, return */ /* If interlaced and not interested in row, return */
if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE)) if (png_ptr->interlaced != 0 &&
(png_ptr->transformations & PNG_INTERLACE) != 0)
{ {
switch (png_ptr->pass) switch (png_ptr->pass)
{ {
case 0: case 0:
if (png_ptr->row_number & 0x07) if ((png_ptr->row_number & 0x07) != 0)
{ {
png_write_finish_row(png_ptr); png_write_finish_row(png_ptr);
return; return;
...@@ -683,7 +770,7 @@ png_write_row(png_structrp png_ptr, png_const_bytep row) ...@@ -683,7 +770,7 @@ png_write_row(png_structrp png_ptr, png_const_bytep row)
break; break;
case 1: case 1:
if ((png_ptr->row_number & 0x07) || png_ptr->width < 5) if ((png_ptr->row_number & 0x07) != 0 || png_ptr->width < 5)
{ {
png_write_finish_row(png_ptr); png_write_finish_row(png_ptr);
return; return;
...@@ -699,7 +786,7 @@ png_write_row(png_structrp png_ptr, png_const_bytep row) ...@@ -699,7 +786,7 @@ png_write_row(png_structrp png_ptr, png_const_bytep row)
break; break;
case 3: case 3:
if ((png_ptr->row_number & 0x03) || png_ptr->width < 3) if ((png_ptr->row_number & 0x03) != 0 || png_ptr->width < 3)
{ {
png_write_finish_row(png_ptr); png_write_finish_row(png_ptr);
return; return;
...@@ -715,7 +802,7 @@ png_write_row(png_structrp png_ptr, png_const_bytep row) ...@@ -715,7 +802,7 @@ png_write_row(png_structrp png_ptr, png_const_bytep row)
break; break;
case 5: case 5:
if ((png_ptr->row_number & 0x01) || png_ptr->width < 2) if ((png_ptr->row_number & 0x01) != 0 || png_ptr->width < 2)
{ {
png_write_finish_row(png_ptr); png_write_finish_row(png_ptr);
return; return;
...@@ -723,7 +810,7 @@ png_write_row(png_structrp png_ptr, png_const_bytep row) ...@@ -723,7 +810,7 @@ png_write_row(png_structrp png_ptr, png_const_bytep row)
break; break;
case 6: case 6:
if (!(png_ptr->row_number & 0x01)) if ((png_ptr->row_number & 0x01) == 0)
{ {
png_write_finish_row(png_ptr); png_write_finish_row(png_ptr);
return; return;
...@@ -757,11 +844,11 @@ png_write_row(png_structrp png_ptr, png_const_bytep row) ...@@ -757,11 +844,11 @@ png_write_row(png_structrp png_ptr, png_const_bytep row)
#ifdef PNG_WRITE_INTERLACING_SUPPORTED #ifdef PNG_WRITE_INTERLACING_SUPPORTED
/* Handle interlacing */ /* Handle interlacing */
if (png_ptr->interlaced && png_ptr->pass < 6 && if (png_ptr->interlaced && png_ptr->pass < 6 &&
(png_ptr->transformations & PNG_INTERLACE)) (png_ptr->transformations & PNG_INTERLACE) != 0)
{ {
png_do_write_interlace(&row_info, png_ptr->row_buf + 1, png_ptr->pass); png_do_write_interlace(&row_info, png_ptr->row_buf + 1, png_ptr->pass);
/* This should always get caught above, but still ... */ /* This should always get caught above, but still ... */
if (!(row_info.width)) if (row_info.width == 0)
{ {
png_write_finish_row(png_ptr); png_write_finish_row(png_ptr);
return; return;
...@@ -771,7 +858,7 @@ png_write_row(png_structrp png_ptr, png_const_bytep row) ...@@ -771,7 +858,7 @@ png_write_row(png_structrp png_ptr, png_const_bytep row)
#ifdef PNG_WRITE_TRANSFORMS_SUPPORTED #ifdef PNG_WRITE_TRANSFORMS_SUPPORTED
/* Handle other transformations */ /* Handle other transformations */
if (png_ptr->transformations) if (png_ptr->transformations != 0)
png_do_write_transformations(png_ptr, &row_info); png_do_write_transformations(png_ptr, &row_info);
#endif #endif
...@@ -779,7 +866,7 @@ png_write_row(png_structrp png_ptr, png_const_bytep row) ...@@ -779,7 +866,7 @@ png_write_row(png_structrp png_ptr, png_const_bytep row)
* which is also the output depth. * which is also the output depth.
*/ */
if (row_info.pixel_depth != png_ptr->pixel_depth || if (row_info.pixel_depth != png_ptr->pixel_depth ||
row_info.pixel_depth != png_ptr->transformed_pixel_depth) row_info.pixel_depth != png_ptr->transformed_pixel_depth)
png_error(png_ptr, "internal write transform logic error"); png_error(png_ptr, "internal write transform logic error");
#ifdef PNG_MNG_FEATURES_SUPPORTED #ifdef PNG_MNG_FEATURES_SUPPORTED
...@@ -792,7 +879,7 @@ png_write_row(png_structrp png_ptr, png_const_bytep row) ...@@ -792,7 +879,7 @@ png_write_row(png_structrp png_ptr, png_const_bytep row)
* 4. The filter_method is 64 and * 4. The filter_method is 64 and
* 5. The color_type is RGB or RGBA * 5. The color_type is RGB or RGBA
*/ */
if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) && if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) != 0 &&
(png_ptr->filter_type == PNG_INTRAPIXEL_DIFFERENCING)) (png_ptr->filter_type == PNG_INTRAPIXEL_DIFFERENCING))
{ {
/* Intrapixel differencing */ /* Intrapixel differencing */
...@@ -825,7 +912,7 @@ png_set_flush(png_structrp png_ptr, int nrows) ...@@ -825,7 +912,7 @@ png_set_flush(png_structrp png_ptr, int nrows)
if (png_ptr == NULL) if (png_ptr == NULL)
return; return;
png_ptr->flush_dist = (nrows < 0 ? 0 : nrows); png_ptr->flush_dist = (nrows < 0 ? 0 : (png_uint_32)nrows);
} }
/* Flush the current output buffers now */ /* Flush the current output buffers now */
...@@ -845,11 +932,7 @@ png_write_flush(png_structrp png_ptr) ...@@ -845,11 +932,7 @@ png_write_flush(png_structrp png_ptr)
png_ptr->flush_rows = 0; png_ptr->flush_rows = 0;
png_flush(png_ptr); png_flush(png_ptr);
} }
#endif /* PNG_WRITE_FLUSH_SUPPORTED */ #endif /* WRITE_FLUSH */
#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
static void png_reset_filter_heuristics(png_structrp png_ptr);/* forward decl */
#endif
/* Free any memory used in png_ptr struct without freeing the struct itself. */ /* Free any memory used in png_ptr struct without freeing the struct itself. */
static void static void
...@@ -858,29 +941,25 @@ png_write_destroy(png_structrp png_ptr) ...@@ -858,29 +941,25 @@ png_write_destroy(png_structrp png_ptr)
png_debug(1, "in png_write_destroy"); png_debug(1, "in png_write_destroy");
/* Free any memory zlib uses */ /* Free any memory zlib uses */
if (png_ptr->flags & PNG_FLAG_ZSTREAM_INITIALIZED) if ((png_ptr->flags & PNG_FLAG_ZSTREAM_INITIALIZED) != 0)
deflateEnd(&png_ptr->zstream); deflateEnd(&png_ptr->zstream);
/* Free our memory. png_free checks NULL for us. */ /* Free our memory. png_free checks NULL for us. */
png_free_buffer_list(png_ptr, &png_ptr->zbuffer_list); png_free_buffer_list(png_ptr, &png_ptr->zbuffer_list);
png_free(png_ptr, png_ptr->row_buf); png_free(png_ptr, png_ptr->row_buf);
png_ptr->row_buf = NULL;
#ifdef PNG_WRITE_FILTER_SUPPORTED #ifdef PNG_WRITE_FILTER_SUPPORTED
png_free(png_ptr, png_ptr->prev_row); png_free(png_ptr, png_ptr->prev_row);
png_free(png_ptr, png_ptr->sub_row); png_free(png_ptr, png_ptr->try_row);
png_free(png_ptr, png_ptr->up_row); png_free(png_ptr, png_ptr->tst_row);
png_free(png_ptr, png_ptr->avg_row); png_ptr->prev_row = NULL;
png_free(png_ptr, png_ptr->paeth_row); png_ptr->try_row = NULL;
#endif png_ptr->tst_row = NULL;
#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
/* Use this to save a little code space, it doesn't free the filter_costs */
png_reset_filter_heuristics(png_ptr);
png_free(png_ptr, png_ptr->filter_costs);
png_free(png_ptr, png_ptr->inv_filter_costs);
#endif #endif
#ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED #ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED
png_free(png_ptr, png_ptr->chunk_list); png_free(png_ptr, png_ptr->chunk_list);
png_ptr->chunk_list = NULL;
#endif #endif
/* The error handling and memory handling information is left intact at this /* The error handling and memory handling information is left intact at this
...@@ -926,7 +1005,7 @@ png_set_filter(png_structrp png_ptr, int method, int filters) ...@@ -926,7 +1005,7 @@ png_set_filter(png_structrp png_ptr, int method, int filters)
return; return;
#ifdef PNG_MNG_FEATURES_SUPPORTED #ifdef PNG_MNG_FEATURES_SUPPORTED
if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) && if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) != 0 &&
(method == PNG_INTRAPIXEL_DIFFERENCING)) (method == PNG_INTRAPIXEL_DIFFERENCING))
method = PNG_FILTER_TYPE_BASE; method = PNG_FILTER_TYPE_BASE;
...@@ -939,8 +1018,8 @@ png_set_filter(png_structrp png_ptr, int method, int filters) ...@@ -939,8 +1018,8 @@ png_set_filter(png_structrp png_ptr, int method, int filters)
case 5: case 5:
case 6: case 6:
case 7: png_app_error(png_ptr, "Unknown row filter for method 0"); case 7: png_app_error(png_ptr, "Unknown row filter for method 0");
/* FALL THROUGH */ #endif /* WRITE_FILTER */
#endif /* PNG_WRITE_FILTER_SUPPORTED */ /* FALLTHROUGH */
case PNG_FILTER_VALUE_NONE: case PNG_FILTER_VALUE_NONE:
png_ptr->do_filter = PNG_FILTER_NONE; break; png_ptr->do_filter = PNG_FILTER_NONE; break;
...@@ -962,211 +1041,88 @@ png_set_filter(png_structrp png_ptr, int method, int filters) ...@@ -962,211 +1041,88 @@ png_set_filter(png_structrp png_ptr, int method, int filters)
#else #else
default: default:
png_app_error(png_ptr, "Unknown row filter for method 0"); png_app_error(png_ptr, "Unknown row filter for method 0");
#endif /* PNG_WRITE_FILTER_SUPPORTED */ #endif /* WRITE_FILTER */
} }
#ifdef PNG_WRITE_FILTER_SUPPORTED
/* If we have allocated the row_buf, this means we have already started /* If we have allocated the row_buf, this means we have already started
* with the image and we should have allocated all of the filter buffers * with the image and we should have allocated all of the filter buffers
* that have been selected. If prev_row isn't already allocated, then * that have been selected. If prev_row isn't already allocated, then
* it is too late to start using the filters that need it, since we * it is too late to start using the filters that need it, since we
* will be missing the data in the previous row. If an application * will be missing the data in the previous row. If an application
* wants to start and stop using particular filters during compression, * wants to start and stop using particular filters during compression,
* it should start out with all of the filters, and then add and * it should start out with all of the filters, and then remove them
* remove them after the start of compression. * or add them back after the start of compression.
*
* NOTE: this is a nasty constraint on the code, because it means that the
* prev_row buffer must be maintained even if there are currently no
* 'prev_row' requiring filters active.
*/ */
if (png_ptr->row_buf != NULL) if (png_ptr->row_buf != NULL)
{ {
#ifdef PNG_WRITE_FILTER_SUPPORTED int num_filters;
if ((png_ptr->do_filter & PNG_FILTER_SUB) && png_ptr->sub_row == NULL) png_alloc_size_t buf_size;
{
png_ptr->sub_row = (png_bytep)png_malloc(png_ptr,
(png_ptr->rowbytes + 1));
png_ptr->sub_row[0] = PNG_FILTER_VALUE_SUB;
}
if ((png_ptr->do_filter & PNG_FILTER_UP) && png_ptr->up_row == NULL) /* Repeat the checks in png_write_start_row; 1 pixel high or wide
{ * images cannot benefit from certain filters. If this isn't done here
if (png_ptr->prev_row == NULL) * the check below will fire on 1 pixel high images.
{ */
png_warning(png_ptr, "Can't add Up filter after starting"); if (png_ptr->height == 1)
png_ptr->do_filter = (png_byte)(png_ptr->do_filter & filters &= ~(PNG_FILTER_UP|PNG_FILTER_AVG|PNG_FILTER_PAETH);
~PNG_FILTER_UP);
}
else
{
png_ptr->up_row = (png_bytep)png_malloc(png_ptr,
(png_ptr->rowbytes + 1));
png_ptr->up_row[0] = PNG_FILTER_VALUE_UP;
}
}
if ((png_ptr->do_filter & PNG_FILTER_AVG) && png_ptr->avg_row == NULL)
{
if (png_ptr->prev_row == NULL)
{
png_warning(png_ptr, "Can't add Average filter after starting");
png_ptr->do_filter = (png_byte)(png_ptr->do_filter &
~PNG_FILTER_AVG);
}
else if (png_ptr->width == 1)
{ filters &= ~(PNG_FILTER_SUB|PNG_FILTER_AVG|PNG_FILTER_PAETH);
png_ptr->avg_row = (png_bytep)png_malloc(png_ptr,
(png_ptr->rowbytes + 1));
png_ptr->avg_row[0] = PNG_FILTER_VALUE_AVG;
}
}
if ((png_ptr->do_filter & PNG_FILTER_PAETH) && if ((filters & (PNG_FILTER_UP|PNG_FILTER_AVG|PNG_FILTER_PAETH)) != 0
png_ptr->paeth_row == NULL) && png_ptr->prev_row == NULL)
{ {
if (png_ptr->prev_row == NULL) /* This is the error case, however it is benign - the previous row
{ * is not available so the filter can't be used. Just warn here.
png_warning(png_ptr, "Can't add Paeth filter after starting"); */
png_ptr->do_filter &= (png_byte)(~PNG_FILTER_PAETH); png_app_warning(png_ptr,
} "png_set_filter: UP/AVG/PAETH cannot be added after start");
filters &= ~(PNG_FILTER_UP|PNG_FILTER_AVG|PNG_FILTER_PAETH);
else
{
png_ptr->paeth_row = (png_bytep)png_malloc(png_ptr,
(png_ptr->rowbytes + 1));
png_ptr->paeth_row[0] = PNG_FILTER_VALUE_PAETH;
}
} }
if (png_ptr->do_filter == PNG_NO_FILTERS) num_filters = 0;
#endif /* PNG_WRITE_FILTER_SUPPORTED */
png_ptr->do_filter = PNG_FILTER_NONE;
}
}
else
png_error(png_ptr, "Unknown custom filter method");
}
/* This allows us to influence the way in which libpng chooses the "best"
* filter for the current scanline. While the "minimum-sum-of-absolute-
* differences metric is relatively fast and effective, there is some
* question as to whether it can be improved upon by trying to keep the
* filtered data going to zlib more consistent, hopefully resulting in
* better compression.
*/
#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED /* GRR 970116 */
/* Convenience reset API. */
static void
png_reset_filter_heuristics(png_structrp png_ptr)
{
/* Clear out any old values in the 'weights' - this must be done because if
* the app calls set_filter_heuristics multiple times with different
* 'num_weights' values we would otherwise potentially have wrong sized
* arrays.
*/
png_ptr->num_prev_filters = 0;
png_ptr->heuristic_method = PNG_FILTER_HEURISTIC_UNWEIGHTED;
if (png_ptr->prev_filters != NULL)
{
png_bytep old = png_ptr->prev_filters;
png_ptr->prev_filters = NULL;
png_free(png_ptr, old);
}
if (png_ptr->filter_weights != NULL)
{
png_uint_16p old = png_ptr->filter_weights;
png_ptr->filter_weights = NULL;
png_free(png_ptr, old);
}
if (png_ptr->inv_filter_weights != NULL)
{
png_uint_16p old = png_ptr->inv_filter_weights;
png_ptr->inv_filter_weights = NULL;
png_free(png_ptr, old);
}
/* Leave the filter_costs - this array is fixed size. */ if (filters & PNG_FILTER_SUB)
} num_filters++;
static int if (filters & PNG_FILTER_UP)
png_init_filter_heuristics(png_structrp png_ptr, int heuristic_method, num_filters++;
int num_weights)
{
if (png_ptr == NULL)
return 0;
/* Clear out the arrays */ if (filters & PNG_FILTER_AVG)
png_reset_filter_heuristics(png_ptr); num_filters++;
/* Check arguments; the 'reset' function makes the correct settings for the if (filters & PNG_FILTER_PAETH)
* unweighted case, but we must handle the weight case by initializing the num_filters++;
* arrays for the caller.
*/
if (heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
{
int i;
if (num_weights > 0)
{
png_ptr->prev_filters = (png_bytep)png_malloc(png_ptr,
(png_uint_32)((sizeof (png_byte)) * num_weights));
/* To make sure that the weighting starts out fairly */ /* Allocate needed row buffers if they have not already been
for (i = 0; i < num_weights; i++) * allocated.
{ */
png_ptr->prev_filters[i] = 255; buf_size = PNG_ROWBYTES(png_ptr->usr_channels * png_ptr->usr_bit_depth,
} png_ptr->width) + 1;
png_ptr->filter_weights = (png_uint_16p)png_malloc(png_ptr,
(png_uint_32)((sizeof (png_uint_16)) * num_weights));
png_ptr->inv_filter_weights = (png_uint_16p)png_malloc(png_ptr, if (png_ptr->try_row == NULL)
(png_uint_32)((sizeof (png_uint_16)) * num_weights)); png_ptr->try_row = png_voidcast(png_bytep,
png_malloc(png_ptr, buf_size));
for (i = 0; i < num_weights; i++) if (num_filters > 1)
{ {
png_ptr->inv_filter_weights[i] = if (png_ptr->tst_row == NULL)
png_ptr->filter_weights[i] = PNG_WEIGHT_FACTOR; png_ptr->tst_row = png_voidcast(png_bytep,
png_malloc(png_ptr, buf_size));
} }
/* Safe to set this now */
png_ptr->num_prev_filters = (png_byte)num_weights;
}
/* If, in the future, there are other filter methods, this would
* need to be based on png_ptr->filter.
*/
if (png_ptr->filter_costs == NULL)
{
png_ptr->filter_costs = (png_uint_16p)png_malloc(png_ptr,
(png_uint_32)((sizeof (png_uint_16)) * PNG_FILTER_VALUE_LAST));
png_ptr->inv_filter_costs = (png_uint_16p)png_malloc(png_ptr,
(png_uint_32)((sizeof (png_uint_16)) * PNG_FILTER_VALUE_LAST));
} }
png_ptr->do_filter = (png_byte)filters;
for (i = 0; i < PNG_FILTER_VALUE_LAST; i++) #endif
{
png_ptr->inv_filter_costs[i] =
png_ptr->filter_costs[i] = PNG_COST_FACTOR;
}
/* All the arrays are inited, safe to set this: */
png_ptr->heuristic_method = PNG_FILTER_HEURISTIC_WEIGHTED;
/* Return the 'ok' code. */
return 1;
}
else if (heuristic_method == PNG_FILTER_HEURISTIC_DEFAULT ||
heuristic_method == PNG_FILTER_HEURISTIC_UNWEIGHTED)
{
return 1;
} }
else else
{ png_error(png_ptr, "Unknown custom filter method");
png_warning(png_ptr, "Unknown filter heuristic method");
return 0;
}
} }
#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED /* DEPRECATED */
/* Provide floating and fixed point APIs */ /* Provide floating and fixed point APIs */
#ifdef PNG_FLOATING_POINT_SUPPORTED #ifdef PNG_FLOATING_POINT_SUPPORTED
void PNGAPI void PNGAPI
...@@ -1174,52 +1130,11 @@ png_set_filter_heuristics(png_structrp png_ptr, int heuristic_method, ...@@ -1174,52 +1130,11 @@ png_set_filter_heuristics(png_structrp png_ptr, int heuristic_method,
int num_weights, png_const_doublep filter_weights, int num_weights, png_const_doublep filter_weights,
png_const_doublep filter_costs) png_const_doublep filter_costs)
{ {
png_debug(1, "in png_set_filter_heuristics"); PNG_UNUSED(png_ptr)
PNG_UNUSED(heuristic_method)
/* The internal API allocates all the arrays and ensures that the elements of PNG_UNUSED(num_weights)
* those arrays are set to the default value. PNG_UNUSED(filter_weights)
*/ PNG_UNUSED(filter_costs)
if (!png_init_filter_heuristics(png_ptr, heuristic_method, num_weights))
return;
/* If using the weighted method copy in the weights. */
if (heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
{
int i;
for (i = 0; i < num_weights; i++)
{
if (filter_weights[i] <= 0.0)
{
png_ptr->inv_filter_weights[i] =
png_ptr->filter_weights[i] = PNG_WEIGHT_FACTOR;
}
else
{
png_ptr->inv_filter_weights[i] =
(png_uint_16)(PNG_WEIGHT_FACTOR*filter_weights[i]+.5);
png_ptr->filter_weights[i] =
(png_uint_16)(PNG_WEIGHT_FACTOR/filter_weights[i]+.5);
}
}
/* Here is where we set the relative costs of the different filters. We
* should take the desired compression level into account when setting
* the costs, so that Paeth, for instance, has a high relative cost at low
* compression levels, while it has a lower relative cost at higher
* compression settings. The filter types are in order of increasing
* relative cost, so it would be possible to do this with an algorithm.
*/
for (i = 0; i < PNG_FILTER_VALUE_LAST; i++) if (filter_costs[i] >= 1.0)
{
png_ptr->inv_filter_costs[i] =
(png_uint_16)(PNG_COST_FACTOR / filter_costs[i] + .5);
png_ptr->filter_costs[i] =
(png_uint_16)(PNG_COST_FACTOR * filter_costs[i] + .5);
}
}
} }
#endif /* FLOATING_POINT */ #endif /* FLOATING_POINT */
...@@ -1229,67 +1144,16 @@ png_set_filter_heuristics_fixed(png_structrp png_ptr, int heuristic_method, ...@@ -1229,67 +1144,16 @@ png_set_filter_heuristics_fixed(png_structrp png_ptr, int heuristic_method,
int num_weights, png_const_fixed_point_p filter_weights, int num_weights, png_const_fixed_point_p filter_weights,
png_const_fixed_point_p filter_costs) png_const_fixed_point_p filter_costs)
{ {
png_debug(1, "in png_set_filter_heuristics_fixed"); PNG_UNUSED(png_ptr)
PNG_UNUSED(heuristic_method)
/* The internal API allocates all the arrays and ensures that the elements of PNG_UNUSED(num_weights)
* those arrays are set to the default value. PNG_UNUSED(filter_weights)
*/ PNG_UNUSED(filter_costs)
if (!png_init_filter_heuristics(png_ptr, heuristic_method, num_weights))
return;
/* If using the weighted method copy in the weights. */
if (heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
{
int i;
for (i = 0; i < num_weights; i++)
{
if (filter_weights[i] <= 0)
{
png_ptr->inv_filter_weights[i] =
png_ptr->filter_weights[i] = PNG_WEIGHT_FACTOR;
}
else
{
png_ptr->inv_filter_weights[i] = (png_uint_16)
((PNG_WEIGHT_FACTOR*filter_weights[i]+PNG_FP_HALF)/PNG_FP_1);
png_ptr->filter_weights[i] = (png_uint_16)((PNG_WEIGHT_FACTOR*
PNG_FP_1+(filter_weights[i]/2))/filter_weights[i]);
}
}
/* Here is where we set the relative costs of the different filters. We
* should take the desired compression level into account when setting
* the costs, so that Paeth, for instance, has a high relative cost at low
* compression levels, while it has a lower relative cost at higher
* compression settings. The filter types are in order of increasing
* relative cost, so it would be possible to do this with an algorithm.
*/
for (i = 0; i < PNG_FILTER_VALUE_LAST; i++)
if (filter_costs[i] >= PNG_FP_1)
{
png_uint_32 tmp;
/* Use a 32 bit unsigned temporary here because otherwise the
* intermediate value will be a 32 bit *signed* integer (ANSI rules)
* and this will get the wrong answer on division.
*/
tmp = PNG_COST_FACTOR*PNG_FP_1 + (filter_costs[i]/2);
tmp /= filter_costs[i];
png_ptr->inv_filter_costs[i] = (png_uint_16)tmp;
tmp = PNG_COST_FACTOR * filter_costs[i] + PNG_FP_HALF;
tmp /= PNG_FP_1;
png_ptr->filter_costs[i] = (png_uint_16)tmp;
}
}
} }
#endif /* FIXED_POINT */ #endif /* FIXED_POINT */
#endif /* PNG_WRITE_WEIGHTED_FILTER_SUPPORTED */ #endif /* WRITE_WEIGHTED_FILTER */
#ifdef PNG_WRITE_CUSTOMIZE_COMPRESSION_SUPPORTED
void PNGAPI void PNGAPI
png_set_compression_level(png_structrp png_ptr, int level) png_set_compression_level(png_structrp png_ptr, int level)
{ {
...@@ -1335,8 +1199,8 @@ png_set_compression_window_bits(png_structrp png_ptr, int window_bits) ...@@ -1335,8 +1199,8 @@ png_set_compression_window_bits(png_structrp png_ptr, int window_bits)
if (png_ptr == NULL) if (png_ptr == NULL)
return; return;
/* Prior to 1.6.0 this would warn but then set the window_bits value, this /* Prior to 1.6.0 this would warn but then set the window_bits value. This
* meant that negative window bits values could be selected which would cause * meant that negative window bits values could be selected that would cause
* libpng to write a non-standard PNG file with raw deflate or gzip * libpng to write a non-standard PNG file with raw deflate or gzip
* compressed IDAT or ancillary chunks. Such files can be read and there is * compressed IDAT or ancillary chunks. Such files can be read and there is
* no warning on read, so this seems like a very bad idea. * no warning on read, so this seems like a very bad idea.
...@@ -1372,6 +1236,7 @@ png_set_compression_method(png_structrp png_ptr, int method) ...@@ -1372,6 +1236,7 @@ png_set_compression_method(png_structrp png_ptr, int method)
png_ptr->zlib_method = method; png_ptr->zlib_method = method;
} }
#endif /* WRITE_CUSTOMIZE_COMPRESSION */
/* The following were added to libpng-1.5.4 */ /* The following were added to libpng-1.5.4 */
#ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED #ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED
...@@ -1445,7 +1310,7 @@ png_set_text_compression_method(png_structrp png_ptr, int method) ...@@ -1445,7 +1310,7 @@ png_set_text_compression_method(png_structrp png_ptr, int method)
png_ptr->zlib_text_method = method; png_ptr->zlib_text_method = method;
} }
#endif /* PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED */ #endif /* WRITE_CUSTOMIZE_ZTXT_COMPRESSION */
/* end of API added to libpng-1.5.4 */ /* end of API added to libpng-1.5.4 */
void PNGAPI void PNGAPI
...@@ -1481,94 +1346,129 @@ png_write_png(png_structrp png_ptr, png_inforp info_ptr, ...@@ -1481,94 +1346,129 @@ png_write_png(png_structrp png_ptr, png_inforp info_ptr,
if (png_ptr == NULL || info_ptr == NULL) if (png_ptr == NULL || info_ptr == NULL)
return; return;
if ((info_ptr->valid & PNG_INFO_IDAT) == 0)
{
png_app_error(png_ptr, "no rows for png_write_image to write");
return;
}
/* Write the file header information. */ /* Write the file header information. */
png_write_info(png_ptr, info_ptr); png_write_info(png_ptr, info_ptr);
/* ------ these transformations don't touch the info structure ------- */ /* ------ these transformations don't touch the info structure ------- */
#ifdef PNG_WRITE_INVERT_SUPPORTED
/* Invert monochrome pixels */ /* Invert monochrome pixels */
if (transforms & PNG_TRANSFORM_INVERT_MONO) if ((transforms & PNG_TRANSFORM_INVERT_MONO) != 0)
#ifdef PNG_WRITE_INVERT_SUPPORTED
png_set_invert_mono(png_ptr); png_set_invert_mono(png_ptr);
#else
png_app_error(png_ptr, "PNG_TRANSFORM_INVERT_MONO not supported");
#endif #endif
#ifdef PNG_WRITE_SHIFT_SUPPORTED
/* Shift the pixels up to a legal bit depth and fill in /* Shift the pixels up to a legal bit depth and fill in
* as appropriate to correctly scale the image. * as appropriate to correctly scale the image.
*/ */
if ((transforms & PNG_TRANSFORM_SHIFT) if ((transforms & PNG_TRANSFORM_SHIFT) != 0)
&& (info_ptr->valid & PNG_INFO_sBIT)) #ifdef PNG_WRITE_SHIFT_SUPPORTED
png_set_shift(png_ptr, &info_ptr->sig_bit); if ((info_ptr->valid & PNG_INFO_sBIT) != 0)
png_set_shift(png_ptr, &info_ptr->sig_bit);
#else
png_app_error(png_ptr, "PNG_TRANSFORM_SHIFT not supported");
#endif #endif
#ifdef PNG_WRITE_PACK_SUPPORTED
/* Pack pixels into bytes */ /* Pack pixels into bytes */
if (transforms & PNG_TRANSFORM_PACKING) if ((transforms & PNG_TRANSFORM_PACKING) != 0)
png_set_packing(png_ptr); #ifdef PNG_WRITE_PACK_SUPPORTED
png_set_packing(png_ptr);
#else
png_app_error(png_ptr, "PNG_TRANSFORM_PACKING not supported");
#endif #endif
#ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED
/* Swap location of alpha bytes from ARGB to RGBA */ /* Swap location of alpha bytes from ARGB to RGBA */
if (transforms & PNG_TRANSFORM_SWAP_ALPHA) if ((transforms & PNG_TRANSFORM_SWAP_ALPHA) != 0)
#ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED
png_set_swap_alpha(png_ptr); png_set_swap_alpha(png_ptr);
#else
png_app_error(png_ptr, "PNG_TRANSFORM_SWAP_ALPHA not supported");
#endif #endif
/* Remove a filler (X) from XRGB/RGBX/AG/GA into to convert it into
* RGB, note that the code expects the input color type to be G or RGB; no
* alpha channel.
*/
if ((transforms & (PNG_TRANSFORM_STRIP_FILLER_AFTER|
PNG_TRANSFORM_STRIP_FILLER_BEFORE)) != 0)
{
#ifdef PNG_WRITE_FILLER_SUPPORTED #ifdef PNG_WRITE_FILLER_SUPPORTED
/* Pack XRGB/RGBX/ARGB/RGBA into RGB (4 channels -> 3 channels) */ if ((transforms & PNG_TRANSFORM_STRIP_FILLER_AFTER) != 0)
if (transforms & PNG_TRANSFORM_STRIP_FILLER_AFTER) {
png_set_filler(png_ptr, 0, PNG_FILLER_AFTER); if ((transforms & PNG_TRANSFORM_STRIP_FILLER_BEFORE) != 0)
png_app_error(png_ptr,
"PNG_TRANSFORM_STRIP_FILLER: BEFORE+AFTER not supported");
else if (transforms & PNG_TRANSFORM_STRIP_FILLER_BEFORE) /* Continue if ignored - this is the pre-1.6.10 behavior */
png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE); png_set_filler(png_ptr, 0, PNG_FILLER_AFTER);
}
else if ((transforms & PNG_TRANSFORM_STRIP_FILLER_BEFORE) != 0)
png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE);
#else
png_app_error(png_ptr, "PNG_TRANSFORM_STRIP_FILLER not supported");
#endif #endif
}
#ifdef PNG_WRITE_BGR_SUPPORTED
/* Flip BGR pixels to RGB */ /* Flip BGR pixels to RGB */
if (transforms & PNG_TRANSFORM_BGR) if ((transforms & PNG_TRANSFORM_BGR) != 0)
#ifdef PNG_WRITE_BGR_SUPPORTED
png_set_bgr(png_ptr); png_set_bgr(png_ptr);
#else
png_app_error(png_ptr, "PNG_TRANSFORM_BGR not supported");
#endif #endif
#ifdef PNG_WRITE_SWAP_SUPPORTED
/* Swap bytes of 16-bit files to most significant byte first */ /* Swap bytes of 16-bit files to most significant byte first */
if (transforms & PNG_TRANSFORM_SWAP_ENDIAN) if ((transforms & PNG_TRANSFORM_SWAP_ENDIAN) != 0)
#ifdef PNG_WRITE_SWAP_SUPPORTED
png_set_swap(png_ptr); png_set_swap(png_ptr);
#else
png_app_error(png_ptr, "PNG_TRANSFORM_SWAP_ENDIAN not supported");
#endif #endif
/* Swap bits of 1-bit, 2-bit, 4-bit packed pixel formats */
if ((transforms & PNG_TRANSFORM_PACKSWAP) != 0)
#ifdef PNG_WRITE_PACKSWAP_SUPPORTED #ifdef PNG_WRITE_PACKSWAP_SUPPORTED
/* Swap bits of 1, 2, 4 bit packed pixel formats */
if (transforms & PNG_TRANSFORM_PACKSWAP)
png_set_packswap(png_ptr); png_set_packswap(png_ptr);
#else
png_app_error(png_ptr, "PNG_TRANSFORM_PACKSWAP not supported");
#endif #endif
#ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED
/* Invert the alpha channel from opacity to transparency */ /* Invert the alpha channel from opacity to transparency */
if (transforms & PNG_TRANSFORM_INVERT_ALPHA) if ((transforms & PNG_TRANSFORM_INVERT_ALPHA) != 0)
#ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED
png_set_invert_alpha(png_ptr); png_set_invert_alpha(png_ptr);
#else
png_app_error(png_ptr, "PNG_TRANSFORM_INVERT_ALPHA not supported");
#endif #endif
/* ----------------------- end of transformations ------------------- */ /* ----------------------- end of transformations ------------------- */
/* Write the bits */ /* Write the bits */
if (info_ptr->valid & PNG_INFO_IDAT) png_write_image(png_ptr, info_ptr->row_pointers);
png_write_image(png_ptr, info_ptr->row_pointers);
/* It is REQUIRED to call this to finish writing the rest of the file */ /* It is REQUIRED to call this to finish writing the rest of the file */
png_write_end(png_ptr, info_ptr); png_write_end(png_ptr, info_ptr);
PNG_UNUSED(transforms) /* Quiet compiler warnings */
PNG_UNUSED(params) PNG_UNUSED(params)
} }
#endif #endif
#ifdef PNG_SIMPLIFIED_WRITE_SUPPORTED #ifdef PNG_SIMPLIFIED_WRITE_SUPPORTED
#ifdef PNG_STDIO_SUPPORTED /* currently required for png_image_write_* */
/* Initialize the write structure - general purpose utility. */ /* Initialize the write structure - general purpose utility. */
static int static int
png_image_write_init(png_imagep image) png_image_write_init(png_imagep image)
{ {
png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, image, png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, image,
png_safe_error, png_safe_warning); png_safe_error, png_safe_warning);
if (png_ptr != NULL) if (png_ptr != NULL)
{ {
...@@ -1577,7 +1477,7 @@ png_image_write_init(png_imagep image) ...@@ -1577,7 +1477,7 @@ png_image_write_init(png_imagep image)
if (info_ptr != NULL) if (info_ptr != NULL)
{ {
png_controlp control = png_voidcast(png_controlp, png_controlp control = png_voidcast(png_controlp,
png_malloc_warn(png_ptr, (sizeof *control))); png_malloc_warn(png_ptr, (sizeof *control)));
if (control != NULL) if (control != NULL)
{ {
...@@ -1614,6 +1514,10 @@ typedef struct ...@@ -1614,6 +1514,10 @@ typedef struct
png_const_voidp first_row; png_const_voidp first_row;
ptrdiff_t row_bytes; ptrdiff_t row_bytes;
png_voidp local_row; png_voidp local_row;
/* Byte count for memory writing */
png_bytep memory;
png_alloc_size_t memory_bytes; /* not used for STDIO */
png_alloc_size_t output_bytes; /* running total */
} png_image_write_control; } png_image_write_control;
/* Write png_uint_16 input to a 16-bit PNG; the png_ptr has already been set to /* Write png_uint_16 input to a 16-bit PNG; the png_ptr has already been set to
...@@ -1624,29 +1528,33 @@ static int ...@@ -1624,29 +1528,33 @@ static int
png_write_image_16bit(png_voidp argument) png_write_image_16bit(png_voidp argument)
{ {
png_image_write_control *display = png_voidcast(png_image_write_control*, png_image_write_control *display = png_voidcast(png_image_write_control*,
argument); argument);
png_imagep image = display->image; png_imagep image = display->image;
png_structrp png_ptr = image->opaque->png_ptr; png_structrp png_ptr = image->opaque->png_ptr;
png_const_uint_16p input_row = png_voidcast(png_const_uint_16p, png_const_uint_16p input_row = png_voidcast(png_const_uint_16p,
display->first_row); display->first_row);
png_uint_16p output_row = png_voidcast(png_uint_16p, display->local_row); png_uint_16p output_row = png_voidcast(png_uint_16p, display->local_row);
png_uint_16p row_end; png_uint_16p row_end;
const int channels = (image->format & PNG_FORMAT_FLAG_COLOR) ? 3 : 1; unsigned int channels = (image->format & PNG_FORMAT_FLAG_COLOR) != 0 ?
3 : 1;
int aindex = 0; int aindex = 0;
png_uint_32 y = image->height; png_uint_32 y = image->height;
if (image->format & PNG_FORMAT_FLAG_ALPHA) if ((image->format & PNG_FORMAT_FLAG_ALPHA) != 0)
{ {
if (image->format & PNG_FORMAT_FLAG_AFIRST) # ifdef PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED
if ((image->format & PNG_FORMAT_FLAG_AFIRST) != 0)
{ {
aindex = -1; aindex = -1;
++input_row; /* To point to the first component */ ++input_row; /* To point to the first component */
++output_row; ++output_row;
} }
else
else aindex = (int)channels;
aindex = channels; # else
aindex = (int)channels;
# endif
} }
else else
...@@ -1658,14 +1566,14 @@ png_write_image_16bit(png_voidp argument) ...@@ -1658,14 +1566,14 @@ png_write_image_16bit(png_voidp argument)
*/ */
row_end = output_row + image->width * (channels+1); row_end = output_row + image->width * (channels+1);
while (y-- > 0) for (; y > 0; --y)
{ {
png_const_uint_16p in_ptr = input_row; png_const_uint_16p in_ptr = input_row;
png_uint_16p out_ptr = output_row; png_uint_16p out_ptr = output_row;
while (out_ptr < row_end) while (out_ptr < row_end)
{ {
const png_uint_16 alpha = in_ptr[aindex]; png_uint_16 alpha = in_ptr[aindex];
png_uint_32 reciprocal = 0; png_uint_32 reciprocal = 0;
int c; int c;
...@@ -1679,7 +1587,7 @@ png_write_image_16bit(png_voidp argument) ...@@ -1679,7 +1587,7 @@ png_write_image_16bit(png_voidp argument)
if (alpha > 0 && alpha < 65535) if (alpha > 0 && alpha < 65535)
reciprocal = ((0xffff<<15)+(alpha>>1))/alpha; reciprocal = ((0xffff<<15)+(alpha>>1))/alpha;
c = channels; c = (int)channels;
do /* always at least one channel */ do /* always at least one channel */
{ {
png_uint_16 component = *in_ptr++; png_uint_16 component = *in_ptr++;
...@@ -1714,7 +1622,7 @@ png_write_image_16bit(png_voidp argument) ...@@ -1714,7 +1622,7 @@ png_write_image_16bit(png_voidp argument)
} }
png_write_row(png_ptr, png_voidcast(png_const_bytep, display->local_row)); png_write_row(png_ptr, png_voidcast(png_const_bytep, display->local_row));
input_row += display->row_bytes/(sizeof (png_uint_16)); input_row += (png_uint_16)display->row_bytes/(sizeof (png_uint_16));
} }
return 1; return 1;
...@@ -1728,11 +1636,11 @@ png_write_image_16bit(png_voidp argument) ...@@ -1728,11 +1636,11 @@ png_write_image_16bit(png_voidp argument)
* calculation can be done to 15 bits of accuracy; however, the output needs to * calculation can be done to 15 bits of accuracy; however, the output needs to
* be scaled in the range 0..255*65535, so include that scaling here. * be scaled in the range 0..255*65535, so include that scaling here.
*/ */
#define UNP_RECIPROCAL(alpha) ((((0xffff*0xff)<<7)+(alpha>>1))/alpha) # define UNP_RECIPROCAL(alpha) ((((0xffff*0xff)<<7)+((alpha)>>1))/(alpha))
static png_byte static png_byte
png_unpremultiply(png_uint_32 component, png_uint_32 alpha, png_unpremultiply(png_uint_32 component, png_uint_32 alpha,
png_uint_32 reciprocal/*from the above macro*/) png_uint_32 reciprocal/*from the above macro*/)
{ {
/* The following gives 1.0 for an alpha of 0, which is fine, otherwise if 0/0 /* The following gives 1.0 for an alpha of 0, which is fine, otherwise if 0/0
* is represented as some other value there is more likely to be a * is represented as some other value there is more likely to be a
...@@ -1779,22 +1687,24 @@ static int ...@@ -1779,22 +1687,24 @@ static int
png_write_image_8bit(png_voidp argument) png_write_image_8bit(png_voidp argument)
{ {
png_image_write_control *display = png_voidcast(png_image_write_control*, png_image_write_control *display = png_voidcast(png_image_write_control*,
argument); argument);
png_imagep image = display->image; png_imagep image = display->image;
png_structrp png_ptr = image->opaque->png_ptr; png_structrp png_ptr = image->opaque->png_ptr;
png_const_uint_16p input_row = png_voidcast(png_const_uint_16p, png_const_uint_16p input_row = png_voidcast(png_const_uint_16p,
display->first_row); display->first_row);
png_bytep output_row = png_voidcast(png_bytep, display->local_row); png_bytep output_row = png_voidcast(png_bytep, display->local_row);
png_uint_32 y = image->height; png_uint_32 y = image->height;
const int channels = (image->format & PNG_FORMAT_FLAG_COLOR) ? 3 : 1; unsigned int channels = (image->format & PNG_FORMAT_FLAG_COLOR) != 0 ?
3 : 1;
if (image->format & PNG_FORMAT_FLAG_ALPHA) if ((image->format & PNG_FORMAT_FLAG_ALPHA) != 0)
{ {
png_bytep row_end; png_bytep row_end;
int aindex; int aindex;
if (image->format & PNG_FORMAT_FLAG_AFIRST) # ifdef PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED
if ((image->format & PNG_FORMAT_FLAG_AFIRST) != 0)
{ {
aindex = -1; aindex = -1;
++input_row; /* To point to the first component */ ++input_row; /* To point to the first component */
...@@ -1802,12 +1712,13 @@ png_write_image_8bit(png_voidp argument) ...@@ -1802,12 +1712,13 @@ png_write_image_8bit(png_voidp argument)
} }
else else
aindex = channels; # endif
aindex = (int)channels;
/* Use row_end in place of a loop counter: */ /* Use row_end in place of a loop counter: */
row_end = output_row + image->width * (channels+1); row_end = output_row + image->width * (channels+1);
while (y-- > 0) for (; y > 0; --y)
{ {
png_const_uint_16p in_ptr = input_row; png_const_uint_16p in_ptr = input_row;
png_bytep out_ptr = output_row; png_bytep out_ptr = output_row;
...@@ -1825,7 +1736,7 @@ png_write_image_8bit(png_voidp argument) ...@@ -1825,7 +1736,7 @@ png_write_image_8bit(png_voidp argument)
if (alphabyte > 0 && alphabyte < 255) if (alphabyte > 0 && alphabyte < 255)
reciprocal = UNP_RECIPROCAL(alpha); reciprocal = UNP_RECIPROCAL(alpha);
c = channels; c = (int)channels;
do /* always at least one channel */ do /* always at least one channel */
*out_ptr++ = png_unpremultiply(*in_ptr++, alpha, reciprocal); *out_ptr++ = png_unpremultiply(*in_ptr++, alpha, reciprocal);
while (--c > 0); while (--c > 0);
...@@ -1836,8 +1747,8 @@ png_write_image_8bit(png_voidp argument) ...@@ -1836,8 +1747,8 @@ png_write_image_8bit(png_voidp argument)
} /* while out_ptr < row_end */ } /* while out_ptr < row_end */
png_write_row(png_ptr, png_voidcast(png_const_bytep, png_write_row(png_ptr, png_voidcast(png_const_bytep,
display->local_row)); display->local_row));
input_row += display->row_bytes/(sizeof (png_uint_16)); input_row += (png_uint_16)display->row_bytes/(sizeof (png_uint_16));
} /* while y */ } /* while y */
} }
...@@ -1848,7 +1759,7 @@ png_write_image_8bit(png_voidp argument) ...@@ -1848,7 +1759,7 @@ png_write_image_8bit(png_voidp argument)
*/ */
png_bytep row_end = output_row + image->width * channels; png_bytep row_end = output_row + image->width * channels;
while (y-- > 0) for (; y > 0; --y)
{ {
png_const_uint_16p in_ptr = input_row; png_const_uint_16p in_ptr = input_row;
png_bytep out_ptr = output_row; png_bytep out_ptr = output_row;
...@@ -1862,7 +1773,7 @@ png_write_image_8bit(png_voidp argument) ...@@ -1862,7 +1773,7 @@ png_write_image_8bit(png_voidp argument)
} }
png_write_row(png_ptr, output_row); png_write_row(png_ptr, output_row);
input_row += display->row_bytes/(sizeof (png_uint_16)); input_row += (png_uint_16)display->row_bytes/(sizeof (png_uint_16));
} }
} }
...@@ -1872,27 +1783,28 @@ png_write_image_8bit(png_voidp argument) ...@@ -1872,27 +1783,28 @@ png_write_image_8bit(png_voidp argument)
static void static void
png_image_set_PLTE(png_image_write_control *display) png_image_set_PLTE(png_image_write_control *display)
{ {
const png_imagep image = display->image; png_imagep image = display->image;
const void *cmap = display->colormap; const void *cmap = display->colormap;
const int entries = image->colormap_entries > 256 ? 256 : int entries = image->colormap_entries > 256 ? 256 :
(int)image->colormap_entries; (int)image->colormap_entries;
/* NOTE: the caller must check for cmap != NULL and entries != 0 */ /* NOTE: the caller must check for cmap != NULL and entries != 0 */
const png_uint_32 format = image->format; png_uint_32 format = image->format;
const int channels = PNG_IMAGE_SAMPLE_CHANNELS(format); unsigned int channels = PNG_IMAGE_SAMPLE_CHANNELS(format);
# ifdef PNG_FORMAT_BGR_SUPPORTED # if defined(PNG_FORMAT_BGR_SUPPORTED) &&\
const int afirst = (format & PNG_FORMAT_FLAG_AFIRST) != 0 && defined(PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED)
(format & PNG_FORMAT_FLAG_ALPHA) != 0; int afirst = (format & PNG_FORMAT_FLAG_AFIRST) != 0 &&
# else (format & PNG_FORMAT_FLAG_ALPHA) != 0;
# else
# define afirst 0 # define afirst 0
# endif # endif
# ifdef PNG_FORMAT_BGR_SUPPORTED # ifdef PNG_FORMAT_BGR_SUPPORTED
const int bgr = (format & PNG_FORMAT_FLAG_BGR) ? 2 : 0; int bgr = (format & PNG_FORMAT_FLAG_BGR) != 0 ? 2 : 0;
# else # else
# define bgr 0 # define bgr 0
# endif # endif
int i, num_trans; int i, num_trans;
png_color palette[256]; png_color palette[256];
...@@ -1906,22 +1818,22 @@ png_image_set_PLTE(png_image_write_control *display) ...@@ -1906,22 +1818,22 @@ png_image_set_PLTE(png_image_write_control *display)
/* This gets automatically converted to sRGB with reversal of the /* This gets automatically converted to sRGB with reversal of the
* pre-multiplication if the color-map has an alpha channel. * pre-multiplication if the color-map has an alpha channel.
*/ */
if (format & PNG_FORMAT_FLAG_LINEAR) if ((format & PNG_FORMAT_FLAG_LINEAR) != 0)
{ {
png_const_uint_16p entry = png_voidcast(png_const_uint_16p, cmap); png_const_uint_16p entry = png_voidcast(png_const_uint_16p, cmap);
entry += i * channels; entry += (unsigned int)i * channels;
if (channels & 1) /* no alpha */ if ((channels & 1) != 0) /* no alpha */
{ {
if (channels >= 3) /* RGB */ if (channels >= 3) /* RGB */
{ {
palette[i].blue = (png_byte)PNG_sRGB_FROM_LINEAR(255 * palette[i].blue = (png_byte)PNG_sRGB_FROM_LINEAR(255 *
entry[(2 ^ bgr)]); entry[(2 ^ bgr)]);
palette[i].green = (png_byte)PNG_sRGB_FROM_LINEAR(255 * palette[i].green = (png_byte)PNG_sRGB_FROM_LINEAR(255 *
entry[1]); entry[1]);
palette[i].red = (png_byte)PNG_sRGB_FROM_LINEAR(255 * palette[i].red = (png_byte)PNG_sRGB_FROM_LINEAR(255 *
entry[bgr]); entry[bgr]);
} }
else /* Gray */ else /* Gray */
...@@ -1949,16 +1861,16 @@ png_image_set_PLTE(png_image_write_control *display) ...@@ -1949,16 +1861,16 @@ png_image_set_PLTE(png_image_write_control *display)
if (channels >= 3) /* RGB */ if (channels >= 3) /* RGB */
{ {
palette[i].blue = png_unpremultiply(entry[afirst + (2 ^ bgr)], palette[i].blue = png_unpremultiply(entry[afirst + (2 ^ bgr)],
alpha, reciprocal); alpha, reciprocal);
palette[i].green = png_unpremultiply(entry[afirst + 1], alpha, palette[i].green = png_unpremultiply(entry[afirst + 1], alpha,
reciprocal); reciprocal);
palette[i].red = png_unpremultiply(entry[afirst + bgr], alpha, palette[i].red = png_unpremultiply(entry[afirst + bgr], alpha,
reciprocal); reciprocal);
} }
else /* gray */ else /* gray */
palette[i].blue = palette[i].red = palette[i].green = palette[i].blue = palette[i].red = palette[i].green =
png_unpremultiply(entry[afirst], alpha, reciprocal); png_unpremultiply(entry[afirst], alpha, reciprocal);
} }
} }
...@@ -1966,7 +1878,7 @@ png_image_set_PLTE(png_image_write_control *display) ...@@ -1966,7 +1878,7 @@ png_image_set_PLTE(png_image_write_control *display)
{ {
png_const_bytep entry = png_voidcast(png_const_bytep, cmap); png_const_bytep entry = png_voidcast(png_const_bytep, cmap);
entry += i * channels; entry += (unsigned int)i * channels;
switch (channels) switch (channels)
{ {
...@@ -1974,7 +1886,7 @@ png_image_set_PLTE(png_image_write_control *display) ...@@ -1974,7 +1886,7 @@ png_image_set_PLTE(png_image_write_control *display)
tRNS[i] = entry[afirst ? 0 : 3]; tRNS[i] = entry[afirst ? 0 : 3];
if (tRNS[i] < 255) if (tRNS[i] < 255)
num_trans = i+1; num_trans = i+1;
/* FALL THROUGH */ /* FALLTHROUGH */
case 3: case 3:
palette[i].blue = entry[afirst + (2 ^ bgr)]; palette[i].blue = entry[afirst + (2 ^ bgr)];
palette[i].green = entry[afirst + 1]; palette[i].green = entry[afirst + 1];
...@@ -1985,7 +1897,7 @@ png_image_set_PLTE(png_image_write_control *display) ...@@ -1985,7 +1897,7 @@ png_image_set_PLTE(png_image_write_control *display)
tRNS[i] = entry[1 ^ afirst]; tRNS[i] = entry[1 ^ afirst];
if (tRNS[i] < 255) if (tRNS[i] < 255)
num_trans = i+1; num_trans = i+1;
/* FALL THROUGH */ /* FALLTHROUGH */
case 1: case 1:
palette[i].blue = palette[i].red = palette[i].green = palette[i].blue = palette[i].red = palette[i].green =
entry[afirst]; entry[afirst];
...@@ -1997,73 +1909,108 @@ png_image_set_PLTE(png_image_write_control *display) ...@@ -1997,73 +1909,108 @@ png_image_set_PLTE(png_image_write_control *display)
} }
} }
# ifdef afirst # ifdef afirst
# undef afirst # undef afirst
# endif # endif
# ifdef bgr # ifdef bgr
# undef bgr # undef bgr
# endif # endif
png_set_PLTE(image->opaque->png_ptr, image->opaque->info_ptr, palette, png_set_PLTE(image->opaque->png_ptr, image->opaque->info_ptr, palette,
entries); entries);
if (num_trans > 0) if (num_trans > 0)
png_set_tRNS(image->opaque->png_ptr, image->opaque->info_ptr, tRNS, png_set_tRNS(image->opaque->png_ptr, image->opaque->info_ptr, tRNS,
num_trans, NULL); num_trans, NULL);
image->colormap_entries = entries; image->colormap_entries = (png_uint_32)entries;
} }
static int static int
png_image_write_main(png_voidp argument) png_image_write_main(png_voidp argument)
{ {
png_image_write_control *display = png_voidcast(png_image_write_control*, png_image_write_control *display = png_voidcast(png_image_write_control*,
argument); argument);
png_imagep image = display->image; png_imagep image = display->image;
png_structrp png_ptr = image->opaque->png_ptr; png_structrp png_ptr = image->opaque->png_ptr;
png_inforp info_ptr = image->opaque->info_ptr; png_inforp info_ptr = image->opaque->info_ptr;
png_uint_32 format = image->format; png_uint_32 format = image->format;
int colormap = (format & PNG_FORMAT_FLAG_COLORMAP) != 0; /* The following four ints are actually booleans */
int linear = !colormap && (format & PNG_FORMAT_FLAG_LINEAR) != 0; /* input */ int colormap = (format & PNG_FORMAT_FLAG_COLORMAP);
int alpha = !colormap && (format & PNG_FORMAT_FLAG_ALPHA) != 0; int linear = !colormap && (format & PNG_FORMAT_FLAG_LINEAR); /* input */
int write_16bit = linear && !colormap && !display->convert_to_8bit; int alpha = !colormap && (format & PNG_FORMAT_FLAG_ALPHA);
int write_16bit = linear && (display->convert_to_8bit == 0);
# ifdef PNG_BENIGN_ERRORS_SUPPORTED # ifdef PNG_BENIGN_ERRORS_SUPPORTED
/* Make sure we error out on any bad situation */ /* Make sure we error out on any bad situation */
png_set_benign_errors(png_ptr, 0/*error*/); png_set_benign_errors(png_ptr, 0/*error*/);
# endif # endif
/* Default the 'row_stride' parameter if required. */ /* Default the 'row_stride' parameter if required, also check the row stride
if (display->row_stride == 0) * and total image size to ensure that they are within the system limits.
display->row_stride = PNG_IMAGE_ROW_STRIDE(*image); */
{
unsigned int channels = PNG_IMAGE_PIXEL_CHANNELS(image->format);
if (image->width <= 0x7fffffffU/channels) /* no overflow */
{
png_uint_32 check;
png_uint_32 png_row_stride = image->width * channels;
if (display->row_stride == 0)
display->row_stride = (png_int_32)/*SAFE*/png_row_stride;
if (display->row_stride < 0)
check = (png_uint_32)(-display->row_stride);
else
check = (png_uint_32)display->row_stride;
if (check >= png_row_stride)
{
/* Now check for overflow of the image buffer calculation; this
* limits the whole image size to 32 bits for API compatibility with
* the current, 32-bit, PNG_IMAGE_BUFFER_SIZE macro.
*/
if (image->height > 0xffffffffU/png_row_stride)
png_error(image->opaque->png_ptr, "memory image too large");
}
else
png_error(image->opaque->png_ptr, "supplied row stride too small");
}
else
png_error(image->opaque->png_ptr, "image row stride too large");
}
/* Set the required transforms then write the rows in the correct order. */ /* Set the required transforms then write the rows in the correct order. */
if (format & PNG_FORMAT_FLAG_COLORMAP) if ((format & PNG_FORMAT_FLAG_COLORMAP) != 0)
{ {
if (display->colormap != NULL && image->colormap_entries > 0) if (display->colormap != NULL && image->colormap_entries > 0)
{ {
png_uint_32 entries = image->colormap_entries; png_uint_32 entries = image->colormap_entries;
png_set_IHDR(png_ptr, info_ptr, image->width, image->height, png_set_IHDR(png_ptr, info_ptr, image->width, image->height,
entries > 16 ? 8 : (entries > 4 ? 4 : (entries > 2 ? 2 : 1)), entries > 16 ? 8 : (entries > 4 ? 4 : (entries > 2 ? 2 : 1)),
PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE, PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
png_image_set_PLTE(display); png_image_set_PLTE(display);
} }
else else
png_error(image->opaque->png_ptr, png_error(image->opaque->png_ptr,
"no color-map for color-mapped image"); "no color-map for color-mapped image");
} }
else else
png_set_IHDR(png_ptr, info_ptr, image->width, image->height, png_set_IHDR(png_ptr, info_ptr, image->width, image->height,
write_16bit ? 16 : 8, write_16bit ? 16 : 8,
((format & PNG_FORMAT_FLAG_COLOR) ? PNG_COLOR_MASK_COLOR : 0) + ((format & PNG_FORMAT_FLAG_COLOR) ? PNG_COLOR_MASK_COLOR : 0) +
((format & PNG_FORMAT_FLAG_ALPHA) ? PNG_COLOR_MASK_ALPHA : 0), ((format & PNG_FORMAT_FLAG_ALPHA) ? PNG_COLOR_MASK_ALPHA : 0),
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
/* Counter-intuitively the data transformations must be called *after* /* Counter-intuitively the data transformations must be called *after*
* png_write_info, not before as in the read code, but the 'set' functions * png_write_info, not before as in the read code, but the 'set' functions
...@@ -2071,22 +2018,22 @@ png_image_write_main(png_voidp argument) ...@@ -2071,22 +2018,22 @@ png_image_write_main(png_voidp argument)
* write an interlaced image. * write an interlaced image.
*/ */
if (write_16bit) if (write_16bit != 0)
{ {
/* The gamma here is 1.0 (linear) and the cHRM chunk matches sRGB. */ /* The gamma here is 1.0 (linear) and the cHRM chunk matches sRGB. */
png_set_gAMA_fixed(png_ptr, info_ptr, PNG_GAMMA_LINEAR); png_set_gAMA_fixed(png_ptr, info_ptr, PNG_GAMMA_LINEAR);
if (!(image->flags & PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB)) if ((image->flags & PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB) == 0)
png_set_cHRM_fixed(png_ptr, info_ptr, png_set_cHRM_fixed(png_ptr, info_ptr,
/* color x y */ /* color x y */
/* white */ 31270, 32900, /* white */ 31270, 32900,
/* red */ 64000, 33000, /* red */ 64000, 33000,
/* green */ 30000, 60000, /* green */ 30000, 60000,
/* blue */ 15000, 6000 /* blue */ 15000, 6000
); );
} }
else if (!(image->flags & PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB)) else if ((image->flags & PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB) == 0)
png_set_sRGB(png_ptr, info_ptr, PNG_sRGB_INTENT_PERCEPTUAL); png_set_sRGB(png_ptr, info_ptr, PNG_sRGB_INTENT_PERCEPTUAL);
/* Else writing an 8-bit file and the *colors* aren't sRGB, but the 8-bit /* Else writing an 8-bit file and the *colors* aren't sRGB, but the 8-bit
...@@ -2101,38 +2048,38 @@ png_image_write_main(png_voidp argument) ...@@ -2101,38 +2048,38 @@ png_image_write_main(png_voidp argument)
/* Now set up the data transformations (*after* the header is written), /* Now set up the data transformations (*after* the header is written),
* remove the handled transformations from the 'format' flags for checking. * remove the handled transformations from the 'format' flags for checking.
* *
* First check for a little endian system if writing 16 bit files. * First check for a little endian system if writing 16-bit files.
*/ */
if (write_16bit) if (write_16bit != 0)
{ {
PNG_CONST png_uint_16 le = 0x0001; png_uint_16 le = 0x0001;
if (*(png_const_bytep)&le) if ((*(png_const_bytep) & le) != 0)
png_set_swap(png_ptr); png_set_swap(png_ptr);
} }
# ifdef PNG_SIMPLIFIED_WRITE_BGR_SUPPORTED # ifdef PNG_SIMPLIFIED_WRITE_BGR_SUPPORTED
if (format & PNG_FORMAT_FLAG_BGR) if ((format & PNG_FORMAT_FLAG_BGR) != 0)
{ {
if (!colormap && (format & PNG_FORMAT_FLAG_COLOR) != 0) if (colormap == 0 && (format & PNG_FORMAT_FLAG_COLOR) != 0)
png_set_bgr(png_ptr); png_set_bgr(png_ptr);
format &= ~PNG_FORMAT_FLAG_BGR; format &= ~PNG_FORMAT_FLAG_BGR;
} }
# endif # endif
# ifdef PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED # ifdef PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED
if (format & PNG_FORMAT_FLAG_AFIRST) if ((format & PNG_FORMAT_FLAG_AFIRST) != 0)
{ {
if (!colormap && (format & PNG_FORMAT_FLAG_ALPHA) != 0) if (colormap == 0 && (format & PNG_FORMAT_FLAG_ALPHA) != 0)
png_set_swap_alpha(png_ptr); png_set_swap_alpha(png_ptr);
format &= ~PNG_FORMAT_FLAG_AFIRST; format &= ~PNG_FORMAT_FLAG_AFIRST;
} }
# endif # endif
/* If there are 16 or fewer color-map entries we wrote a lower bit depth /* If there are 16 or fewer color-map entries we wrote a lower bit depth
* above, but the application data is still byte packed. * above, but the application data is still byte packed.
*/ */
if (colormap && image->colormap_entries <= 16) if (colormap != 0 && image->colormap_entries <= 16)
png_set_packing(png_ptr); png_set_packing(png_ptr);
/* That should have handled all (both) the transforms. */ /* That should have handled all (both) the transforms. */
...@@ -2144,7 +2091,7 @@ png_image_write_main(png_voidp argument) ...@@ -2144,7 +2091,7 @@ png_image_write_main(png_voidp argument)
png_const_bytep row = png_voidcast(png_const_bytep, display->buffer); png_const_bytep row = png_voidcast(png_const_bytep, display->buffer);
ptrdiff_t row_bytes = display->row_stride; ptrdiff_t row_bytes = display->row_stride;
if (linear) if (linear != 0)
row_bytes *= (sizeof (png_uint_16)); row_bytes *= (sizeof (png_uint_16));
if (row_bytes < 0) if (row_bytes < 0)
...@@ -2163,21 +2110,24 @@ png_image_write_main(png_voidp argument) ...@@ -2163,21 +2110,24 @@ png_image_write_main(png_voidp argument)
* it about 50 times. The speed-up in pngstest was about 10-20% of the * it about 50 times. The speed-up in pngstest was about 10-20% of the
* total (user) time on a heavily loaded system. * total (user) time on a heavily loaded system.
*/ */
# ifdef PNG_WRITE_CUSTOMIZE_COMPRESSION_SUPPORTED
png_set_compression_level(png_ptr, 3); png_set_compression_level(png_ptr, 3);
# endif
} }
/* Check for the cases that currently require a pre-transform on the row /* Check for the cases that currently require a pre-transform on the row
* before it is written. This only applies when the input is 16-bit and * 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. * either there is an alpha channel or it is converted to 8-bit.
*/ */
if ((linear && alpha) || (!colormap && display->convert_to_8bit)) if ((linear != 0 && alpha != 0 ) ||
(colormap == 0 && display->convert_to_8bit != 0))
{ {
png_bytep row = png_voidcast(png_bytep, png_malloc(png_ptr, png_bytep row = png_voidcast(png_bytep, png_malloc(png_ptr,
png_get_rowbytes(png_ptr, info_ptr))); png_get_rowbytes(png_ptr, info_ptr)));
int result; int result;
display->local_row = row; display->local_row = row;
if (write_16bit) if (write_16bit != 0)
result = png_safe_execute(image, png_write_image_16bit, display); result = png_safe_execute(image, png_write_image_16bit, display);
else else
result = png_safe_execute(image, png_write_image_8bit, display); result = png_safe_execute(image, png_write_image_8bit, display);
...@@ -2186,7 +2136,7 @@ png_image_write_main(png_voidp argument) ...@@ -2186,7 +2136,7 @@ png_image_write_main(png_voidp argument)
png_free(png_ptr, row); png_free(png_ptr, row);
/* Skip the 'write_end' on error: */ /* Skip the 'write_end' on error: */
if (!result) if (result == 0)
return 0; return 0;
} }
...@@ -2199,7 +2149,7 @@ png_image_write_main(png_voidp argument) ...@@ -2199,7 +2149,7 @@ png_image_write_main(png_voidp argument)
ptrdiff_t row_bytes = display->row_bytes; ptrdiff_t row_bytes = display->row_bytes;
png_uint_32 y = image->height; png_uint_32 y = image->height;
while (y-- > 0) for (; y > 0; --y)
{ {
png_write_row(png_ptr, row); png_write_row(png_ptr, row);
row += row_bytes; row += row_bytes;
...@@ -2210,16 +2160,131 @@ png_image_write_main(png_voidp argument) ...@@ -2210,16 +2160,131 @@ png_image_write_main(png_voidp argument)
return 1; return 1;
} }
static void (PNGCBAPI
image_memory_write)(png_structp png_ptr, png_bytep/*const*/ data, size_t size)
{
png_image_write_control *display = png_voidcast(png_image_write_control*,
png_ptr->io_ptr/*backdoor: png_get_io_ptr(png_ptr)*/);
png_alloc_size_t ob = display->output_bytes;
/* Check for overflow; this should never happen: */
if (size <= ((png_alloc_size_t)-1) - ob)
{
/* I don't think libpng ever does this, but just in case: */
if (size > 0)
{
if (display->memory_bytes >= ob+size) /* writing */
memcpy(display->memory+ob, data, size);
/* Always update the size: */
display->output_bytes = ob+size;
}
}
else
png_error(png_ptr, "png_image_write_to_memory: PNG too big");
}
static void (PNGCBAPI
image_memory_flush)(png_structp png_ptr)
{
PNG_UNUSED(png_ptr)
}
static int
png_image_write_memory(png_voidp argument)
{
png_image_write_control *display = png_voidcast(png_image_write_control*,
argument);
/* The rest of the memory-specific init and write_main in an error protected
* environment. This case needs to use callbacks for the write operations
* since libpng has no built in support for writing to memory.
*/
png_set_write_fn(display->image->opaque->png_ptr, display/*io_ptr*/,
image_memory_write, image_memory_flush);
return png_image_write_main(display);
}
int PNGAPI
png_image_write_to_memory(png_imagep image, void *memory,
png_alloc_size_t * PNG_RESTRICT memory_bytes, int convert_to_8bit,
const void *buffer, png_int_32 row_stride, const void *colormap)
{
/* Write the image to the given buffer, or count the bytes if it is NULL */
if (image != NULL && image->version == PNG_IMAGE_VERSION)
{
if (memory_bytes != NULL && buffer != NULL)
{
/* This is to give the caller an easier error detection in the NULL
* case and guard against uninitialized variable problems:
*/
if (memory == NULL)
*memory_bytes = 0;
if (png_image_write_init(image) != 0)
{
png_image_write_control display;
int result;
memset(&display, 0, (sizeof display));
display.image = image;
display.buffer = buffer;
display.row_stride = row_stride;
display.colormap = colormap;
display.convert_to_8bit = convert_to_8bit;
display.memory = png_voidcast(png_bytep, memory);
display.memory_bytes = *memory_bytes;
display.output_bytes = 0;
result = png_safe_execute(image, png_image_write_memory, &display);
png_image_free(image);
/* write_memory returns true even if we ran out of buffer. */
if (result)
{
/* On out-of-buffer this function returns '0' but still updates
* memory_bytes:
*/
if (memory != NULL && display.output_bytes > *memory_bytes)
result = 0;
*memory_bytes = display.output_bytes;
}
return result;
}
else
return 0;
}
else
return png_image_error(image,
"png_image_write_to_memory: invalid argument");
}
else if (image != NULL)
return png_image_error(image,
"png_image_write_to_memory: incorrect PNG_IMAGE_VERSION");
else
return 0;
}
#ifdef PNG_SIMPLIFIED_WRITE_STDIO_SUPPORTED
int PNGAPI int PNGAPI
png_image_write_to_stdio(png_imagep image, FILE *file, int convert_to_8bit, 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) 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*). */
if (image != NULL && image->version == PNG_IMAGE_VERSION) if (image != NULL && image->version == PNG_IMAGE_VERSION)
{ {
if (file != NULL) if (file != NULL && buffer != NULL)
{ {
if (png_image_write_init(image)) if (png_image_write_init(image) != 0)
{ {
png_image_write_control display; png_image_write_control display;
int result; int result;
...@@ -2248,12 +2313,12 @@ png_image_write_to_stdio(png_imagep image, FILE *file, int convert_to_8bit, ...@@ -2248,12 +2313,12 @@ png_image_write_to_stdio(png_imagep image, FILE *file, int convert_to_8bit,
else else
return png_image_error(image, return png_image_error(image,
"png_image_write_to_stdio: invalid argument"); "png_image_write_to_stdio: invalid argument");
} }
else if (image != NULL) else if (image != NULL)
return png_image_error(image, return png_image_error(image,
"png_image_write_to_stdio: incorrect PNG_IMAGE_VERSION"); "png_image_write_to_stdio: incorrect PNG_IMAGE_VERSION");
else else
return 0; return 0;
...@@ -2261,20 +2326,20 @@ png_image_write_to_stdio(png_imagep image, FILE *file, int convert_to_8bit, ...@@ -2261,20 +2326,20 @@ png_image_write_to_stdio(png_imagep image, FILE *file, int convert_to_8bit,
int PNGAPI int PNGAPI
png_image_write_to_file(png_imagep image, const char *file_name, png_image_write_to_file(png_imagep image, const char *file_name,
int convert_to_8bit, const void *buffer, png_int_32 row_stride, int convert_to_8bit, const void *buffer, png_int_32 row_stride,
const void *colormap) const void *colormap)
{ {
/* Write the image to the named file. */ /* Write the image to the named file. */
if (image != NULL && image->version == PNG_IMAGE_VERSION) if (image != NULL && image->version == PNG_IMAGE_VERSION)
{ {
if (file_name != NULL) if (file_name != NULL && buffer != NULL)
{ {
FILE *fp = fopen(file_name, "wb"); FILE *fp = fopen(file_name, "wb");
if (fp != NULL) if (fp != NULL)
{ {
if (png_image_write_to_stdio(image, fp, convert_to_8bit, buffer, if (png_image_write_to_stdio(image, fp, convert_to_8bit, buffer,
row_stride, colormap)) row_stride, colormap) != 0)
{ {
int error; /* from fflush/fclose */ int error; /* from fflush/fclose */
...@@ -2315,16 +2380,16 @@ png_image_write_to_file(png_imagep image, const char *file_name, ...@@ -2315,16 +2380,16 @@ png_image_write_to_file(png_imagep image, const char *file_name,
else else
return png_image_error(image, return png_image_error(image,
"png_image_write_to_file: invalid argument"); "png_image_write_to_file: invalid argument");
} }
else if (image != NULL) else if (image != NULL)
return png_image_error(image, return png_image_error(image,
"png_image_write_to_file: incorrect PNG_IMAGE_VERSION"); "png_image_write_to_file: incorrect PNG_IMAGE_VERSION");
else else
return 0; return 0;
} }
#endif /* PNG_STDIO_SUPPORTED */ #endif /* SIMPLIFIED_WRITE_STDIO */
#endif /* SIMPLIFIED_WRITE */ #endif /* SIMPLIFIED_WRITE */
#endif /* PNG_WRITE_SUPPORTED */ #endif /* WRITE */
/* pngwtran.c - transforms the data in a row for PNG writers /* pngwtran.c - transforms the data in a row for PNG writers
* *
* Last changed in libpng 1.6.0 [February 14, 2013] * Copyright (c) 2018 Cosmin Truta
* Copyright (c) 1998-2013 Glenn Randers-Pehrson * Copyright (c) 1998-2002,2004,2006-2016,2018 Glenn Randers-Pehrson
* (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * Copyright (c) 1996-1997 Andreas Dilger
* (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
* *
* This code is released under the libpng license. * This code is released under the libpng license.
* For conditions of distribution and use, see the disclaimer * For conditions of distribution and use, see the disclaimer
...@@ -14,90 +14,14 @@ ...@@ -14,90 +14,14 @@
#include "pngpriv.h" #include "pngpriv.h"
#ifdef PNG_WRITE_SUPPORTED #ifdef PNG_WRITE_SUPPORTED
#ifdef PNG_WRITE_TRANSFORMS_SUPPORTED #ifdef PNG_WRITE_TRANSFORMS_SUPPORTED
/* Transform the data according to the user's wishes. The order of
* transformations is significant.
*/
void /* PRIVATE */
png_do_write_transformations(png_structrp png_ptr, png_row_infop row_info)
{
png_debug(1, "in png_do_write_transformations");
if (png_ptr == NULL)
return;
#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED
if (png_ptr->transformations & PNG_USER_TRANSFORM)
if (png_ptr->write_user_transform_fn != NULL)
(*(png_ptr->write_user_transform_fn)) /* User write transform
function */
(png_ptr, /* png_ptr */
row_info, /* row_info: */
/* png_uint_32 width; width of row */
/* png_size_t rowbytes; number of bytes in row */
/* png_byte color_type; color type of pixels */
/* png_byte bit_depth; bit depth of samples */
/* png_byte channels; number of channels (1-4) */
/* png_byte pixel_depth; bits per pixel (depth*channels) */
png_ptr->row_buf + 1); /* start of pixel data for row */
#endif
#ifdef PNG_WRITE_FILLER_SUPPORTED
if (png_ptr->transformations & PNG_FILLER)
png_do_strip_channel(row_info, png_ptr->row_buf + 1,
!(png_ptr->flags & PNG_FLAG_FILLER_AFTER));
#endif
#ifdef PNG_WRITE_PACKSWAP_SUPPORTED
if (png_ptr->transformations & PNG_PACKSWAP)
png_do_packswap(row_info, png_ptr->row_buf + 1);
#endif
#ifdef PNG_WRITE_PACK_SUPPORTED
if (png_ptr->transformations & PNG_PACK)
png_do_pack(row_info, png_ptr->row_buf + 1,
(png_uint_32)png_ptr->bit_depth);
#endif
#ifdef PNG_WRITE_SWAP_SUPPORTED
if (png_ptr->transformations & PNG_SWAP_BYTES)
png_do_swap(row_info, png_ptr->row_buf + 1);
#endif
#ifdef PNG_WRITE_SHIFT_SUPPORTED
if (png_ptr->transformations & PNG_SHIFT)
png_do_shift(row_info, png_ptr->row_buf + 1,
&(png_ptr->shift));
#endif
#ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED
if (png_ptr->transformations & PNG_SWAP_ALPHA)
png_do_write_swap_alpha(row_info, png_ptr->row_buf + 1);
#endif
#ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED
if (png_ptr->transformations & PNG_INVERT_ALPHA)
png_do_write_invert_alpha(row_info, png_ptr->row_buf + 1);
#endif
#ifdef PNG_WRITE_BGR_SUPPORTED
if (png_ptr->transformations & PNG_BGR)
png_do_bgr(row_info, png_ptr->row_buf + 1);
#endif
#ifdef PNG_WRITE_INVERT_SUPPORTED
if (png_ptr->transformations & PNG_INVERT_MONO)
png_do_invert(row_info, png_ptr->row_buf + 1);
#endif
}
#ifdef PNG_WRITE_PACK_SUPPORTED #ifdef PNG_WRITE_PACK_SUPPORTED
/* Pack pixels into bytes. Pass the true bit depth in bit_depth. The /* Pack pixels into bytes. Pass the true bit depth in bit_depth. The
* row_info bit depth should be 8 (one pixel per byte). The channels * row_info bit depth should be 8 (one pixel per byte). The channels
* should be 1 (this only happens on grayscale and paletted images). * should be 1 (this only happens on grayscale and paletted images).
*/ */
void /* PRIVATE */ static void
png_do_pack(png_row_infop row_info, png_bytep row, png_uint_32 bit_depth) png_do_pack(png_row_infop row_info, png_bytep row, png_uint_32 bit_depth)
{ {
png_debug(1, "in png_do_pack"); png_debug(1, "in png_do_pack");
...@@ -147,7 +71,8 @@ png_do_pack(png_row_infop row_info, png_bytep row, png_uint_32 bit_depth) ...@@ -147,7 +71,8 @@ png_do_pack(png_row_infop row_info, png_bytep row, png_uint_32 bit_depth)
case 2: case 2:
{ {
png_bytep sp, dp; png_bytep sp, dp;
int shift, v; unsigned int shift;
int v;
png_uint_32 i; png_uint_32 i;
png_uint_32 row_width = row_info->width; png_uint_32 row_width = row_info->width;
...@@ -186,7 +111,8 @@ png_do_pack(png_row_infop row_info, png_bytep row, png_uint_32 bit_depth) ...@@ -186,7 +111,8 @@ png_do_pack(png_row_infop row_info, png_bytep row, png_uint_32 bit_depth)
case 4: case 4:
{ {
png_bytep sp, dp; png_bytep sp, dp;
int shift, v; unsigned int shift;
int v;
png_uint_32 i; png_uint_32 i;
png_uint_32 row_width = row_info->width; png_uint_32 row_width = row_info->width;
...@@ -242,7 +168,7 @@ png_do_pack(png_row_infop row_info, png_bytep row, png_uint_32 bit_depth) ...@@ -242,7 +168,7 @@ png_do_pack(png_row_infop row_info, png_bytep row, png_uint_32 bit_depth)
* would pass 3 as bit_depth, and this routine would translate the * would pass 3 as bit_depth, and this routine would translate the
* data to 0 to 15. * data to 0 to 15.
*/ */
void /* PRIVATE */ static void
png_do_shift(png_row_infop row_info, png_bytep row, png_do_shift(png_row_infop row_info, png_bytep row,
png_const_color_8p bit_depth) png_const_color_8p bit_depth)
{ {
...@@ -251,9 +177,9 @@ png_do_shift(png_row_infop row_info, png_bytep row, ...@@ -251,9 +177,9 @@ png_do_shift(png_row_infop row_info, png_bytep row,
if (row_info->color_type != PNG_COLOR_TYPE_PALETTE) if (row_info->color_type != PNG_COLOR_TYPE_PALETTE)
{ {
int shift_start[4], shift_dec[4]; int shift_start[4], shift_dec[4];
int channels = 0; unsigned int channels = 0;
if (row_info->color_type & PNG_COLOR_MASK_COLOR) if ((row_info->color_type & PNG_COLOR_MASK_COLOR) != 0)
{ {
shift_start[channels] = row_info->bit_depth - bit_depth->red; shift_start[channels] = row_info->bit_depth - bit_depth->red;
shift_dec[channels] = bit_depth->red; shift_dec[channels] = bit_depth->red;
...@@ -275,7 +201,7 @@ png_do_shift(png_row_infop row_info, png_bytep row, ...@@ -275,7 +201,7 @@ png_do_shift(png_row_infop row_info, png_bytep row,
channels++; channels++;
} }
if (row_info->color_type & PNG_COLOR_MASK_ALPHA) if ((row_info->color_type & PNG_COLOR_MASK_ALPHA) != 0)
{ {
shift_start[channels] = row_info->bit_depth - bit_depth->alpha; shift_start[channels] = row_info->bit_depth - bit_depth->alpha;
shift_dec[channels] = bit_depth->alpha; shift_dec[channels] = bit_depth->alpha;
...@@ -286,9 +212,9 @@ png_do_shift(png_row_infop row_info, png_bytep row, ...@@ -286,9 +212,9 @@ png_do_shift(png_row_infop row_info, png_bytep row,
if (row_info->bit_depth < 8) if (row_info->bit_depth < 8)
{ {
png_bytep bp = row; png_bytep bp = row;
png_size_t i; size_t i;
unsigned int mask; unsigned int mask;
png_size_t row_bytes = row_info->rowbytes; size_t row_bytes = row_info->rowbytes;
if (bit_depth->gray == 1 && row_info->bit_depth == 2) if (bit_depth->gray == 1 && row_info->bit_depth == 2)
mask = 0x55; mask = 0x55;
...@@ -328,8 +254,7 @@ png_do_shift(png_row_infop row_info, png_bytep row, ...@@ -328,8 +254,7 @@ png_do_shift(png_row_infop row_info, png_bytep row,
for (i = 0; i < istop; i++, bp++) for (i = 0; i < istop; i++, bp++)
{ {
unsigned int c = i%channels;
const unsigned int c = i%channels;
int j; int j;
unsigned int v, out; unsigned int v, out;
...@@ -357,7 +282,7 @@ png_do_shift(png_row_infop row_info, png_bytep row, ...@@ -357,7 +282,7 @@ png_do_shift(png_row_infop row_info, png_bytep row,
for (bp = row, i = 0; i < istop; i++) for (bp = row, i = 0; i < istop; i++)
{ {
const unsigned int c = i%channels; unsigned int c = i%channels;
int j; int j;
unsigned int value, v; unsigned int value, v;
...@@ -381,7 +306,7 @@ png_do_shift(png_row_infop row_info, png_bytep row, ...@@ -381,7 +306,7 @@ png_do_shift(png_row_infop row_info, png_bytep row,
#endif #endif
#ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED #ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED
void /* PRIVATE */ static void
png_do_write_swap_alpha(png_row_infop row_info, png_bytep row) png_do_write_swap_alpha(png_row_infop row_info, png_bytep row)
{ {
png_debug(1, "in png_do_write_swap_alpha"); png_debug(1, "in png_do_write_swap_alpha");
...@@ -429,7 +354,7 @@ png_do_write_swap_alpha(png_row_infop row_info, png_bytep row) ...@@ -429,7 +354,7 @@ png_do_write_swap_alpha(png_row_infop row_info, png_bytep row)
*(dp++) = save[1]; *(dp++) = save[1];
} }
} }
#endif /* PNG_WRITE_16BIT_SUPPORTED */ #endif /* WRITE_16BIT */
} }
else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
...@@ -468,14 +393,14 @@ png_do_write_swap_alpha(png_row_infop row_info, png_bytep row) ...@@ -468,14 +393,14 @@ png_do_write_swap_alpha(png_row_infop row_info, png_bytep row)
*(dp++) = save[1]; *(dp++) = save[1];
} }
} }
#endif /* PNG_WRITE_16BIT_SUPPORTED */ #endif /* WRITE_16BIT */
} }
} }
} }
#endif #endif
#ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED #ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED
void /* PRIVATE */ static void
png_do_write_invert_alpha(png_row_infop row_info, png_bytep row) png_do_write_invert_alpha(png_row_infop row_info, png_bytep row)
{ {
png_debug(1, "in png_do_write_invert_alpha"); png_debug(1, "in png_do_write_invert_alpha");
...@@ -498,7 +423,7 @@ png_do_write_invert_alpha(png_row_infop row_info, png_bytep row) ...@@ -498,7 +423,7 @@ png_do_write_invert_alpha(png_row_infop row_info, png_bytep row)
*(dp++) = *(sp++); *(dp++) = *(sp++);
*/ */
sp+=3; dp = sp; sp+=3; dp = sp;
*(dp++) = (png_byte)(255 - *(sp++)); *dp = (png_byte)(255 - *(sp++));
} }
} }
...@@ -522,10 +447,10 @@ png_do_write_invert_alpha(png_row_infop row_info, png_bytep row) ...@@ -522,10 +447,10 @@ png_do_write_invert_alpha(png_row_infop row_info, png_bytep row)
*/ */
sp+=6; dp = sp; sp+=6; dp = sp;
*(dp++) = (png_byte)(255 - *(sp++)); *(dp++) = (png_byte)(255 - *(sp++));
*(dp++) = (png_byte)(255 - *(sp++)); *dp = (png_byte)(255 - *(sp++));
} }
} }
#endif /* PNG_WRITE_16BIT_SUPPORTED */ #endif /* WRITE_16BIT */
} }
else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
...@@ -560,78 +485,91 @@ png_do_write_invert_alpha(png_row_infop row_info, png_bytep row) ...@@ -560,78 +485,91 @@ png_do_write_invert_alpha(png_row_infop row_info, png_bytep row)
*/ */
sp+=2; dp = sp; sp+=2; dp = sp;
*(dp++) = (png_byte)(255 - *(sp++)); *(dp++) = (png_byte)(255 - *(sp++));
*(dp++) = (png_byte)(255 - *(sp++)); *dp = (png_byte)(255 - *(sp++));
} }
} }
#endif /* PNG_WRITE_16BIT_SUPPORTED */ #endif /* WRITE_16BIT */
} }
} }
} }
#endif #endif
#endif /* PNG_WRITE_TRANSFORMS_SUPPORTED */
#ifdef PNG_MNG_FEATURES_SUPPORTED /* Transform the data according to the user's wishes. The order of
/* Undoes intrapixel differencing */ * transformations is significant.
*/
void /* PRIVATE */ void /* PRIVATE */
png_do_write_intrapixel(png_row_infop row_info, png_bytep row) png_do_write_transformations(png_structrp png_ptr, png_row_infop row_info)
{ {
png_debug(1, "in png_do_write_intrapixel"); png_debug(1, "in png_do_write_transformations");
if ((row_info->color_type & PNG_COLOR_MASK_COLOR)) if (png_ptr == NULL)
{ return;
int bytes_per_pixel;
png_uint_32 row_width = row_info->width;
if (row_info->bit_depth == 8)
{
png_bytep rp;
png_uint_32 i;
if (row_info->color_type == PNG_COLOR_TYPE_RGB) #ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED
bytes_per_pixel = 3; if ((png_ptr->transformations & PNG_USER_TRANSFORM) != 0)
if (png_ptr->write_user_transform_fn != NULL)
(*(png_ptr->write_user_transform_fn)) /* User write transform
function */
(png_ptr, /* png_ptr */
row_info, /* row_info: */
/* png_uint_32 width; width of row */
/* size_t rowbytes; number of bytes in row */
/* png_byte color_type; color type of pixels */
/* png_byte bit_depth; bit depth of samples */
/* png_byte channels; number of channels (1-4) */
/* png_byte pixel_depth; bits per pixel (depth*channels) */
png_ptr->row_buf + 1); /* start of pixel data for row */
#endif
else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) #ifdef PNG_WRITE_FILLER_SUPPORTED
bytes_per_pixel = 4; if ((png_ptr->transformations & PNG_FILLER) != 0)
png_do_strip_channel(row_info, png_ptr->row_buf + 1,
!(png_ptr->flags & PNG_FLAG_FILLER_AFTER));
#endif
else #ifdef PNG_WRITE_PACKSWAP_SUPPORTED
return; if ((png_ptr->transformations & PNG_PACKSWAP) != 0)
png_do_packswap(row_info, png_ptr->row_buf + 1);
#endif
for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel) #ifdef PNG_WRITE_PACK_SUPPORTED
{ if ((png_ptr->transformations & PNG_PACK) != 0)
*(rp) = (png_byte)((*rp - *(rp + 1)) & 0xff); png_do_pack(row_info, png_ptr->row_buf + 1,
*(rp + 2) = (png_byte)((*(rp + 2) - *(rp + 1)) & 0xff); (png_uint_32)png_ptr->bit_depth);
} #endif
}
#ifdef PNG_WRITE_16BIT_SUPPORTED #ifdef PNG_WRITE_SWAP_SUPPORTED
else if (row_info->bit_depth == 16) # ifdef PNG_16BIT_SUPPORTED
{ if ((png_ptr->transformations & PNG_SWAP_BYTES) != 0)
png_bytep rp; png_do_swap(row_info, png_ptr->row_buf + 1);
png_uint_32 i; # endif
#endif
if (row_info->color_type == PNG_COLOR_TYPE_RGB) #ifdef PNG_WRITE_SHIFT_SUPPORTED
bytes_per_pixel = 6; if ((png_ptr->transformations & PNG_SHIFT) != 0)
png_do_shift(row_info, png_ptr->row_buf + 1,
&(png_ptr->shift));
#endif
else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) #ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED
bytes_per_pixel = 8; if ((png_ptr->transformations & PNG_SWAP_ALPHA) != 0)
png_do_write_swap_alpha(row_info, png_ptr->row_buf + 1);
#endif
else #ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED
return; if ((png_ptr->transformations & PNG_INVERT_ALPHA) != 0)
png_do_write_invert_alpha(row_info, png_ptr->row_buf + 1);
#endif
for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel) #ifdef PNG_WRITE_BGR_SUPPORTED
{ if ((png_ptr->transformations & PNG_BGR) != 0)
png_uint_32 s0 = (*(rp ) << 8) | *(rp + 1); png_do_bgr(row_info, png_ptr->row_buf + 1);
png_uint_32 s1 = (*(rp + 2) << 8) | *(rp + 3); #endif
png_uint_32 s2 = (*(rp + 4) << 8) | *(rp + 5);
png_uint_32 red = (png_uint_32)((s0 - s1) & 0xffffL); #ifdef PNG_WRITE_INVERT_SUPPORTED
png_uint_32 blue = (png_uint_32)((s2 - s1) & 0xffffL); if ((png_ptr->transformations & PNG_INVERT_MONO) != 0)
*(rp ) = (png_byte)((red >> 8) & 0xff); png_do_invert(row_info, png_ptr->row_buf + 1);
*(rp + 1) = (png_byte)(red & 0xff); #endif
*(rp + 4) = (png_byte)((blue >> 8) & 0xff);
*(rp + 5) = (png_byte)(blue & 0xff);
}
}
#endif /* PNG_WRITE_16BIT_SUPPORTED */
}
} }
#endif /* PNG_MNG_FEATURES_SUPPORTED */ #endif /* WRITE_TRANSFORMS */
#endif /* PNG_WRITE_SUPPORTED */ #endif /* WRITE */
/* pngwutil.c - utilities to write a PNG file /* pngwutil.c - utilities to write a PNG file
* *
* Last changed in libpng 1.6.2 [April 25, 2013] * Copyright (c) 2018 Cosmin Truta
* Copyright (c) 1998-2013 Glenn Randers-Pehrson * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
* (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * Copyright (c) 1996-1997 Andreas Dilger
* (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
* *
* This code is released under the libpng license. * This code is released under the libpng license.
* For conditions of distribution and use, see the disclaimer * For conditions of distribution and use, see the disclaimer
...@@ -23,10 +23,10 @@ ...@@ -23,10 +23,10 @@
void PNGAPI void PNGAPI
png_save_uint_32(png_bytep buf, png_uint_32 i) png_save_uint_32(png_bytep buf, png_uint_32 i)
{ {
buf[0] = (png_byte)((i >> 24) & 0xff); buf[0] = (png_byte)((i >> 24) & 0xffU);
buf[1] = (png_byte)((i >> 16) & 0xff); buf[1] = (png_byte)((i >> 16) & 0xffU);
buf[2] = (png_byte)((i >> 8) & 0xff); buf[2] = (png_byte)((i >> 8) & 0xffU);
buf[3] = (png_byte)(i & 0xff); buf[3] = (png_byte)( i & 0xffU);
} }
/* Place a 16-bit number into a buffer in PNG byte order. /* Place a 16-bit number into a buffer in PNG byte order.
...@@ -36,8 +36,8 @@ png_save_uint_32(png_bytep buf, png_uint_32 i) ...@@ -36,8 +36,8 @@ png_save_uint_32(png_bytep buf, png_uint_32 i)
void PNGAPI void PNGAPI
png_save_uint_16(png_bytep buf, unsigned int i) png_save_uint_16(png_bytep buf, unsigned int i)
{ {
buf[0] = (png_byte)((i >> 8) & 0xff); buf[0] = (png_byte)((i >> 8) & 0xffU);
buf[1] = (png_byte)(i & 0xff); buf[1] = (png_byte)( i & 0xffU);
} }
#endif #endif
...@@ -59,7 +59,7 @@ png_write_sig(png_structrp png_ptr) ...@@ -59,7 +59,7 @@ png_write_sig(png_structrp png_ptr)
/* Write the rest of the 8 byte signature */ /* Write the rest of the 8 byte signature */
png_write_data(png_ptr, &png_signature[png_ptr->sig_bytes], png_write_data(png_ptr, &png_signature[png_ptr->sig_bytes],
(png_size_t)(8 - png_ptr->sig_bytes)); (size_t)(8 - png_ptr->sig_bytes));
if (png_ptr->sig_bytes < 3) if (png_ptr->sig_bytes < 3)
png_ptr->mode |= PNG_HAVE_PNG_SIGNATURE; png_ptr->mode |= PNG_HAVE_PNG_SIGNATURE;
...@@ -124,8 +124,7 @@ png_write_chunk_start(png_structrp png_ptr, png_const_bytep chunk_string, ...@@ -124,8 +124,7 @@ png_write_chunk_start(png_structrp png_ptr, png_const_bytep chunk_string,
* given to png_write_chunk_header(). * given to png_write_chunk_header().
*/ */
void PNGAPI void PNGAPI
png_write_chunk_data(png_structrp png_ptr, png_const_bytep data, png_write_chunk_data(png_structrp png_ptr, png_const_bytep data, size_t length)
png_size_t length)
{ {
/* Write the data, and run the CRC over it */ /* Write the data, and run the CRC over it */
if (png_ptr == NULL) if (png_ptr == NULL)
...@@ -136,7 +135,7 @@ png_write_chunk_data(png_structrp png_ptr, png_const_bytep data, ...@@ -136,7 +135,7 @@ png_write_chunk_data(png_structrp png_ptr, png_const_bytep data,
png_write_data(png_ptr, data, length); png_write_data(png_ptr, data, length);
/* Update the CRC after writing the data, /* Update the CRC after writing the data,
* in case that the user I/O routine alters it. * in case the user I/O routine alters it.
*/ */
png_calculate_crc(png_ptr, data, length); png_calculate_crc(png_ptr, data, length);
} }
...@@ -160,7 +159,7 @@ png_write_chunk_end(png_structrp png_ptr) ...@@ -160,7 +159,7 @@ png_write_chunk_end(png_structrp png_ptr)
/* Write the crc in a single operation */ /* Write the crc in a single operation */
png_save_uint_32(buf, png_ptr->crc); png_save_uint_32(buf, png_ptr->crc);
png_write_data(png_ptr, buf, (png_size_t)4); png_write_data(png_ptr, buf, 4);
} }
/* Write a PNG chunk all at once. The type is an array of ASCII characters /* Write a PNG chunk all at once. The type is an array of ASCII characters
...@@ -174,14 +173,14 @@ png_write_chunk_end(png_structrp png_ptr) ...@@ -174,14 +173,14 @@ png_write_chunk_end(png_structrp png_ptr)
*/ */
static void static void
png_write_complete_chunk(png_structrp png_ptr, png_uint_32 chunk_name, png_write_complete_chunk(png_structrp png_ptr, png_uint_32 chunk_name,
png_const_bytep data, png_size_t length) png_const_bytep data, size_t length)
{ {
if (png_ptr == NULL) if (png_ptr == NULL)
return; return;
/* On 64 bit architectures 'length' may not fit in a png_uint_32. */ /* On 64-bit architectures 'length' may not fit in a png_uint_32. */
if (length > PNG_UINT_31_MAX) if (length > PNG_UINT_31_MAX)
png_error(png_ptr, "length exceeds PNG maxima"); png_error(png_ptr, "length exceeds PNG maximum");
png_write_chunk_header(png_ptr, chunk_name, (png_uint_32)length); png_write_chunk_header(png_ptr, chunk_name, (png_uint_32)length);
png_write_chunk_data(png_ptr, data, length); png_write_chunk_data(png_ptr, data, length);
...@@ -191,10 +190,10 @@ png_write_complete_chunk(png_structrp png_ptr, png_uint_32 chunk_name, ...@@ -191,10 +190,10 @@ png_write_complete_chunk(png_structrp png_ptr, png_uint_32 chunk_name,
/* This is the API that calls the internal function above. */ /* This is the API that calls the internal function above. */
void PNGAPI void PNGAPI
png_write_chunk(png_structrp png_ptr, png_const_bytep chunk_string, png_write_chunk(png_structrp png_ptr, png_const_bytep chunk_string,
png_const_bytep data, png_size_t length) png_const_bytep data, size_t length)
{ {
png_write_complete_chunk(png_ptr, PNG_CHUNK_FROM_STRING(chunk_string), data, png_write_complete_chunk(png_ptr, PNG_CHUNK_FROM_STRING(chunk_string), data,
length); length);
} }
/* This is used below to find the size of an image to pass to png_deflate_claim, /* This is used below to find the size of an image to pass to png_deflate_claim,
...@@ -204,14 +203,14 @@ png_write_chunk(png_structrp png_ptr, png_const_bytep chunk_string, ...@@ -204,14 +203,14 @@ png_write_chunk(png_structrp png_ptr, png_const_bytep chunk_string,
static png_alloc_size_t static png_alloc_size_t
png_image_size(png_structrp png_ptr) png_image_size(png_structrp png_ptr)
{ {
/* Only return sizes up to the maximum of a png_uint_32, do this by limiting /* Only return sizes up to the maximum of a png_uint_32; do this by limiting
* the width and height used to 15 bits. * the width and height used to 15 bits.
*/ */
png_uint_32 h = png_ptr->height; png_uint_32 h = png_ptr->height;
if (png_ptr->rowbytes < 32768 && h < 32768) if (png_ptr->rowbytes < 32768 && h < 32768)
{ {
if (png_ptr->interlaced) if (png_ptr->interlaced != 0)
{ {
/* Interlacing makes the image larger because of the replication of /* Interlacing makes the image larger because of the replication of
* both the filter byte and the padding to a byte boundary. * both the filter byte and the padding to a byte boundary.
...@@ -286,17 +285,16 @@ optimize_cmf(png_bytep data, png_alloc_size_t data_size) ...@@ -286,17 +285,16 @@ optimize_cmf(png_bytep data, png_alloc_size_t data_size)
} }
} }
} }
#else #endif /* WRITE_OPTIMIZE_CMF */
# define optimize_cmf(dp,dl) ((void)0)
#endif /* PNG_WRITE_OPTIMIZE_CMF_SUPPORTED */
/* Initialize the compressor for the appropriate type of compression. */ /* Initialize the compressor for the appropriate type of compression. */
static int static int
png_deflate_claim(png_structrp png_ptr, png_uint_32 owner, png_deflate_claim(png_structrp png_ptr, png_uint_32 owner,
png_alloc_size_t data_size) png_alloc_size_t data_size)
{ {
if (png_ptr->zowner != 0) if (png_ptr->zowner != 0)
{ {
#if defined(PNG_WARNINGS_SUPPORTED) || defined(PNG_ERROR_TEXT_SUPPORTED)
char msg[64]; char msg[64];
PNG_STRING_FROM_CHUNK(msg, owner); PNG_STRING_FROM_CHUNK(msg, owner);
...@@ -308,7 +306,8 @@ png_deflate_claim(png_structrp png_ptr, png_uint_32 owner, ...@@ -308,7 +306,8 @@ png_deflate_claim(png_structrp png_ptr, png_uint_32 owner,
* are minimal. * are minimal.
*/ */
(void)png_safecat(msg, (sizeof msg), 10, " using zstream"); (void)png_safecat(msg, (sizeof msg), 10, " using zstream");
# if PNG_LIBPNG_BUILD_BASE_TYPE >= PNG_LIBPNG_BUILD_RC #endif
#if PNG_RELEASE_BUILD
png_warning(png_ptr, msg); png_warning(png_ptr, msg);
/* Attempt sane error recovery */ /* Attempt sane error recovery */
...@@ -319,9 +318,9 @@ png_deflate_claim(png_structrp png_ptr, png_uint_32 owner, ...@@ -319,9 +318,9 @@ png_deflate_claim(png_structrp png_ptr, png_uint_32 owner,
} }
png_ptr->zowner = 0; png_ptr->zowner = 0;
# else #else
png_error(png_ptr, msg); png_error(png_ptr, msg);
# endif #endif
} }
{ {
...@@ -334,7 +333,7 @@ png_deflate_claim(png_structrp png_ptr, png_uint_32 owner, ...@@ -334,7 +333,7 @@ png_deflate_claim(png_structrp png_ptr, png_uint_32 owner,
if (owner == png_IDAT) if (owner == png_IDAT)
{ {
if (png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_STRATEGY) if ((png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_STRATEGY) != 0)
strategy = png_ptr->zlib_strategy; strategy = png_ptr->zlib_strategy;
else if (png_ptr->do_filter != PNG_FILTER_NONE) else if (png_ptr->do_filter != PNG_FILTER_NONE)
...@@ -346,20 +345,20 @@ png_deflate_claim(png_structrp png_ptr, png_uint_32 owner, ...@@ -346,20 +345,20 @@ png_deflate_claim(png_structrp png_ptr, png_uint_32 owner,
else else
{ {
# ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED #ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED
level = png_ptr->zlib_text_level; level = png_ptr->zlib_text_level;
method = png_ptr->zlib_text_method; method = png_ptr->zlib_text_method;
windowBits = png_ptr->zlib_text_window_bits; windowBits = png_ptr->zlib_text_window_bits;
memLevel = png_ptr->zlib_text_mem_level; memLevel = png_ptr->zlib_text_mem_level;
strategy = png_ptr->zlib_text_strategy; strategy = png_ptr->zlib_text_strategy;
# else #else
/* If customization is not supported the values all come from the /* If customization is not supported the values all come from the
* IDAT values except for the strategy, which is fixed to the * IDAT values except for the strategy, which is fixed to the
* default. (This is the pre-1.6.0 behavior too, although it was * default. (This is the pre-1.6.0 behavior too, although it was
* implemented in a very different way.) * implemented in a very different way.)
*/ */
strategy = Z_DEFAULT_STRATEGY; strategy = Z_DEFAULT_STRATEGY;
# endif #endif
} }
/* Adjust 'windowBits' down if larger than 'data_size'; to stop this /* Adjust 'windowBits' down if larger than 'data_size'; to stop this
...@@ -386,7 +385,7 @@ png_deflate_claim(png_structrp png_ptr, png_uint_32 owner, ...@@ -386,7 +385,7 @@ png_deflate_claim(png_structrp png_ptr, png_uint_32 owner,
} }
/* Check against the previous initialized values, if any. */ /* Check against the previous initialized values, if any. */
if ((png_ptr->flags & PNG_FLAG_ZSTREAM_INITIALIZED) && if ((png_ptr->flags & PNG_FLAG_ZSTREAM_INITIALIZED) != 0 &&
(png_ptr->zlib_set_level != level || (png_ptr->zlib_set_level != level ||
png_ptr->zlib_set_method != method || png_ptr->zlib_set_method != method ||
png_ptr->zlib_set_window_bits != windowBits || png_ptr->zlib_set_window_bits != windowBits ||
...@@ -408,15 +407,15 @@ png_deflate_claim(png_structrp png_ptr, png_uint_32 owner, ...@@ -408,15 +407,15 @@ png_deflate_claim(png_structrp png_ptr, png_uint_32 owner,
png_ptr->zstream.avail_out = 0; png_ptr->zstream.avail_out = 0;
/* Now initialize if required, setting the new parameters, otherwise just /* Now initialize if required, setting the new parameters, otherwise just
* to a simple reset to the previous parameters. * do a simple reset to the previous parameters.
*/ */
if (png_ptr->flags & PNG_FLAG_ZSTREAM_INITIALIZED) if ((png_ptr->flags & PNG_FLAG_ZSTREAM_INITIALIZED) != 0)
ret = deflateReset(&png_ptr->zstream); ret = deflateReset(&png_ptr->zstream);
else else
{ {
ret = deflateInit2(&png_ptr->zstream, level, method, windowBits, ret = deflateInit2(&png_ptr->zstream, level, method, windowBits,
memLevel, strategy); memLevel, strategy);
if (ret == Z_OK) if (ret == Z_OK)
png_ptr->flags |= PNG_FLAG_ZSTREAM_INITIALIZED; png_ptr->flags |= PNG_FLAG_ZSTREAM_INITIALIZED;
...@@ -477,7 +476,7 @@ typedef struct ...@@ -477,7 +476,7 @@ typedef struct
static void static void
png_text_compress_init(compression_state *comp, png_const_bytep input, png_text_compress_init(compression_state *comp, png_const_bytep input,
png_alloc_size_t input_len) png_alloc_size_t input_len)
{ {
comp->input = input; comp->input = input;
comp->input_len = input_len; comp->input_len = input_len;
...@@ -487,12 +486,12 @@ png_text_compress_init(compression_state *comp, png_const_bytep input, ...@@ -487,12 +486,12 @@ png_text_compress_init(compression_state *comp, png_const_bytep input,
/* Compress the data in the compression state input */ /* Compress the data in the compression state input */
static int static int
png_text_compress(png_structrp png_ptr, png_uint_32 chunk_name, png_text_compress(png_structrp png_ptr, png_uint_32 chunk_name,
compression_state *comp, png_uint_32 prefix_len) compression_state *comp, png_uint_32 prefix_len)
{ {
int ret; int ret;
/* To find the length of the output it is necessary to first compress the /* To find the length of the output it is necessary to first compress the
* input, the result is buffered rather than using the two-pass algorithm * input. The result is buffered rather than using the two-pass algorithm
* that is used on the inflate side; deflate is assumed to be slower and a * that is used on the inflate side; deflate is assumed to be slower and a
* PNG writer is assumed to have more memory available than a PNG reader. * PNG writer is assumed to have more memory available than a PNG reader.
* *
...@@ -579,7 +578,7 @@ png_text_compress(png_structrp png_ptr, png_uint_32 chunk_name, ...@@ -579,7 +578,7 @@ png_text_compress(png_structrp png_ptr, png_uint_32 chunk_name,
/* Compress the data */ /* Compress the data */
ret = deflate(&png_ptr->zstream, ret = deflate(&png_ptr->zstream,
input_len > 0 ? Z_NO_FLUSH : Z_FINISH); input_len > 0 ? Z_NO_FLUSH : Z_FINISH);
/* Claw back input data that was not consumed (because avail_in is /* Claw back input data that was not consumed (because avail_in is
* reset above every time round the loop). * reset above every time round the loop).
...@@ -589,7 +588,7 @@ png_text_compress(png_structrp png_ptr, png_uint_32 chunk_name, ...@@ -589,7 +588,7 @@ png_text_compress(png_structrp png_ptr, png_uint_32 chunk_name,
} }
while (ret == Z_OK); while (ret == Z_OK);
/* There may be some space left in the last output buffer, this needs to /* There may be some space left in the last output buffer. This needs to
* be subtracted from output_len. * be subtracted from output_len.
*/ */
output_len -= png_ptr->zstream.avail_out; output_len -= png_ptr->zstream.avail_out;
...@@ -612,14 +611,15 @@ png_text_compress(png_structrp png_ptr, png_uint_32 chunk_name, ...@@ -612,14 +611,15 @@ png_text_compress(png_structrp png_ptr, png_uint_32 chunk_name,
/* Reset zlib for another zTXt/iTXt or image data */ /* Reset zlib for another zTXt/iTXt or image data */
png_ptr->zowner = 0; png_ptr->zowner = 0;
/* The only success case is Z_STREAM_END, input_len must be 0, if not this /* The only success case is Z_STREAM_END, input_len must be 0; if not this
* is an internal error. * is an internal error.
*/ */
if (ret == Z_STREAM_END && input_len == 0) if (ret == Z_STREAM_END && input_len == 0)
{ {
#ifdef PNG_WRITE_OPTIMIZE_CMF_SUPPORTED
/* Fix up the deflate header, if required */ /* Fix up the deflate header, if required */
optimize_cmf(comp->output, comp->input_len); optimize_cmf(comp->output, comp->input_len);
#endif
/* But Z_OK is returned, not Z_STREAM_END; this allows the claim /* But Z_OK is returned, not Z_STREAM_END; this allows the claim
* function above to return Z_STREAM_END on an error (though it never * function above to return Z_STREAM_END on an error (though it never
* does in the current versions of zlib.) * does in the current versions of zlib.)
...@@ -662,89 +662,7 @@ png_write_compressed_data_out(png_structrp png_ptr, compression_state *comp) ...@@ -662,89 +662,7 @@ png_write_compressed_data_out(png_structrp png_ptr, compression_state *comp)
if (output_len > 0) if (output_len > 0)
png_error(png_ptr, "error writing ancillary chunked compressed data"); png_error(png_ptr, "error writing ancillary chunked compressed data");
} }
#endif /* PNG_WRITE_COMPRESSED_TEXT_SUPPORTED */ #endif /* WRITE_COMPRESSED_TEXT */
#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_pCAL_SUPPORTED) || \
defined(PNG_WRITE_iCCP_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED)
/* Check that the tEXt or zTXt keyword is valid per PNG 1.0 specification,
* and if invalid, correct the keyword rather than discarding the entire
* chunk. The PNG 1.0 specification requires keywords 1-79 characters in
* length, forbids leading or trailing whitespace, multiple internal spaces,
* and the non-break space (0x80) from ISO 8859-1. Returns keyword length.
*
* The 'new_key' buffer must be 80 characters in size (for the keyword plus a
* trailing '\0'). If this routine returns 0 then there was no keyword, or a
* valid one could not be generated, and the caller must png_error.
*/
static png_uint_32
png_check_keyword(png_structrp png_ptr, png_const_charp key, png_bytep new_key)
{
png_const_charp orig_key = key;
png_uint_32 key_len = 0;
int bad_character = 0;
int space = 1;
png_debug(1, "in png_check_keyword");
if (key == NULL)
{
*new_key = 0;
return 0;
}
while (*key && key_len < 79)
{
png_byte ch = (png_byte)(0xff & *key++);
if ((ch > 32 && ch <= 126) || (ch >= 161 /*&& ch <= 255*/))
*new_key++ = ch, ++key_len, space = 0;
else if (!space)
{
/* A space or an invalid character when one wasn't seen immediately
* before; output just a space.
*/
*new_key++ = 32, ++key_len, space = 1;
/* If the character was not a space then it is invalid. */
if (ch != 32)
bad_character = ch;
}
else if (!bad_character)
bad_character = ch; /* just skip it, record the first error */
}
if (key_len > 0 && space) /* trailing space */
{
--key_len, --new_key;
if (!bad_character)
bad_character = 32;
}
/* Terminate the keyword */
*new_key = 0;
if (key_len == 0)
return 0;
/* Try to only output one warning per keyword: */
if (*key) /* keyword too long */
png_warning(png_ptr, "keyword truncated");
else if (bad_character)
{
PNG_WARNING_PARAMETERS(p)
png_warning_parameter(p, 1, orig_key);
png_warning_parameter_signed(p, 2, PNG_NUMBER_FORMAT_02x, bad_character);
png_formatted_warning(png_ptr, p, "keyword \"@1\": bad character '0x@2'");
}
return key_len;
}
#endif
/* Write the IHDR chunk, and update the png_struct with the necessary /* Write the IHDR chunk, and update the png_struct with the necessary
* information. Note that the rest of this code depends upon this * information. Note that the rest of this code depends upon this
...@@ -756,6 +674,7 @@ png_write_IHDR(png_structrp png_ptr, png_uint_32 width, png_uint_32 height, ...@@ -756,6 +674,7 @@ png_write_IHDR(png_structrp png_ptr, png_uint_32 width, png_uint_32 height,
int interlace_type) int interlace_type)
{ {
png_byte buf[13]; /* Buffer to store the IHDR info */ png_byte buf[13]; /* Buffer to store the IHDR info */
int is_invalid_depth;
png_debug(1, "in png_write_IHDR"); png_debug(1, "in png_write_IHDR");
...@@ -781,11 +700,11 @@ png_write_IHDR(png_structrp png_ptr, png_uint_32 width, png_uint_32 height, ...@@ -781,11 +700,11 @@ png_write_IHDR(png_structrp png_ptr, png_uint_32 width, png_uint_32 height,
break; break;
case PNG_COLOR_TYPE_RGB: case PNG_COLOR_TYPE_RGB:
is_invalid_depth = (bit_depth != 8);
#ifdef PNG_WRITE_16BIT_SUPPORTED #ifdef PNG_WRITE_16BIT_SUPPORTED
if (bit_depth != 8 && bit_depth != 16) is_invalid_depth = (is_invalid_depth && bit_depth != 16);
#else
if (bit_depth != 8)
#endif #endif
if (is_invalid_depth)
png_error(png_ptr, "Invalid bit depth for RGB image"); png_error(png_ptr, "Invalid bit depth for RGB image");
png_ptr->channels = 3; png_ptr->channels = 3;
...@@ -807,18 +726,22 @@ png_write_IHDR(png_structrp png_ptr, png_uint_32 width, png_uint_32 height, ...@@ -807,18 +726,22 @@ png_write_IHDR(png_structrp png_ptr, png_uint_32 width, png_uint_32 height,
break; break;
case PNG_COLOR_TYPE_GRAY_ALPHA: case PNG_COLOR_TYPE_GRAY_ALPHA:
if (bit_depth != 8 && bit_depth != 16) is_invalid_depth = (bit_depth != 8);
#ifdef PNG_WRITE_16BIT_SUPPORTED
is_invalid_depth = (is_invalid_depth && bit_depth != 16);
#endif
if (is_invalid_depth)
png_error(png_ptr, "Invalid bit depth for grayscale+alpha image"); png_error(png_ptr, "Invalid bit depth for grayscale+alpha image");
png_ptr->channels = 2; png_ptr->channels = 2;
break; break;
case PNG_COLOR_TYPE_RGB_ALPHA: case PNG_COLOR_TYPE_RGB_ALPHA:
is_invalid_depth = (bit_depth != 8);
#ifdef PNG_WRITE_16BIT_SUPPORTED #ifdef PNG_WRITE_16BIT_SUPPORTED
if (bit_depth != 8 && bit_depth != 16) is_invalid_depth = (is_invalid_depth && bit_depth != 16);
#else
if (bit_depth != 8)
#endif #endif
if (is_invalid_depth)
png_error(png_ptr, "Invalid bit depth for RGBA image"); png_error(png_ptr, "Invalid bit depth for RGBA image");
png_ptr->channels = 4; png_ptr->channels = 4;
...@@ -845,8 +768,8 @@ png_write_IHDR(png_structrp png_ptr, png_uint_32 width, png_uint_32 height, ...@@ -845,8 +768,8 @@ png_write_IHDR(png_structrp png_ptr, png_uint_32 width, png_uint_32 height,
*/ */
if ( if (
#ifdef PNG_MNG_FEATURES_SUPPORTED #ifdef PNG_MNG_FEATURES_SUPPORTED
!((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) && !((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) != 0 &&
((png_ptr->mode&PNG_HAVE_PNG_SIGNATURE) == 0) && ((png_ptr->mode & PNG_HAVE_PNG_SIGNATURE) == 0) &&
(color_type == PNG_COLOR_TYPE_RGB || (color_type == PNG_COLOR_TYPE_RGB ||
color_type == PNG_COLOR_TYPE_RGB_ALPHA) && color_type == PNG_COLOR_TYPE_RGB_ALPHA) &&
(filter_type == PNG_INTRAPIXEL_DIFFERENCING)) && (filter_type == PNG_INTRAPIXEL_DIFFERENCING)) &&
...@@ -896,9 +819,9 @@ png_write_IHDR(png_structrp png_ptr, png_uint_32 width, png_uint_32 height, ...@@ -896,9 +819,9 @@ png_write_IHDR(png_structrp png_ptr, png_uint_32 width, png_uint_32 height,
buf[12] = (png_byte)interlace_type; buf[12] = (png_byte)interlace_type;
/* Write the chunk */ /* Write the chunk */
png_write_complete_chunk(png_ptr, png_IHDR, buf, (png_size_t)13); png_write_complete_chunk(png_ptr, png_IHDR, buf, 13);
if (!(png_ptr->do_filter)) if ((png_ptr->do_filter) == PNG_NO_FILTERS)
{ {
if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE || if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE ||
png_ptr->bit_depth < 8) png_ptr->bit_depth < 8)
...@@ -919,17 +842,20 @@ void /* PRIVATE */ ...@@ -919,17 +842,20 @@ void /* PRIVATE */
png_write_PLTE(png_structrp png_ptr, png_const_colorp palette, png_write_PLTE(png_structrp png_ptr, png_const_colorp palette,
png_uint_32 num_pal) png_uint_32 num_pal)
{ {
png_uint_32 i; png_uint_32 max_palette_length, i;
png_const_colorp pal_ptr; png_const_colorp pal_ptr;
png_byte buf[3]; png_byte buf[3];
png_debug(1, "in png_write_PLTE"); png_debug(1, "in png_write_PLTE");
max_palette_length = (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) ?
(1 << png_ptr->bit_depth) : PNG_MAX_PALETTE_LENGTH;
if (( if ((
#ifdef PNG_MNG_FEATURES_SUPPORTED #ifdef PNG_MNG_FEATURES_SUPPORTED
!(png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE) && (png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE) == 0 &&
#endif #endif
num_pal == 0) || num_pal > 256) num_pal == 0) || num_pal > max_palette_length)
{ {
if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
{ {
...@@ -943,7 +869,7 @@ png_write_PLTE(png_structrp png_ptr, png_const_colorp palette, ...@@ -943,7 +869,7 @@ png_write_PLTE(png_structrp png_ptr, png_const_colorp palette,
} }
} }
if (!(png_ptr->color_type&PNG_COLOR_MASK_COLOR)) if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) == 0)
{ {
png_warning(png_ptr, png_warning(png_ptr,
"Ignoring request to write a PLTE chunk in grayscale PNG"); "Ignoring request to write a PLTE chunk in grayscale PNG");
...@@ -962,7 +888,7 @@ png_write_PLTE(png_structrp png_ptr, png_const_colorp palette, ...@@ -962,7 +888,7 @@ png_write_PLTE(png_structrp png_ptr, png_const_colorp palette,
buf[0] = pal_ptr->red; buf[0] = pal_ptr->red;
buf[1] = pal_ptr->green; buf[1] = pal_ptr->green;
buf[2] = pal_ptr->blue; buf[2] = pal_ptr->blue;
png_write_chunk_data(png_ptr, buf, (png_size_t)3); png_write_chunk_data(png_ptr, buf, 3);
} }
#else #else
...@@ -976,7 +902,7 @@ png_write_PLTE(png_structrp png_ptr, png_const_colorp palette, ...@@ -976,7 +902,7 @@ png_write_PLTE(png_structrp png_ptr, png_const_colorp palette,
buf[0] = pal_ptr[i].red; buf[0] = pal_ptr[i].red;
buf[1] = pal_ptr[i].green; buf[1] = pal_ptr[i].green;
buf[2] = pal_ptr[i].blue; buf[2] = pal_ptr[i].blue;
png_write_chunk_data(png_ptr, buf, (png_size_t)3); png_write_chunk_data(png_ptr, buf, 3);
} }
#endif #endif
...@@ -998,12 +924,12 @@ png_write_PLTE(png_structrp png_ptr, png_const_colorp palette, ...@@ -998,12 +924,12 @@ png_write_PLTE(png_structrp png_ptr, png_const_colorp palette,
* Z_FINISH: this is the end of the input, do a Z_FINISH and clean up * Z_FINISH: this is the end of the input, do a Z_FINISH and clean up
* *
* The routine manages the acquire and release of the png_ptr->zstream by * The routine manages the acquire and release of the png_ptr->zstream by
* checking and (at the end) clearing png_ptr->zowner, it does some sanity * checking and (at the end) clearing png_ptr->zowner; it does some sanity
* checks on the 'mode' flags while doing this. * checks on the 'mode' flags while doing this.
*/ */
void /* PRIVATE */ void /* PRIVATE */
png_compress_IDAT(png_structrp png_ptr, png_const_bytep input, png_compress_IDAT(png_structrp png_ptr, png_const_bytep input,
png_alloc_size_t input_len, int flush) png_alloc_size_t input_len, int flush)
{ {
if (png_ptr->zowner != png_IDAT) if (png_ptr->zowner != png_IDAT)
{ {
...@@ -1015,7 +941,7 @@ png_compress_IDAT(png_structrp png_ptr, png_const_bytep input, ...@@ -1015,7 +941,7 @@ png_compress_IDAT(png_structrp png_ptr, png_const_bytep input,
if (png_ptr->zbuffer_list == NULL) if (png_ptr->zbuffer_list == NULL)
{ {
png_ptr->zbuffer_list = png_voidcast(png_compression_bufferp, png_ptr->zbuffer_list = png_voidcast(png_compression_bufferp,
png_malloc(png_ptr, PNG_COMPRESSION_BUFFER_SIZE(png_ptr))); png_malloc(png_ptr, PNG_COMPRESSION_BUFFER_SIZE(png_ptr)));
png_ptr->zbuffer_list->next = NULL; png_ptr->zbuffer_list->next = NULL;
} }
...@@ -1058,7 +984,7 @@ png_compress_IDAT(png_structrp png_ptr, png_const_bytep input, ...@@ -1058,7 +984,7 @@ png_compress_IDAT(png_structrp png_ptr, png_const_bytep input,
input_len += png_ptr->zstream.avail_in; input_len += png_ptr->zstream.avail_in;
png_ptr->zstream.avail_in = 0; png_ptr->zstream.avail_in = 0;
/* OUTPUT: write complete IDAT chunks when avail_out drops to zero, note /* OUTPUT: write complete IDAT chunks when avail_out drops to zero. Note
* that these two zstream fields are preserved across the calls, therefore * that these two zstream fields are preserved across the calls, therefore
* there is no need to set these up on entry to the loop. * there is no need to set these up on entry to the loop.
*/ */
...@@ -1070,13 +996,14 @@ png_compress_IDAT(png_structrp png_ptr, png_const_bytep input, ...@@ -1070,13 +996,14 @@ png_compress_IDAT(png_structrp png_ptr, png_const_bytep input,
/* Write an IDAT containing the data then reset the buffer. The /* Write an IDAT containing the data then reset the buffer. The
* first IDAT may need deflate header optimization. * first IDAT may need deflate header optimization.
*/ */
# ifdef PNG_WRITE_OPTIMIZE_CMF_SUPPORTED #ifdef PNG_WRITE_OPTIMIZE_CMF_SUPPORTED
if (!(png_ptr->mode & PNG_HAVE_IDAT) && if ((png_ptr->mode & PNG_HAVE_IDAT) == 0 &&
png_ptr->compression_type == PNG_COMPRESSION_TYPE_BASE) png_ptr->compression_type == PNG_COMPRESSION_TYPE_BASE)
optimize_cmf(data, png_image_size(png_ptr)); optimize_cmf(data, png_image_size(png_ptr));
# endif #endif
png_write_complete_chunk(png_ptr, png_IDAT, data, size); if (size > 0)
png_write_complete_chunk(png_ptr, png_IDAT, data, size);
png_ptr->mode |= PNG_HAVE_IDAT; png_ptr->mode |= PNG_HAVE_IDAT;
png_ptr->zstream.next_out = data; png_ptr->zstream.next_out = data;
...@@ -1090,7 +1017,7 @@ png_compress_IDAT(png_structrp png_ptr, png_const_bytep input, ...@@ -1090,7 +1017,7 @@ png_compress_IDAT(png_structrp png_ptr, png_const_bytep input,
continue; continue;
} }
/* The order of these checks doesn't matter much; it just effect which /* The order of these checks doesn't matter much; it just affects which
* possible error might be detected if multiple things go wrong at once. * possible error might be detected if multiple things go wrong at once.
*/ */
if (ret == Z_OK) /* most likely return code! */ if (ret == Z_OK) /* most likely return code! */
...@@ -1116,13 +1043,14 @@ png_compress_IDAT(png_structrp png_ptr, png_const_bytep input, ...@@ -1116,13 +1043,14 @@ png_compress_IDAT(png_structrp png_ptr, png_const_bytep input,
png_bytep data = png_ptr->zbuffer_list->output; png_bytep data = png_ptr->zbuffer_list->output;
uInt size = png_ptr->zbuffer_size - png_ptr->zstream.avail_out; uInt size = png_ptr->zbuffer_size - png_ptr->zstream.avail_out;
# ifdef PNG_WRITE_OPTIMIZE_CMF_SUPPORTED #ifdef PNG_WRITE_OPTIMIZE_CMF_SUPPORTED
if (!(png_ptr->mode & PNG_HAVE_IDAT) && if ((png_ptr->mode & PNG_HAVE_IDAT) == 0 &&
png_ptr->compression_type == PNG_COMPRESSION_TYPE_BASE) png_ptr->compression_type == PNG_COMPRESSION_TYPE_BASE)
optimize_cmf(data, png_image_size(png_ptr)); optimize_cmf(data, png_image_size(png_ptr));
# endif #endif
png_write_complete_chunk(png_ptr, png_IDAT, data, size); if (size > 0)
png_write_complete_chunk(png_ptr, png_IDAT, data, size);
png_ptr->zstream.avail_out = 0; png_ptr->zstream.avail_out = 0;
png_ptr->zstream.next_out = NULL; png_ptr->zstream.next_out = NULL;
png_ptr->mode |= PNG_HAVE_IDAT | PNG_AFTER_IDAT; png_ptr->mode |= PNG_HAVE_IDAT | PNG_AFTER_IDAT;
...@@ -1146,7 +1074,7 @@ png_write_IEND(png_structrp png_ptr) ...@@ -1146,7 +1074,7 @@ png_write_IEND(png_structrp png_ptr)
{ {
png_debug(1, "in png_write_IEND"); png_debug(1, "in png_write_IEND");
png_write_complete_chunk(png_ptr, png_IEND, NULL, (png_size_t)0); png_write_complete_chunk(png_ptr, png_IEND, NULL, 0);
png_ptr->mode |= PNG_HAVE_IEND; png_ptr->mode |= PNG_HAVE_IEND;
} }
...@@ -1161,7 +1089,7 @@ png_write_gAMA_fixed(png_structrp png_ptr, png_fixed_point file_gamma) ...@@ -1161,7 +1089,7 @@ png_write_gAMA_fixed(png_structrp png_ptr, png_fixed_point file_gamma)
/* file_gamma is saved in 1/100,000ths */ /* file_gamma is saved in 1/100,000ths */
png_save_uint_32(buf, (png_uint_32)file_gamma); png_save_uint_32(buf, (png_uint_32)file_gamma);
png_write_complete_chunk(png_ptr, png_gAMA, buf, (png_size_t)4); png_write_complete_chunk(png_ptr, png_gAMA, buf, 4);
} }
#endif #endif
...@@ -1179,7 +1107,7 @@ png_write_sRGB(png_structrp png_ptr, int srgb_intent) ...@@ -1179,7 +1107,7 @@ png_write_sRGB(png_structrp png_ptr, int srgb_intent)
"Invalid sRGB rendering intent specified"); "Invalid sRGB rendering intent specified");
buf[0]=(png_byte)srgb_intent; buf[0]=(png_byte)srgb_intent;
png_write_complete_chunk(png_ptr, png_sRGB, buf, (png_size_t)1); png_write_complete_chunk(png_ptr, png_sRGB, buf, 1);
} }
#endif #endif
...@@ -1193,6 +1121,7 @@ png_write_iCCP(png_structrp png_ptr, png_const_charp name, ...@@ -1193,6 +1121,7 @@ png_write_iCCP(png_structrp png_ptr, png_const_charp name,
png_uint_32 profile_len; png_uint_32 profile_len;
png_byte new_name[81]; /* 1 byte for the compression byte */ png_byte new_name[81]; /* 1 byte for the compression byte */
compression_state comp; compression_state comp;
png_uint_32 temp;
png_debug(1, "in png_write_iCCP"); png_debug(1, "in png_write_iCCP");
...@@ -1207,7 +1136,8 @@ png_write_iCCP(png_structrp png_ptr, png_const_charp name, ...@@ -1207,7 +1136,8 @@ png_write_iCCP(png_structrp png_ptr, png_const_charp name,
if (profile_len < 132) if (profile_len < 132)
png_error(png_ptr, "ICC profile too short"); png_error(png_ptr, "ICC profile too short");
if (profile_len & 0x03) 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)"); png_error(png_ptr, "ICC profile length invalid (not a multiple of 4)");
{ {
...@@ -1251,8 +1181,8 @@ png_write_sPLT(png_structrp png_ptr, png_const_sPLT_tp spalette) ...@@ -1251,8 +1181,8 @@ png_write_sPLT(png_structrp png_ptr, png_const_sPLT_tp spalette)
png_uint_32 name_len; png_uint_32 name_len;
png_byte new_name[80]; png_byte new_name[80];
png_byte entrybuf[10]; png_byte entrybuf[10];
png_size_t entry_size = (spalette->depth == 8 ? 6 : 10); size_t entry_size = (spalette->depth == 8 ? 6 : 10);
png_size_t palette_size = entry_size * spalette->nentries; size_t palette_size = entry_size * (size_t)spalette->nentries;
png_sPLT_entryp ep; png_sPLT_entryp ep;
#ifndef PNG_POINTER_INDEXING_SUPPORTED #ifndef PNG_POINTER_INDEXING_SUPPORTED
int i; int i;
...@@ -1269,10 +1199,9 @@ png_write_sPLT(png_structrp png_ptr, png_const_sPLT_tp spalette) ...@@ -1269,10 +1199,9 @@ png_write_sPLT(png_structrp png_ptr, png_const_sPLT_tp spalette)
png_write_chunk_header(png_ptr, png_sPLT, png_write_chunk_header(png_ptr, png_sPLT,
(png_uint_32)(name_len + 2 + palette_size)); (png_uint_32)(name_len + 2 + palette_size));
png_write_chunk_data(png_ptr, (png_bytep)new_name, png_write_chunk_data(png_ptr, (png_bytep)new_name, (size_t)(name_len + 1));
(png_size_t)(name_len + 1));
png_write_chunk_data(png_ptr, &spalette->depth, (png_size_t)1); png_write_chunk_data(png_ptr, &spalette->depth, 1);
/* Loop through each palette entry, writing appropriately */ /* Loop through each palette entry, writing appropriately */
#ifdef PNG_POINTER_INDEXING_SUPPORTED #ifdef PNG_POINTER_INDEXING_SUPPORTED
...@@ -1334,12 +1263,12 @@ void /* PRIVATE */ ...@@ -1334,12 +1263,12 @@ void /* PRIVATE */
png_write_sBIT(png_structrp png_ptr, png_const_color_8p sbit, int color_type) png_write_sBIT(png_structrp png_ptr, png_const_color_8p sbit, int color_type)
{ {
png_byte buf[4]; png_byte buf[4];
png_size_t size; size_t size;
png_debug(1, "in png_write_sBIT"); png_debug(1, "in png_write_sBIT");
/* Make sure we don't depend upon the order of PNG_COLOR_8 */ /* Make sure we don't depend upon the order of PNG_COLOR_8 */
if (color_type & PNG_COLOR_MASK_COLOR) if ((color_type & PNG_COLOR_MASK_COLOR) != 0)
{ {
png_byte maxbits; png_byte maxbits;
...@@ -1372,7 +1301,7 @@ png_write_sBIT(png_structrp png_ptr, png_const_color_8p sbit, int color_type) ...@@ -1372,7 +1301,7 @@ png_write_sBIT(png_structrp png_ptr, png_const_color_8p sbit, int color_type)
size = 1; size = 1;
} }
if (color_type & PNG_COLOR_MASK_ALPHA) if ((color_type & PNG_COLOR_MASK_ALPHA) != 0)
{ {
if (sbit->alpha == 0 || sbit->alpha > png_ptr->usr_bit_depth) if (sbit->alpha == 0 || sbit->alpha > png_ptr->usr_bit_depth)
{ {
...@@ -1434,12 +1363,12 @@ png_write_tRNS(png_structrp png_ptr, png_const_bytep trans_alpha, ...@@ -1434,12 +1363,12 @@ png_write_tRNS(png_structrp png_ptr, png_const_bytep trans_alpha,
/* Write the chunk out as it is */ /* Write the chunk out as it is */
png_write_complete_chunk(png_ptr, png_tRNS, trans_alpha, png_write_complete_chunk(png_ptr, png_tRNS, trans_alpha,
(png_size_t)num_trans); (size_t)num_trans);
} }
else if (color_type == PNG_COLOR_TYPE_GRAY) else if (color_type == PNG_COLOR_TYPE_GRAY)
{ {
/* One 16 bit value */ /* One 16-bit value */
if (tran->gray >= (1 << png_ptr->bit_depth)) if (tran->gray >= (1 << png_ptr->bit_depth))
{ {
png_app_warning(png_ptr, png_app_warning(png_ptr,
...@@ -1449,27 +1378,27 @@ png_write_tRNS(png_structrp png_ptr, png_const_bytep trans_alpha, ...@@ -1449,27 +1378,27 @@ png_write_tRNS(png_structrp png_ptr, png_const_bytep trans_alpha,
} }
png_save_uint_16(buf, tran->gray); png_save_uint_16(buf, tran->gray);
png_write_complete_chunk(png_ptr, png_tRNS, buf, (png_size_t)2); png_write_complete_chunk(png_ptr, png_tRNS, buf, 2);
} }
else if (color_type == PNG_COLOR_TYPE_RGB) else if (color_type == PNG_COLOR_TYPE_RGB)
{ {
/* Three 16 bit values */ /* Three 16-bit values */
png_save_uint_16(buf, tran->red); png_save_uint_16(buf, tran->red);
png_save_uint_16(buf + 2, tran->green); png_save_uint_16(buf + 2, tran->green);
png_save_uint_16(buf + 4, tran->blue); png_save_uint_16(buf + 4, tran->blue);
#ifdef PNG_WRITE_16BIT_SUPPORTED #ifdef PNG_WRITE_16BIT_SUPPORTED
if (png_ptr->bit_depth == 8 && (buf[0] | buf[2] | buf[4])) if (png_ptr->bit_depth == 8 && (buf[0] | buf[2] | buf[4]) != 0)
#else #else
if (buf[0] | buf[2] | buf[4]) if ((buf[0] | buf[2] | buf[4]) != 0)
#endif #endif
{ {
png_app_warning(png_ptr, png_app_warning(png_ptr,
"Ignoring attempt to write 16-bit tRNS chunk when bit_depth is 8"); "Ignoring attempt to write 16-bit tRNS chunk when bit_depth is 8");
return; return;
} }
png_write_complete_chunk(png_ptr, png_tRNS, buf, (png_size_t)6); png_write_complete_chunk(png_ptr, png_tRNS, buf, 6);
} }
else else
...@@ -1492,8 +1421,8 @@ png_write_bKGD(png_structrp png_ptr, png_const_color_16p back, int color_type) ...@@ -1492,8 +1421,8 @@ png_write_bKGD(png_structrp png_ptr, png_const_color_16p back, int color_type)
{ {
if ( if (
#ifdef PNG_MNG_FEATURES_SUPPORTED #ifdef PNG_MNG_FEATURES_SUPPORTED
(png_ptr->num_palette || (png_ptr->num_palette != 0 ||
(!(png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE))) && (png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE) == 0) &&
#endif #endif
back->index >= png_ptr->num_palette) back->index >= png_ptr->num_palette)
{ {
...@@ -1502,27 +1431,28 @@ png_write_bKGD(png_structrp png_ptr, png_const_color_16p back, int color_type) ...@@ -1502,27 +1431,28 @@ png_write_bKGD(png_structrp png_ptr, png_const_color_16p back, int color_type)
} }
buf[0] = back->index; buf[0] = back->index;
png_write_complete_chunk(png_ptr, png_bKGD, buf, (png_size_t)1); png_write_complete_chunk(png_ptr, png_bKGD, buf, 1);
} }
else if (color_type & PNG_COLOR_MASK_COLOR) else if ((color_type & PNG_COLOR_MASK_COLOR) != 0)
{ {
png_save_uint_16(buf, back->red); png_save_uint_16(buf, back->red);
png_save_uint_16(buf + 2, back->green); png_save_uint_16(buf + 2, back->green);
png_save_uint_16(buf + 4, back->blue); png_save_uint_16(buf + 4, back->blue);
#ifdef PNG_WRITE_16BIT_SUPPORTED #ifdef PNG_WRITE_16BIT_SUPPORTED
if (png_ptr->bit_depth == 8 && (buf[0] | buf[2] | buf[4])) if (png_ptr->bit_depth == 8 && (buf[0] | buf[2] | buf[4]) != 0)
#else #else
if (buf[0] | buf[2] | buf[4]) if ((buf[0] | buf[2] | buf[4]) != 0)
#endif #endif
{ {
png_warning(png_ptr, png_warning(png_ptr,
"Ignoring attempt to write 16-bit bKGD chunk when bit_depth is 8"); "Ignoring attempt to write 16-bit bKGD chunk "
"when bit_depth is 8");
return; return;
} }
png_write_complete_chunk(png_ptr, png_bKGD, buf, (png_size_t)6); png_write_complete_chunk(png_ptr, png_bKGD, buf, 6);
} }
else else
...@@ -1536,8 +1466,30 @@ png_write_bKGD(png_structrp png_ptr, png_const_color_16p back, int color_type) ...@@ -1536,8 +1466,30 @@ png_write_bKGD(png_structrp png_ptr, png_const_color_16p back, int color_type)
} }
png_save_uint_16(buf, back->gray); png_save_uint_16(buf, back->gray);
png_write_complete_chunk(png_ptr, png_bKGD, buf, (png_size_t)2); png_write_complete_chunk(png_ptr, png_bKGD, buf, 2);
}
}
#endif
#ifdef PNG_WRITE_eXIf_SUPPORTED
/* Write the Exif data */
void /* PRIVATE */
png_write_eXIf(png_structrp png_ptr, png_bytep exif, int num_exif)
{
int i;
png_byte buf[1];
png_debug(1, "in png_write_eXIf");
png_write_chunk_header(png_ptr, png_eXIf, (png_uint_32)(num_exif));
for (i = 0; i < num_exif; i++)
{
buf[0] = exif[i];
png_write_chunk_data(png_ptr, buf, 1);
} }
png_write_chunk_end(png_ptr);
} }
#endif #endif
...@@ -1565,7 +1517,7 @@ png_write_hIST(png_structrp png_ptr, png_const_uint_16p hist, int num_hist) ...@@ -1565,7 +1517,7 @@ png_write_hIST(png_structrp png_ptr, png_const_uint_16p hist, int num_hist)
for (i = 0; i < num_hist; i++) for (i = 0; i < num_hist; i++)
{ {
png_save_uint_16(buf, hist[i]); png_save_uint_16(buf, hist[i]);
png_write_chunk_data(png_ptr, buf, (png_size_t)2); png_write_chunk_data(png_ptr, buf, 2);
} }
png_write_chunk_end(png_ptr); png_write_chunk_end(png_ptr);
...@@ -1576,7 +1528,7 @@ png_write_hIST(png_structrp png_ptr, png_const_uint_16p hist, int num_hist) ...@@ -1576,7 +1528,7 @@ png_write_hIST(png_structrp png_ptr, png_const_uint_16p hist, int num_hist)
/* Write a tEXt chunk */ /* Write a tEXt chunk */
void /* PRIVATE */ void /* PRIVATE */
png_write_tEXt(png_structrp png_ptr, png_const_charp key, png_const_charp text, png_write_tEXt(png_structrp png_ptr, png_const_charp key, png_const_charp text,
png_size_t text_len) size_t text_len)
{ {
png_uint_32 key_len; png_uint_32 key_len;
png_byte new_key[80]; png_byte new_key[80];
...@@ -1608,7 +1560,7 @@ png_write_tEXt(png_structrp png_ptr, png_const_charp key, png_const_charp text, ...@@ -1608,7 +1560,7 @@ png_write_tEXt(png_structrp png_ptr, png_const_charp key, png_const_charp text,
*/ */
png_write_chunk_data(png_ptr, new_key, key_len + 1); png_write_chunk_data(png_ptr, new_key, key_len + 1);
if (text_len) if (text_len != 0)
png_write_chunk_data(png_ptr, (png_const_bytep)text, text_len); png_write_chunk_data(png_ptr, (png_const_bytep)text, text_len);
png_write_chunk_end(png_ptr); png_write_chunk_end(png_ptr);
...@@ -1619,14 +1571,13 @@ png_write_tEXt(png_structrp png_ptr, png_const_charp key, png_const_charp text, ...@@ -1619,14 +1571,13 @@ png_write_tEXt(png_structrp png_ptr, png_const_charp key, png_const_charp text,
/* Write a compressed text chunk */ /* Write a compressed text chunk */
void /* PRIVATE */ void /* PRIVATE */
png_write_zTXt(png_structrp png_ptr, png_const_charp key, png_const_charp text, png_write_zTXt(png_structrp png_ptr, png_const_charp key, png_const_charp text,
png_size_t text_len, int compression) int compression)
{ {
png_uint_32 key_len; png_uint_32 key_len;
png_byte new_key[81]; png_byte new_key[81];
compression_state comp; compression_state comp;
png_debug(1, "in png_write_zTXt"); png_debug(1, "in png_write_zTXt");
PNG_UNUSED(text_len) /* Always use strlen */
if (compression == PNG_TEXT_COMPRESSION_NONE) if (compression == PNG_TEXT_COMPRESSION_NONE)
{ {
...@@ -1648,7 +1599,7 @@ png_write_zTXt(png_structrp png_ptr, png_const_charp key, png_const_charp text, ...@@ -1648,7 +1599,7 @@ png_write_zTXt(png_structrp png_ptr, png_const_charp key, png_const_charp text,
/* Compute the compressed data; do it now for the length */ /* Compute the compressed data; do it now for the length */
png_text_compress_init(&comp, (png_const_bytep)text, png_text_compress_init(&comp, (png_const_bytep)text,
text == NULL ? 0 : strlen(text)); text == NULL ? 0 : strlen(text));
if (png_text_compress(png_ptr, png_zTXt, &comp, key_len) != Z_OK) if (png_text_compress(png_ptr, png_zTXt, &comp, key_len) != Z_OK)
png_error(png_ptr, png_ptr->zstream.msg); png_error(png_ptr, png_ptr->zstream.msg);
...@@ -1674,7 +1625,7 @@ png_write_iTXt(png_structrp png_ptr, int compression, png_const_charp key, ...@@ -1674,7 +1625,7 @@ png_write_iTXt(png_structrp png_ptr, int compression, png_const_charp key,
png_const_charp lang, png_const_charp lang_key, png_const_charp text) png_const_charp lang, png_const_charp lang_key, png_const_charp text)
{ {
png_uint_32 key_len, prefix_len; png_uint_32 key_len, prefix_len;
png_size_t lang_len, lang_key_len; size_t lang_len, lang_key_len;
png_byte new_key[82]; png_byte new_key[82];
compression_state comp; compression_state comp;
...@@ -1734,7 +1685,7 @@ png_write_iTXt(png_structrp png_ptr, int compression, png_const_charp key, ...@@ -1734,7 +1685,7 @@ png_write_iTXt(png_structrp png_ptr, int compression, png_const_charp key,
png_text_compress_init(&comp, (png_const_bytep)text, strlen(text)); png_text_compress_init(&comp, (png_const_bytep)text, strlen(text));
if (compression) if (compression != 0)
{ {
if (png_text_compress(png_ptr, png_iTXt, &comp, prefix_len) != Z_OK) if (png_text_compress(png_ptr, png_iTXt, &comp, prefix_len) != Z_OK)
png_error(png_ptr, png_ptr->zstream.msg); png_error(png_ptr, png_ptr->zstream.msg);
...@@ -1757,11 +1708,11 @@ png_write_iTXt(png_structrp png_ptr, int compression, png_const_charp key, ...@@ -1757,11 +1708,11 @@ png_write_iTXt(png_structrp png_ptr, int compression, png_const_charp key,
png_write_chunk_data(png_ptr, (png_const_bytep)lang_key, lang_key_len); png_write_chunk_data(png_ptr, (png_const_bytep)lang_key, lang_key_len);
if (compression) if (compression != 0)
png_write_compressed_data_out(png_ptr, &comp); png_write_compressed_data_out(png_ptr, &comp);
else else
png_write_chunk_data(png_ptr, (png_const_bytep)text, comp.input_len); png_write_chunk_data(png_ptr, (png_const_bytep)text, comp.output_len);
png_write_chunk_end(png_ptr); png_write_chunk_end(png_ptr);
} }
...@@ -1784,7 +1735,7 @@ png_write_oFFs(png_structrp png_ptr, png_int_32 x_offset, png_int_32 y_offset, ...@@ -1784,7 +1735,7 @@ png_write_oFFs(png_structrp png_ptr, png_int_32 x_offset, png_int_32 y_offset,
png_save_int_32(buf + 4, y_offset); png_save_int_32(buf + 4, y_offset);
buf[8] = (png_byte)unit_type; buf[8] = (png_byte)unit_type;
png_write_complete_chunk(png_ptr, png_oFFs, buf, (png_size_t)9); png_write_complete_chunk(png_ptr, png_oFFs, buf, 9);
} }
#endif #endif
#ifdef PNG_WRITE_pCAL_SUPPORTED #ifdef PNG_WRITE_pCAL_SUPPORTED
...@@ -1795,7 +1746,7 @@ png_write_pCAL(png_structrp png_ptr, png_charp purpose, png_int_32 X0, ...@@ -1795,7 +1746,7 @@ png_write_pCAL(png_structrp png_ptr, png_charp purpose, png_int_32 X0,
png_charpp params) png_charpp params)
{ {
png_uint_32 purpose_len; png_uint_32 purpose_len;
png_size_t units_len, total_len; size_t units_len, total_len;
png_size_tp params_len; png_size_tp params_len;
png_byte buf[10]; png_byte buf[10];
png_byte new_purpose[80]; png_byte new_purpose[80];
...@@ -1819,7 +1770,7 @@ png_write_pCAL(png_structrp png_ptr, png_charp purpose, png_int_32 X0, ...@@ -1819,7 +1770,7 @@ png_write_pCAL(png_structrp png_ptr, png_charp purpose, png_int_32 X0,
total_len = purpose_len + units_len + 10; total_len = purpose_len + units_len + 10;
params_len = (png_size_tp)png_malloc(png_ptr, params_len = (png_size_tp)png_malloc(png_ptr,
(png_alloc_size_t)(nparams * (sizeof (png_size_t)))); (png_alloc_size_t)((png_alloc_size_t)nparams * (sizeof (size_t))));
/* Find the length of each parameter, making sure we don't count the /* Find the length of each parameter, making sure we don't count the
* null terminator for the last parameter. * null terminator for the last parameter.
...@@ -1839,8 +1790,8 @@ png_write_pCAL(png_structrp png_ptr, png_charp purpose, png_int_32 X0, ...@@ -1839,8 +1790,8 @@ png_write_pCAL(png_structrp png_ptr, png_charp purpose, png_int_32 X0,
png_save_int_32(buf + 4, X1); png_save_int_32(buf + 4, X1);
buf[8] = (png_byte)type; buf[8] = (png_byte)type;
buf[9] = (png_byte)nparams; buf[9] = (png_byte)nparams;
png_write_chunk_data(png_ptr, buf, (png_size_t)10); png_write_chunk_data(png_ptr, buf, 10);
png_write_chunk_data(png_ptr, (png_const_bytep)units, (png_size_t)units_len); png_write_chunk_data(png_ptr, (png_const_bytep)units, (size_t)units_len);
for (i = 0; i < nparams; i++) for (i = 0; i < nparams; i++)
{ {
...@@ -1859,7 +1810,7 @@ png_write_sCAL_s(png_structrp png_ptr, int unit, png_const_charp width, ...@@ -1859,7 +1810,7 @@ png_write_sCAL_s(png_structrp png_ptr, int unit, png_const_charp width,
png_const_charp height) png_const_charp height)
{ {
png_byte buf[64]; png_byte buf[64];
png_size_t wlen, hlen, total_len; size_t wlen, hlen, total_len;
png_debug(1, "in png_write_sCAL_s"); png_debug(1, "in png_write_sCAL_s");
...@@ -1900,7 +1851,7 @@ png_write_pHYs(png_structrp png_ptr, png_uint_32 x_pixels_per_unit, ...@@ -1900,7 +1851,7 @@ png_write_pHYs(png_structrp png_ptr, png_uint_32 x_pixels_per_unit,
png_save_uint_32(buf + 4, y_pixels_per_unit); png_save_uint_32(buf + 4, y_pixels_per_unit);
buf[8] = (png_byte)unit_type; buf[8] = (png_byte)unit_type;
png_write_complete_chunk(png_ptr, png_pHYs, buf, (png_size_t)9); png_write_complete_chunk(png_ptr, png_pHYs, buf, 9);
} }
#endif #endif
...@@ -1930,7 +1881,7 @@ png_write_tIME(png_structrp png_ptr, png_const_timep mod_time) ...@@ -1930,7 +1881,7 @@ png_write_tIME(png_structrp png_ptr, png_const_timep mod_time)
buf[5] = mod_time->minute; buf[5] = mod_time->minute;
buf[6] = mod_time->second; buf[6] = mod_time->second;
png_write_complete_chunk(png_ptr, png_tIME, buf, (png_size_t)7); png_write_complete_chunk(png_ptr, png_tIME, buf, 7);
} }
#endif #endif
...@@ -1942,21 +1893,25 @@ png_write_start_row(png_structrp png_ptr) ...@@ -1942,21 +1893,25 @@ png_write_start_row(png_structrp png_ptr)
/* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */
/* Start of interlace block */ /* Start of interlace block */
static PNG_CONST png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; static const png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
/* Offset to next interlace block */ /* Offset to next interlace block */
static PNG_CONST png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; static const png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
/* Start of interlace block in the y direction */ /* Start of interlace block in the y direction */
static PNG_CONST png_byte png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1}; static const png_byte png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1};
/* Offset to next interlace block in the y direction */ /* Offset to next interlace block in the y direction */
static PNG_CONST png_byte png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; static const png_byte png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
#endif #endif
png_alloc_size_t buf_size; png_alloc_size_t buf_size;
int usr_pixel_depth; int usr_pixel_depth;
#ifdef PNG_WRITE_FILTER_SUPPORTED
png_byte filters;
#endif
png_debug(1, "in png_write_start_row"); png_debug(1, "in png_write_start_row");
usr_pixel_depth = png_ptr->usr_channels * png_ptr->usr_bit_depth; usr_pixel_depth = png_ptr->usr_channels * png_ptr->usr_bit_depth;
...@@ -1967,56 +1922,61 @@ png_write_start_row(png_structrp png_ptr) ...@@ -1967,56 +1922,61 @@ png_write_start_row(png_structrp png_ptr)
png_ptr->maximum_pixel_depth = (png_byte)usr_pixel_depth; png_ptr->maximum_pixel_depth = (png_byte)usr_pixel_depth;
/* Set up row buffer */ /* Set up row buffer */
png_ptr->row_buf = (png_bytep)png_malloc(png_ptr, buf_size); png_ptr->row_buf = png_voidcast(png_bytep, png_malloc(png_ptr, buf_size));
png_ptr->row_buf[0] = PNG_FILTER_VALUE_NONE; png_ptr->row_buf[0] = PNG_FILTER_VALUE_NONE;
#ifdef PNG_WRITE_FILTER_SUPPORTED #ifdef PNG_WRITE_FILTER_SUPPORTED
/* Set up filtering buffer, if using this filter */ filters = png_ptr->do_filter;
if (png_ptr->do_filter & PNG_FILTER_SUB)
{
png_ptr->sub_row = (png_bytep)png_malloc(png_ptr, png_ptr->rowbytes + 1);
png_ptr->sub_row[0] = PNG_FILTER_VALUE_SUB; if (png_ptr->height == 1)
} filters &= 0xff & ~(PNG_FILTER_UP|PNG_FILTER_AVG|PNG_FILTER_PAETH);
if (png_ptr->width == 1)
filters &= 0xff & ~(PNG_FILTER_SUB|PNG_FILTER_AVG|PNG_FILTER_PAETH);
if (filters == 0)
filters = PNG_FILTER_NONE;
/* We only need to keep the previous row if we are using one of these. */ png_ptr->do_filter = filters;
if (png_ptr->do_filter & (PNG_FILTER_AVG | PNG_FILTER_UP | PNG_FILTER_PAETH))
if (((filters & (PNG_FILTER_SUB | PNG_FILTER_UP | PNG_FILTER_AVG |
PNG_FILTER_PAETH)) != 0) && png_ptr->try_row == NULL)
{ {
/* Set up previous row buffer */ int num_filters = 0;
png_ptr->prev_row = (png_bytep)png_calloc(png_ptr, buf_size);
if (png_ptr->do_filter & PNG_FILTER_UP) png_ptr->try_row = png_voidcast(png_bytep, png_malloc(png_ptr, buf_size));
{
png_ptr->up_row = (png_bytep)png_malloc(png_ptr,
png_ptr->rowbytes + 1);
png_ptr->up_row[0] = PNG_FILTER_VALUE_UP; if (filters & PNG_FILTER_SUB)
} num_filters++;
if (png_ptr->do_filter & PNG_FILTER_AVG) if (filters & PNG_FILTER_UP)
{ num_filters++;
png_ptr->avg_row = (png_bytep)png_malloc(png_ptr,
png_ptr->rowbytes + 1);
png_ptr->avg_row[0] = PNG_FILTER_VALUE_AVG; if (filters & PNG_FILTER_AVG)
} num_filters++;
if (png_ptr->do_filter & PNG_FILTER_PAETH) if (filters & PNG_FILTER_PAETH)
{ num_filters++;
png_ptr->paeth_row = (png_bytep)png_malloc(png_ptr,
png_ptr->rowbytes + 1);
png_ptr->paeth_row[0] = PNG_FILTER_VALUE_PAETH; if (num_filters > 1)
} png_ptr->tst_row = png_voidcast(png_bytep, png_malloc(png_ptr,
buf_size));
} }
#endif /* PNG_WRITE_FILTER_SUPPORTED */
/* We only need to keep the previous row if we are using one of the following
* filters.
*/
if ((filters & (PNG_FILTER_AVG | PNG_FILTER_UP | PNG_FILTER_PAETH)) != 0)
png_ptr->prev_row = png_voidcast(png_bytep,
png_calloc(png_ptr, buf_size));
#endif /* WRITE_FILTER */
#ifdef PNG_WRITE_INTERLACING_SUPPORTED #ifdef PNG_WRITE_INTERLACING_SUPPORTED
/* If interlaced, we need to set up width and height of pass */ /* If interlaced, we need to set up width and height of pass */
if (png_ptr->interlaced) if (png_ptr->interlaced != 0)
{ {
if (!(png_ptr->transformations & PNG_INTERLACE)) if ((png_ptr->transformations & PNG_INTERLACE) == 0)
{ {
png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 - png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 -
png_pass_ystart[0]) / png_pass_yinc[0]; png_pass_ystart[0]) / png_pass_yinc[0];
...@@ -2048,16 +2008,16 @@ png_write_finish_row(png_structrp png_ptr) ...@@ -2048,16 +2008,16 @@ png_write_finish_row(png_structrp png_ptr)
/* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */
/* Start of interlace block */ /* Start of interlace block */
static PNG_CONST png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; static const png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
/* Offset to next interlace block */ /* Offset to next interlace block */
static PNG_CONST png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; static const png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
/* Start of interlace block in the y direction */ /* Start of interlace block in the y direction */
static PNG_CONST png_byte png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1}; static const png_byte png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1};
/* Offset to next interlace block in the y direction */ /* Offset to next interlace block in the y direction */
static PNG_CONST png_byte png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; static const png_byte png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
#endif #endif
png_debug(1, "in png_write_finish_row"); png_debug(1, "in png_write_finish_row");
...@@ -2071,10 +2031,10 @@ png_write_finish_row(png_structrp png_ptr) ...@@ -2071,10 +2031,10 @@ png_write_finish_row(png_structrp png_ptr)
#ifdef PNG_WRITE_INTERLACING_SUPPORTED #ifdef PNG_WRITE_INTERLACING_SUPPORTED
/* If interlaced, go to next pass */ /* If interlaced, go to next pass */
if (png_ptr->interlaced) if (png_ptr->interlaced != 0)
{ {
png_ptr->row_number = 0; png_ptr->row_number = 0;
if (png_ptr->transformations & PNG_INTERLACE) if ((png_ptr->transformations & PNG_INTERLACE) != 0)
{ {
png_ptr->pass++; png_ptr->pass++;
} }
...@@ -2099,7 +2059,7 @@ png_write_finish_row(png_structrp png_ptr) ...@@ -2099,7 +2059,7 @@ png_write_finish_row(png_structrp png_ptr)
png_pass_ystart[png_ptr->pass]) / png_pass_ystart[png_ptr->pass]) /
png_pass_yinc[png_ptr->pass]; png_pass_yinc[png_ptr->pass];
if (png_ptr->transformations & PNG_INTERLACE) if ((png_ptr->transformations & PNG_INTERLACE) != 0)
break; break;
} while (png_ptr->usr_width == 0 || png_ptr->num_rows == 0); } while (png_ptr->usr_width == 0 || png_ptr->num_rows == 0);
...@@ -2111,8 +2071,8 @@ png_write_finish_row(png_structrp png_ptr) ...@@ -2111,8 +2071,8 @@ png_write_finish_row(png_structrp png_ptr)
{ {
if (png_ptr->prev_row != NULL) if (png_ptr->prev_row != NULL)
memset(png_ptr->prev_row, 0, memset(png_ptr->prev_row, 0,
(png_size_t)(PNG_ROWBYTES(png_ptr->usr_channels* PNG_ROWBYTES(png_ptr->usr_channels *
png_ptr->usr_bit_depth, png_ptr->width)) + 1); png_ptr->usr_bit_depth, png_ptr->width) + 1);
return; return;
} }
...@@ -2138,10 +2098,10 @@ png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass) ...@@ -2138,10 +2098,10 @@ png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass)
/* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */
/* Start of interlace block */ /* Start of interlace block */
static PNG_CONST png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; static const png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
/* Offset to next interlace block */ /* Offset to next interlace block */
static PNG_CONST png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; static const png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
png_debug(1, "in png_do_write_interlace"); png_debug(1, "in png_do_write_interlace");
...@@ -2155,7 +2115,7 @@ png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass) ...@@ -2155,7 +2115,7 @@ png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass)
{ {
png_bytep sp; png_bytep sp;
png_bytep dp; png_bytep dp;
int shift; unsigned int shift;
int d; int d;
int value; int value;
png_uint_32 i; png_uint_32 i;
...@@ -2168,7 +2128,7 @@ png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass) ...@@ -2168,7 +2128,7 @@ png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass)
for (i = png_pass_start[pass]; i < row_width; for (i = png_pass_start[pass]; i < row_width;
i += png_pass_inc[pass]) i += png_pass_inc[pass])
{ {
sp = row + (png_size_t)(i >> 3); sp = row + (size_t)(i >> 3);
value = (int)(*sp >> (7 - (int)(i & 0x07))) & 0x01; value = (int)(*sp >> (7 - (int)(i & 0x07))) & 0x01;
d |= (value << shift); d |= (value << shift);
...@@ -2193,7 +2153,7 @@ png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass) ...@@ -2193,7 +2153,7 @@ png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass)
{ {
png_bytep sp; png_bytep sp;
png_bytep dp; png_bytep dp;
int shift; unsigned int shift;
int d; int d;
int value; int value;
png_uint_32 i; png_uint_32 i;
...@@ -2206,7 +2166,7 @@ png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass) ...@@ -2206,7 +2166,7 @@ png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass)
for (i = png_pass_start[pass]; i < row_width; for (i = png_pass_start[pass]; i < row_width;
i += png_pass_inc[pass]) i += png_pass_inc[pass])
{ {
sp = row + (png_size_t)(i >> 2); sp = row + (size_t)(i >> 2);
value = (*sp >> ((3 - (int)(i & 0x03)) << 1)) & 0x03; value = (*sp >> ((3 - (int)(i & 0x03)) << 1)) & 0x03;
d |= (value << shift); d |= (value << shift);
...@@ -2230,7 +2190,7 @@ png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass) ...@@ -2230,7 +2190,7 @@ png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass)
{ {
png_bytep sp; png_bytep sp;
png_bytep dp; png_bytep dp;
int shift; unsigned int shift;
int d; int d;
int value; int value;
png_uint_32 i; png_uint_32 i;
...@@ -2242,7 +2202,7 @@ png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass) ...@@ -2242,7 +2202,7 @@ png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass)
for (i = png_pass_start[pass]; i < row_width; for (i = png_pass_start[pass]; i < row_width;
i += png_pass_inc[pass]) i += png_pass_inc[pass])
{ {
sp = row + (png_size_t)(i >> 1); sp = row + (size_t)(i >> 1);
value = (*sp >> ((1 - (int)(i & 0x01)) << 2)) & 0x0f; value = (*sp >> ((1 - (int)(i & 0x01)) << 2)) & 0x0f;
d |= (value << shift); d |= (value << shift);
...@@ -2268,7 +2228,7 @@ png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass) ...@@ -2268,7 +2228,7 @@ png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass)
png_bytep dp; png_bytep dp;
png_uint_32 i; png_uint_32 i;
png_uint_32 row_width = row_info->width; png_uint_32 row_width = row_info->width;
png_size_t pixel_bytes; size_t pixel_bytes;
/* Start at the beginning */ /* Start at the beginning */
dp = row; dp = row;
...@@ -2281,7 +2241,7 @@ png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass) ...@@ -2281,7 +2241,7 @@ png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass)
i += png_pass_inc[pass]) i += png_pass_inc[pass])
{ {
/* Find out where the original pixel is */ /* Find out where the original pixel is */
sp = row + (png_size_t)i * pixel_bytes; sp = row + (size_t)i * pixel_bytes;
/* Move the pixel */ /* Move the pixel */
if (dp != sp) if (dp != sp)
...@@ -2305,691 +2265,487 @@ png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass) ...@@ -2305,691 +2265,487 @@ png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass)
} }
#endif #endif
/* This filters the row, chooses which filter to use, if it has not already /* This filters the row, chooses which filter to use, if it has not already
* been specified by the application, and then writes the row out with the * been specified by the application, and then writes the row out with the
* chosen filter. * chosen filter.
*/ */
static void png_write_filtered_row(png_structrp png_ptr, png_bytep filtered_row, static void /* PRIVATE */
png_size_t row_bytes); png_write_filtered_row(png_structrp png_ptr, png_bytep filtered_row,
size_t row_bytes);
#define PNG_MAXSUM (((png_uint_32)(-1)) >> 1)
#define PNG_HISHIFT 10
#define PNG_LOMASK ((png_uint_32)0xffffL)
#define PNG_HIMASK ((png_uint_32)(~PNG_LOMASK >> PNG_HISHIFT))
void /* PRIVATE */
png_write_find_filter(png_structrp png_ptr, png_row_infop row_info)
{
png_bytep best_row;
#ifdef PNG_WRITE_FILTER_SUPPORTED
png_bytep prev_row, row_buf;
png_uint_32 mins, bpp;
png_byte filter_to_do = png_ptr->do_filter;
png_size_t row_bytes = row_info->rowbytes;
#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
int num_p_filters = png_ptr->num_prev_filters;
#endif
png_debug(1, "in png_write_find_filter");
#ifndef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
if (png_ptr->row_number == 0 && filter_to_do == PNG_ALL_FILTERS)
{
/* These will never be selected so we need not test them. */
filter_to_do &= ~(PNG_FILTER_UP | PNG_FILTER_PAETH);
}
#endif
/* Find out how many bytes offset each pixel is */
bpp = (row_info->pixel_depth + 7) >> 3;
prev_row = png_ptr->prev_row;
#endif
best_row = png_ptr->row_buf;
#ifdef PNG_WRITE_FILTER_SUPPORTED #ifdef PNG_WRITE_FILTER_SUPPORTED
row_buf = best_row; static size_t /* PRIVATE */
mins = PNG_MAXSUM; png_setup_sub_row(png_structrp png_ptr, png_uint_32 bpp,
size_t row_bytes, size_t lmins)
/* The prediction method we use is to find which method provides the {
* smallest value when summing the absolute values of the distances png_bytep rp, dp, lp;
* from zero, using anything >= 128 as negative numbers. This is known size_t i;
* as the "minimum sum of absolute differences" heuristic. Other size_t sum = 0;
* heuristics are the "weighted minimum sum of absolute differences" unsigned int v;
* (experimental and can in theory improve compression), and the "zlib
* predictive" method (not implemented yet), which does test compressions
* of lines using different filter methods, and then chooses the
* (series of) filter(s) that give minimum compressed data size (VERY
* computationally expensive).
*
* GRR 980525: consider also
*
* (1) minimum sum of absolute differences from running average (i.e.,
* keep running sum of non-absolute differences & count of bytes)
* [track dispersion, too? restart average if dispersion too large?]
*
* (1b) minimum sum of absolute differences from sliding average, probably
* with window size <= deflate window (usually 32K)
*
* (2) minimum sum of squared differences from zero or running average
* (i.e., ~ root-mean-square approach)
*/
png_ptr->try_row[0] = PNG_FILTER_VALUE_SUB;
/* We don't need to test the 'no filter' case if this is the only filter for (i = 0, rp = png_ptr->row_buf + 1, dp = png_ptr->try_row + 1; i < bpp;
* that has been chosen, as it doesn't actually do anything to the data. i++, rp++, dp++)
*/
if ((filter_to_do & PNG_FILTER_NONE) && filter_to_do != PNG_FILTER_NONE)
{ {
png_bytep rp; v = *dp = *rp;
png_uint_32 sum = 0; #ifdef PNG_USE_ABS
png_size_t i; sum += 128 - abs((int)v - 128);
int v; #else
sum += (v < 128) ? v : 256 - v;
for (i = 0, rp = row_buf + 1; i < row_bytes; i++, rp++)
{
v = *rp;
sum += (v < 128) ? v : 256 - v;
}
#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
{
png_uint_32 sumhi, sumlo;
int j;
sumlo = sum & PNG_LOMASK;
sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK; /* Gives us some footroom */
/* Reduce the sum if we match any of the previous rows */
for (j = 0; j < num_p_filters; j++)
{
if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_NONE)
{
sumlo = (sumlo * png_ptr->filter_weights[j]) >>
PNG_WEIGHT_SHIFT;
sumhi = (sumhi * png_ptr->filter_weights[j]) >>
PNG_WEIGHT_SHIFT;
}
}
/* Factor in the cost of this filter (this is here for completeness,
* but it makes no sense to have a "cost" for the NONE filter, as
* it has the minimum possible computational cost - none).
*/
sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_NONE]) >>
PNG_COST_SHIFT;
sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_NONE]) >>
PNG_COST_SHIFT;
if (sumhi > PNG_HIMASK)
sum = PNG_MAXSUM;
else
sum = (sumhi << PNG_HISHIFT) + sumlo;
}
#endif #endif
mins = sum;
} }
/* Sub filter */ for (lp = png_ptr->row_buf + 1; i < row_bytes;
if (filter_to_do == PNG_FILTER_SUB) i++, rp++, lp++, dp++)
/* It's the only filter so no testing is needed */
{ {
png_bytep rp, lp, dp; v = *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff);
png_size_t i; #ifdef PNG_USE_ABS
sum += 128 - abs((int)v - 128);
for (i = 0, rp = row_buf + 1, dp = png_ptr->sub_row + 1; i < bpp; #else
i++, rp++, dp++) sum += (v < 128) ? v : 256 - v;
{ #endif
*dp = *rp;
}
for (lp = row_buf + 1; i < row_bytes;
i++, rp++, lp++, dp++)
{
*dp = (png_byte)(((int)*rp - (int)*lp) & 0xff);
}
best_row = png_ptr->sub_row; if (sum > lmins) /* We are already worse, don't continue. */
break;
} }
else if (filter_to_do & PNG_FILTER_SUB) return (sum);
{ }
png_bytep rp, dp, lp;
png_uint_32 sum = 0, lmins = mins;
png_size_t i;
int v;
#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED static void /* PRIVATE */
/* We temporarily increase the "minimum sum" by the factor we png_setup_sub_row_only(png_structrp png_ptr, png_uint_32 bpp,
* would reduce the sum of this filter, so that we can do the size_t row_bytes)
* early exit comparison without scaling the sum each time. {
*/ png_bytep rp, dp, lp;
if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) size_t i;
{
int j;
png_uint_32 lmhi, lmlo;
lmlo = lmins & PNG_LOMASK;
lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;
for (j = 0; j < num_p_filters; j++) png_ptr->try_row[0] = PNG_FILTER_VALUE_SUB;
{
if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_SUB)
{
lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
PNG_WEIGHT_SHIFT;
lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >> for (i = 0, rp = png_ptr->row_buf + 1, dp = png_ptr->try_row + 1; i < bpp;
PNG_WEIGHT_SHIFT; i++, rp++, dp++)
} {
} *dp = *rp;
}
lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >> for (lp = png_ptr->row_buf + 1; i < row_bytes;
PNG_COST_SHIFT; i++, rp++, lp++, dp++)
{
*dp = (png_byte)(((int)*rp - (int)*lp) & 0xff);
}
}
lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >> static size_t /* PRIVATE */
PNG_COST_SHIFT; png_setup_up_row(png_structrp png_ptr, size_t row_bytes, size_t lmins)
{
png_bytep rp, dp, pp;
size_t i;
size_t sum = 0;
unsigned int v;
if (lmhi > PNG_HIMASK) png_ptr->try_row[0] = PNG_FILTER_VALUE_UP;
lmins = PNG_MAXSUM;
else for (i = 0, rp = png_ptr->row_buf + 1, dp = png_ptr->try_row + 1,
lmins = (lmhi << PNG_HISHIFT) + lmlo; pp = png_ptr->prev_row + 1; i < row_bytes;
} i++, rp++, pp++, dp++)
{
v = *dp = (png_byte)(((int)*rp - (int)*pp) & 0xff);
#ifdef PNG_USE_ABS
sum += 128 - abs((int)v - 128);
#else
sum += (v < 128) ? v : 256 - v;
#endif #endif
for (i = 0, rp = row_buf + 1, dp = png_ptr->sub_row + 1; i < bpp; if (sum > lmins) /* We are already worse, don't continue. */
i++, rp++, dp++) break;
{ }
v = *dp = *rp;
sum += (v < 128) ? v : 256 - v;
}
for (lp = row_buf + 1; i < row_bytes;
i++, rp++, lp++, dp++)
{
v = *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff);
sum += (v < 128) ? v : 256 - v;
if (sum > lmins) /* We are already worse, don't continue. */
break;
}
#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED return (sum);
if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) }
{ static void /* PRIVATE */
int j; png_setup_up_row_only(png_structrp png_ptr, size_t row_bytes)
png_uint_32 sumhi, sumlo; {
sumlo = sum & PNG_LOMASK; png_bytep rp, dp, pp;
sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK; size_t i;
for (j = 0; j < num_p_filters; j++) png_ptr->try_row[0] = PNG_FILTER_VALUE_UP;
{
if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_SUB)
{
sumlo = (sumlo * png_ptr->inv_filter_weights[j]) >>
PNG_WEIGHT_SHIFT;
sumhi = (sumhi * png_ptr->inv_filter_weights[j]) >> for (i = 0, rp = png_ptr->row_buf + 1, dp = png_ptr->try_row + 1,
PNG_WEIGHT_SHIFT; pp = png_ptr->prev_row + 1; i < row_bytes;
} i++, rp++, pp++, dp++)
} {
*dp = (png_byte)(((int)*rp - (int)*pp) & 0xff);
}
}
sumlo = (sumlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >> static size_t /* PRIVATE */
PNG_COST_SHIFT; png_setup_avg_row(png_structrp png_ptr, png_uint_32 bpp,
size_t row_bytes, size_t lmins)
{
png_bytep rp, dp, pp, lp;
png_uint_32 i;
size_t sum = 0;
unsigned int v;
sumhi = (sumhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >> png_ptr->try_row[0] = PNG_FILTER_VALUE_AVG;
PNG_COST_SHIFT;
if (sumhi > PNG_HIMASK) for (i = 0, rp = png_ptr->row_buf + 1, dp = png_ptr->try_row + 1,
sum = PNG_MAXSUM; pp = png_ptr->prev_row + 1; i < bpp; i++)
{
v = *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff);
else #ifdef PNG_USE_ABS
sum = (sumhi << PNG_HISHIFT) + sumlo; sum += 128 - abs((int)v - 128);
} #else
sum += (v < 128) ? v : 256 - v;
#endif #endif
if (sum < mins)
{
mins = sum;
best_row = png_ptr->sub_row;
}
} }
/* Up filter */ for (lp = png_ptr->row_buf + 1; i < row_bytes; i++)
if (filter_to_do == PNG_FILTER_UP)
{ {
png_bytep rp, dp, pp; v = *dp++ = (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2))
png_size_t i; & 0xff);
for (i = 0, rp = row_buf + 1, dp = png_ptr->up_row + 1, #ifdef PNG_USE_ABS
pp = prev_row + 1; i < row_bytes; sum += 128 - abs((int)v - 128);
i++, rp++, pp++, dp++) #else
{ sum += (v < 128) ? v : 256 - v;
*dp = (png_byte)(((int)*rp - (int)*pp) & 0xff); #endif
}
best_row = png_ptr->up_row; if (sum > lmins) /* We are already worse, don't continue. */
break;
} }
else if (filter_to_do & PNG_FILTER_UP) return (sum);
{ }
png_bytep rp, dp, pp; static void /* PRIVATE */
png_uint_32 sum = 0, lmins = mins; png_setup_avg_row_only(png_structrp png_ptr, png_uint_32 bpp,
png_size_t i; size_t row_bytes)
int v; {
png_bytep rp, dp, pp, lp;
png_uint_32 i;
#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED png_ptr->try_row[0] = PNG_FILTER_VALUE_AVG;
if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
{
int j;
png_uint_32 lmhi, lmlo;
lmlo = lmins & PNG_LOMASK;
lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;
for (j = 0; j < num_p_filters; j++) for (i = 0, rp = png_ptr->row_buf + 1, dp = png_ptr->try_row + 1,
{ pp = png_ptr->prev_row + 1; i < bpp; i++)
if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_UP) {
{ *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff);
lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >> }
PNG_WEIGHT_SHIFT;
lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >> for (lp = png_ptr->row_buf + 1; i < row_bytes; i++)
PNG_WEIGHT_SHIFT; {
} *dp++ = (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2))
} & 0xff);
}
}
lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_UP]) >> static size_t /* PRIVATE */
PNG_COST_SHIFT; png_setup_paeth_row(png_structrp png_ptr, png_uint_32 bpp,
size_t row_bytes, size_t lmins)
{
png_bytep rp, dp, pp, cp, lp;
size_t i;
size_t sum = 0;
unsigned int v;
lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_UP]) >> png_ptr->try_row[0] = PNG_FILTER_VALUE_PAETH;
PNG_COST_SHIFT;
if (lmhi > PNG_HIMASK) for (i = 0, rp = png_ptr->row_buf + 1, dp = png_ptr->try_row + 1,
lmins = PNG_MAXSUM; pp = png_ptr->prev_row + 1; i < bpp; i++)
{
v = *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff);
else #ifdef PNG_USE_ABS
lmins = (lmhi << PNG_HISHIFT) + lmlo; sum += 128 - abs((int)v - 128);
} #else
sum += (v < 128) ? v : 256 - v;
#endif #endif
}
for (i = 0, rp = row_buf + 1, dp = png_ptr->up_row + 1, for (lp = png_ptr->row_buf + 1, cp = png_ptr->prev_row + 1; i < row_bytes;
pp = prev_row + 1; i < row_bytes; i++) i++)
{ {
v = *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff); int a, b, c, pa, pb, pc, p;
sum += (v < 128) ? v : 256 - v;
if (sum > lmins) /* We are already worse, don't continue. */
break;
}
#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
{
int j;
png_uint_32 sumhi, sumlo;
sumlo = sum & PNG_LOMASK;
sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;
for (j = 0; j < num_p_filters; j++) b = *pp++;
{ c = *cp++;
if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_UP) a = *lp++;
{
sumlo = (sumlo * png_ptr->filter_weights[j]) >>
PNG_WEIGHT_SHIFT;
sumhi = (sumhi * png_ptr->filter_weights[j]) >> p = b - c;
PNG_WEIGHT_SHIFT; pc = a - c;
}
}
sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_UP]) >> #ifdef PNG_USE_ABS
PNG_COST_SHIFT; pa = abs(p);
pb = abs(pc);
pc = abs(p + pc);
#else
pa = p < 0 ? -p : p;
pb = pc < 0 ? -pc : pc;
pc = (p + pc) < 0 ? -(p + pc) : p + pc;
#endif
sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_UP]) >> p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c;
PNG_COST_SHIFT;
if (sumhi > PNG_HIMASK) v = *dp++ = (png_byte)(((int)*rp++ - p) & 0xff);
sum = PNG_MAXSUM;
else #ifdef PNG_USE_ABS
sum = (sumhi << PNG_HISHIFT) + sumlo; sum += 128 - abs((int)v - 128);
} #else
sum += (v < 128) ? v : 256 - v;
#endif #endif
if (sum < mins) if (sum > lmins) /* We are already worse, don't continue. */
{ break;
mins = sum;
best_row = png_ptr->up_row;
}
} }
/* Avg filter */ return (sum);
if (filter_to_do == PNG_FILTER_AVG) }
{ static void /* PRIVATE */
png_bytep rp, dp, pp, lp; png_setup_paeth_row_only(png_structrp png_ptr, png_uint_32 bpp,
png_uint_32 i; size_t row_bytes)
{
png_bytep rp, dp, pp, cp, lp;
size_t i;
for (i = 0, rp = row_buf + 1, dp = png_ptr->avg_row + 1, png_ptr->try_row[0] = PNG_FILTER_VALUE_PAETH;
pp = prev_row + 1; i < bpp; i++)
{
*dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff);
}
for (lp = row_buf + 1; i < row_bytes; i++) for (i = 0, rp = png_ptr->row_buf + 1, dp = png_ptr->try_row + 1,
{ pp = png_ptr->prev_row + 1; i < bpp; i++)
*dp++ = (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2)) {
& 0xff); *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff);
}
best_row = png_ptr->avg_row;
} }
else if (filter_to_do & PNG_FILTER_AVG) for (lp = png_ptr->row_buf + 1, cp = png_ptr->prev_row + 1; i < row_bytes;
i++)
{ {
png_bytep rp, dp, pp, lp; int a, b, c, pa, pb, pc, p;
png_uint_32 sum = 0, lmins = mins;
png_size_t i;
int v;
#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
{
int j;
png_uint_32 lmhi, lmlo;
lmlo = lmins & PNG_LOMASK;
lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;
for (j = 0; j < num_p_filters; j++)
{
if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_AVG)
{
lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
PNG_WEIGHT_SHIFT;
lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
PNG_WEIGHT_SHIFT;
}
}
lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_AVG]) >> b = *pp++;
PNG_COST_SHIFT; c = *cp++;
a = *lp++;
lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_AVG]) >> p = b - c;
PNG_COST_SHIFT; pc = a - c;
if (lmhi > PNG_HIMASK) #ifdef PNG_USE_ABS
lmins = PNG_MAXSUM; pa = abs(p);
pb = abs(pc);
else pc = abs(p + pc);
lmins = (lmhi << PNG_HISHIFT) + lmlo; #else
} pa = p < 0 ? -p : p;
pb = pc < 0 ? -pc : pc;
pc = (p + pc) < 0 ? -(p + pc) : p + pc;
#endif #endif
for (i = 0, rp = row_buf + 1, dp = png_ptr->avg_row + 1, p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c;
pp = prev_row + 1; i < bpp; i++)
{
v = *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff);
sum += (v < 128) ? v : 256 - v;
}
for (lp = row_buf + 1; i < row_bytes; i++) *dp++ = (png_byte)(((int)*rp++ - p) & 0xff);
{ }
v = *dp++ = }
(png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2)) & 0xff); #endif /* WRITE_FILTER */
sum += (v < 128) ? v : 256 - v;
if (sum > lmins) /* We are already worse, don't continue. */
break;
}
#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED void /* PRIVATE */
if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) png_write_find_filter(png_structrp png_ptr, png_row_infop row_info)
{ {
int j; #ifndef PNG_WRITE_FILTER_SUPPORTED
png_uint_32 sumhi, sumlo; png_write_filtered_row(png_ptr, png_ptr->row_buf, row_info->rowbytes+1);
sumlo = sum & PNG_LOMASK; #else
sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK; unsigned int filter_to_do = png_ptr->do_filter;
png_bytep row_buf;
png_bytep best_row;
png_uint_32 bpp;
size_t mins;
size_t row_bytes = row_info->rowbytes;
for (j = 0; j < num_p_filters; j++) png_debug(1, "in png_write_find_filter");
{
if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_NONE)
{
sumlo = (sumlo * png_ptr->filter_weights[j]) >>
PNG_WEIGHT_SHIFT;
sumhi = (sumhi * png_ptr->filter_weights[j]) >> /* Find out how many bytes offset each pixel is */
PNG_WEIGHT_SHIFT; bpp = (row_info->pixel_depth + 7) >> 3;
}
}
sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_AVG]) >> row_buf = png_ptr->row_buf;
PNG_COST_SHIFT; mins = PNG_SIZE_MAX - 256/* so we can detect potential overflow of the
running sum */;
sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_AVG]) >> /* The prediction method we use is to find which method provides the
PNG_COST_SHIFT; * smallest value when summing the absolute values of the distances
* from zero, using anything >= 128 as negative numbers. This is known
* as the "minimum sum of absolute differences" heuristic. Other
* heuristics are the "weighted minimum sum of absolute differences"
* (experimental and can in theory improve compression), and the "zlib
* predictive" method (not implemented yet), which does test compressions
* of lines using different filter methods, and then chooses the
* (series of) filter(s) that give minimum compressed data size (VERY
* computationally expensive).
*
* GRR 980525: consider also
*
* (1) minimum sum of absolute differences from running average (i.e.,
* keep running sum of non-absolute differences & count of bytes)
* [track dispersion, too? restart average if dispersion too large?]
*
* (1b) minimum sum of absolute differences from sliding average, probably
* with window size <= deflate window (usually 32K)
*
* (2) minimum sum of squared differences from zero or running average
* (i.e., ~ root-mean-square approach)
*/
if (sumhi > PNG_HIMASK)
sum = PNG_MAXSUM;
else /* We don't need to test the 'no filter' case if this is the only filter
sum = (sumhi << PNG_HISHIFT) + sumlo; * that has been chosen, as it doesn't actually do anything to the data.
} */
#endif best_row = png_ptr->row_buf;
if (sum < mins) if (PNG_SIZE_MAX/128 <= row_bytes)
{ {
mins = sum; /* Overflow can occur in the calculation, just select the lowest set
best_row = png_ptr->avg_row; * filter.
} */
filter_to_do &= 0U-filter_to_do;
} }
else if ((filter_to_do & PNG_FILTER_NONE) != 0 &&
/* Paeth filter */ filter_to_do != PNG_FILTER_NONE)
if (filter_to_do == PNG_FILTER_PAETH)
{ {
png_bytep rp, dp, pp, cp, lp; /* Overflow not possible and multiple filters in the list, including the
png_size_t i; * 'none' filter.
*/
for (i = 0, rp = row_buf + 1, dp = png_ptr->paeth_row + 1, png_bytep rp;
pp = prev_row + 1; i < bpp; i++) size_t sum = 0;
{ size_t i;
*dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff); unsigned int v;
}
for (lp = row_buf + 1, cp = prev_row + 1; i < row_bytes; i++)
{ {
int a, b, c, pa, pb, pc, p; for (i = 0, rp = row_buf + 1; i < row_bytes; i++, rp++)
{
b = *pp++; v = *rp;
c = *cp++;
a = *lp++;
p = b - c;
pc = a - c;
#ifdef PNG_USE_ABS #ifdef PNG_USE_ABS
pa = abs(p); sum += 128 - abs((int)v - 128);
pb = abs(pc);
pc = abs(p + pc);
#else #else
pa = p < 0 ? -p : p; sum += (v < 128) ? v : 256 - v;
pb = pc < 0 ? -pc : pc;
pc = (p + pc) < 0 ? -(p + pc) : p + pc;
#endif #endif
}
}
p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c; mins = sum;
}
*dp++ = (png_byte)(((int)*rp++ - p) & 0xff); /* Sub filter */
} if (filter_to_do == PNG_FILTER_SUB)
best_row = png_ptr->paeth_row; /* It's the only filter so no testing is needed */
{
png_setup_sub_row_only(png_ptr, bpp, row_bytes);
best_row = png_ptr->try_row;
} }
else if (filter_to_do & PNG_FILTER_PAETH) else if ((filter_to_do & PNG_FILTER_SUB) != 0)
{ {
png_bytep rp, dp, pp, cp, lp; size_t sum;
png_uint_32 sum = 0, lmins = mins; size_t lmins = mins;
png_size_t i;
int v;
#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED sum = png_setup_sub_row(png_ptr, bpp, row_bytes, lmins);
if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
{
int j;
png_uint_32 lmhi, lmlo;
lmlo = lmins & PNG_LOMASK;
lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;
for (j = 0; j < num_p_filters; j++) if (sum < mins)
{
mins = sum;
best_row = png_ptr->try_row;
if (png_ptr->tst_row != NULL)
{ {
if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_PAETH) png_ptr->try_row = png_ptr->tst_row;
{ png_ptr->tst_row = best_row;
lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
PNG_WEIGHT_SHIFT;
lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
PNG_WEIGHT_SHIFT;
}
} }
}
}
lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_PAETH]) >> /* Up filter */
PNG_COST_SHIFT; if (filter_to_do == PNG_FILTER_UP)
{
lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_PAETH]) >> png_setup_up_row_only(png_ptr, row_bytes);
PNG_COST_SHIFT; best_row = png_ptr->try_row;
}
if (lmhi > PNG_HIMASK) else if ((filter_to_do & PNG_FILTER_UP) != 0)
lmins = PNG_MAXSUM; {
size_t sum;
size_t lmins = mins;
else sum = png_setup_up_row(png_ptr, row_bytes, lmins);
lmins = (lmhi << PNG_HISHIFT) + lmlo;
}
#endif
for (i = 0, rp = row_buf + 1, dp = png_ptr->paeth_row + 1, if (sum < mins)
pp = prev_row + 1; i < bpp; i++)
{ {
v = *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff); mins = sum;
best_row = png_ptr->try_row;
sum += (v < 128) ? v : 256 - v; if (png_ptr->tst_row != NULL)
{
png_ptr->try_row = png_ptr->tst_row;
png_ptr->tst_row = best_row;
}
} }
}
for (lp = row_buf + 1, cp = prev_row + 1; i < row_bytes; i++) /* Avg filter */
{ if (filter_to_do == PNG_FILTER_AVG)
int a, b, c, pa, pb, pc, p; {
png_setup_avg_row_only(png_ptr, bpp, row_bytes);
b = *pp++; best_row = png_ptr->try_row;
c = *cp++; }
a = *lp++;
#ifndef PNG_SLOW_PAETH
p = b - c;
pc = a - c;
#ifdef PNG_USE_ABS
pa = abs(p);
pb = abs(pc);
pc = abs(p + pc);
#else
pa = p < 0 ? -p : p;
pb = pc < 0 ? -pc : pc;
pc = (p + pc) < 0 ? -(p + pc) : p + pc;
#endif
p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c;
#else /* PNG_SLOW_PAETH */
p = a + b - c;
pa = abs(p - a);
pb = abs(p - b);
pc = abs(p - c);
if (pa <= pb && pa <= pc)
p = a;
else if (pb <= pc)
p = b;
else
p = c;
#endif /* PNG_SLOW_PAETH */
v = *dp++ = (png_byte)(((int)*rp++ - p) & 0xff);
sum += (v < 128) ? v : 256 - v; else if ((filter_to_do & PNG_FILTER_AVG) != 0)
{
size_t sum;
size_t lmins = mins;
if (sum > lmins) /* We are already worse, don't continue. */ sum= png_setup_avg_row(png_ptr, bpp, row_bytes, lmins);
break;
}
#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED if (sum < mins)
if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
{ {
int j; mins = sum;
png_uint_32 sumhi, sumlo; best_row = png_ptr->try_row;
sumlo = sum & PNG_LOMASK; if (png_ptr->tst_row != NULL)
sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;
for (j = 0; j < num_p_filters; j++)
{ {
if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_PAETH) png_ptr->try_row = png_ptr->tst_row;
{ png_ptr->tst_row = best_row;
sumlo = (sumlo * png_ptr->filter_weights[j]) >>
PNG_WEIGHT_SHIFT;
sumhi = (sumhi * png_ptr->filter_weights[j]) >>
PNG_WEIGHT_SHIFT;
}
} }
}
}
sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_PAETH]) >> /* Paeth filter */
PNG_COST_SHIFT; if (filter_to_do == PNG_FILTER_PAETH)
{
png_setup_paeth_row_only(png_ptr, bpp, row_bytes);
best_row = png_ptr->try_row;
}
sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_PAETH]) >> else if ((filter_to_do & PNG_FILTER_PAETH) != 0)
PNG_COST_SHIFT; {
size_t sum;
size_t lmins = mins;
if (sumhi > PNG_HIMASK) sum = png_setup_paeth_row(png_ptr, bpp, row_bytes, lmins);
sum = PNG_MAXSUM;
else
sum = (sumhi << PNG_HISHIFT) + sumlo;
}
#endif
if (sum < mins) if (sum < mins)
{ {
best_row = png_ptr->paeth_row; best_row = png_ptr->try_row;
if (png_ptr->tst_row != NULL)
{
png_ptr->try_row = png_ptr->tst_row;
png_ptr->tst_row = best_row;
}
} }
} }
#endif /* PNG_WRITE_FILTER_SUPPORTED */
/* Do the actual writing of the filtered row data from the chosen filter. */ /* Do the actual writing of the filtered row data from the chosen filter. */
png_write_filtered_row(png_ptr, best_row, row_info->rowbytes+1); png_write_filtered_row(png_ptr, best_row, row_info->rowbytes+1);
#ifdef PNG_WRITE_FILTER_SUPPORTED #endif /* WRITE_FILTER */
#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
/* Save the type of filter we picked this time for future calculations */
if (png_ptr->num_prev_filters > 0)
{
int j;
for (j = 1; j < num_p_filters; j++)
{
png_ptr->prev_filters[j] = png_ptr->prev_filters[j - 1];
}
png_ptr->prev_filters[j] = best_row[0];
}
#endif
#endif /* PNG_WRITE_FILTER_SUPPORTED */
} }
/* Do the actual writing of a previously filtered row. */ /* Do the actual writing of a previously filtered row. */
static void static void
png_write_filtered_row(png_structrp png_ptr, png_bytep filtered_row, png_write_filtered_row(png_structrp png_ptr, png_bytep filtered_row,
png_size_t full_row_length/*includes filter byte*/) size_t full_row_length/*includes filter byte*/)
{ {
png_debug(1, "in png_write_filtered_row"); png_debug(1, "in png_write_filtered_row");
...@@ -2997,6 +2753,7 @@ png_write_filtered_row(png_structrp png_ptr, png_bytep filtered_row, ...@@ -2997,6 +2753,7 @@ png_write_filtered_row(png_structrp png_ptr, png_bytep filtered_row,
png_compress_IDAT(png_ptr, filtered_row, full_row_length, Z_NO_FLUSH); png_compress_IDAT(png_ptr, filtered_row, full_row_length, Z_NO_FLUSH);
#ifdef PNG_WRITE_FILTER_SUPPORTED
/* Swap the current and previous rows */ /* Swap the current and previous rows */
if (png_ptr->prev_row != NULL) if (png_ptr->prev_row != NULL)
{ {
...@@ -3006,6 +2763,7 @@ png_write_filtered_row(png_structrp png_ptr, png_bytep filtered_row, ...@@ -3006,6 +2763,7 @@ png_write_filtered_row(png_structrp png_ptr, png_bytep filtered_row,
png_ptr->prev_row = png_ptr->row_buf; png_ptr->prev_row = png_ptr->row_buf;
png_ptr->row_buf = tptr; png_ptr->row_buf = tptr;
} }
#endif /* WRITE_FILTER */
/* Finish row - updates counters and flushes zlib if last row */ /* Finish row - updates counters and flushes zlib if last row */
png_write_finish_row(png_ptr); png_write_finish_row(png_ptr);
...@@ -3018,6 +2776,6 @@ png_write_filtered_row(png_structrp png_ptr, png_bytep filtered_row, ...@@ -3018,6 +2776,6 @@ png_write_filtered_row(png_structrp png_ptr, png_bytep filtered_row,
{ {
png_write_flush(png_ptr); png_write_flush(png_ptr);
} }
#endif #endif /* WRITE_FLUSH */
} }
#endif /* PNG_WRITE_SUPPORTED */ #endif /* WRITE */
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment