Imported from libpng-0.96.tar

This commit is contained in:
Andreas Dilger
1997-05-16 02:46:07 -05:00
committed by Glenn Randers-Pehrson
parent 02ad0efbc8
commit 47a0c422ca
40 changed files with 6833 additions and 3520 deletions

View File

@@ -1,28 +1,32 @@
/* pngwrite.c - general routines to write a PNG file
/* pngwrite.c - general routines to write a png file
libpng 1.0 beta 4 - version 0.90
libpng 1.0 beta 6 - version 0.96
For conditions of distribution and use, see copyright notice in png.h
Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
January 10, 1997
Copyright (c) 1996, 1997 Andreas Dilger
May 12, 1997
*/
/* get internal access to png.h */
#define PNG_INTERNAL
#include "png.h"
/* 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 encurage 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. */
/* 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 encurage
* 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
png_write_info(png_structp png_ptr, png_infop info_ptr)
{
int i;
png_debug(1, "in png_write_info\n");
png_write_sig(png_ptr); /* write PNG signature */
/* write IHDR information. */
png_write_IHDR(png_ptr, info_ptr->width, info_ptr->height,
@@ -47,7 +51,8 @@ png_write_info(png_structp png_ptr, png_infop info_ptr)
info_ptr->x_blue, info_ptr->y_blue);
#endif
if (info_ptr->valid & PNG_INFO_PLTE)
png_write_PLTE(png_ptr, info_ptr->palette, info_ptr->num_palette);
png_write_PLTE(png_ptr, info_ptr->palette,
(png_uint_32)info_ptr->num_palette);
else if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
png_error(png_ptr, "Valid palette required for paletted images\n");
#if defined(PNG_WRITE_tRNS_SUPPORTED)
@@ -63,16 +68,22 @@ png_write_info(png_structp png_ptr, png_infop info_ptr)
if (info_ptr->valid & PNG_INFO_hIST)
png_write_hIST(png_ptr, info_ptr->hist, info_ptr->num_palette);
#endif
#if defined(PNG_WRITE_pHYs_SUPPORTED)
if (info_ptr->valid & PNG_INFO_pHYs)
png_write_pHYs(png_ptr, info_ptr->x_pixels_per_unit,
info_ptr->y_pixels_per_unit, info_ptr->phys_unit_type);
#endif
#if defined(PNG_WRITE_oFFs_SUPPORTED)
if (info_ptr->valid & PNG_INFO_oFFs)
png_write_oFFs(png_ptr, info_ptr->x_offset, info_ptr->y_offset,
info_ptr->offset_unit_type);
#endif
#if defined(PNG_WRITE_pCAL_SUPPORTED)
if (info_ptr->valid & PNG_INFO_pCAL)
png_write_pCAL(png_ptr, info_ptr->pcal_purpose, info_ptr->pcal_X0,
info_ptr->pcal_X1, info_ptr->pcal_type, info_ptr->pcal_nparams,
info_ptr->pcal_units, info_ptr->pcal_params);
#endif
#if defined(PNG_WRITE_pHYs_SUPPORTED)
if (info_ptr->valid & PNG_INFO_pHYs)
png_write_pHYs(png_ptr, info_ptr->x_pixels_per_unit,
info_ptr->y_pixels_per_unit, info_ptr->phys_unit_type);
#endif
#if defined(PNG_WRITE_tIME_SUPPORTED)
if (info_ptr->valid & PNG_INFO_tIME)
{
@@ -82,15 +93,68 @@ png_write_info(png_structp png_ptr, png_infop info_ptr)
#endif
#if defined(PNG_WRITE_tEXt_SUPPORTED) || defined(PNG_WRITE_zTXt_SUPPORTED)
/* Check to see if we need to write text chunks */
if (info_ptr->num_text)
for (i = 0; i < info_ptr->num_text; i++)
{
int i; /* local counter */
png_debug2(2, "Writing header text chunk %d, type %d\n", i,
info_ptr->text[i].compression);
/* If we want a compressed text chunk */
if (info_ptr->text[i].compression >= PNG_TEXT_COMPRESSION_zTXt)
{
#if defined(PNG_WRITE_zTXt_SUPPORTED)
/* write compressed chunk */
png_write_zTXt(png_ptr, info_ptr->text[i].key,
info_ptr->text[i].text, info_ptr->text[i].text_length,
info_ptr->text[i].compression);
#else
png_warning(png_ptr, "Unable to write compressed text\n");
#endif
/* Mark this chunk as written */
info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR;
}
else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE)
{
#if defined(PNG_WRITE_tEXt_SUPPORTED)
/* write uncompressed chunk */
png_write_tEXt(png_ptr, info_ptr->text[i].key,
info_ptr->text[i].text, info_ptr->text[i].text_length);
#else
png_warning(png_ptr, "Unable to write uncompressed text\n");
#endif
/* Mark this chunk as written */
info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;
}
}
#endif
}
/* loop through the text chunks */
/* 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
png_write_end(png_structp png_ptr, png_infop info_ptr)
{
png_debug(1, "in png_write_end\n");
if (!(png_ptr->mode & PNG_HAVE_IDAT))
png_error(png_ptr, "No IDATs written into file");
/* see if user wants us to write information chunks */
if (info_ptr != NULL)
{
int i; /* local index variable */
#if defined(PNG_WRITE_tIME_SUPPORTED)
/* check to see if user has supplied a time chunk */
if (info_ptr->valid & PNG_INFO_tIME &&
!(png_ptr->flags & PNG_FLAG_WROTE_tIME))
png_write_tIME(png_ptr, &(info_ptr->mod_time));
#endif
#if defined(PNG_WRITE_tEXt_SUPPORTED) || defined(PNG_WRITE_zTXt_SUPPORTED)
/* loop through comment chunks */
for (i = 0; i < info_ptr->num_text; i++)
{
/* if chunk is compressed */
if (info_ptr->text[i].compression >= 0)
png_debug2(2, "Writing trailer text chunk %d, type %d\n", i,
info_ptr->text[i].compression);
if (info_ptr->text[i].compression >= PNG_TEXT_COMPRESSION_zTXt)
{
#if defined(PNG_WRITE_zTXt_SUPPORTED)
/* write compressed chunk */
@@ -100,8 +164,10 @@ png_write_info(png_structp png_ptr, png_infop info_ptr)
#else
png_warning(png_ptr, "Unable to write compressed text\n");
#endif
/* Mark this chunk as written */
info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR;
}
else
else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE)
{
#if defined(PNG_WRITE_tEXt_SUPPORTED)
/* write uncompressed chunk */
@@ -110,60 +176,9 @@ png_write_info(png_structp png_ptr, png_infop info_ptr)
#else
png_warning(png_ptr, "Unable to write uncompressed text\n");
#endif
}
}
}
#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
png_write_end(png_structp png_ptr, png_infop info_ptr)
{
if (!(png_ptr->mode & PNG_HAVE_IDAT))
png_error(png_ptr, "No IDATs written into file");
/* see if user wants us to write information chunks */
if (info_ptr)
{
#if defined(PNG_WRITE_tIME_SUPPORTED)
/* check to see if user has supplied a time chunk */
if (info_ptr->valid & PNG_INFO_tIME &&
!(png_ptr->flags & PNG_FLAG_WROTE_tIME))
png_write_tIME(png_ptr, &(info_ptr->mod_time));
#endif
#if defined(PNG_WRITE_tEXt_SUPPORTED) || defined(PNG_WRITE_zTXt_SUPPORTED)
/* check to see if we need to write comment chunks */
if (info_ptr->num_text)
{
int i; /* local index variable */
/* loop through comment chunks */
for (i = 0; i < info_ptr->num_text; i++)
{
#if defined(PNG_WRITE_zTXt_SUPPORTED)
/* check to see if comment is to be compressed */
if (info_ptr->text[i].compression >= 0)
{
/* write compressed chunk */
png_write_zTXt(png_ptr, info_ptr->text[i].key,
info_ptr->text[i].text, info_ptr->text[i].text_length,
info_ptr->text[i].compression);
}
#if defined(PNG_WRITE_tEXt_SUPPORTED)
else
#endif
#endif
#if defined(PNG_WRITE_tEXt_SUPPORTED)
{
/* write uncompressed chunk */
png_write_tEXt(png_ptr, info_ptr->text[i].key,
info_ptr->text[i].text, info_ptr->text[i].text_length);
}
#endif
/* Mark this chunk as written */
info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;
}
}
#endif
@@ -171,7 +186,7 @@ png_write_end(png_structp png_ptr, png_infop info_ptr)
png_ptr->mode |= PNG_AFTER_IDAT;
/* write end of png file */
/* write end of PNG file */
png_write_IEND(png_ptr);
}
@@ -179,6 +194,7 @@ png_write_end(png_structp png_ptr, png_infop info_ptr)
void
png_convert_from_struct_tm(png_timep ptime, struct tm FAR * ttime)
{
png_debug(1, "in png_convert_from_struct_tm\n");
ptime->year = (png_uint_16)(1900 + ttime->tm_year);
ptime->month = (png_byte)(ttime->tm_mon + 1);
ptime->day = (png_byte)ttime->tm_mday;
@@ -192,12 +208,13 @@ png_convert_from_time_t(png_timep ptime, time_t ttime)
{
struct tm *tbuf;
png_debug(1, "in png_convert_from_time_t\n");
tbuf = gmtime(&ttime);
png_convert_from_struct_tm(ptime, tbuf);
}
#endif
/* initialize png structure, and allocate any memory needed */
/* Initialize png_ptr structure, and allocate any memory needed */
png_structp
png_create_write_struct(png_const_charp user_png_ver, voidp error_ptr,
png_error_ptr error_fn, png_error_ptr warn_fn)
@@ -206,6 +223,7 @@ png_create_write_struct(png_const_charp user_png_ver, voidp error_ptr,
#ifdef USE_FAR_KEYWORD
jmp_buf jmpbuf;
#endif
png_debug(1, "in png_create_write_struct\n");
if ((png_ptr = (png_structp)png_create_struct(PNG_STRUCT_PNG)) == NULL)
{
return (png_structp)NULL;
@@ -225,16 +243,16 @@ png_create_write_struct(png_const_charp user_png_ver, voidp error_ptr,
#endif
png_set_error_fn(png_ptr, error_ptr, error_fn, warn_fn);
if (user_png_ver == NULL || png_strcmp(user_png_ver, png_libpng_ver))
/* Libpng 0.90 and later are binary incompatible with libpng 0.89, so
* we must recompile any applications that use any older library version.
* For versions after libpng 1.0, we will be compatible, so we need
* only check the first digit.
*/
if (user_png_ver == NULL || user_png_ver[0] != png_libpng_ver[0] ||
(png_libpng_ver[0] == '0' && user_png_ver[2] < '9'))
{
if (user_png_ver == NULL || user_png_ver[0] != png_libpng_ver[0])
{
png_error(png_ptr, "Incompatible libpng versions");
}
else
{
png_warning(png_ptr, "Different libpng versions");
}
png_error(png_ptr,
"Incompatible libpng version in application and library");
}
/* initialize zbuf - compression buffer */
@@ -247,12 +265,13 @@ png_create_write_struct(png_const_charp user_png_ver, voidp error_ptr,
}
/* initialize png structure, and allocate any memory needed */
/* Initialize png_ptr structure, and allocate any memory needed */
void
png_write_init(png_structp png_ptr)
{
jmp_buf tmp_jmp; /* to save current jump buffer */
png_debug(1, "in png_write_init\n");
/* save jump buffer and error functions */
png_memcpy(tmp_jmp, png_ptr->jmpbuf, sizeof (jmp_buf));
@@ -266,6 +285,11 @@ png_write_init(png_structp png_ptr)
png_ptr->zbuf_size = PNG_ZBUF_SIZE;
png_ptr->zbuf = png_malloc(png_ptr, png_ptr->zbuf_size);
png_set_write_fn(png_ptr, NULL, NULL, NULL);
#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
png_set_filter_heuristics(png_ptr, PNG_FILTER_HEURISTIC_DEFAULT,
1, NULL, NULL);
#endif
}
/* write a few rows of image data. If the image is interlaced,
@@ -279,6 +303,7 @@ png_write_rows(png_structp png_ptr, png_bytepp row,
png_uint_32 i; /* row counter */
png_bytepp rp; /* row pointer */
png_debug(1, "in png_write_rows\n");
/* loop through the rows */
for (i = 0, rp = row; i < num_rows; i++, rp++)
{
@@ -295,6 +320,7 @@ png_write_image(png_structp png_ptr, png_bytepp image)
int pass, num_pass; /* pass variables */
png_bytepp rp; /* points to current row */
png_debug(1, "in png_write_image\n");
/* intialize interlace handling. If image is not interlaced,
this will set pass to 1 */
num_pass = png_set_interlace_handling(png_ptr);
@@ -313,6 +339,7 @@ png_write_image(png_structp png_ptr, png_bytepp image)
void
png_write_row(png_structp png_ptr, png_bytep row)
{
png_debug(1, "in png_write_row\n");
/* initialize transformations and other stuff if first time */
if (png_ptr->row_number == 0 && png_ptr->pass == 0)
{
@@ -388,8 +415,15 @@ png_write_row(png_structp png_ptr, png_bytep row)
png_ptr->row_info.rowbytes = ((png_ptr->row_info.width *
(png_uint_32)png_ptr->row_info.pixel_depth + 7) >> 3);
/* copy users row into buffer, leaving room for filter byte */
png_memcpy(png_ptr->row_buf + 1, row, (png_size_t)png_ptr->row_info.rowbytes);
png_debug1(4, "row_info->color_type = %d\n", png_ptr->row_info.color_type);
png_debug1(4, "row_info->width = %d\n", png_ptr->row_info.width);
png_debug1(4, "row_info->channels = %d\n", png_ptr->row_info.channels);
png_debug1(4, "row_info->bit_depth = %d\n", png_ptr->row_info.bit_depth);
png_debug1(4, "row_info->pixel_depth = %d\n", png_ptr->row_info.pixel_depth);
png_debug1(4, "row_info->rowbytes = %d\n", png_ptr->row_info.rowbytes);
/* Copy user's row into buffer, leaving room for filter byte. */
png_memcpy(png_ptr->row_buf + 1, row, png_ptr->row_info.rowbytes);
#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
/* handle interlacing */
@@ -411,7 +445,7 @@ png_write_row(png_structp png_ptr, png_bytep row)
if (png_ptr->transformations)
png_do_write_transformations(png_ptr);
/* find a filter if necessary, filter the row and write it out */
/* Find a filter if necessary, filter the row and write it out. */
png_write_find_filter(png_ptr, &(png_ptr->row_info));
}
@@ -420,6 +454,7 @@ png_write_row(png_structp png_ptr, png_bytep row)
void
png_set_flush(png_structp png_ptr, int nrows)
{
png_debug(1, "in png_set_flush\n");
png_ptr->flush_dist = (nrows < 0 ? 0 : nrows);
}
@@ -429,6 +464,7 @@ png_write_flush(png_structp png_ptr)
{
int wrote_IDAT;
png_debug(1, "in png_write_flush\n");
/* We have already written out all of the data */
if (png_ptr->row_number >= png_ptr->num_rows)
return;
@@ -444,13 +480,13 @@ png_write_flush(png_structp png_ptr)
/* check for compression errors */
if (ret != Z_OK)
{
if (png_ptr->zstream.msg)
if (png_ptr->zstream.msg != NULL)
png_error(png_ptr, png_ptr->zstream.msg);
else
png_error(png_ptr, "zlib error");
}
if (!png_ptr->zstream.avail_out)
if (!(png_ptr->zstream.avail_out))
{
/* write the IDAT and reset the zlib output buffer */
png_write_IDAT(png_ptr, png_ptr->zbuf,
@@ -482,19 +518,20 @@ png_destroy_write_struct(png_structpp png_ptr_ptr, png_infopp info_ptr_ptr)
png_structp png_ptr = NULL;
png_infop info_ptr = NULL;
if (png_ptr_ptr)
png_debug(1, "in png_destroy_write_struct\n");
if (png_ptr_ptr != NULL)
png_ptr = *png_ptr_ptr;
if (info_ptr_ptr)
if (info_ptr_ptr != NULL)
info_ptr = *info_ptr_ptr;
if (info_ptr)
if (info_ptr != NULL)
{
png_destroy_struct((png_voidp)info_ptr);
*info_ptr_ptr = (png_infop)NULL;
}
if (png_ptr)
if (png_ptr != NULL)
{
png_write_destroy(png_ptr);
png_destroy_struct((png_voidp)png_ptr);
@@ -503,7 +540,7 @@ png_destroy_write_struct(png_structpp png_ptr_ptr, png_infopp info_ptr_ptr)
}
/* free any memory used in png struct (old method) */
/* Free any memory used in png_ptr struct (old method) */
void
png_write_destroy(png_structp png_ptr)
{
@@ -512,6 +549,7 @@ png_write_destroy(png_structp png_ptr)
png_error_ptr warning_fn;
png_voidp error_ptr;
png_debug(1, "in png_write_destroy\n");
/* free any memory zlib uses */
deflateEnd(&png_ptr->zstream);
@@ -523,6 +561,13 @@ png_write_destroy(png_structp png_ptr)
png_free(png_ptr, png_ptr->up_row);
png_free(png_ptr, png_ptr->avg_row);
png_free(png_ptr, png_ptr->paeth_row);
#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
png_free(png_ptr, png_ptr->prev_filters);
png_free(png_ptr, png_ptr->filter_weights);
png_free(png_ptr, png_ptr->inv_filter_weights);
png_free(png_ptr, png_ptr->filter_costs);
png_free(png_ptr, png_ptr->inv_filter_costs);
#endif /* PNG_WRITE_WEIGHTED_FILTER_SUPPORTED */
/* reset structure */
png_memcpy(tmp_jmp, png_ptr->jmpbuf, sizeof (jmp_buf));
@@ -540,71 +585,79 @@ png_write_destroy(png_structp png_ptr)
png_memcpy(png_ptr->jmpbuf, tmp_jmp, sizeof (jmp_buf));
}
/* Allow the application to select one or more filters to use */
/* Allow the application to select one or more row filters to use. */
void
png_set_filter(png_structp png_ptr, int method, int filters)
{
/* We allow 'method' only for future expansion of the base filter method */
if (method == 0)
png_debug(1, "in png_set_filter\n");
/* We allow 'method' only for future expansion of the base filter method. */
if (method == PNG_FILTER_TYPE_BASE)
{
switch (filters & (PNG_ALL_FILTERS | 0x07))
{
case 5:
case 6:
case 7: png_warning(png_ptr, "Unknown custom row filter for method 0");
case 0: png_ptr->do_filter = PNG_FILTER_NONE; break;
case 1: png_ptr->do_filter = PNG_FILTER_SUB; break;
case 2: png_ptr->do_filter = PNG_FILTER_UP; break;
case 3: png_ptr->do_filter = PNG_FILTER_AVG; break;
case 4: png_ptr->do_filter = PNG_FILTER_PAETH; break;
case 7: png_warning(png_ptr, "Unknown row filter for method 0");
case PNG_FILTER_VALUE_NONE: png_ptr->do_filter=PNG_FILTER_NONE; break;
case PNG_FILTER_VALUE_SUB: png_ptr->do_filter=PNG_FILTER_SUB; break;
case PNG_FILTER_VALUE_UP: png_ptr->do_filter=PNG_FILTER_UP; break;
case PNG_FILTER_VALUE_AVG: png_ptr->do_filter=PNG_FILTER_AVG; break;
case PNG_FILTER_VALUE_PAETH: png_ptr->do_filter=PNG_FILTER_PAETH;break;
default: png_ptr->do_filter = (png_byte)filters; break;
}
/* If we have allocated the row_buf, then we should have also allocated
* all of the filter buffers that have been selected.
/* 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.
*/
if (png_ptr->row_buf)
if (png_ptr->row_buf != NULL)
{
if (png_ptr->do_filter & PNG_FILTER_SUB && !(png_ptr->sub_row))
if (png_ptr->do_filter & PNG_FILTER_SUB && png_ptr->sub_row == NULL)
{
png_ptr->sub_row = (png_bytep )png_malloc(png_ptr,
png_ptr->sub_row = (png_bytep)png_malloc(png_ptr,
png_ptr->rowbytes + 1);
png_ptr->sub_row[0] = 1; /* Set the row filter type */
png_ptr->sub_row[0] = PNG_FILTER_VALUE_SUB;
}
if (png_ptr->do_filter & PNG_FILTER_UP && !(png_ptr->up_row))
if (png_ptr->do_filter & PNG_FILTER_UP && png_ptr->up_row == NULL)
{
if (!(png_ptr->prev_row))
if (png_ptr->prev_row == NULL)
{
png_warning(png_ptr, "Can't to add up filter after starting");
png_warning(png_ptr, "Can't add Up filter after starting");
png_ptr->do_filter &= ~PNG_FILTER_UP;
}
else
{
png_ptr->up_row = (png_bytep )png_malloc(png_ptr,
png_ptr->up_row = (png_bytep)png_malloc(png_ptr,
png_ptr->rowbytes + 1);
png_ptr->up_row[0] = 2; /* Set the row filter type */
png_ptr->up_row[0] = PNG_FILTER_VALUE_UP;
}
}
if (png_ptr->do_filter & PNG_FILTER_AVG && !(png_ptr->avg_row))
if (png_ptr->do_filter & PNG_FILTER_AVG && png_ptr->avg_row == NULL)
{
if (!(png_ptr->prev_row))
if (png_ptr->prev_row == NULL)
{
png_warning(png_ptr, "Can't add average filter after starting");
png_warning(png_ptr, "Can't add Average filter after starting");
png_ptr->do_filter &= ~PNG_FILTER_AVG;
}
else
{
png_ptr->up_row = (png_bytep )png_malloc(png_ptr,
png_ptr->avg_row = (png_bytep)png_malloc(png_ptr,
png_ptr->rowbytes + 1);
png_ptr->up_row[0] = 3; /* Set the row filter type */
png_ptr->avg_row[0] = PNG_FILTER_VALUE_AVG;
}
}
if (png_ptr->do_filter & PNG_FILTER_PAETH && !(png_ptr->paeth_row))
if (png_ptr->do_filter & PNG_FILTER_PAETH &&
png_ptr->paeth_row == NULL)
{
if (!(png_ptr->prev_row))
if (png_ptr->prev_row == NULL)
{
png_warning(png_ptr, "Can't add Paeth filter after starting");
png_ptr->do_filter &= ~PNG_FILTER_PAETH;
@@ -613,7 +666,7 @@ png_set_filter(png_structp png_ptr, int method, int filters)
{
png_ptr->paeth_row = (png_bytep )png_malloc(png_ptr,
png_ptr->rowbytes + 1);
png_ptr->paeth_row[0] = 4; /* Set the row filter type */
png_ptr->paeth_row[0] = PNG_FILTER_VALUE_PAETH;
}
}
@@ -622,12 +675,137 @@ png_set_filter(png_structp png_ptr, int method, int filters)
}
}
else
png_error(png_ptr, "Unknown custom filter method");
png_error(png_ptr, "Unknown custom filter method");
}
/* This allows us to influence the way in which libpng chooses the "best"
* filter for the current scanline. While the "minimum-sum-of-absolute-
* differences metric is relatively fast and effective, there is some
* question as to whether it can be improved upon by trying to keep the
* filtered data going to zlib more consistent, hopefully resulting in
* better compression. */
#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) /* GRR 970116 */
void
png_set_filter_heuristics(png_structp png_ptr, int heuristic_method,
int num_weights, png_doublep filter_weights,
png_doublep filter_costs)
{
int i;
png_debug(1, "in png_set_filter_heuristics\n");
if (heuristic_method >= PNG_FILTER_HEURISTIC_LAST)
{
png_warning(png_ptr, "Unknown filter heuristic method");
return;
}
if (heuristic_method == PNG_FILTER_HEURISTIC_DEFAULT)
{
heuristic_method = PNG_FILTER_HEURISTIC_UNWEIGHTED;
}
if (num_weights < 0 || filter_weights == NULL ||
heuristic_method == PNG_FILTER_HEURISTIC_UNWEIGHTED)
{
num_weights = 0;
}
png_ptr->num_prev_filters = num_weights;
png_ptr->heuristic_method = heuristic_method;
if (num_weights > 0)
{
if (png_ptr->prev_filters == NULL)
{
png_ptr->prev_filters = (png_bytep)png_malloc(png_ptr,
sizeof(png_byte) * num_weights);
/* To make sure that the weighting starts out fairly */
for (i = 0; i < num_weights; i++)
{
png_ptr->prev_filters[i] = 255;
}
}
if (png_ptr->filter_weights == NULL)
{
png_ptr->filter_weights = (png_uint_16p)png_malloc(png_ptr,
sizeof(png_uint_16) * num_weights);
png_ptr->inv_filter_weights = (png_uint_16p)png_malloc(png_ptr,
sizeof(png_uint_16) * num_weights);
for (i = 0; i < num_weights; i++)
{
png_ptr->inv_filter_weights[i] =
png_ptr->filter_weights[i] = PNG_WEIGHT_FACTOR;
}
}
for (i = 0; i < num_weights; i++)
{
if (filter_weights[i] < 0.0)
{
png_ptr->inv_filter_weights[i] =
png_ptr->filter_weights[i] = PNG_WEIGHT_FACTOR;
}
else
{
png_ptr->inv_filter_weights[i] =
(png_uint_16)((double)PNG_WEIGHT_FACTOR*filter_weights[i]+0.5);
png_ptr->filter_weights[i] =
(png_uint_16)((double)PNG_WEIGHT_FACTOR/filter_weights[i]+0.5);
}
}
}
/* If, in the future, there are other filter methods, this would
* need to be based on png_ptr->filter.
*/
if (png_ptr->filter_costs == NULL)
{
png_ptr->filter_costs = (png_uint_16p)png_malloc(png_ptr,
sizeof(png_uint_16) * PNG_FILTER_VALUE_LAST);
png_ptr->inv_filter_costs = (png_uint_16p)png_malloc(png_ptr,
sizeof(png_uint_16) * PNG_FILTER_VALUE_LAST);
for (i = 0; i < PNG_FILTER_VALUE_LAST; i++)
{
png_ptr->inv_filter_costs[i] =
png_ptr->filter_costs[i] = PNG_COST_FACTOR;
}
}
/* 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 == NULL || filter_costs[i] < 0.0)
{
png_ptr->inv_filter_costs[i] =
png_ptr->filter_costs[i] = PNG_COST_FACTOR;
}
else if (filter_costs[i] >= 1.0)
{
png_ptr->inv_filter_costs[i] =
(png_uint_16)((double)PNG_COST_FACTOR / filter_costs[i] + 0.5);
png_ptr->filter_costs[i] =
(png_uint_16)((double)PNG_COST_FACTOR * filter_costs[i] + 0.5);
}
}
}
#endif /* PNG_WRITE_WEIGHTED_FILTER_SUPPORTED */
void
png_set_compression_level(png_structp png_ptr, int level)
{
png_debug(1, "in png_set_compression_level\n");
png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_LEVEL;
png_ptr->zlib_level = level;
}
@@ -635,6 +813,7 @@ png_set_compression_level(png_structp png_ptr, int level)
void
png_set_compression_mem_level(png_structp png_ptr, int mem_level)
{
png_debug(1, "in png_set_compression_mem_level\n");
png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_MEM_LEVEL;
png_ptr->zlib_mem_level = mem_level;
}
@@ -642,6 +821,7 @@ png_set_compression_mem_level(png_structp png_ptr, int mem_level)
void
png_set_compression_strategy(png_structp png_ptr, int strategy)
{
png_debug(1, "in png_set_compression_strategy\n");
png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_STRATEGY;
png_ptr->zlib_strategy = strategy;
}
@@ -658,6 +838,7 @@ png_set_compression_window_bits(png_structp png_ptr, int window_bits)
void
png_set_compression_method(png_structp png_ptr, int method)
{
png_debug(1, "in png_set_compression_method\n");
if (method != 8)
png_warning(png_ptr, "Only compression method 8 is supported by PNG");
png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_METHOD;