/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/* pngwutil.c - utilities to write a PNG file
*
* This file is available under and governed by the GNU General Public
* License version 2 only, as published by the Free Software Foundation.
* However, the following notice accompanied the original version of this
* file and, per its terms, should not be removed:
*
* Last changed in libpng 1.5.4 [July 7, 2011]
* Copyright (c) 1998-2011 Glenn Randers-Pehrson
* (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
* (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
*
* This code is released under the libpng license.
* For conditions of distribution and use, see the disclaimer
* and license in png.h
*/
#include "pngpriv.h"
#ifdef PNG_WRITE_SUPPORTED
/* Place a 32-bit number into a buffer in PNG byte order. We work
* with unsigned numbers for convenience, although one supported
* ancillary chunk uses signed (two's complement) numbers.
*/
void PNGAPI
{
}
#ifdef PNG_SAVE_INT_32_SUPPORTED
/* The png_save_int_32 function assumes integers are stored in two's
* complement format. If this isn't the case, then this routine needs to
* be modified to write data in two's complement format. Note that,
* the following works correctly even if png_int_32 has more than 32 bits
* (compare the more complex code required on read for sign extention.)
*/
void PNGAPI
{
}
#endif
/* Place a 16-bit number into a buffer in PNG byte order.
* The parameter is declared unsigned int, not png_uint_16,
* just to avoid potential problems on pre-ANSI C compilers.
*/
void PNGAPI
{
}
#endif
/* Simple function to write the signature. If we have already written
* the magic bytes of the signature, or more likely, the PNG stream is
* being embedded into another stream and doesn't need its own signature,
* we should call png_set_sig_bytes() to tell libpng how many of the
* bytes have already been written.
*/
void PNGAPI
{
#ifdef PNG_IO_STATE_SUPPORTED
/* Inform the I/O callback that the signature is being written */
#endif
/* Write the rest of the 8 byte signature */
}
/* Write a PNG chunk all at once. The type is an array of ASCII characters
* representing the chunk name. The array must be at least 4 bytes in
* length, and does not need to be null terminated. To be safe, pass the
* pre-defined chunk names here, and if you need a new one, define it
* where the others are defined. The length is the length of the data.
* All the data must be present. If that is not possible, use the
* png_write_chunk_start(), png_write_chunk_data(), and png_write_chunk_end()
* functions instead.
*/
void PNGAPI
{
return;
}
/* Write the start of a PNG chunk. The type is the chunk type.
* The total_length is the sum of the lengths of all the data you will be
* passing in png_write_chunk_data().
*/
void PNGAPI
{
(unsigned long)length);
return;
#ifdef PNG_IO_STATE_SUPPORTED
/* Inform the I/O callback that the chunk header is being written.
* PNG_IO_CHUNK_HDR requires a single I/O call.
*/
#endif
/* Write the length and the chunk name */
/* Put the chunk name into png_ptr->chunk_name */
/* Reset the crc and run it over the chunk name */
#ifdef PNG_IO_STATE_SUPPORTED
/* Inform the I/O callback that chunk data will (possibly) be written.
* PNG_IO_CHUNK_DATA does NOT require a specific number of I/O calls.
*/
#endif
}
/* Write the data of a PNG chunk started with png_write_chunk_start().
* Note that multiple calls to this function are allowed, and that the
* sum of the lengths from these calls *must* add up to the total_length
* given to png_write_chunk_start().
*/
void PNGAPI
{
/* Write the data, and run the CRC over it */
return;
{
/* Update the CRC after writing the data,
* in case that the user I/O routine alters it.
*/
}
}
/* Finish a chunk started with png_write_chunk_start(). */
void PNGAPI
{
#ifdef PNG_IO_STATE_SUPPORTED
/* Inform the I/O callback that the chunk CRC is being written.
* PNG_IO_CHUNK_CRC requires a single I/O function call.
*/
#endif
/* Write the crc in a single operation */
}
/* Initialize the compressor for the appropriate type of compression. */
static void
{
{
/* If already initialized for 'state' do not re-init. */
{
/* If actually initialized for another state do a deflateEnd. */
{
who = "end";
}
/* zlib itself detects an incomplete state on deflateEnd */
{
case PNG_ZLIB_FOR_TEXT:
who = "text";
break;
# endif
case PNG_ZLIB_FOR_IDAT:
who = "IDAT";
break;
default:
}
else /* an error in deflateEnd or deflateInit2 */
{
"zlib failed to initialize compressor (");
switch (ret)
{
case Z_VERSION_ERROR:
break;
case Z_STREAM_ERROR:
break;
case Z_MEM_ERROR:
break;
default:
break;
}
}
}
/* Here on success, claim the zstream: */
}
else
}
/* The opposite: release the stream. It is also reset, this API will warn on
* error but will not fail.
*/
static void
{
{
{
switch (ret)
{
case Z_VERSION_ERROR:
err = "version";
break;
case Z_STREAM_ERROR:
err = "stream";
break;
case Z_MEM_ERROR:
err = "memory";
break;
default:
err = "unknown";
break;
}
else
err = "[no zlib message]";
"zlib failed to reset compressor: @1(@2): @3");
}
}
else
}
/* This pair of functions encapsulates the operation of (a) compressing a
* text string, and (b) issuing it later as a series of chunk data writes.
* The compression_state structure is shared context for these functions
* set up by the caller in order to make the whole mess thread-safe.
*/
typedef struct
{
/* Compress given text into storage in the png_ptr structure */
static int /* PRIVATE */
{
int ret;
comp->num_output_ptr = 0;
comp->max_output_ptr = 0;
/* We may just want to pass the text right through */
if (compression == PNG_TEXT_COMPRESSION_NONE)
{
return((int)text_len);
}
if (compression >= PNG_TEXT_COMPRESSION_LAST)
{
}
/* We can't write the chunk until we find out how much data we have,
* which means we need to run the compressor first and save the
* output. This shouldn't be a problem, as the vast majority of
* comments should be reasonable, but we will set up an array of
* malloc'd pointers to be sure.
*
* If we knew the application was well behaved, we could simplify this
* greatly by assuming we can always malloc an output buffer large
* enough to hold the compressed text ((1001 * text_len / 1000) + 12)
* and malloc this directly. The only time this would be a bad idea is
* if we can't malloc more than 64K and we have 64K of random input
* data, or if the input string is incredibly large (although this
* wouldn't cause a failure, just a slowdown due to swapping).
*/
/* Set up the compression buffers */
/* TODO: the following cast hides a potential overflow problem. */
/* NOTE: assume zlib doesn't overwrite the input */
/* This is the same compression loop as in png_write_row() */
do
{
/* Compress the data */
{
/* Error */
else
}
/* Check to see if we need more room */
{
/* Make sure the output array has room */
{
int old_max;
{
* png_sizeof(png_charp));
}
else
}
/* Save the data */
comp->num_output_ptr++;
/* and reset the buffer */
}
/* Continue until we don't have any more to compress */
/* Finish the compression */
do
{
/* Tell zlib we are finished */
{
/* Check to see if we need more room */
{
/* Check to make sure our output array has room */
{
int old_max;
{
/* This could be optimized to realloc() */
png_sizeof(png_charp)));
}
else
png_sizeof(png_charp)));
}
/* Save the data */
comp->num_output_ptr++;
/* and reset the buffer pointers */
}
}
else if (ret != Z_STREAM_END)
{
/* We got an error */
else
}
} while (ret != Z_STREAM_END);
/* Text length is number of buffers plus last buffer */
return((int)text_len);
}
/* Ship the compressed text out via chunk writes */
static void /* PRIVATE */
{
int i;
/* Handle the no-compression case */
{
return;
}
{
/* Optimize the CMF field in the zlib stream. This hack of the zlib
* stream is compliant to the stream specification.
*/
if (comp->num_output_ptr)
else
{
unsigned int z_cinfo;
unsigned int half_z_window_size;
while (uncompressed_text_size <= half_z_window_size &&
half_z_window_size >= 256)
{
z_cinfo--;
half_z_window_size >>= 1;
}
if (comp->num_output_ptr)
{
{
int tmp;
}
}
else
{
int tmp;
}
}
else
"Invalid zlib compression method or flags in non-IDAT chunk");
}
#endif /* PNG_WRITE_OPTIMIZE_CMF_SUPPORTED */
/* Write saved output buffers, if any */
for (i = 0; i < comp->num_output_ptr; i++)
{
}
if (comp->max_output_ptr != 0)
/* Write anything left in zbuf */
}
#endif /* PNG_WRITE_COMPRESSED_TEXT_SUPPORTED */
/* Write the IHDR chunk, and update the png_struct with the necessary
* information. Note that the rest of this code depends upon this
* information being correct.
*/
void /* PRIVATE */
int interlace_type)
{
/* Check that we have valid input data from the application info */
switch (color_type)
{
case PNG_COLOR_TYPE_GRAY:
switch (bit_depth)
{
case 1:
case 2:
case 4:
case 8:
#ifdef PNG_WRITE_16BIT_SUPPORTED
case 16:
#endif
default:
"Invalid bit depth for grayscale image");
}
break;
case PNG_COLOR_TYPE_RGB:
#ifdef PNG_WRITE_16BIT_SUPPORTED
#else
if (bit_depth != 8)
#endif
break;
case PNG_COLOR_TYPE_PALETTE:
switch (bit_depth)
{
case 1:
case 2:
case 4:
case 8:
break;
default:
}
break;
break;
case PNG_COLOR_TYPE_RGB_ALPHA:
#ifdef PNG_WRITE_16BIT_SUPPORTED
#else
if (bit_depth != 8)
#endif
break;
default:
}
{
}
/* Write filter_method 64 (intrapixel differencing) only if
* 1. Libpng was compiled with PNG_MNG_FEATURES_SUPPORTED and
* 2. Libpng did not write a PNG signature (this filter_method is only
* used in PNG datastreams that are embedded in MNG datastreams) and
* 3. The application called png_permit_mng_features with a mask that
* included PNG_FLAG_MNG_FILTER_64 and
* 4. The filter_method is 64 and
* 5. The color_type is RGB or RGBA
*/
if (
#ifdef PNG_MNG_FEATURES_SUPPORTED
(color_type == PNG_COLOR_TYPE_RGB ||
(filter_type == PNG_INTRAPIXEL_DIFFERENCING)) &&
#endif
{
}
if (interlace_type != PNG_INTERLACE_NONE &&
{
}
#else
#endif
/* Save the relevent information */
#ifdef PNG_MNG_FEATURES_SUPPORTED
#endif
/* Set the usr info, so any transformations can modify it */
/* Pack the header information into the buffer */
/* Write the chunk */
/* Initialize zlib with PNG info */
{
else
}
{
else
}
#else
#endif /* PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED */
#endif /* PNG_WRITE_COMPRESSED_TEXT_SUPPORTED */
/* Record that the compressor has not yet been initialized. */
}
/* Write the palette. We are careful not to trust png_color to be in the
* correct order for PNG, so people can redefine it to any convenient
* structure.
*/
void /* PRIVATE */
{
png_uint_32 i;
if ((
#ifdef PNG_MNG_FEATURES_SUPPORTED
#endif
{
{
}
else
{
return;
}
}
{
"Ignoring request to write a PLTE chunk in grayscale PNG");
return;
}
{
}
#else
/* This is a little slower but some buggy compilers need to do this
* instead
*/
for (i = 0; i < num_pal; i++)
{
}
#endif
}
/* Write an IDAT chunk */
void /* PRIVATE */
{
{
/* Optimize the CMF field in the zlib stream. This hack of the zlib
* stream is compliant to the stream specification.
*/
{
/* Avoid memory underflows and multiplication overflows.
*
* The conditions below are practically always satisfied;
* however, they still must be checked.
*/
if (length >= 2 &&
{
/* Compute the maximum possible length of the datastream */
/* Number of pixels, plus for each row a filter byte
* and possibly a padding byte, so increase the maximum
* size to account for these.
*/
unsigned int z_cinfo;
unsigned int half_z_window_size;
/* If it's interlaced, each block of 8 rows is sent as up to
* 14 rows, i.e., 6 additional rows, each with a filter byte
* and possibly a padding byte
*/
if (png_ptr->interlaced)
while (uncompressed_idat_size <= half_z_window_size &&
half_z_window_size >= 256)
{
z_cinfo--;
half_z_window_size >>= 1;
}
{
int tmp;
}
}
}
else
"Invalid zlib compression method or flags in IDAT");
}
#endif /* PNG_WRITE_OPTIMIZE_CMF_SUPPORTED */
/* Prior to 1.5.4 this code was replicated in every caller (except at the
* end, where it isn't technically necessary). Since this function has
* flushed the data we can safely reset the zlib output buffer here.
*/
}
/* Write an IEND chunk */
void /* PRIVATE */
{
}
#ifdef PNG_WRITE_gAMA_SUPPORTED
/* Write a gAMA chunk */
void /* PRIVATE */
{
/* file_gamma is saved in 1/100,000ths */
}
#endif
#ifdef PNG_WRITE_sRGB_SUPPORTED
/* Write a sRGB chunk */
void /* PRIVATE */
{
if (srgb_intent >= PNG_sRGB_INTENT_LAST)
"Invalid sRGB rendering intent specified");
}
#endif
#ifdef PNG_WRITE_iCCP_SUPPORTED
/* Write an iCCP chunk */
void /* PRIVATE */
{
int embedded_profile_len = 0;
comp.num_output_ptr = 0;
comp.max_output_ptr = 0;
return;
profile_len = 0;
if (profile_len > 3)
if (embedded_profile_len < 0)
{
"Embedded profile length in iCCP chunk is negative");
return;
}
if (profile_len < embedded_profile_len)
{
"Embedded profile length too large in iCCP chunk");
return;
}
if (profile_len > embedded_profile_len)
{
"Truncating profile to actual length in iCCP chunk");
}
if (profile_len)
/* Make sure we include the NULL after the name and the compression type */
if (profile_len)
{
}
}
#endif
#ifdef PNG_WRITE_sPLT_SUPPORTED
/* Write a sPLT chunk */
void /* PRIVATE */
{
#ifndef PNG_POINTER_INDEXING_SUPPORTED
int i;
#endif
return;
/* Make sure we include the NULL after the name */
/* Loop through each palette entry, writing appropriately */
{
{
}
else
{
}
}
#else
{
{
}
else
{
}
}
#endif
}
#endif
#ifdef PNG_WRITE_sBIT_SUPPORTED
/* Write the sBIT chunk */
void /* PRIVATE */
{
/* Make sure we don't depend upon the order of PNG_COLOR_8 */
if (color_type & PNG_COLOR_MASK_COLOR)
{
{
return;
}
size = 3;
}
else
{
{
return;
}
size = 1;
}
if (color_type & PNG_COLOR_MASK_ALPHA)
{
{
return;
}
}
}
#endif
#ifdef PNG_WRITE_cHRM_SUPPORTED
/* Write the cHRM chunk */
void /* PRIVATE */
{
/* Each value is saved in 1/100,000ths */
#ifdef PNG_CHECK_cHRM_SUPPORTED
#endif
{
}
}
#endif
#ifdef PNG_WRITE_tRNS_SUPPORTED
/* Write the tRNS chunk */
void /* PRIVATE */
{
if (color_type == PNG_COLOR_TYPE_PALETTE)
{
{
return;
}
/* Write the chunk out as it is */
}
else if (color_type == PNG_COLOR_TYPE_GRAY)
{
/* One 16 bit value */
{
"Ignoring attempt to write tRNS chunk out-of-range for bit_depth");
return;
}
}
else if (color_type == PNG_COLOR_TYPE_RGB)
{
/* Three 16 bit values */
#ifdef PNG_WRITE_16BIT_SUPPORTED
#else
#endif
{
"Ignoring attempt to write 16-bit tRNS chunk when bit_depth is 8");
return;
}
}
else
{
}
}
#endif
#ifdef PNG_WRITE_bKGD_SUPPORTED
/* Write the background chunk */
void /* PRIVATE */
{
if (color_type == PNG_COLOR_TYPE_PALETTE)
{
if (
#ifdef PNG_MNG_FEATURES_SUPPORTED
(png_ptr->num_palette ||
#endif
{
return;
}
}
else if (color_type & PNG_COLOR_MASK_COLOR)
{
#ifdef PNG_WRITE_16BIT_SUPPORTED
#else
#endif
{
"Ignoring attempt to write 16-bit bKGD chunk when bit_depth is 8");
return;
}
}
else
{
{
"Ignoring attempt to write bKGD chunk out-of-range for bit_depth");
return;
}
}
}
#endif
#ifdef PNG_WRITE_hIST_SUPPORTED
/* Write the histogram */
void /* PRIVATE */
{
int i;
{
return;
}
for (i = 0; i < num_hist; i++)
{
}
}
#endif
#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 is allocated to hold the corrected keyword and must be freed
* by the calling routine. This avoids problems with trying to write to
* static keywords without having to have duplicate copies of the strings.
*/
png_size_t /* PRIVATE */
{
int kflag;
int kwarn=0;
{
return ((png_size_t)0);
}
{
return ((png_size_t)0);
}
/* Replace non-printing characters with a blank and print a warning */
{
{
*dp = ' ';
}
else
{
}
}
*dp = '\0';
/* Remove any trailing white space. */
if (*kp == ' ')
{
while (*kp == ' ')
{
*(kp--) = '\0';
key_len--;
}
}
/* Remove any leading white space. */
if (*kp == ' ')
{
while (*kp == ' ')
{
kp++;
key_len--;
}
}
/* Remove multiple internal spaces. */
{
{
kflag = 1;
}
else if (*kp == ' ')
{
key_len--;
kwarn = 1;
}
else
{
kflag = 0;
}
}
*dp = '\0';
if (kwarn)
if (key_len == 0)
{
}
if (key_len > 79)
{
key_len = 79;
}
return (key_len);
}
#endif
#ifdef PNG_WRITE_tEXt_SUPPORTED
/* Write a tEXt chunk */
void /* PRIVATE */
{
return;
text_len = 0;
else
/* Make sure we include the 0 after the key */
/*
* We leave it to the application to meet PNG-1.0 requirements on the
* contents of the text. PNG-1.0 through PNG-1.2 discourage the use of
* any non-Latin-1 characters except for NEWLINE. ISO PNG will forbid them.
* The NUL character is forbidden by PNG-1.0 through PNG-1.2 and ISO PNG.
*/
if (text_len)
}
#endif
#ifdef PNG_WRITE_zTXt_SUPPORTED
/* Write a compressed text chunk */
void /* PRIVATE */
{
comp.num_output_ptr = 0;
comp.max_output_ptr = 0;
{
return;
}
{
return;
}
/* Compute the compressed data; do it now for the length */
&comp);
/* Write start of chunk */
/* Write key */
/* Write compression */
/* Write the compressed data */
/* Close the chunk */
}
#endif
#ifdef PNG_WRITE_iTXt_SUPPORTED
/* Write an iTXt chunk */
void /* PRIVATE */
{
comp.num_output_ptr = 0;
comp.max_output_ptr = 0;
return;
{
lang_len = 0;
}
lang_key_len = 0;
else
text_len = 0;
else
/* Compute the compressed data; do it now for the length */
&comp);
/* Make sure we include the compression flag, the compression byte,
* and the NULs after the key, lang, and lang_key parts
*/
5 /* comp byte, comp flag, terminators for key, lang and lang_key */
+ key_len
+ lang_len
+ text_len));
/* We leave it to the application to meet PNG-1.0 requirements on the
* contents of the text. PNG-1.0 through PNG-1.2 discourage the use of
* any non-Latin-1 characters except for NEWLINE. ISO PNG will forbid them.
* The NUL character is forbidden by PNG-1.0 through PNG-1.2 and ISO PNG.
*/
/* Set the compression flag */
if (compression == PNG_ITXT_COMPRESSION_NONE ||
cbuf[0] = 0;
else /* compression == PNG_ITXT_COMPRESSION_zTXt */
cbuf[0] = 1;
/* Set the compression method */
cbuf[1] = 0;
cbuf[0] = 0;
}
#endif
#ifdef PNG_WRITE_oFFs_SUPPORTED
/* Write the oFFs chunk */
void /* PRIVATE */
int unit_type)
{
if (unit_type >= PNG_OFFSET_LAST)
}
#endif
#ifdef PNG_WRITE_pCAL_SUPPORTED
/* Write the pCAL chunk (described in the PNG extensions document) */
void /* PRIVATE */
{
int i;
if (type >= PNG_EQUATION_LAST)
/* Find the length of each parameter, making sure we don't count the
* null terminator for the last parameter.
*/
for (i = 0; i < nparams; i++)
{
(unsigned long)params_len[i]);
}
for (i = 0; i < nparams; i++)
{
(png_size_t)params_len[i]);
}
}
#endif
#ifdef PNG_WRITE_sCAL_SUPPORTED
/* Write the sCAL chunk */
void /* PRIVATE */
{
if (total_len > 64)
{
return;
}
}
#endif
#ifdef PNG_WRITE_pHYs_SUPPORTED
/* Write the pHYs chunk */
void /* PRIVATE */
int unit_type)
{
if (unit_type >= PNG_RESOLUTION_LAST)
}
#endif
#ifdef PNG_WRITE_tIME_SUPPORTED
/* Write the tIME chunk. Use either png_convert_from_struct_tm()
* or png_convert_from_time_t(), or fill in the structure yourself.
*/
void /* PRIVATE */
{
{
return;
}
}
#endif
/* Initializes the row writing capability of libpng */
void /* PRIVATE */
{
/* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */
/* Start of interlace block */
/* Offset to next interlace block */
/* Start of interlace block in the y direction */
/* Offset to next interlace block in the y direction */
#endif
/* Set up row buffer */
#ifdef PNG_WRITE_FILTER_SUPPORTED
/* Set up filtering buffer, if using this filter */
{
}
/* We only need to keep the previous row if we are using one of these. */
{
/* Set up previous row buffer */
{
}
{
}
{
}
}
#endif /* PNG_WRITE_FILTER_SUPPORTED */
/* If interlaced, we need to set up width and height of pass */
if (png_ptr->interlaced)
{
{
png_pass_ystart[0]) / png_pass_yinc[0];
png_pass_start[0]) / png_pass_inc[0];
}
else
{
}
}
else
#endif
{
}
}
/* Internal use only. Called when finished processing a row of data. */
void /* PRIVATE */
{
/* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */
/* Start of interlace block */
/* Offset to next interlace block */
/* Start of interlace block in the y direction */
/* Offset to next interlace block in the y direction */
#endif
int ret;
/* Next row */
png_ptr->row_number++;
/* See if we are done */
return;
/* If interlaced, go to next pass */
if (png_ptr->interlaced)
{
png_ptr->row_number = 0;
{
}
else
{
/* Loop until we find a non-zero width or height pass */
do
{
break;
break;
}
/* Reset the row above the image for the next pass */
{
return;
}
}
#endif
/* If we get here, we've just written the last row, so we need
to flush the compressor */
do
{
/* Tell the compressor we are done */
/* Check for an error */
{
/* Check to see if we need more room */
{
}
}
else if (ret != Z_STREAM_END)
{
else
}
} while (ret != Z_STREAM_END);
/* Write any extra space */
{
}
}
/* Pick out the correct pixels for the interlace pass.
* The basic idea here is to go through the row with a source
* pointer and a destination pointer (sp and dp), and copy the
* correct pixels for the pass. As the row gets compacted,
* sp will always be >= dp, so we should never overwrite anything.
* See the default: case for the easiest code to understand.
*/
void /* PRIVATE */
{
/* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */
/* Start of interlace block */
/* Offset to next interlace block */
/* We don't have to do anything on the last pass (6) */
if (pass < 6)
{
/* Each pixel depth is handled separately */
switch (row_info->pixel_depth)
{
case 1:
{
int shift;
int d;
int value;
png_uint_32 i;
d = 0;
shift = 7;
i += png_pass_inc[pass])
{
if (shift == 0)
{
shift = 7;
d = 0;
}
else
shift--;
}
if (shift != 7)
break;
}
case 2:
{
int shift;
int d;
int value;
png_uint_32 i;
shift = 6;
d = 0;
i += png_pass_inc[pass])
{
if (shift == 0)
{
shift = 6;
d = 0;
}
else
shift -= 2;
}
if (shift != 6)
break;
}
case 4:
{
int shift;
int d;
int value;
png_uint_32 i;
shift = 4;
d = 0;
i += png_pass_inc[pass])
{
if (shift == 0)
{
shift = 4;
d = 0;
}
else
shift -= 4;
}
if (shift != 4)
break;
}
default:
{
png_uint_32 i;
/* Start at the beginning */
/* Find out how many bytes each pixel takes up */
/* Loop through the row, only looking at the pixels that matter */
i += png_pass_inc[pass])
{
/* Find out where the original pixel is */
/* Move the pixel */
/* Next pixel */
dp += pixel_bytes;
}
break;
}
}
/* Set new row width */
png_pass_start[pass]) /
}
}
#endif
/* 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
* chosen filter.
*/
void /* PRIVATE */
{
#ifdef PNG_WRITE_FILTER_SUPPORTED
#endif
{
/* These will never be selected so we need not test them. */
}
#endif
/* Find out how many bytes offset each pixel is */
#endif
#ifdef PNG_WRITE_FILTER_SUPPORTED
mins = PNG_MAXSUM;
/* The prediction method we use is to find which method provides the
* 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)
*/
/* We don't need to test the 'no filter' case if this is the only filter
* that has been chosen, as it doesn't actually do anything to the data.
*/
{
png_size_t i;
int v;
{
v = *rp;
}
{
int j;
/* Reduce the sum if we match any of the previous rows */
for (j = 0; j < num_p_filters; j++)
{
{
}
}
/* 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).
*/
if (sumhi > PNG_HIMASK)
sum = PNG_MAXSUM;
else
}
#endif
}
/* Sub filter */
if (filter_to_do == PNG_FILTER_SUB)
/* It's the only filter so no testing is needed */
{
png_size_t i;
{
}
{
}
}
else if (filter_to_do & PNG_FILTER_SUB)
{
png_size_t i;
int v;
/* We temporarily increase the "minimum sum" by the factor we
* would reduce the sum of this filter, so that we can do the
* early exit comparison without scaling the sum each time.
*/
{
int j;
for (j = 0; j < num_p_filters; j++)
{
{
}
}
if (lmhi > PNG_HIMASK)
lmins = PNG_MAXSUM;
else
}
#endif
{
}
{
break;
}
{
int j;
for (j = 0; j < num_p_filters; j++)
{
{
}
}
if (sumhi > PNG_HIMASK)
sum = PNG_MAXSUM;
else
}
#endif
{
}
}
/* Up filter */
if (filter_to_do == PNG_FILTER_UP)
{
png_size_t i;
{
}
}
else if (filter_to_do & PNG_FILTER_UP)
{
png_size_t i;
int v;
{
int j;
for (j = 0; j < num_p_filters; j++)
{
{
}
}
if (lmhi > PNG_HIMASK)
lmins = PNG_MAXSUM;
else
}
#endif
{
break;
}
{
int j;
for (j = 0; j < num_p_filters; j++)
{
{
}
}
if (sumhi > PNG_HIMASK)
sum = PNG_MAXSUM;
else
}
#endif
{
}
}
/* Avg filter */
if (filter_to_do == PNG_FILTER_AVG)
{
png_uint_32 i;
{
}
{
& 0xff);
}
}
else if (filter_to_do & PNG_FILTER_AVG)
{
png_size_t i;
int v;
{
int j;
for (j = 0; j < num_p_filters; j++)
{
{
}
}
if (lmhi > PNG_HIMASK)
lmins = PNG_MAXSUM;
else
}
#endif
{
}
{
v = *dp++ =
break;
}
{
int j;
for (j = 0; j < num_p_filters; j++)
{
{
}
}
if (sumhi > PNG_HIMASK)
sum = PNG_MAXSUM;
else
}
#endif
{
}
}
/* Paeth filter */
if (filter_to_do == PNG_FILTER_PAETH)
{
png_size_t i;
{
}
{
b = *pp++;
c = *cp++;
a = *lp++;
p = b - c;
pc = a - c;
#ifdef PNG_USE_ABS
#else
pa = p < 0 ? -p : p;
#endif
}
}
else if (filter_to_do & PNG_FILTER_PAETH)
{
png_size_t i;
int v;
{
int j;
for (j = 0; j < num_p_filters; j++)
{
{
}
}
if (lmhi > PNG_HIMASK)
lmins = PNG_MAXSUM;
else
}
#endif
{
}
{
b = *pp++;
c = *cp++;
a = *lp++;
#ifndef PNG_SLOW_PAETH
p = b - c;
pc = a - c;
#ifdef PNG_USE_ABS
#else
pa = p < 0 ? -p : p;
#endif
#else /* PNG_SLOW_PAETH */
p = a + b - c;
p = a;
p = b;
else
p = c;
#endif /* PNG_SLOW_PAETH */
break;
}
{
int j;
for (j = 0; j < num_p_filters; j++)
{
{
}
}
if (sumhi > PNG_HIMASK)
sum = PNG_MAXSUM;
else
}
#endif
{
}
}
#endif /* PNG_WRITE_FILTER_SUPPORTED */
/* Do the actual writing of the filtered row data from the chosen filter. */
#ifdef PNG_WRITE_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++)
{
}
}
#endif
#endif /* PNG_WRITE_FILTER_SUPPORTED */
}
/* Do the actual writing of a previously filtered row. */
static void
{
/* Set up the zlib input buffer */
/* Repeat until we have compressed all the data */
do
{
/* Record the number of bytes available - zlib supports at least 65535
* bytes at one step, depending on the size of the zlib type 'uInt', the
* maximum size zlib can write at once is ZLIB_IO_MAX (from pngpriv.h).
* Use this because on 16 bit systems 'rowbytes' can be up to 65536 (i.e.
* one more than 16 bits) and, in this case 'rowbytes+1' can overflow a
* uInt. ZLIB_IO_MAX can be safely reduced to cause zlib to be called
* with smaller chunks of data.
*/
{
if (avail > ZLIB_IO_MAX)
{
avail -= ZLIB_IO_MAX;
}
else
{
/* So this will fit in the available uInt space: */
avail = 0;
}
}
/* Compress the data */
/* Check for compression errors */
{
else
}
/* See if it is time to write another IDAT */
{
/* Write the IDAT and reset the zlib output buffer */
}
/* Repeat until all data has been compressed */
/* Swap the current and previous rows */
{
}
/* Finish row - updates counters and flushes zlib if last row */
#ifdef PNG_WRITE_FLUSH_SUPPORTED
png_ptr->flush_rows++;
if (png_ptr->flush_dist > 0 &&
{
}
#endif
}
#endif /* PNG_WRITE_SUPPORTED */