/*
* 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.
*/
/* pngwrite.c - general routines 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
/* 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,
* and put it in the correct location here. If you want the chunk written
* after the image data, put it in png_write_end(). I strongly encourage
* you to supply a PNG_INFO_ flag, and check info_ptr->valid before writing
* the chunk, as that will keep the code from breaking if you want to just
* write a plain PNG file. If you have long comments, I suggest writing
* them in png_write_end(), and compressing them.
*/
void PNGAPI
{
return;
{
/* Write PNG signature */
#ifdef PNG_MNG_FEATURES_SUPPORTED
{
}
#endif
/* Write IHDR information. */
#else
0);
#endif
/* The rest of these check to see if the valid field has the appropriate
* flag set, and if it does, writes the chunk.
*/
#ifdef PNG_WRITE_gAMA_SUPPORTED
#endif
#ifdef PNG_WRITE_sRGB_SUPPORTED
#endif
#ifdef PNG_WRITE_iCCP_SUPPORTED
#endif
#ifdef PNG_WRITE_sBIT_SUPPORTED
#endif
#ifdef PNG_WRITE_cHRM_SUPPORTED
#endif
if (info_ptr->unknown_chunks_num)
{
up++)
{
if (keep != PNG_HANDLE_CHUNK_NEVER &&
{
}
}
}
#endif
}
}
void PNGAPI
{
#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED)
int i;
#endif
return;
#ifdef PNG_WRITE_tRNS_SUPPORTED
{
/* Invert the alpha channel (in tRNS) */
{
int j;
info_ptr->trans_alpha[j] =
}
#endif
}
#endif
#ifdef PNG_WRITE_bKGD_SUPPORTED
#endif
#ifdef PNG_WRITE_hIST_SUPPORTED
#endif
#ifdef PNG_WRITE_oFFs_SUPPORTED
#endif
#ifdef PNG_WRITE_pCAL_SUPPORTED
#endif
#ifdef PNG_WRITE_sCAL_SUPPORTED
#endif /* sCAL */
#ifdef PNG_WRITE_pHYs_SUPPORTED
#endif /* pHYs */
#ifdef PNG_WRITE_tIME_SUPPORTED
{
}
#endif /* tIME */
#ifdef PNG_WRITE_sPLT_SUPPORTED
for (i = 0; i < (int)info_ptr->splt_palettes_num; i++)
#endif /* sPLT */
#ifdef PNG_WRITE_TEXT_SUPPORTED
/* Check to see if we need to write text chunks */
{
/* An internationalized chunk? */
{
#ifdef PNG_WRITE_iTXt_SUPPORTED
/* Write international chunk */
#else
#endif
/* Mark this chunk as written */
}
/* If we want a compressed text chunk */
{
#ifdef PNG_WRITE_zTXt_SUPPORTED
/* Write compressed chunk */
#else
#endif
/* Mark this chunk as written */
}
{
#ifdef PNG_WRITE_tEXt_SUPPORTED
/* Write uncompressed chunk */
0);
/* Mark this chunk as written */
#else
/* Can't get here */
#endif
}
}
#endif /* tEXt */
if (info_ptr->unknown_chunks_num)
{
up++)
{
if (keep != PNG_HANDLE_CHUNK_NEVER &&
{
}
}
}
#endif
}
/* Writes the end of the PNG file. If you don't want to write comments or
* time information, you can pass NULL for info. If you already wrote these
* in png_write_info(), do not write them again here. If you have long
* comments, I suggest writing them here, and compressing them.
*/
void PNGAPI
{
return;
/* See if user wants us to write information chunks */
{
#ifdef PNG_WRITE_TEXT_SUPPORTED
int i; /* local index variable */
#endif
#ifdef PNG_WRITE_tIME_SUPPORTED
/* Check to see if user has supplied a time chunk */
#endif
#ifdef PNG_WRITE_TEXT_SUPPORTED
/* Loop through comment chunks */
{
/* An internationalized chunk? */
{
#ifdef PNG_WRITE_iTXt_SUPPORTED
/* Write international chunk */
#else
#endif
/* Mark this chunk as written */
}
{
#ifdef PNG_WRITE_zTXt_SUPPORTED
/* Write compressed chunk */
#else
#endif
/* Mark this chunk as written */
}
{
#ifdef PNG_WRITE_tEXt_SUPPORTED
/* Write uncompressed chunk */
#else
#endif
/* Mark this chunk as written */
}
}
#endif
if (info_ptr->unknown_chunks_num)
{
up++)
{
if (keep != PNG_HANDLE_CHUNK_NEVER &&
{
}
}
}
#endif
}
/* Write end of PNG file */
/* 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
* do not set png_ptr->output_flush_fn to crash. If your application
* experiences a problem, please try building libpng with
* PNG_WRITE_FLUSH_AFTER_IEND_SUPPORTED defined, and report the event to
* png-mng-implement at lists.sf.net .
*/
#ifdef PNG_WRITE_FLUSH_SUPPORTED
# endif
#endif
}
#ifdef PNG_CONVERT_tIME_SUPPORTED
/* "tm" structure is not supported on WindowsCE */
void PNGAPI
{
}
void PNGAPI
{
}
#endif
/* Initialize png_ptr structure, and allocate any memory needed */
{
#ifdef PNG_USER_MEM_SUPPORTED
}
/* Alternate initialize png_ptr structure, and allocate any memory needed */
{
#endif /* PNG_USER_MEM_SUPPORTED */
volatile int png_cleanup_needed = 0;
#ifdef PNG_SETJMP_SUPPORTED
volatile
#endif
#ifdef PNG_SETJMP_SUPPORTED
#ifdef USE_FAR_KEYWORD
#endif
#endif
#ifdef PNG_USER_MEM_SUPPORTED
#else
#endif /* PNG_USER_MEM_SUPPORTED */
return (NULL);
/* Added at libpng-1.2.6 */
#endif
#ifdef PNG_SETJMP_SUPPORTED
/* Applications that neglect to set up their own setjmp() and then
encounter a png_error() will longjmp here. Since the jmpbuf is
then meaningless we abort instead of returning. */
#ifdef USE_FAR_KEYWORD
if (setjmp(tmp_jmpbuf))
#else
#endif
#ifdef USE_FAR_KEYWORD
#endif
PNG_ABORT();
#endif
#ifdef PNG_USER_MEM_SUPPORTED
#endif /* PNG_USER_MEM_SUPPORTED */
png_cleanup_needed = 1;
/* Initialize zbuf - compression buffer */
if (!png_cleanup_needed)
{
png_cleanup_needed = 1;
}
if (png_cleanup_needed)
{
/* Clean up PNG structure and deallocate any memory. */
#ifdef PNG_USER_MEM_SUPPORTED
#else
#endif
return (NULL);
}
#endif
return (png_ptr);
}
/* Write a few rows of image data. If the image is interlaced,
* either you will have to write the 7 sub images, or, if you
* have called png_set_interlace_handling(), you will have to
* "write" the image seven times.
*/
void PNGAPI
{
png_uint_32 i; /* row counter */
return;
/* Loop through the rows */
{
}
}
/* Write the image. You only need to call this function once, even
* if you are writing an interlaced image.
*/
void PNGAPI
{
png_uint_32 i; /* row index */
return;
/* Initialize interlace handling. If image is not interlaced,
* this will set pass to 1
*/
#else
num_pass = 1;
#endif
/* Loop through passes */
{
/* Loop through image */
{
}
}
}
/* Called by user to write a row of image data */
void PNGAPI
{
return;
/* Initialize transformations and other stuff if first time */
{
/* Make sure we wrote the header info */
"png_write_info was never called before png_write_row");
/* Check for transforms that have been set but were defined out */
#if !defined(PNG_WRITE_INVERT_SUPPORTED) && defined(PNG_READ_INVERT_SUPPORTED)
#endif
#if !defined(PNG_WRITE_FILLER_SUPPORTED) && defined(PNG_READ_FILLER_SUPPORTED)
#endif
#if !defined(PNG_WRITE_PACKSWAP_SUPPORTED) && \
defined(PNG_READ_PACKSWAP_SUPPORTED)
"PNG_WRITE_PACKSWAP_SUPPORTED is not defined");
#endif
#if !defined(PNG_WRITE_PACK_SUPPORTED) && defined(PNG_READ_PACK_SUPPORTED)
#endif
#if !defined(PNG_WRITE_SHIFT_SUPPORTED) && defined(PNG_READ_SHIFT_SUPPORTED)
#endif
#if !defined(PNG_WRITE_BGR_SUPPORTED) && defined(PNG_READ_BGR_SUPPORTED)
#endif
#if !defined(PNG_WRITE_SWAP_SUPPORTED) && defined(PNG_READ_SWAP_SUPPORTED)
#endif
}
/* If interlaced and not interested in row, return */
{
{
case 0:
{
return;
}
break;
case 1:
{
return;
}
break;
case 2:
{
return;
}
break;
case 3:
{
return;
}
break;
case 4:
{
return;
}
break;
case 5:
{
return;
}
break;
case 6:
{
return;
}
break;
default: /* error: ignore it */
break;
}
}
#endif
/* Set up row info for transformations */
/* Copy user's row into buffer, leaving room for filter byte. */
/* Handle interlacing */
{
/* This should always get caught above, but still ... */
{
return;
}
}
#endif
/* Handle other transformations */
if (png_ptr->transformations)
#endif
#ifdef PNG_MNG_FEATURES_SUPPORTED
/* 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
*/
{
/* Intrapixel differencing */
}
#endif
/* Find a filter if necessary, filter the row and write it out. */
}
#ifdef PNG_WRITE_FLUSH_SUPPORTED
/* Set the automatic flush interval or 0 to turn flushing off */
void PNGAPI
{
return;
}
/* Flush the current output buffers now */
void PNGAPI
{
int wrote_IDAT;
return;
/* We have already written out all of the data */
return;
do
{
int ret;
/* Compress the data */
wrote_IDAT = 0;
/* Check for compression errors */
{
else
}
{
/* Write the IDAT and reset the zlib output buffer */
wrote_IDAT = 1;
}
} while (wrote_IDAT == 1);
/* If there is any data left to be output, write it into a new IDAT */
{
/* Write the IDAT and reset the zlib output buffer */
}
png_ptr->flush_rows = 0;
}
#endif /* PNG_WRITE_FLUSH_SUPPORTED */
/* Free all memory used by the write */
void PNGAPI
{
#ifdef PNG_USER_MEM_SUPPORTED
#endif
if (png_ptr_ptr != NULL)
{
png_ptr = *png_ptr_ptr;
#ifdef PNG_USER_MEM_SUPPORTED
#endif
}
#ifdef PNG_USER_MEM_SUPPORTED
{
}
#endif
if (info_ptr_ptr != NULL)
info_ptr = *info_ptr_ptr;
{
{
if (png_ptr->num_chunk_list)
{
png_ptr->num_chunk_list = 0;
}
#endif
}
#ifdef PNG_USER_MEM_SUPPORTED
#else
#endif
*info_ptr_ptr = NULL;
}
{
#ifdef PNG_USER_MEM_SUPPORTED
#else
#endif
*png_ptr_ptr = NULL;
}
}
/* Free any memory used in png_ptr struct (old method) */
void /* PRIVATE */
{
#ifdef PNG_SETJMP_SUPPORTED
#endif
#ifdef PNG_WARNINGS_SUPPORTED
#endif
#ifdef PNG_USER_MEM_SUPPORTED
#endif
/* Free any memory zlib uses */
/* Free our memory. png_free checks NULL for us. */
#ifdef PNG_WRITE_FILTER_SUPPORTED
#endif
/* Use this to save a little code space, it doesn't free the filter_costs */
#endif
#ifdef PNG_SETJMP_SUPPORTED
/* Reset structure */
#endif
#ifdef PNG_WARNINGS_SUPPORTED
#endif
#ifdef PNG_USER_MEM_SUPPORTED
#endif
#ifdef PNG_WARNINGS_SUPPORTED
#endif
#ifdef PNG_USER_MEM_SUPPORTED
#endif
#ifdef PNG_SETJMP_SUPPORTED
#endif
}
/* Allow the application to select one or more row filters to use. */
void PNGAPI
{
return;
#ifdef PNG_MNG_FEATURES_SUPPORTED
#endif
if (method == PNG_FILTER_TYPE_BASE)
{
{
#ifdef PNG_WRITE_FILTER_SUPPORTED
case 5:
case 6:
#endif /* PNG_WRITE_FILTER_SUPPORTED */
case PNG_FILTER_VALUE_NONE:
#ifdef PNG_WRITE_FILTER_SUPPORTED
case PNG_FILTER_VALUE_SUB:
case PNG_FILTER_VALUE_UP:
case PNG_FILTER_VALUE_AVG:
case PNG_FILTER_VALUE_PAETH:
default:
#else
default:
#endif /* PNG_WRITE_FILTER_SUPPORTED */
}
/* 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
* 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
* will be missing the data in the previous row. If an application
* wants to start and stop using particular filters during compression,
* it should start out with all of the filters, and then add and
* remove them after the start of compression.
*/
{
#ifdef PNG_WRITE_FILTER_SUPPORTED
{
}
{
{
}
else
{
}
}
{
{
}
else
{
}
}
{
{
}
else
{
}
}
#endif /* PNG_WRITE_FILTER_SUPPORTED */
}
}
else
}
/* 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
{
/* 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;
{
}
{
}
{
}
/* Leave the filter_costs - this array is fixed size. */
}
static int
int num_weights)
{
return 0;
/* Clear out the arrays */
/* Check arguments; the 'reset' function makes the correct settings for the
* unweighted case, but we must handle the weight case by initializing the
* arrays for the caller.
*/
{
int i;
if (num_weights > 0)
{
/* To make sure that the weighting starts out fairly */
for (i = 0; i < num_weights; i++)
{
}
for (i = 0; i < num_weights; i++)
{
png_ptr->inv_filter_weights[i] =
}
/* Safe to set this now */
}
/* If, in the future, there are other filter methods, this would
* need to be based on png_ptr->filter.
*/
{
}
for (i = 0; i < PNG_FILTER_VALUE_LAST; i++)
{
png_ptr->inv_filter_costs[i] =
}
/* All the arrays are inited, safe to set this: */
/* Return the 'ok' code. */
return 1;
}
else if (heuristic_method == PNG_FILTER_HEURISTIC_DEFAULT ||
{
return 1;
}
else
{
return 0;
}
}
/* Provide floating and fixed point APIs */
#ifdef PNG_FLOATING_POINT_SUPPORTED
void PNGAPI
{
/* The internal API allocates all the arrays and ensures that the elements of
* those arrays are set to the default value.
*/
return;
/* If using the weighted method copy in the weights. */
{
int i;
for (i = 0; i < num_weights; i++)
{
if (filter_weights[i] <= 0.0)
{
png_ptr->inv_filter_weights[i] =
}
else
{
png_ptr->inv_filter_weights[i] =
png_ptr->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.
*/
{
png_ptr->inv_filter_costs[i] =
png_ptr->filter_costs[i] =
}
}
}
#endif /* FLOATING_POINT */
#ifdef PNG_FIXED_POINT_SUPPORTED
void PNGAPI
{
/* The internal API allocates all the arrays and ensures that the elements of
* those arrays are set to the default value.
*/
return;
/* If using the weighted method copy in the weights. */
{
int i;
for (i = 0; i < num_weights; i++)
{
if (filter_weights[i] <= 0)
{
png_ptr->inv_filter_weights[i] =
}
else
{
}
}
/* 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)
{
/* 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 /= filter_costs[i];
}
}
}
#endif /* FIXED_POINT */
#endif /* PNG_WRITE_WEIGHTED_FILTER_SUPPORTED */
void PNGAPI
{
return;
}
void PNGAPI
{
return;
}
void PNGAPI
{
return;
}
/* If PNG_WRITE_OPTIMIZE_CMF_SUPPORTED is defined, libpng will use a
* smaller value of window_bits if it can do so safely.
*/
void PNGAPI
{
return;
if (window_bits > 15)
else if (window_bits < 8)
#ifndef WBITS_8_OK
/* Avoid libpng bug with 256-byte windows */
if (window_bits == 8)
{
window_bits = 9;
}
#endif
}
void PNGAPI
{
return;
if (method != 8)
}
/* The following were added to libpng-1.5.4 */
void PNGAPI
{
return;
}
void PNGAPI
{
return;
}
void PNGAPI
{
return;
}
/* If PNG_WRITE_OPTIMIZE_CMF_SUPPORTED is defined, libpng will use a
* smaller value of window_bits if it can do so safely.
*/
void PNGAPI
{
return;
if (window_bits > 15)
else if (window_bits < 8)
#ifndef WBITS_8_OK
/* Avoid libpng bug with 256-byte windows */
if (window_bits == 8)
{
window_bits = 9;
}
#endif
}
void PNGAPI
{
return;
if (method != 8)
}
#endif /* PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED */
/* end of API added to libpng-1.5.4 */
void PNGAPI
{
return;
}
void PNGAPI
{
return;
}
#endif
#ifdef PNG_INFO_IMAGE_SUPPORTED
void PNGAPI
{
return;
/* Write the file header information. */
/* ------ these transformations don't touch the info structure ------- */
#ifdef PNG_WRITE_INVERT_SUPPORTED
/* Invert monochrome pixels */
#endif
#ifdef PNG_WRITE_SHIFT_SUPPORTED
/* Shift the pixels up to a legal bit depth and fill in
* as appropriate to correctly scale the image.
*/
if ((transforms & PNG_TRANSFORM_SHIFT)
#endif
#ifdef PNG_WRITE_PACK_SUPPORTED
/* Pack pixels into bytes */
if (transforms & PNG_TRANSFORM_PACKING)
#endif
/* Swap location of alpha bytes from ARGB to RGBA */
#endif
#ifdef PNG_WRITE_FILLER_SUPPORTED
else if (transforms & PNG_TRANSFORM_STRIP_FILLER_BEFORE)
#endif
#ifdef PNG_WRITE_BGR_SUPPORTED
/* Flip BGR pixels to RGB */
if (transforms & PNG_TRANSFORM_BGR)
#endif
#ifdef PNG_WRITE_SWAP_SUPPORTED
/* Swap bytes of 16-bit files to most significant byte first */
#endif
#ifdef PNG_WRITE_PACKSWAP_SUPPORTED
/* Swap bits of 1, 2, 4 bit packed pixel formats */
if (transforms & PNG_TRANSFORM_PACKSWAP)
#endif
/* Invert the alpha channel from opacity to transparency */
#endif
/* ----------------------- end of transformations ------------------- */
/* Write the bits */
/* It is REQUIRED to call this to finish writing the rest of the file */
}
#endif
#endif /* PNG_WRITE_SUPPORTED */