/* pngwutil.c - utilities to write a PNG file * * Copyright (c) 2018-2024 Cosmin Truta * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson * Copyright (c) 1996-1997 Andreas Dilger * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. * * This code is released under the libpng license. * For conditions of distribution and use, see the disclaimer * and license in png.h * * This file contains routines that are only called from within * libpng itself during the course of writing an image.
*/
#include"pngpriv.h"
#ifdef PNG_WRITE_SUPPORTED
#ifdef PNG_WRITE_INTERLACING_SUPPORTED /* Arrays to facilitate interlacing - use pass (0 - 6) as index. */
/* Start of interlace block */ staticconst png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; /* Offset to next interlace block */ staticconst png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; /* Start of interlace block in the y direction */ staticconst png_byte png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1}; /* Offset to next interlace block in the y direction */ staticconst png_byte png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
/* TODO: Move these arrays to a common utility module to avoid duplication. */ #endif
#ifdef PNG_WRITE_INT_FUNCTIONS_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
png_save_uint_32(png_bytep buf, png_uint_32 i)
{
buf[0] = (png_byte)((i >> 24) & 0xffU);
buf[1] = (png_byte)((i >> 16) & 0xffU);
buf[2] = (png_byte)((i >> 8) & 0xffU);
buf[3] = (png_byte)( i & 0xffU);
}
/* 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
png_save_uint_16(png_bytep buf, unsignedint i)
{
buf[0] = (png_byte)((i >> 8) & 0xffU);
buf[1] = (png_byte)( i & 0xffU);
} #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
png_write_sig(png_structrp png_ptr)
{
png_byte png_signature[8] = {137, 80, 78, 71, 13, 10, 26, 10};
#ifdef PNG_IO_STATE_SUPPORTED /* Inform the I/O callback that the signature is being written */
png_ptr->io_state = PNG_IO_WRITING | PNG_IO_SIGNATURE; #endif
/* Write the rest of the 8 byte signature */
png_write_data(png_ptr, &png_signature[png_ptr->sig_bytes],
(size_t)(8 - png_ptr->sig_bytes));
if (png_ptr->sig_bytes < 3)
png_ptr->mode |= PNG_HAVE_PNG_SIGNATURE;
}
/* 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().
*/ staticvoid
png_write_chunk_header(png_structrp png_ptr, png_uint_32 chunk_name,
png_uint_32 length)
{
png_byte buf[8];
#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.
*/
png_ptr->io_state = PNG_IO_WRITING | PNG_IO_CHUNK_HDR; #endif
/* Write the length and the chunk name */
png_save_uint_32(buf, length);
png_save_uint_32(buf + 4, chunk_name);
png_write_data(png_ptr, buf, 8);
/* Put the chunk name into png_ptr->chunk_name */
png_ptr->chunk_name = chunk_name;
/* Reset the crc and run it over the chunk name */
png_reset_crc(png_ptr);
png_calculate_crc(png_ptr, buf + 4, 4);
#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.
*/
png_ptr->io_state = PNG_IO_WRITING | PNG_IO_CHUNK_DATA; #endif
}
/* Write the data of a PNG chunk started with png_write_chunk_header(). * 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_header().
*/ void PNGAPI
png_write_chunk_data(png_structrp png_ptr, png_const_bytep data, size_t length)
{ /* Write the data, and run the CRC over it */ if (png_ptr == NULL) return;
/* Update the CRC after writing the data, * in case the user I/O routine alters it.
*/
png_calculate_crc(png_ptr, data, length);
}
}
/* Finish a chunk started with png_write_chunk_header(). */ void PNGAPI
png_write_chunk_end(png_structrp png_ptr)
{
png_byte buf[4];
if (png_ptr == NULL) return;
#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.
*/
png_ptr->io_state = PNG_IO_WRITING | PNG_IO_CHUNK_CRC; #endif
/* Write the crc in a single operation */
png_save_uint_32(buf, png_ptr->crc);
png_write_data(png_ptr, buf, 4);
}
/* 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.
*/ staticvoid
png_write_complete_chunk(png_structrp png_ptr, png_uint_32 chunk_name,
png_const_bytep data, size_t length)
{ if (png_ptr == NULL) return;
/* On 64-bit architectures 'length' may not fit in a png_uint_32. */ if (length > PNG_UINT_31_MAX)
png_error(png_ptr, "length exceeds PNG maximum");
/* This is the API that calls the internal function above. */ void PNGAPI
png_write_chunk(png_structrp png_ptr, png_const_bytep chunk_string,
png_const_bytep data, size_t length)
{
png_write_complete_chunk(png_ptr, PNG_CHUNK_FROM_STRING(chunk_string), data,
length);
}
/* This is used below to find the size of an image to pass to png_deflate_claim, * so it only needs to be accurate if the size is less than 16384 bytes (the * point at which a lower LZ window size can be used.)
*/ static png_alloc_size_t
png_image_size(png_structrp png_ptr)
{ /* Only return sizes up to the maximum of a png_uint_32; do this by limiting * the width and height used to 15 bits.
*/
png_uint_32 h = png_ptr->height;
if (png_ptr->rowbytes < 32768 && h < 32768)
{ if (png_ptr->interlaced != 0)
{ /* Interlacing makes the image larger because of the replication of * both the filter byte and the padding to a byte boundary.
*/
png_uint_32 w = png_ptr->width; unsignedint pd = png_ptr->pixel_depth;
png_alloc_size_t cb_base; int pass;
#ifdef PNG_WRITE_OPTIMIZE_CMF_SUPPORTED /* This is the code to hack the first two bytes of the deflate stream (the * deflate header) to correct the windowBits value to match the actual data * size. Note that the second argument is the *uncompressed* size but the * first argument is the *compressed* data (and it must be deflate * compressed.)
*/ staticvoid
optimize_cmf(png_bytep data, png_alloc_size_t data_size)
{ /* Optimize the CMF field in the zlib stream. The resultant zlib stream is * still compliant to the stream specification.
*/ if (data_size <= 16384) /* else windowBits must be 15 */
{ unsignedint z_cmf = data[0]; /* zlib compression method and flags */
/* Initialize the compressor for the appropriate type of compression. */ staticint
png_deflate_claim(png_structrp png_ptr, png_uint_32 owner,
png_alloc_size_t data_size)
{ if (png_ptr->zowner != 0)
{ #ifdefined(PNG_WARNINGS_SUPPORTED) || defined(PNG_ERROR_TEXT_SUPPORTED) char msg[64];
PNG_STRING_FROM_CHUNK(msg, owner);
msg[4] = ':';
msg[5] = ' ';
PNG_STRING_FROM_CHUNK(msg+6, png_ptr->zowner); /* So the message that results is "<chunk> using zstream"; this is an * internal error, but is very useful for debugging. i18n requirements * are minimal.
*/
(void)png_safecat(msg, (sizeof msg), 10, " using zstream"); #endif #if PNG_RELEASE_BUILD
png_warning(png_ptr, msg);
/* Attempt sane error recovery */ if (png_ptr->zowner == png_IDAT) /* don't steal from IDAT */
{
png_ptr->zstream.msg = PNGZ_MSG_CAST("in use by IDAT"); return Z_STREAM_ERROR;
}
{ int level = png_ptr->zlib_level; int method = png_ptr->zlib_method; int windowBits = png_ptr->zlib_window_bits; int memLevel = png_ptr->zlib_mem_level; int strategy; /* set below */ int ret; /* zlib return code */
if (owner == png_IDAT)
{ if ((png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_STRATEGY) != 0)
strategy = png_ptr->zlib_strategy;
else
{ #ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED
level = png_ptr->zlib_text_level;
method = png_ptr->zlib_text_method;
windowBits = png_ptr->zlib_text_window_bits;
memLevel = png_ptr->zlib_text_mem_level;
strategy = png_ptr->zlib_text_strategy; #else /* If customization is not supported the values all come from 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 * implemented in a very different way.)
*/
strategy = Z_DEFAULT_STRATEGY; #endif
}
/* Adjust 'windowBits' down if larger than 'data_size'; to stop this * happening just pass 32768 as the data_size parameter. Notice that zlib * requires an extra 262 bytes in the window in addition to the data to be * able to see the whole of the data, so if data_size+262 takes us to the * next windowBits size we need to fix up the value later. (Because even * though deflate needs the extra window, inflate does not!)
*/ if (data_size <= 16384)
{ /* IMPLEMENTATION NOTE: this 'half_window_size' stuff is only here to * work round a Microsoft Visual C misbehavior which, contrary to C-90, * widens the result of the following shift to 64-bits if (and, * apparently, only if) it is used in a test.
*/ unsignedint half_window_size = 1U << (windowBits-1);
/* For safety clear out the input and output pointers (currently zlib * doesn't use them on Init, but it might in the future).
*/
png_ptr->zstream.next_in = NULL;
png_ptr->zstream.avail_in = 0;
png_ptr->zstream.next_out = NULL;
png_ptr->zstream.avail_out = 0;
/* Now initialize if required, setting the new parameters, otherwise just * do a simple reset to the previous parameters.
*/ if ((png_ptr->flags & PNG_FLAG_ZSTREAM_INITIALIZED) != 0)
ret = deflateReset(&png_ptr->zstream);
else
{
ret = deflateInit2(&png_ptr->zstream, level, method, windowBits,
memLevel, strategy);
if (ret == Z_OK)
png_ptr->flags |= PNG_FLAG_ZSTREAM_INITIALIZED;
}
/* The return code is from either deflateReset or deflateInit2; they have * pretty much the same set of error codes.
*/ if (ret == Z_OK)
png_ptr->zowner = owner;
else
png_zstream_error(png_ptr, ret);
return ret;
}
}
/* Clean up (or trim) a linked list of compression buffers. */ void/* PRIVATE */
png_free_buffer_list(png_structrp png_ptr, png_compression_bufferp *listp)
{
png_compression_bufferp list = *listp;
if (list != NULL)
{
*listp = NULL;
do
{
png_compression_bufferp next = list->next;
png_free(png_ptr, list);
list = next;
} while (list != NULL);
}
}
#ifdef PNG_WRITE_COMPRESSED_TEXT_SUPPORTED /* 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 to allow access to the relevant local variables. * * compression_buffer (new in 1.6.0) is just a linked list of zbuffer_size * temporary buffers. From 1.6.0 it is retained in png_struct so that it will * be correctly freed in the event of a write error (previous implementations * just leaked memory.)
*/ typedefstruct
{
png_const_bytep input; /* The uncompressed input data */
png_alloc_size_t input_len; /* Its length */
png_uint_32 output_len; /* Final compressed length */
png_byte output[1024]; /* First block of output */
} compression_state;
/* Compress the data in the compression state input */ staticint
png_text_compress(png_structrp png_ptr, png_uint_32 chunk_name,
compression_state *comp, png_uint_32 prefix_len)
{ int ret;
/* 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 * 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. * * IMPLEMENTATION NOTE: the zlib API deflateBound() can be used to find an * upper limit on the output size, but it is always bigger than the input * size so it is likely to be more efficient to use this linked-list * approach.
*/
ret = png_deflate_claim(png_ptr, chunk_name, comp->input_len);
if (ret != Z_OK) return ret;
/* Set up the compression buffers, we need a loop here to avoid overflowing a * uInt. Use ZLIB_IO_MAX to limit the input. The output is always limited * by the output buffer size, so there is no need to check that. Since this * is ANSI-C we know that an 'int', hence a uInt, is always at least 16 bits * in size.
*/
{
png_compression_bufferp *end = &png_ptr->zbuffer_list;
png_alloc_size_t input_len = comp->input_len; /* may be zero! */
png_uint_32 output_len;
/* zlib updates these for us: */
png_ptr->zstream.next_in = PNGZ_INPUT_CAST(comp->input);
png_ptr->zstream.avail_in = 0; /* Set below */
png_ptr->zstream.next_out = comp->output;
png_ptr->zstream.avail_out = (sizeof comp->output);
output_len = png_ptr->zstream.avail_out;
do
{
uInt avail_in = ZLIB_IO_MAX;
if (avail_in > input_len)
avail_in = (uInt)input_len;
input_len -= avail_in;
png_ptr->zstream.avail_in = avail_in;
if (png_ptr->zstream.avail_out == 0)
{
png_compression_buffer *next;
/* Chunk data is limited to 2^31 bytes in length, so the prefix * length must be counted here.
*/ if (output_len + prefix_len > PNG_UINT_31_MAX)
{
ret = Z_MEM_ERROR; break;
}
/* Need a new (malloc'ed) buffer, but there may be one present * already.
*/
next = *end; if (next == NULL)
{
next = png_voidcast(png_compression_bufferp, png_malloc_base
(png_ptr, PNG_COMPRESSION_BUFFER_SIZE(png_ptr)));
if (next == NULL)
{
ret = Z_MEM_ERROR; break;
}
/* Link in this buffer (so that it will be freed later) */
next->next = NULL;
*end = next;
}
/* Move 'end' to the next buffer pointer. */
end = &next->next;
}
/* Compress the data */
ret = deflate(&png_ptr->zstream,
input_len > 0 ? Z_NO_FLUSH : Z_FINISH);
/* Claw back input data that was not consumed (because avail_in is * reset above every time round the loop).
*/
input_len += png_ptr->zstream.avail_in;
png_ptr->zstream.avail_in = 0; /* safety */
} while (ret == Z_OK);
/* There may be some space left in the last output buffer. This needs to * be subtracted from output_len.
*/
output_len -= png_ptr->zstream.avail_out;
png_ptr->zstream.avail_out = 0; /* safety */
comp->output_len = output_len;
/* Now double check the output length, put in a custom message if it is * too long. Otherwise ensure the z_stream::msg pointer is set to * something.
*/ if (output_len + prefix_len >= PNG_UINT_31_MAX)
{
png_ptr->zstream.msg = PNGZ_MSG_CAST("compressed data too long");
ret = Z_MEM_ERROR;
}
else
png_zstream_error(png_ptr, ret);
/* Reset zlib for another zTXt/iTXt or image data */
png_ptr->zowner = 0;
/* The only success case is Z_STREAM_END, input_len must be 0; if not this * is an internal error.
*/ if (ret == Z_STREAM_END && input_len == 0)
{ #ifdef PNG_WRITE_OPTIMIZE_CMF_SUPPORTED /* Fix up the deflate header, if required */
optimize_cmf(comp->output, comp->input_len); #endif /* 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 * does in the current versions of zlib.)
*/ return Z_OK;
}
else return ret;
}
}
/* Ship the compressed text out via chunk writes */ staticvoid
png_write_compressed_data_out(png_structrp png_ptr, compression_state *comp)
{
png_uint_32 output_len = comp->output_len;
png_const_bytep output = comp->output;
png_uint_32 avail = (sizeof comp->output);
png_compression_buffer *next = png_ptr->zbuffer_list;
for (;;)
{ if (avail > output_len)
avail = output_len;
png_write_chunk_data(png_ptr, output, avail);
output_len -= avail;
if (output_len == 0 || next == NULL) break;
avail = png_ptr->zbuffer_size;
output = next->output;
next = next->next;
}
/* This is an internal error; 'next' must have been NULL! */ if (output_len > 0)
png_error(png_ptr, "error writing ancillary chunked compressed data");
} #endif/* WRITE_COMPRESSED_TEXT */
/* 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 */
png_write_IHDR(png_structrp png_ptr, png_uint_32 width, png_uint_32 height, int bit_depth, int color_type, int compression_type, int filter_type, int interlace_type)
{
png_byte buf[13]; /* Buffer to store the IHDR info */ int is_invalid_depth;
png_debug(1, "in png_write_IHDR");
/* 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
png_ptr->channels = 1; break;
default:
png_error(png_ptr, "Invalid bit depth for grayscale image");
} break;
case PNG_COLOR_TYPE_RGB:
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 RGB image");
png_ptr->channels = 3; break;
case PNG_COLOR_TYPE_PALETTE: switch (bit_depth)
{ case 1: case 2: case 4: case 8:
png_ptr->channels = 1; break;
default:
png_error(png_ptr, "Invalid bit depth for paletted image");
} break;
case PNG_COLOR_TYPE_GRAY_ALPHA:
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_ptr->channels = 2; break;
case PNG_COLOR_TYPE_RGB_ALPHA:
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 RGBA image");
png_ptr->channels = 4; break;
default:
png_error(png_ptr, "Invalid image color type specified");
}
if (compression_type != PNG_COMPRESSION_TYPE_BASE)
{
png_warning(png_ptr, "Invalid compression type specified");
compression_type = PNG_COMPRESSION_TYPE_BASE;
}
/* 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
!((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) != 0 &&
((png_ptr->mode & PNG_HAVE_PNG_SIGNATURE) == 0) &&
(color_type == PNG_COLOR_TYPE_RGB ||
color_type == PNG_COLOR_TYPE_RGB_ALPHA) &&
(filter_type == PNG_INTRAPIXEL_DIFFERENCING)) && #endif
filter_type != PNG_FILTER_TYPE_BASE)
{
png_warning(png_ptr, "Invalid filter type specified");
filter_type = PNG_FILTER_TYPE_BASE;
}
/* Save the relevant information */
png_ptr->bit_depth = (png_byte)bit_depth;
png_ptr->color_type = (png_byte)color_type;
png_ptr->interlaced = (png_byte)interlace_type; #ifdef PNG_MNG_FEATURES_SUPPORTED
png_ptr->filter_type = (png_byte)filter_type; #endif
png_ptr->compression_type = (png_byte)compression_type;
png_ptr->width = width;
png_ptr->height = height;
png_ptr->pixel_depth = (png_byte)(bit_depth * png_ptr->channels);
png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth, width); /* Set the usr info, so any transformations can modify it */
png_ptr->usr_width = png_ptr->width;
png_ptr->usr_bit_depth = png_ptr->bit_depth;
png_ptr->usr_channels = png_ptr->channels;
/* Pack the header information into the buffer */
png_save_uint_32(buf, width);
png_save_uint_32(buf + 4, height);
buf[8] = (png_byte)bit_depth;
buf[9] = (png_byte)color_type;
buf[10] = (png_byte)compression_type;
buf[11] = (png_byte)filter_type;
buf[12] = (png_byte)interlace_type;
/* Write the chunk */
png_write_complete_chunk(png_ptr, png_IHDR, buf, 13);
png_ptr->mode = PNG_HAVE_IHDR; /* not READY_FOR_ZTXT */
}
/* 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_write_PLTE(png_structrp png_ptr, png_const_colorp palette,
png_uint_32 num_pal)
{
png_uint_32 max_palette_length, i;
png_const_colorp pal_ptr;
png_byte buf[3];
/* This is similar to png_text_compress, above, except that it does not require * all of the data at once and, instead of buffering the compressed result, * writes it as IDAT chunks. Unlike png_text_compress it *can* png_error out * because it calls the write interface. As a result it does its own error * reporting and does not return an error code. In the event of error it will * just call png_error. The input data length may exceed 32-bits. The 'flush' * parameter is exactly the same as that to deflate, with the following * meanings: * * Z_NO_FLUSH: normal incremental output of compressed data * Z_SYNC_FLUSH: do a SYNC_FLUSH, used by png_write_flush * 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 * checking and (at the end) clearing png_ptr->zowner; it does some sanity * checks on the 'mode' flags while doing this.
*/ void/* PRIVATE */
png_compress_IDAT(png_structrp png_ptr, png_const_bytep input,
png_alloc_size_t input_len, int flush)
{ if (png_ptr->zowner != png_IDAT)
{ /* First time. Ensure we have a temporary buffer for compression and * trim the buffer list if it has more than one entry to free memory. * If 'WRITE_COMPRESSED_TEXT' is not set the list will never have been * created at this point, but the check here is quick and safe.
*/ if (png_ptr->zbuffer_list == NULL)
{
png_ptr->zbuffer_list = png_voidcast(png_compression_bufferp,
png_malloc(png_ptr, PNG_COMPRESSION_BUFFER_SIZE(png_ptr)));
png_ptr->zbuffer_list->next = NULL;
}
/* It is a terminal error if we can't claim the zstream. */ if (png_deflate_claim(png_ptr, png_IDAT, png_image_size(png_ptr)) != Z_OK)
png_error(png_ptr, png_ptr->zstream.msg);
/* The output state is maintained in png_ptr->zstream, so it must be * initialized here after the claim.
*/
png_ptr->zstream.next_out = png_ptr->zbuffer_list->output;
png_ptr->zstream.avail_out = png_ptr->zbuffer_size;
}
/* Now loop reading and writing until all the input is consumed or an error * terminates the operation. The _out values are maintained across calls to * this function, but the input must be reset each time.
*/
png_ptr->zstream.next_in = PNGZ_INPUT_CAST(input);
png_ptr->zstream.avail_in = 0; /* set below */ for (;;)
{ int ret;
/* INPUT: from the row data */
uInt avail = ZLIB_IO_MAX;
if (avail > input_len)
avail = (uInt)input_len; /* safe because of the check */
/* OUTPUT: write complete IDAT chunks when avail_out drops to zero. Note * that these two zstream fields are preserved across the calls, therefore * there is no need to set these up on entry to the loop.
*/ if (png_ptr->zstream.avail_out == 0)
{
png_bytep data = png_ptr->zbuffer_list->output;
uInt size = png_ptr->zbuffer_size;
/* Write an IDAT containing the data then reset the buffer. The * first IDAT may need deflate header optimization.
*/ #ifdef PNG_WRITE_OPTIMIZE_CMF_SUPPORTED if ((png_ptr->mode & PNG_HAVE_IDAT) == 0 &&
png_ptr->compression_type == PNG_COMPRESSION_TYPE_BASE)
optimize_cmf(data, png_image_size(png_ptr)); #endif
/* For SYNC_FLUSH or FINISH it is essential to keep calling zlib with * the same flush parameter until it has finished output, for NO_FLUSH * it doesn't matter.
*/ if (ret == Z_OK && flush != Z_NO_FLUSH) continue;
}
/* 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.
*/ if (ret == Z_OK) /* most likely return code! */
{ /* If all the input has been consumed then just return. If Z_FINISH * was used as the flush parameter something has gone wrong if we get * here.
*/ if (input_len == 0)
{ if (flush == Z_FINISH)
png_error(png_ptr, "Z_OK on Z_FINISH with output space");
return;
}
}
elseif (ret == Z_STREAM_END && flush == Z_FINISH)
{ /* This is the end of the IDAT data; any pending output must be * flushed. For small PNG files we may still be at the beginning.
*/
png_bytep data = png_ptr->zbuffer_list->output;
uInt size = png_ptr->zbuffer_size - png_ptr->zstream.avail_out;
/* These are all internal problems: the profile should have been checked * before when it was stored.
*/ if (profile == NULL)
png_error(png_ptr, "No profile for iCCP chunk"); /* internal error */
profile_len = png_get_uint_32(profile);
if (profile_len < 132)
png_error(png_ptr, "ICC profile too short");
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)");
if (key_len == 0)
png_error(png_ptr, "tEXt: invalid keyword");
if (text == NULL || *text == '\0')
text_len = 0;
else
text_len = strlen(text);
if (text_len > PNG_UINT_31_MAX - (key_len+1))
png_error(png_ptr, "tEXt: text too long");
/* Make sure we include the 0 after the key */
png_write_chunk_header(png_ptr, png_tEXt,
(png_uint_32)/*checked above*/(key_len + text_len + 1)); /* * 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.
*/
png_write_chunk_data(png_ptr, new_key, key_len + 1);
if (text_len != 0)
png_write_chunk_data(png_ptr, (png_const_bytep)text, text_len);
png_write_chunk_end(png_ptr);
} #endif
#ifdef PNG_WRITE_zTXt_SUPPORTED /* Write a compressed text chunk */ void/* PRIVATE */
png_write_zTXt(png_structrp png_ptr, png_const_charp key, png_const_charp text, int compression)
{
png_uint_32 key_len;
png_byte new_key[81];
compression_state comp;
if (key_len == 0)
png_error(png_ptr, "iTXt: invalid keyword");
/* Set the compression flag */ switch (compression)
{ case PNG_ITXT_COMPRESSION_NONE: case PNG_TEXT_COMPRESSION_NONE:
compression = new_key[++key_len] = 0; /* no compression */ break;
case PNG_TEXT_COMPRESSION_zTXt: case PNG_ITXT_COMPRESSION_zTXt:
compression = new_key[++key_len] = 1; /* compressed */ break;
new_key[++key_len] = PNG_COMPRESSION_TYPE_BASE;
++key_len; /* for the keywod separator */
/* 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, however, * specifies that the text is UTF-8 and this really doesn't require any * checking. * * The NUL character is forbidden by PNG-1.0 through PNG-1.2 and ISO PNG. * * TODO: validate the language tag correctly (see the spec.)
*/ if (lang == NULL) lang = ""; /* empty language is valid */
lang_len = strlen(lang)+1; if (lang_key == NULL) lang_key = ""; /* may be empty */
lang_key_len = strlen(lang_key)+1; if (text == NULL) text = ""; /* may be empty */
/* 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++)
{
params_len[i] = strlen(params[i]) + (i == nparams - 1 ? 0 : 1);
png_debug2(3, "pCAL parameter %d length = %lu", i,
(unsignedlong)params_len[i]);
total_len += params_len[i];
}
#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 */
png_write_tIME(png_structrp png_ptr, png_const_timep mod_time)
{
png_byte buf[7];
png_debug(1, "in png_write_tIME");
if (mod_time->month > 12 || mod_time->month < 1 ||
mod_time->day > 31 || mod_time->day < 1 ||
mod_time->hour > 23 || mod_time->second > 60)
{
png_warning(png_ptr, "Invalid time specified for tIME chunk"); return;
}
if (png_ptr->num_frames_written == 0 && (x_offset != 0 || y_offset != 0))
png_error(png_ptr, "x and/or y offset for the first frame aren't 0"); if (png_ptr->num_frames_written == 0 &&
(width != png_ptr->first_frame_width ||
height != png_ptr->first_frame_height))
png_error(png_ptr, "width and/or height in the first frame's fcTL " "don't match the ones in IHDR");
if (num_filters > 1)
png_ptr->tst_row = png_voidcast(png_bytep, png_malloc(png_ptr,
buf_size));
}
/* 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 /* If interlaced, we need to set up width and height of pass */ if (png_ptr->interlaced != 0)
{ if ((png_ptr->transformations & PNG_INTERLACE) == 0)
{
png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 -
png_pass_ystart[0]) / png_pass_yinc[0];
/* Internal use only. Called when finished processing a row of data. */ void/* PRIVATE */
png_write_finish_row(png_structrp png_ptr)
{
png_debug(1, "in png_write_finish_row");
/* Next row */
png_ptr->row_number++;
/* See if we are done */ if (png_ptr->row_number < png_ptr->num_rows) return;
#ifdef PNG_WRITE_INTERLACING_SUPPORTED /* If interlaced, go to next pass */ if (png_ptr->interlaced != 0)
{
png_ptr->row_number = 0; if ((png_ptr->transformations & PNG_INTERLACE) != 0)
{
png_ptr->pass++;
}
else
{ /* Loop until we find a non-zero width or height pass */ do
{
png_ptr->pass++;