#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 *withunsignednumbersforconvenience,althoughonesupported *ancillarychunkusessigned(two'scomplement)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. *Theparameterisdeclaredunsignedint,notpng_uint_16, *justtoavoidpotentialproblemsonpre-ANSICcompilers.
*/ 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 *themagicbytesofthesignature,ormorelikely,thePNGstreamis *beingembeddedintoanotherstreamanddoesn'tneeditsownsignature, *weshouldcallpng_set_sig_bytes()totelllibpnghowmanyofthe *byteshavealreadybeenwritten.
*/ 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. *Thetotal_lengthisthesumofthelengthsofallthedatayouwillbe *passinginpng_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_HDRrequiresasingleI/Ocall.
*/
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_DATAdoesNOTrequireaspecificnumberofI/Ocalls.
*/
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(). *Notethatmultiplecallstothisfunctionareallowed,andthatthe *sumofthelengthsfromthesecalls*must*adduptothetotal_length *giventopng_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, *incasetheuserI/Oroutinealtersit.
*/
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_CRCrequiresasingleI/Ofunctioncall.
*/
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 *representingthechunkname.Thearraymustbeatleast4bytesin *length,anddoesnotneedtobenullterminated.Tobesafe,passthe *pre-definedchunknameshere,andifyouneedanewone,defineit *wheretheothersaredefined.Thelengthisthelengthofthedata. *Allthedatamustbepresent.Ifthatisnotpossible,usethe *png_write_chunk_start(),png_write_chunk_data(),andpng_write_chunk_end() *functionsinstead.
*/ 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, *soitonlyneedstobeaccurateifthesizeislessthan16384bytes(the *pointatwhichalowerLZwindowsizecanbeused.)
*/ 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 *thewidthandheightusedto15bits.
*/
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 *boththefilterbyteandthepaddingtoabyteboundary.
*/
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 *deflateheader)tocorrectthewindowBitsvaluetomatchtheactualdata *size.Notethatthesecondargumentisthe*uncompressed*sizebutthe *firstargumentisthe*compressed*data(anditmustbedeflate *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 *stillcomplianttothestreamspecification.
*/ 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 *internalerror,butisveryusefulfordebugging.i18nrequirements *areminimal.
*/
(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 *IDATvaluesexceptforthestrategy,whichisfixedtothe *default.(Thisisthepre-1.6.0behaviortoo,althoughitwas *implementedinaverydifferentway.)
*/
strategy = Z_DEFAULT_STRATEGY; #endif
}
/* Adjust 'windowBits' down if larger than 'data_size'; to stop this *happeningjustpass32768asthedata_sizeparameter.Noticethatzlib *requiresanextra262bytesinthewindowinadditiontothedatatobe *abletoseethewholeofthedata,soifdata_size+262takesustothe *nextwindowBitssizeweneedtofixupthevaluelater.(Becauseeven *thoughdeflateneedstheextrawindow,inflatedoesnot!)
*/ if (data_size <= 16384)
{ /* IMPLEMENTATION NOTE: this 'half_window_size' stuff is only here to *workroundaMicrosoftVisualCmisbehaviorwhich,contrarytoC-90, *widenstheresultofthefollowingshiftto64-bitsif(and, *apparently,onlyif)itisusedinatest.
*/ unsignedint half_window_size = 1U << (windowBits-1);
/* For safety clear out the input and output pointers (currently zlib *doesn'tusethemonInit,butitmightinthefuture).
*/
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 *doasimpleresettothepreviousparameters.
*/ 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 *prettymuchthesamesetoferrorcodes.
*/ 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 *textstring,and(b)issuingitlaterasaseriesofchunkdatawrites. *Thecompression_statestructureissharedcontextforthesefunctions *setupbythecallertoallowaccesstotherelevantlocalvariables. * *compression_buffer(newin1.6.0)isjustalinkedlistofzbuffer_size *temporarybuffers.From1.6.0itisretainedinpng_structsothatitwill *becorrectlyfreedintheeventofawriteerror(previousimplementations *justleakedmemory.)
*/ 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.Theresultisbufferedratherthanusingthetwo-passalgorithm *thatisusedontheinflateside;deflateisassumedtobesloweranda *PNGwriterisassumedtohavemorememoryavailablethanaPNGreader. * *IMPLEMENTATIONNOTE:thezlibAPIdeflateBound()canbeusedtofindan *upperlimitontheoutputsize,butitisalwaysbiggerthantheinput *sizesoitislikelytobemoreefficienttousethislinked-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.UseZLIB_IO_MAXtolimittheinput.Theoutputisalwayslimited *bytheoutputbuffersize,sothereisnoneedtocheckthat.Sincethis *isANSI-Cweknowthatan'int',henceauInt,isalwaysatleast16bits *insize.
*/
{
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 *lengthmustbecountedhere.
*/ 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 *resetaboveeverytimeroundtheloop).
*/
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 *besubtractedfromoutput_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 *toolong.Otherwiseensurethez_stream::msgpointerissetto *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 *isaninternalerror.
*/ 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 *functionabovetoreturnZ_STREAM_ENDonanerror(thoughitnever *doesinthecurrentversionsofzlib.)
*/ 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.Notethattherestofthiscodedependsuponthis *informationbeingcorrect.
*/ 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)
{ case1: case2: case4: case8: #ifdef PNG_WRITE_16BIT_SUPPORTED case16: #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");
/* 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 *correctorderforPNG,sopeoplecanredefineittoanyconvenient *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 *allofthedataatonceand,insteadofbufferingthecompressedresult, *writesitasIDATchunks.Unlikepng_text_compressit*can*png_errorout *becauseitcallsthewriteinterface.Asaresultitdoesitsownerror *reportinganddoesnotreturnanerrorcode.Intheeventoferroritwill *justcallpng_error.Theinputdatalengthmayexceed32-bits.The'flush' *parameterisexactlythesameasthattodeflate,withthefollowing *meanings: * *Z_NO_FLUSH:normalincrementaloutputofcompresseddata *Z_SYNC_FLUSH:doaSYNC_FLUSH,usedbypng_write_flush *Z_FINISH:thisistheendoftheinput,doaZ_FINISHandcleanup * *Theroutinemanagestheacquireandreleaseofthepng_ptr->zstreamby *checkingand(attheend)clearingpng_ptr->zowner;itdoessomesanity *checksonthe'mode'flagswhiledoingthis.
*/ 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 *trimthebufferlistifithasmorethanoneentrytofreememory. *If'WRITE_COMPRESSED_TEXT'isnotsetthelistwillneverhavebeen *createdatthispoint,butthecheckhereisquickandsafe.
*/ 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 *initializedhereaftertheclaim.
*/
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 *terminatestheoperation.The_outvaluesaremaintainedacrosscallsto *thisfunction,buttheinputmustbereseteachtime.
*/
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 *thatthesetwozstreamfieldsarepreservedacrossthecalls,therefore *thereisnoneedtosettheseuponentrytotheloop.
*/ 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 *firstIDATmayneeddeflateheaderoptimization.
*/ #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 *thesameflushparameteruntilithasfinishedoutput,forNO_FLUSH *itdoesn'tmatter.
*/ if (ret == Z_OK && flush != Z_NO_FLUSH) continue;
}
/* The order of these checks doesn't matter much; it just affects which *possibleerrormightbedetectedifmultiplethingsgowrongatonce.
*/ if (ret == Z_OK) /* most likely return code! */
{ /* If all the input has been consumed then just return. If Z_FINISH *wasusedastheflushparametersomethinghasgonewrongifweget *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.ForsmallPNGfileswemaystillbeatthebeginning.
*/
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 *beforewhenitwasstored.
*/ if (profile == NULL)
png_error(png_ptr, "No profile for iCCP chunk"); /* internal error */
if (profile_len < 132)
png_error(png_ptr, "ICC profile too short");
if (png_get_uint_32(profile) != profile_len)
png_error(png_ptr, "Incorrect data in iCCP");
temp = (png_uint_32) (*(profile+8)); if (temp > 3 && (profile_len & 0x03))
png_error(png_ptr, "ICC profile length invalid (not a multiple of 4)");
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)); /* *WeleaveittotheapplicationtomeetPNG-1.0requirementsonthe *contentsofthetext.PNG-1.0throughPNG-1.2discouragetheuseof *anynon-Latin-1charactersexceptforNEWLINE.ISOPNGwillforbidthem. *TheNULcharacterisforbiddenbyPNG-1.0throughPNG-1.2andISOPNG.
*/
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 keyword separator */
/* We leave it to the application to meet PNG-1.0 requirements on the *contentsofthetext.PNG-1.0throughPNG-1.2discouragetheuseof *anynon-Latin-1charactersexceptforNEWLINE.ISOPNG,however, *specifiesthatthetextisUTF-8andthisreallydoesn'trequireany *checking. * *TheNULcharacterisforbiddenbyPNG-1.0throughPNG-1.2andISOPNG. * *TODO:validatethelanguagetagcorrectly(seethespec.)
*/ 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 *nullterminatorforthelastparameter.
*/ 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];
}
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++;
if ((png_ptr->transformations & PNG_INTERLACE) != 0) break;
} while (png_ptr->usr_width == 0 || png_ptr->num_rows == 0);
}
/* Reset the row above the image for the next pass */ if (png_ptr->pass < 7)
{ if (png_ptr->prev_row != NULL)
memset(png_ptr->prev_row, 0,
PNG_ROWBYTES(png_ptr->usr_channels *
png_ptr->usr_bit_depth, png_ptr->width) + 1);
return;
}
} #endif
/* If we get here, we've just written the last row, so we need
to flush the compressor */
png_compress_IDAT(png_ptr, NULL, 0, Z_FINISH);
}
#ifdef PNG_WRITE_INTERLACING_SUPPORTED /* Pick out the correct pixels for the interlace pass. *Thebasicideahereistogothroughtherowwithasource *pointerandadestinationpointer(spanddp),andcopythe *correctpixelsforthepass.Astherowgetscompacted, *spwillalwaysbe>=dp,soweshouldneveroverwriteanything. *Seethedefault:casefortheeasiestcodetounderstand.
*/ void/* PRIVATE */
png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass)
{
png_debug(1, "in png_do_write_interlace");
/* 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)
{ case1:
{
png_bytep sp;
png_bytep dp; unsignedint shift; int d; int value;
png_uint_32 i;
png_uint_32 row_width = row_info->width;
dp = row;
d = 0;
shift = 7;
for (i = png_pass_start[pass]; i < row_width;
i += png_pass_inc[pass])
{
sp = row + (size_t)(i >> 3);
value = (int)(*sp >> (7 - (int)(i & 0x07))) & 0x01;
d |= (value << shift);
if (shift == 0)
{
shift = 7;
*dp++ = (png_byte)d;
d = 0;
}
else
shift--;
} if (shift != 7)
*dp = (png_byte)d;
break;
}
case2:
{
png_bytep sp;
png_bytep dp; unsignedint shift; int d; int value;
png_uint_32 i;
png_uint_32 row_width = row_info->width;
dp = row;
shift = 6;
d = 0;
for (i = png_pass_start[pass]; i < row_width;
i += png_pass_inc[pass])
{
sp = row + (size_t)(i >> 2);
value = (*sp >> ((3 - (int)(i & 0x03)) << 1)) & 0x03;
d |= (value << shift);
if (shift == 0)
{
shift = 6;
*dp++ = (png_byte)d;
d = 0;
}
/* Find out how many bytes each pixel takes up */
pixel_bytes = (row_info->pixel_depth >> 3);
/* Loop through the row, only looking at the pixels that matter */ for (i = png_pass_start[pass]; i < row_width;
i += png_pass_inc[pass])
{ /* Find out where the original pixel is */
sp = row + (size_t)i * pixel_bytes;
/* Move the pixel */ if (dp != sp)
memcpy(dp, sp, pixel_bytes);
/* Next pixel */
dp += pixel_bytes;
} break;
}
} /* Set new row width */
row_info->width = (row_info->width +
png_pass_inc[pass] - 1 -
png_pass_start[pass]) /
png_pass_inc[pass];
/* This filters the row, chooses which filter to use, if it has not already *beenspecifiedbytheapplication,andthenwritestherowoutwiththe *chosenfilter.
*/ staticvoid/* PRIVATE */
png_write_filtered_row(png_structrp png_ptr, png_bytep filtered_row,
size_t row_bytes);
/* Find out how many bytes offset each pixel is */
bpp = (row_info->pixel_depth + 7) >> 3;
row_buf = png_ptr->row_buf;
mins = PNG_SIZE_MAX - 256/* so we can detect potential overflow of the
running sum */;
/* The prediction method we use is to find which method provides the *smallestvaluewhensummingtheabsolutevaluesofthedistances *fromzero,usinganything>=128asnegativenumbers.Thisisknown *asthe"minimumsumofabsolutedifferences"heuristic.Other *heuristicsarethe"weightedminimumsumofabsolutedifferences" *(experimentalandcanintheoryimprovecompression),andthe"zlib *predictive"method(notimplementedyet),whichdoestestcompressions *oflinesusingdifferentfiltermethods,andthenchoosesthe *(seriesof)filter(s)thatgiveminimumcompresseddatasize(VERY *computationallyexpensive). * *GRR980525:consideralso * *(1)minimumsumofabsolutedifferencesfromrunningaverage(i.e., *keeprunningsumofnon-absolutedifferences&countofbytes) *[trackdispersion,too?restartaverageifdispersiontoolarge?] * *(1b)minimumsumofabsolutedifferencesfromslidingaverage,probably *withwindowsize<=deflatewindow(usually32K) * *(2)minimumsumofsquareddifferencesfromzeroorrunningaverage *(i.e.,~root-mean-squareapproach)
*/
/* We don't need to test the 'no filter' case if this is the only filter *thathasbeenchosen,asitdoesn'tactuallydoanythingtothedata.
*/
best_row = png_ptr->row_buf;
if (PNG_SIZE_MAX/128 <= row_bytes)
{ /* Overflow can occur in the calculation, just select the lowest set *filter.
*/
filter_to_do &= 0U-filter_to_do;
} elseif ((filter_to_do & PNG_FILTER_NONE) != 0 &&
filter_to_do != PNG_FILTER_NONE)
{ /* Overflow not possible and multiple filters in the list, including the *'none'filter.
*/
png_bytep rp;
size_t sum = 0;
size_t i; unsignedint v;
{ for (i = 0, rp = row_buf + 1; i < row_bytes; i++, rp++)
{
v = *rp; #ifdef PNG_USE_ABS
sum += 128 - abs((int)v - 128); #else
sum += (v < 128) ? v : 256 - v; #endif
}
}
mins = sum;
}
/* Sub filter */ if (filter_to_do == PNG_FILTER_SUB) /* 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;
}
/* 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);
#endif/* WRITE_FILTER */
}
/* Do the actual writing of a previously filtered row. */ staticvoid
png_write_filtered_row(png_structrp png_ptr, png_bytep filtered_row,
size_t full_row_length/*includes filter byte*/)
{
png_debug(1, "in png_write_filtered_row");
void/* PRIVATE */
png_write_reinit(png_structp png_ptr, png_infop info_ptr,
png_uint_32 width, png_uint_32 height)
{ 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 (width > png_ptr->first_frame_width ||
height > png_ptr->first_frame_height)
png_error(png_ptr, "width and/or height for a frame greater than " "the ones in IHDR");
¤ Diese beiden folgenden Angebotsgruppen bietet das Unternehmen0.63Angebot
(Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-09-29)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.