blob: 5aec80ce8333ac1678fa7355e7bae9c81e76e1c6 [file] [log] [blame]
Guy Schalnat0d580581995-07-20 02:43:20 -05001
Andreas Dilger47a0c421997-05-16 02:46:07 -05002/* pngwutil.c - utilities to write a PNG file
Guy Schalnat0d580581995-07-20 02:43:20 -05003
Andreas Dilger47a0c421997-05-16 02:46:07 -05004 libpng 1.0 beta 6 - version 0.96
Guy Schalnat0d580581995-07-20 02:43:20 -05005 For conditions of distribution and use, see copyright notice in png.h
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06006 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
Andreas Dilger47a0c421997-05-16 02:46:07 -05007 Copyright (c) 1996, 1997 Andreas Dilger
8 May 12, 1997
Guy Schalnat0d580581995-07-20 02:43:20 -05009 */
Andreas Dilger47a0c421997-05-16 02:46:07 -050010
Guy Schalnat0d580581995-07-20 02:43:20 -050011#define PNG_INTERNAL
12#include "png.h"
13
Andreas Dilger47a0c421997-05-16 02:46:07 -050014/* Place a 32-bit number into a buffer in PNG byte order. We work
15 * with unsigned numbers for convenience, although one supported
16 * ancillary chunk uses signed (two's complement) numbers.
17 */
Guy Schalnat0d580581995-07-20 02:43:20 -050018void
Guy Schalnat6d764711995-12-19 03:22:19 -060019png_save_uint_32(png_bytep buf, png_uint_32 i)
Guy Schalnat0d580581995-07-20 02:43:20 -050020{
21 buf[0] = (png_byte)((i >> 24) & 0xff);
22 buf[1] = (png_byte)((i >> 16) & 0xff);
23 buf[2] = (png_byte)((i >> 8) & 0xff);
24 buf[3] = (png_byte)(i & 0xff);
25}
26
Andreas Dilger47a0c421997-05-16 02:46:07 -050027#if defined(PNG_WRITE_pCAL_SUPPORTED)
28/* The png_save_int_32 function assumes integers are stored in two's
29 complement format. If this isn't the case, then this routine needs to
30 be modified to write data in two's complement format. */
31void
32png_save_int_32(png_bytep buf, png_int_32 i)
33{
34 buf[0] = (png_byte)((i >> 24) & 0xff);
35 buf[1] = (png_byte)((i >> 16) & 0xff);
36 buf[2] = (png_byte)((i >> 8) & 0xff);
37 buf[3] = (png_byte)(i & 0xff);
38}
39#endif
40
41/* Place a 16-bit number into a buffer in PNG byte order. */
Guy Schalnat0d580581995-07-20 02:43:20 -050042void
Guy Schalnat6d764711995-12-19 03:22:19 -060043png_save_uint_16(png_bytep buf, png_uint_16 i)
Guy Schalnat0d580581995-07-20 02:43:20 -050044{
45 buf[0] = (png_byte)((i >> 8) & 0xff);
46 buf[1] = (png_byte)(i & 0xff);
47}
48
Andreas Dilger47a0c421997-05-16 02:46:07 -050049/* Write a PNG chunk all at once. The type is an array of ASCII characters
Guy Schalnat0d580581995-07-20 02:43:20 -050050 representing the chunk name. The array must be at least 4 bytes in
51 length, and does not need to be null terminated. To be safe, pass the
52 pre-defined chunk names here, and if you need a new one, define it
53 where the others are defined. The length is the length of the data.
54 All the data must be present. If that is not possible, use the
55 png_write_chunk_start(), png_write_chunk_data(), and png_write_chunk_end()
56 functions instead. */
57void
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060058png_write_chunk(png_structp png_ptr, png_bytep chunk_name,
Andreas Dilger47a0c421997-05-16 02:46:07 -050059 png_bytep data, png_size_t length)
Guy Schalnat0d580581995-07-20 02:43:20 -050060{
Andreas Dilger47a0c421997-05-16 02:46:07 -050061 png_write_chunk_start(png_ptr, chunk_name, (png_uint_32)length);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060062 png_write_chunk_data(png_ptr, data, length);
63 png_write_chunk_end(png_ptr);
Guy Schalnat0d580581995-07-20 02:43:20 -050064}
65
Andreas Dilger47a0c421997-05-16 02:46:07 -050066/* Write the start of a PNG chunk. The type is the chunk type.
Guy Schalnat0d580581995-07-20 02:43:20 -050067 The total_length is the sum of the lengths of all the data you will be
68 passing in png_write_chunk_data() */
69void
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060070png_write_chunk_start(png_structp png_ptr, png_bytep chunk_name,
71 png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -050072{
Andreas Dilger47a0c421997-05-16 02:46:07 -050073 png_byte buf[4];
74 png_debug2(0, "Writing %s chunk (%d bytes)\n", chunk_name, length);
75
Guy Schalnat0d580581995-07-20 02:43:20 -050076 /* write the length */
Andreas Dilger47a0c421997-05-16 02:46:07 -050077 png_save_uint_32(buf, length);
78 png_write_data(png_ptr, buf, (png_size_t)4);
79
Guy Schalnat0d580581995-07-20 02:43:20 -050080 /* write the chunk name */
Andreas Dilger47a0c421997-05-16 02:46:07 -050081 png_write_data(png_ptr, chunk_name, (png_size_t)4);
Guy Schalnat0d580581995-07-20 02:43:20 -050082 /* reset the crc and run it over the chunk name */
83 png_reset_crc(png_ptr);
Andreas Dilger47a0c421997-05-16 02:46:07 -050084 png_calculate_crc(png_ptr, chunk_name, (png_size_t)4);
Guy Schalnat0d580581995-07-20 02:43:20 -050085}
86
Andreas Dilger47a0c421997-05-16 02:46:07 -050087/* Write the data of a PNG chunk started with png_write_chunk_start().
Guy Schalnat0d580581995-07-20 02:43:20 -050088 Note that multiple calls to this function are allowed, and that the
89 sum of the lengths from these calls *must* add up to the total_length
Andreas Dilger47a0c421997-05-16 02:46:07 -050090 given to png_write_chunk_start(). */
Guy Schalnat0d580581995-07-20 02:43:20 -050091void
Andreas Dilger47a0c421997-05-16 02:46:07 -050092png_write_chunk_data(png_structp png_ptr, png_bytep data, png_size_t length)
Guy Schalnat0d580581995-07-20 02:43:20 -050093{
Andreas Dilger47a0c421997-05-16 02:46:07 -050094 /* write the data, and run the CRC over it */
95 if (data != NULL && length > 0)
Guy Schalnat0d580581995-07-20 02:43:20 -050096 {
97 png_calculate_crc(png_ptr, data, length);
Guy Schalnat6d764711995-12-19 03:22:19 -060098 png_write_data(png_ptr, data, length);
Guy Schalnat0d580581995-07-20 02:43:20 -050099 }
100}
101
Andreas Dilger47a0c421997-05-16 02:46:07 -0500102/* Finish a chunk started with png_write_chunk_start(). */
Guy Schalnat0d580581995-07-20 02:43:20 -0500103void
Guy Schalnat6d764711995-12-19 03:22:19 -0600104png_write_chunk_end(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -0500105{
Andreas Dilger47a0c421997-05-16 02:46:07 -0500106 png_byte buf[4];
107
Guy Schalnat0d580581995-07-20 02:43:20 -0500108 /* write the crc */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600109#ifdef PNG_USE_OWN_CRC
Andreas Dilger47a0c421997-05-16 02:46:07 -0500110 png_save_uint_32(buf, ~png_ptr->crc);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600111#else
Andreas Dilger47a0c421997-05-16 02:46:07 -0500112 png_save_uint_32(buf, png_ptr->crc);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600113#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -0500114
115 png_write_data(png_ptr, buf, (png_size_t)4);
Guy Schalnat0d580581995-07-20 02:43:20 -0500116}
117
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600118/* Simple function to write the signature. If we have already written
119 * the magic bytes of the signature, or more likely, the PNG stream is
120 * being embedded into another stream and doesn't need its own signature,
121 * we should call png_set_sig_bytes() to tell libpng how many of the
122 * bytes have already been written. */
Guy Schalnat0d580581995-07-20 02:43:20 -0500123void
Guy Schalnat6d764711995-12-19 03:22:19 -0600124png_write_sig(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -0500125{
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600126 /* write the rest of the 8 byte signature */
127 png_write_data(png_ptr, &png_sig[png_ptr->sig_bytes],
Andreas Dilger47a0c421997-05-16 02:46:07 -0500128 (png_size_t)8 - png_ptr->sig_bytes);
Guy Schalnat0d580581995-07-20 02:43:20 -0500129}
130
131/* Write the IHDR chunk, and update the png_struct with the necessary
132 information. Note that the rest of this code depends upon this
133 information being correct. */
134void
Guy Schalnat6d764711995-12-19 03:22:19 -0600135png_write_IHDR(png_structp png_ptr, png_uint_32 width, png_uint_32 height,
Guy Schalnat0d580581995-07-20 02:43:20 -0500136 int bit_depth, int color_type, int compression_type, int filter_type,
137 int interlace_type)
138{
139 png_byte buf[13]; /* buffer to store the IHDR info */
140
Andreas Dilger47a0c421997-05-16 02:46:07 -0500141 png_debug(1, "in png_write_IHDR\n");
Guy Schalnate5a37791996-06-05 15:50:50 -0500142 /* Check that we have valid input data from the application info */
143 switch (color_type)
144 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500145 case PNG_COLOR_TYPE_GRAY:
Guy Schalnate5a37791996-06-05 15:50:50 -0500146 switch (bit_depth)
147 {
148 case 1:
149 case 2:
150 case 4:
151 case 8:
152 case 16: png_ptr->channels = 1; break;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500153 default: png_error(png_ptr,"Invalid bit depth for grayscale image");
Guy Schalnate5a37791996-06-05 15:50:50 -0500154 }
155 break;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500156 case PNG_COLOR_TYPE_RGB:
Guy Schalnate5a37791996-06-05 15:50:50 -0500157 if (bit_depth != 8 && bit_depth != 16)
158 png_error(png_ptr, "Invalid bit depth for RGB image");
159 png_ptr->channels = 3;
160 break;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500161 case PNG_COLOR_TYPE_PALETTE:
Guy Schalnate5a37791996-06-05 15:50:50 -0500162 switch (bit_depth)
163 {
164 case 1:
165 case 2:
166 case 4:
167 case 8: png_ptr->channels = 1; break;
168 default: png_error(png_ptr, "Invalid bit depth for paletted image");
169 }
170 break;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500171 case PNG_COLOR_TYPE_GRAY_ALPHA:
Guy Schalnate5a37791996-06-05 15:50:50 -0500172 if (bit_depth != 8 && bit_depth != 16)
173 png_error(png_ptr, "Invalid bit depth for grayscale+alpha image");
174 png_ptr->channels = 2;
175 break;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500176 case PNG_COLOR_TYPE_RGB_ALPHA:
Guy Schalnate5a37791996-06-05 15:50:50 -0500177 if (bit_depth != 8 && bit_depth != 16)
178 png_error(png_ptr, "Invalid bit depth for RGBA image");
179 png_ptr->channels = 4;
180 break;
181 default:
182 png_error(png_ptr, "Invalid image color type specified");
183 }
184
Andreas Dilger47a0c421997-05-16 02:46:07 -0500185 if (compression_type != PNG_COMPRESSION_TYPE_BASE)
Guy Schalnate5a37791996-06-05 15:50:50 -0500186 {
187 png_warning(png_ptr, "Invalid compression type specified");
Andreas Dilger47a0c421997-05-16 02:46:07 -0500188 compression_type = PNG_COMPRESSION_TYPE_BASE;
Guy Schalnate5a37791996-06-05 15:50:50 -0500189 }
190
Andreas Dilger47a0c421997-05-16 02:46:07 -0500191 if (filter_type != PNG_FILTER_TYPE_BASE)
Guy Schalnate5a37791996-06-05 15:50:50 -0500192 {
193 png_warning(png_ptr, "Invalid filter type specified");
Andreas Dilger47a0c421997-05-16 02:46:07 -0500194 filter_type = PNG_FILTER_TYPE_BASE;
Guy Schalnate5a37791996-06-05 15:50:50 -0500195 }
196
Andreas Dilger47a0c421997-05-16 02:46:07 -0500197 if (interlace_type != PNG_INTERLACE_NONE &&
198 interlace_type != PNG_INTERLACE_ADAM7)
Guy Schalnate5a37791996-06-05 15:50:50 -0500199 {
200 png_warning(png_ptr, "Invalid interlace type specified");
Andreas Dilger47a0c421997-05-16 02:46:07 -0500201 interlace_type = PNG_INTERLACE_ADAM7;
Guy Schalnate5a37791996-06-05 15:50:50 -0500202 }
203
204 /* save off the relevent information */
205 png_ptr->bit_depth = (png_byte)bit_depth;
206 png_ptr->color_type = (png_byte)color_type;
207 png_ptr->interlaced = (png_byte)interlace_type;
208 png_ptr->width = width;
209 png_ptr->height = height;
210
211 png_ptr->pixel_depth = (png_byte)(bit_depth * png_ptr->channels);
Andreas Dilger47a0c421997-05-16 02:46:07 -0500212 png_ptr->rowbytes = ((width * (png_size_t)png_ptr->pixel_depth + 7) >> 3);
Guy Schalnate5a37791996-06-05 15:50:50 -0500213 /* set the usr info, so any transformations can modify it */
214 png_ptr->usr_width = png_ptr->width;
215 png_ptr->usr_bit_depth = png_ptr->bit_depth;
216 png_ptr->usr_channels = png_ptr->channels;
217
Guy Schalnat0d580581995-07-20 02:43:20 -0500218 /* pack the header information into the buffer */
219 png_save_uint_32(buf, width);
220 png_save_uint_32(buf + 4, height);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600221 buf[8] = (png_byte)bit_depth;
222 buf[9] = (png_byte)color_type;
223 buf[10] = (png_byte)compression_type;
224 buf[11] = (png_byte)filter_type;
225 buf[12] = (png_byte)interlace_type;
Guy Schalnat0d580581995-07-20 02:43:20 -0500226
227 /* write the chunk */
Andreas Dilger47a0c421997-05-16 02:46:07 -0500228 png_write_chunk(png_ptr, png_IHDR, buf, (png_size_t)13);
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500229
Andreas Dilger47a0c421997-05-16 02:46:07 -0500230 /* initialize zlib with PNG info */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600231 png_ptr->zstream.zalloc = png_zalloc;
232 png_ptr->zstream.zfree = png_zfree;
233 png_ptr->zstream.opaque = (voidpf)png_ptr;
Guy Schalnate5a37791996-06-05 15:50:50 -0500234 if (!(png_ptr->do_filter))
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500235 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500236 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE ||
237 png_ptr->bit_depth < 8)
Guy Schalnate5a37791996-06-05 15:50:50 -0500238 png_ptr->do_filter = PNG_FILTER_NONE;
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500239 else
Guy Schalnate5a37791996-06-05 15:50:50 -0500240 png_ptr->do_filter = PNG_ALL_FILTERS;
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500241 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500242 if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_STRATEGY))
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500243 {
Guy Schalnate5a37791996-06-05 15:50:50 -0500244 if (png_ptr->do_filter != PNG_FILTER_NONE)
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500245 png_ptr->zlib_strategy = Z_FILTERED;
246 else
247 png_ptr->zlib_strategy = Z_DEFAULT_STRATEGY;
248 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500249 if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_LEVEL))
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500250 png_ptr->zlib_level = Z_DEFAULT_COMPRESSION;
Guy Schalnate5a37791996-06-05 15:50:50 -0500251 if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_MEM_LEVEL))
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500252 png_ptr->zlib_mem_level = 8;
Guy Schalnate5a37791996-06-05 15:50:50 -0500253 if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_WINDOW_BITS))
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500254 png_ptr->zlib_window_bits = 15;
Guy Schalnate5a37791996-06-05 15:50:50 -0500255 if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_METHOD))
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500256 png_ptr->zlib_method = 8;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600257 deflateInit2(&png_ptr->zstream, png_ptr->zlib_level,
Andreas Dilger47a0c421997-05-16 02:46:07 -0500258 png_ptr->zlib_method, png_ptr->zlib_window_bits,
259 png_ptr->zlib_mem_level, png_ptr->zlib_strategy);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600260 png_ptr->zstream.next_out = png_ptr->zbuf;
261 png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500262
Guy Schalnate5a37791996-06-05 15:50:50 -0500263 png_ptr->mode = PNG_HAVE_IHDR;
Guy Schalnat0d580581995-07-20 02:43:20 -0500264}
265
266/* write the palette. We are careful not to trust png_color to be in the
267 correct order for PNG, so people can redefine it to any convient
268 structure. */
269void
Andreas Dilger47a0c421997-05-16 02:46:07 -0500270png_write_PLTE(png_structp png_ptr, png_colorp palette, png_uint_32 num_pal)
Guy Schalnat0d580581995-07-20 02:43:20 -0500271{
Andreas Dilger47a0c421997-05-16 02:46:07 -0500272 png_uint_32 i;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600273 png_colorp pal_ptr;
Guy Schalnat0d580581995-07-20 02:43:20 -0500274 png_byte buf[3];
275
Andreas Dilger47a0c421997-05-16 02:46:07 -0500276 png_debug(1, "in png_write_PLTE\n");
277 if (num_pal == 0 || num_pal > 256)
Guy Schalnate5a37791996-06-05 15:50:50 -0500278 {
279 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
280 {
281 png_error(png_ptr, "Invalid number of colors in palette");
282 }
283 else
284 {
285 png_warning(png_ptr, "Invalid number of colors in palette");
286 return;
287 }
288 }
289
Andreas Dilger47a0c421997-05-16 02:46:07 -0500290 png_ptr->num_palette = (png_uint_16)num_pal;
291 png_debug1(3, "num_palette = %d\n", png_ptr->num_palette);
Guy Schalnate5a37791996-06-05 15:50:50 -0500292
Andreas Dilger47a0c421997-05-16 02:46:07 -0500293 png_write_chunk_start(png_ptr, png_PLTE, num_pal * 3);
294 for (i = 0, pal_ptr = palette; i < num_pal; i++, pal_ptr++)
Guy Schalnat0d580581995-07-20 02:43:20 -0500295 {
296 buf[0] = pal_ptr->red;
297 buf[1] = pal_ptr->green;
298 buf[2] = pal_ptr->blue;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500299 png_write_chunk_data(png_ptr, buf, (png_size_t)3);
Guy Schalnat0d580581995-07-20 02:43:20 -0500300 }
301 png_write_chunk_end(png_ptr);
Guy Schalnate5a37791996-06-05 15:50:50 -0500302 png_ptr->mode |= PNG_HAVE_PLTE;
Guy Schalnat0d580581995-07-20 02:43:20 -0500303}
304
305/* write an IDAT chunk */
306void
Andreas Dilger47a0c421997-05-16 02:46:07 -0500307png_write_IDAT(png_structp png_ptr, png_bytep data, png_size_t length)
Guy Schalnat0d580581995-07-20 02:43:20 -0500308{
Andreas Dilger47a0c421997-05-16 02:46:07 -0500309 png_debug(1, "in png_write_IDAT\n");
Guy Schalnat0d580581995-07-20 02:43:20 -0500310 png_write_chunk(png_ptr, png_IDAT, data, length);
Guy Schalnate5a37791996-06-05 15:50:50 -0500311 png_ptr->mode |= PNG_HAVE_IDAT;
Guy Schalnat0d580581995-07-20 02:43:20 -0500312}
313
314/* write an IEND chunk */
315void
Guy Schalnat6d764711995-12-19 03:22:19 -0600316png_write_IEND(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -0500317{
Andreas Dilger47a0c421997-05-16 02:46:07 -0500318 png_debug(1, "in png_write_IEND\n");
319 png_write_chunk(png_ptr, png_IEND, NULL, (png_size_t)0);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600320 png_ptr->mode |= PNG_HAVE_IEND;
Guy Schalnat0d580581995-07-20 02:43:20 -0500321}
322
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500323#if defined(PNG_WRITE_gAMA_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500324/* write a gAMA chunk */
325void
Andreas Dilger47a0c421997-05-16 02:46:07 -0500326png_write_gAMA(png_structp png_ptr, double file_gamma)
Guy Schalnat0d580581995-07-20 02:43:20 -0500327{
328 png_uint_32 igamma;
329 png_byte buf[4];
330
Andreas Dilger47a0c421997-05-16 02:46:07 -0500331 png_debug(1, "in png_write_gAMA\n");
332 /* file_gamma is saved in 1/100,000ths */
333 igamma = (png_uint_32)(file_gamma * 100000.0 + 0.5);
Guy Schalnat0d580581995-07-20 02:43:20 -0500334 png_save_uint_32(buf, igamma);
Andreas Dilger47a0c421997-05-16 02:46:07 -0500335 png_write_chunk(png_ptr, png_gAMA, buf, (png_size_t)4);
Guy Schalnat0d580581995-07-20 02:43:20 -0500336}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500337#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500338
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500339#if defined(PNG_WRITE_sBIT_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500340/* write the sBIT chunk */
341void
Guy Schalnat6d764711995-12-19 03:22:19 -0600342png_write_sBIT(png_structp png_ptr, png_color_8p sbit, int color_type)
Guy Schalnat0d580581995-07-20 02:43:20 -0500343{
344 png_byte buf[4];
Andreas Dilger47a0c421997-05-16 02:46:07 -0500345 png_size_t size;
Guy Schalnat0d580581995-07-20 02:43:20 -0500346
Andreas Dilger47a0c421997-05-16 02:46:07 -0500347 png_debug(1, "in png_write_sBIT\n");
Guy Schalnat6d764711995-12-19 03:22:19 -0600348 /* make sure we don't depend upon the order of PNG_COLOR_8 */
Guy Schalnat0d580581995-07-20 02:43:20 -0500349 if (color_type & PNG_COLOR_MASK_COLOR)
350 {
Guy Schalnate5a37791996-06-05 15:50:50 -0500351 int maxbits;
352
353 maxbits = color_type==PNG_COLOR_TYPE_PALETTE ? 8:png_ptr->usr_bit_depth;
354 if (sbit->red == 0 || sbit->red > maxbits ||
355 sbit->green == 0 || sbit->green > maxbits ||
356 sbit->blue == 0 || sbit->blue > maxbits)
357 {
358 png_warning(png_ptr, "Invalid sBIT depth specified");
359 return;
360 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500361 buf[0] = sbit->red;
362 buf[1] = sbit->green;
363 buf[2] = sbit->blue;
364 size = 3;
365 }
366 else
367 {
Guy Schalnate5a37791996-06-05 15:50:50 -0500368 if (sbit->gray == 0 || sbit->gray > png_ptr->usr_bit_depth)
369 {
370 png_warning(png_ptr, "Invalid sBIT depth specified");
371 return;
372 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500373 buf[0] = sbit->gray;
374 size = 1;
375 }
376
377 if (color_type & PNG_COLOR_MASK_ALPHA)
378 {
Guy Schalnate5a37791996-06-05 15:50:50 -0500379 if (sbit->alpha == 0 || sbit->alpha > png_ptr->usr_bit_depth)
380 {
381 png_warning(png_ptr, "Invalid sBIT depth specified");
382 return;
383 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500384 buf[size++] = sbit->alpha;
385 }
386
Andreas Dilger47a0c421997-05-16 02:46:07 -0500387 png_write_chunk(png_ptr, png_sBIT, buf, size);
Guy Schalnat0d580581995-07-20 02:43:20 -0500388}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500389#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500390
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500391#if defined(PNG_WRITE_cHRM_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500392/* write the cHRM chunk */
393void
Andreas Dilger47a0c421997-05-16 02:46:07 -0500394png_write_cHRM(png_structp png_ptr, double white_x, double white_y,
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600395 double red_x, double red_y, double green_x, double green_y,
396 double blue_x, double blue_y)
Guy Schalnat0d580581995-07-20 02:43:20 -0500397{
398 png_uint_32 itemp;
399 png_byte buf[32];
400
Andreas Dilger47a0c421997-05-16 02:46:07 -0500401 png_debug(1, "in png_write_cHRM\n");
Guy Schalnat0d580581995-07-20 02:43:20 -0500402 /* each value is saved int 1/100,000ths */
Guy Schalnate5a37791996-06-05 15:50:50 -0500403 if (white_x < 0 || white_x > 0.8 || white_y < 0 || white_y > 0.8 ||
404 white_x + white_y > 1.0)
405 {
406 png_warning(png_ptr, "Invalid cHRM white point specified");
407 return;
408 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500409 itemp = (png_uint_32)(white_x * 100000.0 + 0.5);
410 png_save_uint_32(buf, itemp);
411 itemp = (png_uint_32)(white_y * 100000.0 + 0.5);
412 png_save_uint_32(buf + 4, itemp);
Guy Schalnate5a37791996-06-05 15:50:50 -0500413
414 if (red_x < 0 || red_x > 0.8 || red_y < 0 || red_y > 0.8 ||
415 red_x + red_y > 1.0)
416 {
417 png_warning(png_ptr, "Invalid cHRM red point specified");
418 return;
419 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500420 itemp = (png_uint_32)(red_x * 100000.0 + 0.5);
421 png_save_uint_32(buf + 8, itemp);
422 itemp = (png_uint_32)(red_y * 100000.0 + 0.5);
423 png_save_uint_32(buf + 12, itemp);
Guy Schalnate5a37791996-06-05 15:50:50 -0500424
425 if (green_x < 0 || green_x > 0.8 || green_y < 0 || green_y > 0.8 ||
426 green_x + green_y > 1.0)
427 {
428 png_warning(png_ptr, "Invalid cHRM green point specified");
429 return;
430 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500431 itemp = (png_uint_32)(green_x * 100000.0 + 0.5);
432 png_save_uint_32(buf + 16, itemp);
433 itemp = (png_uint_32)(green_y * 100000.0 + 0.5);
434 png_save_uint_32(buf + 20, itemp);
Guy Schalnate5a37791996-06-05 15:50:50 -0500435
436 if (blue_x < 0 || blue_x > 0.8 || blue_y < 0 || blue_y > 0.8 ||
437 blue_x + blue_y > 1.0)
438 {
439 png_warning(png_ptr, "Invalid cHRM blue point specified");
440 return;
441 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500442 itemp = (png_uint_32)(blue_x * 100000.0 + 0.5);
443 png_save_uint_32(buf + 24, itemp);
444 itemp = (png_uint_32)(blue_y * 100000.0 + 0.5);
445 png_save_uint_32(buf + 28, itemp);
Guy Schalnate5a37791996-06-05 15:50:50 -0500446
Andreas Dilger47a0c421997-05-16 02:46:07 -0500447 png_write_chunk(png_ptr, png_cHRM, buf, (png_size_t)32);
Guy Schalnat0d580581995-07-20 02:43:20 -0500448}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500449#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500450
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500451#if defined(PNG_WRITE_tRNS_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500452/* write the tRNS chunk */
453void
Guy Schalnat6d764711995-12-19 03:22:19 -0600454png_write_tRNS(png_structp png_ptr, png_bytep trans, png_color_16p tran,
Guy Schalnat0d580581995-07-20 02:43:20 -0500455 int num_trans, int color_type)
456{
457 png_byte buf[6];
458
Andreas Dilger47a0c421997-05-16 02:46:07 -0500459 png_debug(1, "in png_write_tRNS\n");
Guy Schalnat0d580581995-07-20 02:43:20 -0500460 if (color_type == PNG_COLOR_TYPE_PALETTE)
461 {
Guy Schalnate5a37791996-06-05 15:50:50 -0500462 if (num_trans <= 0 || num_trans > png_ptr->num_palette)
463 {
464 png_warning(png_ptr,"Invalid number of transparent colors specified");
465 return;
466 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500467 /* write the chunk out as it is */
Andreas Dilger47a0c421997-05-16 02:46:07 -0500468 png_write_chunk(png_ptr, png_tRNS, trans, (png_size_t)num_trans);
Guy Schalnat0d580581995-07-20 02:43:20 -0500469 }
470 else if (color_type == PNG_COLOR_TYPE_GRAY)
471 {
472 /* one 16 bit value */
473 png_save_uint_16(buf, tran->gray);
Andreas Dilger47a0c421997-05-16 02:46:07 -0500474 png_write_chunk(png_ptr, png_tRNS, buf, (png_size_t)2);
Guy Schalnat0d580581995-07-20 02:43:20 -0500475 }
476 else if (color_type == PNG_COLOR_TYPE_RGB)
477 {
478 /* three 16 bit values */
479 png_save_uint_16(buf, tran->red);
480 png_save_uint_16(buf + 2, tran->green);
481 png_save_uint_16(buf + 4, tran->blue);
Andreas Dilger47a0c421997-05-16 02:46:07 -0500482 png_write_chunk(png_ptr, png_tRNS, buf, (png_size_t)6);
Guy Schalnat0d580581995-07-20 02:43:20 -0500483 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500484 else
485 {
486 png_warning(png_ptr, "Can't write tRNS with and alpha channel");
487 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500488}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500489#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500490
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500491#if defined(PNG_WRITE_bKGD_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500492/* write the background chunk */
493void
Guy Schalnat6d764711995-12-19 03:22:19 -0600494png_write_bKGD(png_structp png_ptr, png_color_16p back, int color_type)
Guy Schalnat0d580581995-07-20 02:43:20 -0500495{
496 png_byte buf[6];
497
Andreas Dilger47a0c421997-05-16 02:46:07 -0500498 png_debug(1, "in png_write_bKGD\n");
Guy Schalnat0d580581995-07-20 02:43:20 -0500499 if (color_type == PNG_COLOR_TYPE_PALETTE)
500 {
Guy Schalnate5a37791996-06-05 15:50:50 -0500501 if (back->index > png_ptr->num_palette)
502 {
503 png_warning(png_ptr, "Invalid background palette index");
504 return;
505 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500506 buf[0] = back->index;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500507 png_write_chunk(png_ptr, png_bKGD, buf, (png_size_t)1);
Guy Schalnat0d580581995-07-20 02:43:20 -0500508 }
509 else if (color_type & PNG_COLOR_MASK_COLOR)
510 {
511 png_save_uint_16(buf, back->red);
512 png_save_uint_16(buf + 2, back->green);
513 png_save_uint_16(buf + 4, back->blue);
Andreas Dilger47a0c421997-05-16 02:46:07 -0500514 png_write_chunk(png_ptr, png_bKGD, buf, (png_size_t)6);
Guy Schalnat0d580581995-07-20 02:43:20 -0500515 }
516 else
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600517 {
Guy Schalnat0d580581995-07-20 02:43:20 -0500518 png_save_uint_16(buf, back->gray);
Andreas Dilger47a0c421997-05-16 02:46:07 -0500519 png_write_chunk(png_ptr, png_bKGD, buf, (png_size_t)2);
Guy Schalnat0d580581995-07-20 02:43:20 -0500520 }
521}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500522#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500523
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500524#if defined(PNG_WRITE_hIST_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500525/* write the histogram */
526void
Andreas Dilger47a0c421997-05-16 02:46:07 -0500527png_write_hIST(png_structp png_ptr, png_uint_16p hist, png_uint_32 num_hist)
Guy Schalnat0d580581995-07-20 02:43:20 -0500528{
Andreas Dilger47a0c421997-05-16 02:46:07 -0500529 png_uint_32 i;
Guy Schalnat0d580581995-07-20 02:43:20 -0500530 png_byte buf[3];
531
Andreas Dilger47a0c421997-05-16 02:46:07 -0500532 png_debug(1, "in png_write_hIST\n");
533 if (num_hist > png_ptr->num_palette)
Guy Schalnate5a37791996-06-05 15:50:50 -0500534 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500535 png_debug2(3, "num_hist = %d, num_palette = %d\n", num_hist,
536 png_ptr->num_palette);
Guy Schalnate5a37791996-06-05 15:50:50 -0500537 png_warning(png_ptr, "Invalid number of histogram entries specified");
538 return;
539 }
540
Andreas Dilger47a0c421997-05-16 02:46:07 -0500541 png_write_chunk_start(png_ptr, png_hIST, num_hist * 2);
542 for (i = 0; i < num_hist; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -0500543 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600544 png_save_uint_16(buf, hist[i]);
Andreas Dilger47a0c421997-05-16 02:46:07 -0500545 png_write_chunk_data(png_ptr, buf, (png_size_t)2);
Guy Schalnat0d580581995-07-20 02:43:20 -0500546 }
547 png_write_chunk_end(png_ptr);
548}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500549#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500550
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600551#if defined(PNG_WRITE_tEXt_SUPPORTED) || defined(PNG_WRITE_zTXt_SUPPORTED)
552/* Check that the tEXt or zTXt keyword is valid per PNG 1.0 specification,
553 * and if invalid, correct the keyword rather than discarding the entire
554 * chunk. The PNG 1.0 specification requires keywords 1-79 characters in
555 * length, forbids leading or trailing whitespace, multiple internal spaces,
556 * and the non-break space (0x80) from ISO 8859-1. Returns keyword length.
Andreas Dilger47a0c421997-05-16 02:46:07 -0500557 *
558 * The new_key is allocated to hold the corrected keyword and must be freed
559 * by the calling routine. This avoids problems with trying to write to
560 * static keywords without having to have duplicate copies of the strings.
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600561 */
Andreas Dilger47a0c421997-05-16 02:46:07 -0500562png_size_t
563png_check_keyword(png_structp png_ptr, png_charp key, png_bytepp new_key)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600564{
Andreas Dilger47a0c421997-05-16 02:46:07 -0500565 png_size_t key_len;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600566 png_charp kp;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500567 png_bytep dp;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600568 int kflag;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600569
Andreas Dilger47a0c421997-05-16 02:46:07 -0500570 png_debug(1, "in png_check_keyword\n");
571 *new_key = NULL;
572
573 if (key == NULL || (key_len = png_strlen(key)) == 0)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600574 {
575 char msg[40];
576
577 sprintf(msg, "Zero length %s keyword", png_ptr->chunk_name);
578 png_warning(png_ptr, msg);
579 return 0;
580 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600581
Andreas Dilger47a0c421997-05-16 02:46:07 -0500582 png_debug1(2, "Keyword to be checked is '%s'\n", key);
583
584 *new_key = (png_bytep)png_malloc(png_ptr, key_len + 1);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600585
586 /* Replace non-printing characters with a blank and print a warning */
Andreas Dilger47a0c421997-05-16 02:46:07 -0500587 for (kp = key, dp = *new_key; *kp != '\0'; kp++, dp++)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600588 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500589 if (*kp < 0x20 || ((png_byte)*kp > 0x7E && (png_byte)*kp < 0xA1))
590 {
591 char msg[40];
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600592
Andreas Dilger47a0c421997-05-16 02:46:07 -0500593 sprintf(msg, "Invalid %s keyword character 0x%02X",
594 png_ptr->chunk_name, *kp);
595 png_warning(png_ptr, msg);
596 *dp = ' ';
597 }
598 else
599 {
600 *dp = *kp;
601 }
602 }
603 *dp = '\0';
604
605 /* Remove any trailing white space. */
606 kp = *new_key + key_len - 1;
607 if (*kp == ' ')
608 {
609 char msg[50];
610 sprintf(msg, "Trailing spaces removed from %s keyword",
611 png_ptr->chunk_name);
612
613 png_warning(png_ptr, msg);
614
615 while (*kp == ' ')
616 {
617 *(kp--) = '\0';
618 key_len--;
619 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600620 }
621
622 /* Remove any leading white space. */
Andreas Dilger47a0c421997-05-16 02:46:07 -0500623 kp = *new_key;
624 if (*kp == ' ')
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600625 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500626 char msg[50];
627 sprintf(msg, "Leading spaces removed from %s keyword",
628 png_ptr->chunk_name);
629
630 png_warning(png_ptr, msg);
631
632 while (*kp == ' ')
633 {
634 kp++;
635 key_len--;
636 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600637 }
638
Andreas Dilger47a0c421997-05-16 02:46:07 -0500639 png_debug1(2, "Checking for multiple internal spaces in '%s'\n", kp);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600640
Andreas Dilger47a0c421997-05-16 02:46:07 -0500641 /* Remove multiple internal spaces. */
642 for (kflag = 0, dp = *new_key; *kp != '\0'; kp++)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600643 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500644 if (*kp == ' ' && kflag == 0)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600645 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500646 *(dp++) = *kp;
647 kflag = 1;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600648 }
Andreas Dilger47a0c421997-05-16 02:46:07 -0500649 else if (*kp == ' ')
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600650 {
651 key_len--;
652 }
653 else
654 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500655 *(dp++) = *kp;
656 kflag = 0;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600657 }
658 }
Andreas Dilger47a0c421997-05-16 02:46:07 -0500659 *dp = '\0';
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600660
661 if (key_len == 0)
Andreas Dilger47a0c421997-05-16 02:46:07 -0500662 {
663 char msg[40];
664
665 sprintf(msg, "Zero length %s keyword", png_ptr->chunk_name);
666 png_warning(png_ptr, msg);
667 }
668
669 if (key_len > 79)
670 {
671 char msg[50];
672
673 sprintf(msg, "%s keyword length must be 1 - 79 characters",
674 png_ptr->chunk_name);
675 png_warning(png_ptr, msg);
676 new_key[79] = '\0';
677 key_len = 79;
678 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600679
680 return key_len;
681}
682#endif
683
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500684#if defined(PNG_WRITE_tEXt_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500685/* write a tEXt chunk */
686void
Guy Schalnat6d764711995-12-19 03:22:19 -0600687png_write_tEXt(png_structp png_ptr, png_charp key, png_charp text,
Andreas Dilger47a0c421997-05-16 02:46:07 -0500688 png_size_t text_len)
Guy Schalnat0d580581995-07-20 02:43:20 -0500689{
Andreas Dilger47a0c421997-05-16 02:46:07 -0500690 png_size_t key_len;
691 png_bytep new_key;
Guy Schalnat0d580581995-07-20 02:43:20 -0500692
Andreas Dilger47a0c421997-05-16 02:46:07 -0500693 png_debug(1, "in png_write_tEXt\n");
694 if (key == NULL || (key_len = png_check_keyword(png_ptr, key, &new_key))==0)
695 {
696 char msg[40];
697
698 sprintf(msg, "Empty keyword in %s chunk", "tEXt");
699 png_warning(png_ptr, msg);
Guy Schalnate5a37791996-06-05 15:50:50 -0500700 return;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500701 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500702
Andreas Dilger47a0c421997-05-16 02:46:07 -0500703 if (text == NULL || *text == '\0')
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600704 text_len = 0;
705
706 /* make sure we include the 0 after the key */
Andreas Dilger47a0c421997-05-16 02:46:07 -0500707 png_write_chunk_start(png_ptr, png_tEXt, (png_uint_32)key_len+text_len+1);
708 png_write_chunk_data(png_ptr, new_key, key_len + 1);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600709 if (text_len)
Andreas Dilger47a0c421997-05-16 02:46:07 -0500710 png_write_chunk_data(png_ptr, (png_bytep)text, text_len);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600711
Guy Schalnat0d580581995-07-20 02:43:20 -0500712 png_write_chunk_end(png_ptr);
Andreas Dilger47a0c421997-05-16 02:46:07 -0500713 png_free(png_ptr, new_key);
Guy Schalnat0d580581995-07-20 02:43:20 -0500714}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500715#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500716
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500717#if defined(PNG_WRITE_zTXt_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -0500718/* write a compressed text chunk */
Guy Schalnat0d580581995-07-20 02:43:20 -0500719void
Guy Schalnat6d764711995-12-19 03:22:19 -0600720png_write_zTXt(png_structp png_ptr, png_charp key, png_charp text,
Andreas Dilger47a0c421997-05-16 02:46:07 -0500721 png_size_t text_len, int compression)
Guy Schalnat0d580581995-07-20 02:43:20 -0500722{
Andreas Dilger47a0c421997-05-16 02:46:07 -0500723 png_size_t key_len;
Guy Schalnat0d580581995-07-20 02:43:20 -0500724 char buf[1];
Andreas Dilger47a0c421997-05-16 02:46:07 -0500725 png_bytep new_key;
Guy Schalnat0d580581995-07-20 02:43:20 -0500726 int i, ret;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600727 png_charpp output_ptr = NULL; /* array of pointers to output */
Guy Schalnat0d580581995-07-20 02:43:20 -0500728 int num_output_ptr = 0; /* number of output pointers used */
729 int max_output_ptr = 0; /* size of output_ptr */
730
Andreas Dilger47a0c421997-05-16 02:46:07 -0500731 png_debug(1, "in png_write_zTXt\n");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600732
Andreas Dilger47a0c421997-05-16 02:46:07 -0500733 if (key == NULL || (key_len = png_check_keyword(png_ptr, key, &new_key))==0)
Guy Schalnate5a37791996-06-05 15:50:50 -0500734 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500735 char msg[40];
736
737 sprintf(msg, "Empty keyword in %s chunk", "zTXt");
738 png_warning(png_ptr, msg);
739 return;
Guy Schalnate5a37791996-06-05 15:50:50 -0500740 }
741
Andreas Dilger47a0c421997-05-16 02:46:07 -0500742 if (text == NULL || *text == '\0' || compression==PNG_TEXT_COMPRESSION_NONE)
743 {
744 png_write_tEXt(png_ptr, new_key, text, (png_size_t)0);
745 png_free(png_ptr, new_key);
746 return;
747 }
748
749 png_free(png_ptr, new_key);
750
751 if (compression >= PNG_TEXT_COMPRESSION_LAST)
752 {
753 char msg[50];
754 sprintf(msg, "Unknown zTXt compression type %d", compression);
755 png_warning(png_ptr, msg);
756 compression = PNG_TEXT_COMPRESSION_zTXt;
757 }
758
759 /* We can't write the chunk until we find out how much data we have,
760 * which means we need to run the compressor first, and save the
761 * output. This shouldn't be a problem, as the vast majority of
762 * comments should be reasonable, but we will set up an array of
763 * malloc'd pointers to be sure.
764 *
765 * If we knew the application was well behaved, we could simplify this
766 * greatly by assuming we can always malloc an output buffer large
767 * enough to hold the compressed text ((1001 * text_len / 1000) + 12)
768 * and malloc this directly. The only time this would be a bad idea is
769 * if we can't malloc more than 64K and we have 64K of random input
770 * data, or if the input string is incredibly large (although this
771 * wouldn't cause a failure, just a slowdown due to swapping).
772 */
Guy Schalnat0d580581995-07-20 02:43:20 -0500773
774 /* set up the compression buffers */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600775 png_ptr->zstream.avail_in = (uInt)text_len;
776 png_ptr->zstream.next_in = (Bytef *)text;
777 png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
778 png_ptr->zstream.next_out = (Bytef *)png_ptr->zbuf;
Guy Schalnat0d580581995-07-20 02:43:20 -0500779
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600780 /* this is the same compression loop as in png_write_row() */
Guy Schalnat0d580581995-07-20 02:43:20 -0500781 do
782 {
783 /* compress the data */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600784 ret = deflate(&png_ptr->zstream, Z_NO_FLUSH);
Guy Schalnat0d580581995-07-20 02:43:20 -0500785 if (ret != Z_OK)
786 {
787 /* error */
Andreas Dilger47a0c421997-05-16 02:46:07 -0500788 if (png_ptr->zstream.msg != NULL)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600789 png_error(png_ptr, png_ptr->zstream.msg);
Guy Schalnat0d580581995-07-20 02:43:20 -0500790 else
Guy Schalnat6d764711995-12-19 03:22:19 -0600791 png_error(png_ptr, "zlib error");
Guy Schalnat0d580581995-07-20 02:43:20 -0500792 }
793 /* check to see if we need more room */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600794 if (!png_ptr->zstream.avail_out && png_ptr->zstream.avail_in)
Guy Schalnat0d580581995-07-20 02:43:20 -0500795 {
796 /* make sure the output array has room */
797 if (num_output_ptr >= max_output_ptr)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600798 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500799 int old_max;
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500800
801 old_max = max_output_ptr;
Guy Schalnat0d580581995-07-20 02:43:20 -0500802 max_output_ptr = num_output_ptr + 4;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500803 if (output_ptr != NULL)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600804 {
805 png_charpp old_ptr;
Guy Schalnat4ee97b01996-01-16 01:51:56 -0600806
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600807 old_ptr = output_ptr;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600808 output_ptr = (png_charpp)png_malloc(png_ptr,
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600809 max_output_ptr * sizeof (png_charpp));
Andreas Dilger47a0c421997-05-16 02:46:07 -0500810 png_memcpy(output_ptr, old_ptr, old_max * sizeof (png_charp));
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600811 png_free(png_ptr, old_ptr);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600812 }
813 else
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600814 output_ptr = (png_charpp)png_malloc(png_ptr,
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600815 max_output_ptr * sizeof (png_charp));
Guy Schalnat0d580581995-07-20 02:43:20 -0500816 }
817
818 /* save the data */
Andreas Dilger47a0c421997-05-16 02:46:07 -0500819 output_ptr[num_output_ptr] = png_malloc(png_ptr, png_ptr->zbuf_size);
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500820 png_memcpy(output_ptr[num_output_ptr], png_ptr->zbuf,
Andreas Dilger47a0c421997-05-16 02:46:07 -0500821 png_ptr->zbuf_size);
Guy Schalnat0d580581995-07-20 02:43:20 -0500822 num_output_ptr++;
823
824 /* and reset the buffer */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600825 png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
826 png_ptr->zstream.next_out = png_ptr->zbuf;
Guy Schalnat0d580581995-07-20 02:43:20 -0500827 }
828 /* continue until we don't have anymore to compress */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600829 } while (png_ptr->zstream.avail_in);
Guy Schalnat0d580581995-07-20 02:43:20 -0500830
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600831 /* finish the compression */
Guy Schalnat0d580581995-07-20 02:43:20 -0500832 do
833 {
834 /* tell zlib we are finished */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600835 ret = deflate(&png_ptr->zstream, Z_FINISH);
Guy Schalnat0d580581995-07-20 02:43:20 -0500836 if (ret != Z_OK && ret != Z_STREAM_END)
837 {
838 /* we got an error */
Andreas Dilger47a0c421997-05-16 02:46:07 -0500839 if (png_ptr->zstream.msg != NULL)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600840 png_error(png_ptr, png_ptr->zstream.msg);
Guy Schalnat0d580581995-07-20 02:43:20 -0500841 else
Guy Schalnat6d764711995-12-19 03:22:19 -0600842 png_error(png_ptr, "zlib error");
Guy Schalnat0d580581995-07-20 02:43:20 -0500843 }
844
845 /* check to see if we need more room */
Andreas Dilger47a0c421997-05-16 02:46:07 -0500846 if (!(png_ptr->zstream.avail_out) && ret == Z_OK)
Guy Schalnat0d580581995-07-20 02:43:20 -0500847 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600848 /* check to make sure our output array has room */
849 if (num_output_ptr >= max_output_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -0500850 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500851 int old_max;
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500852
853 old_max = max_output_ptr;
Guy Schalnat0d580581995-07-20 02:43:20 -0500854 max_output_ptr = num_output_ptr + 4;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500855 if (output_ptr != NULL)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600856 {
857 png_charpp old_ptr;
Guy Schalnat0d580581995-07-20 02:43:20 -0500858
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600859 old_ptr = output_ptr;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500860 /* This could be optimized to realloc() */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600861 output_ptr = (png_charpp)png_malloc(png_ptr,
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600862 max_output_ptr * sizeof (png_charpp));
Andreas Dilger47a0c421997-05-16 02:46:07 -0500863 png_memcpy(output_ptr, old_ptr, old_max * sizeof (png_charp));
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600864 png_free(png_ptr, old_ptr);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600865 }
866 else
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600867 output_ptr = (png_charpp)png_malloc(png_ptr,
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600868 max_output_ptr * sizeof (png_charp));
869 }
Guy Schalnat4ee97b01996-01-16 01:51:56 -0600870
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600871 /* save off the data */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600872 output_ptr[num_output_ptr] = png_malloc(png_ptr,
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600873 png_ptr->zbuf_size);
874 png_memcpy(output_ptr[num_output_ptr], png_ptr->zbuf,
Andreas Dilger47a0c421997-05-16 02:46:07 -0500875 png_ptr->zbuf_size);
Guy Schalnat0d580581995-07-20 02:43:20 -0500876 num_output_ptr++;
877
878 /* and reset the buffer pointers */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600879 png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
880 png_ptr->zstream.next_out = png_ptr->zbuf;
Guy Schalnat0d580581995-07-20 02:43:20 -0500881 }
882 } while (ret != Z_STREAM_END);
883
884 /* text length is number of buffers plus last buffer */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600885 text_len = png_ptr->zbuf_size * num_output_ptr;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600886 if (png_ptr->zstream.avail_out < png_ptr->zbuf_size)
Andreas Dilger47a0c421997-05-16 02:46:07 -0500887 text_len += png_ptr->zbuf_size - (png_size_t)png_ptr->zstream.avail_out;
Guy Schalnat0d580581995-07-20 02:43:20 -0500888
889 /* write start of chunk */
Andreas Dilger47a0c421997-05-16 02:46:07 -0500890 png_write_chunk_start(png_ptr, png_zTXt, (png_uint_32)(key_len+text_len+2));
Guy Schalnat0d580581995-07-20 02:43:20 -0500891 /* write key */
Andreas Dilger47a0c421997-05-16 02:46:07 -0500892 png_write_chunk_data(png_ptr, (png_bytep)key, key_len + 1);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600893 buf[0] = (png_byte)compression;
Guy Schalnat0d580581995-07-20 02:43:20 -0500894 /* write compression */
Andreas Dilger47a0c421997-05-16 02:46:07 -0500895 png_write_chunk_data(png_ptr, (png_bytep)buf, (png_size_t)1);
Guy Schalnat0d580581995-07-20 02:43:20 -0500896
897 /* write saved output buffers, if any */
898 for (i = 0; i < num_output_ptr; i++)
899 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500900 png_write_chunk_data(png_ptr,(png_bytep)output_ptr[i],png_ptr->zbuf_size);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600901 png_free(png_ptr, output_ptr[i]);
Guy Schalnat0d580581995-07-20 02:43:20 -0500902 }
Andreas Dilger47a0c421997-05-16 02:46:07 -0500903 if (max_output_ptr != 0)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600904 png_free(png_ptr, output_ptr);
Guy Schalnat0d580581995-07-20 02:43:20 -0500905 /* write anything left in zbuf */
Andreas Dilger47a0c421997-05-16 02:46:07 -0500906 if (png_ptr->zstream.avail_out < (png_uint_32)png_ptr->zbuf_size)
Guy Schalnat0d580581995-07-20 02:43:20 -0500907 png_write_chunk_data(png_ptr, png_ptr->zbuf,
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600908 png_ptr->zbuf_size - png_ptr->zstream.avail_out);
Guy Schalnat0d580581995-07-20 02:43:20 -0500909 /* close the chunk */
910 png_write_chunk_end(png_ptr);
911
912 /* reset zlib for another zTXt or the image data */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600913 deflateReset(&png_ptr->zstream);
Guy Schalnat0d580581995-07-20 02:43:20 -0500914}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500915#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500916
Andreas Dilger47a0c421997-05-16 02:46:07 -0500917
918#if defined(PNG_WRITE_oFFs_SUPPORTED)
919/* write the oFFs chunk */
920void
921png_write_oFFs(png_structp png_ptr, png_uint_32 x_offset,
922 png_uint_32 y_offset,
923 int unit_type)
924{
925 png_byte buf[9];
926
927 png_debug(1, "in png_write_oFFs\n");
928 if (unit_type >= PNG_OFFSET_LAST)
929 png_warning(png_ptr, "Unrecognized unit type for oFFs chunk");
930
931 png_save_uint_32(buf, x_offset);
932 png_save_uint_32(buf + 4, y_offset);
933 buf[8] = (png_byte)unit_type;
934
935 png_write_chunk(png_ptr, png_oFFs, buf, (png_size_t)9);
936}
937#endif
938
939#if defined(PNG_WRITE_pCAL_SUPPORTED)
940/* write the pCAL chunk (png-scivis-19970203) */
941void
942png_write_pCAL(png_structp png_ptr, png_charp purpose, png_int_32 X0,
943 png_int_32 X1, int type, int nparams, png_charp units, png_charpp params)
944{
945 png_size_t purpose_len, units_len, total_len;
946 png_uint_32p params_len;
947 png_byte buf[10];
948 png_bytep new_purpose;
949 int i;
950
951 png_debug1(1, "in png_write_pCAL (%d parameters)\n", nparams);
952 if (type >= PNG_EQUATION_LAST)
953 png_warning(png_ptr, "Unrecognized equation type for pCAL chunk");
954
955 purpose_len = png_check_keyword(png_ptr, purpose, &new_purpose) + 1;
956 png_debug1(3, "pCAL purpose length = %d\n", purpose_len);
957 units_len = png_strlen(units) + (nparams == 0 ? 0 : 1);
958 png_debug1(3, "pCAL units length = %d\n", units_len);
959 total_len = purpose_len + units_len + 10;
960
961 params_len = (png_uint_32p)png_malloc(png_ptr, nparams*sizeof(png_uint_32));
962
963 /* Find the length of each parameter, making sure we don't count the
964 null terminator for the last parameter. */
965 for (i = 0; i < nparams; i++)
966 {
967 params_len[i] = png_strlen(params[i]) + (i == nparams - 1 ? 0 : 1);
968 png_debug2(3, "pCAL parameter %d length = %d\n", i, params_len[i]);
969 total_len += (png_size_t)params_len[i];
970 }
971
972 png_debug1(3, "pCAL total length = %d\n", total_len);
973 png_write_chunk_start(png_ptr, png_pCAL, total_len);
974 png_write_chunk_data(png_ptr, new_purpose, purpose_len);
975 png_save_int_32(buf, X0);
976 png_save_int_32(buf + 4, X1);
977 buf[8] = (png_byte)type;
978 buf[9] = (png_byte)nparams;
979 png_write_chunk_data(png_ptr, buf, (png_size_t)10);
980 png_write_chunk_data(png_ptr, (png_bytep)units, (png_size_t)units_len);
981
982 png_free(png_ptr, new_purpose);
983
984 for (i = 0; i < nparams; i++)
985 {
986 png_write_chunk_data(png_ptr, (png_bytep)params[i],
987 (png_size_t)params_len[i]);
988 }
989
990 png_write_chunk_end(png_ptr);
991}
992#endif
993
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500994#if defined(PNG_WRITE_pHYs_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500995/* write the pHYs chunk */
996void
Guy Schalnat6d764711995-12-19 03:22:19 -0600997png_write_pHYs(png_structp png_ptr, png_uint_32 x_pixels_per_unit,
Guy Schalnat0d580581995-07-20 02:43:20 -0500998 png_uint_32 y_pixels_per_unit,
999 int unit_type)
1000{
1001 png_byte buf[9];
1002
Andreas Dilger47a0c421997-05-16 02:46:07 -05001003 png_debug(1, "in png_write_pHYs\n");
Guy Schalnate5a37791996-06-05 15:50:50 -05001004 if (unit_type >= PNG_RESOLUTION_LAST)
1005 png_warning(png_ptr, "Unrecognized unit type for pHYs chunk");
1006
Guy Schalnat0d580581995-07-20 02:43:20 -05001007 png_save_uint_32(buf, x_pixels_per_unit);
1008 png_save_uint_32(buf + 4, y_pixels_per_unit);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001009 buf[8] = (png_byte)unit_type;
Guy Schalnat0d580581995-07-20 02:43:20 -05001010
Andreas Dilger47a0c421997-05-16 02:46:07 -05001011 png_write_chunk(png_ptr, png_pHYs, buf, (png_size_t)9);
Guy Schalnat0d580581995-07-20 02:43:20 -05001012}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001013#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001014
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001015#if defined(PNG_WRITE_tIME_SUPPORTED)
1016/* write the tIME chunk. Use either png_convert_from_struct_tm()
1017 or png_convert_from_time_t(), or fill in the structure yourself */
Guy Schalnat0d580581995-07-20 02:43:20 -05001018void
Guy Schalnat6d764711995-12-19 03:22:19 -06001019png_write_tIME(png_structp png_ptr, png_timep mod_time)
Guy Schalnat0d580581995-07-20 02:43:20 -05001020{
1021 png_byte buf[7];
1022
Andreas Dilger47a0c421997-05-16 02:46:07 -05001023 png_debug(1, "in png_write_tIME\n");
Guy Schalnate5a37791996-06-05 15:50:50 -05001024 if (mod_time->month > 12 || mod_time->month < 1 ||
1025 mod_time->day > 31 || mod_time->day < 1 ||
1026 mod_time->hour > 23 || mod_time->second > 60)
1027 {
1028 png_warning(png_ptr, "Invalid time specified for tIME chunk");
1029 return;
1030 }
1031
Guy Schalnat0d580581995-07-20 02:43:20 -05001032 png_save_uint_16(buf, mod_time->year);
1033 buf[2] = mod_time->month;
1034 buf[3] = mod_time->day;
1035 buf[4] = mod_time->hour;
1036 buf[5] = mod_time->minute;
1037 buf[6] = mod_time->second;
1038
Andreas Dilger47a0c421997-05-16 02:46:07 -05001039 png_write_chunk(png_ptr, png_tIME, buf, (png_size_t)7);
Guy Schalnat0d580581995-07-20 02:43:20 -05001040}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001041#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001042
1043/* initializes the row writing capability of libpng */
1044void
Guy Schalnat6d764711995-12-19 03:22:19 -06001045png_write_start_row(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -05001046{
Andreas Dilger47a0c421997-05-16 02:46:07 -05001047 png_size_t buf_size;
1048
1049 png_debug(1, "in png_write_start_row\n");
1050 buf_size = (png_size_t)(((png_ptr->width * png_ptr->usr_channels *
1051 png_ptr->usr_bit_depth + 7) >> 3) + 1);
1052
Guy Schalnat0d580581995-07-20 02:43:20 -05001053 /* set up row buffer */
Andreas Dilger47a0c421997-05-16 02:46:07 -05001054 png_ptr->row_buf = (png_bytep)png_malloc(png_ptr, buf_size);
1055 png_ptr->row_buf[0] = PNG_FILTER_VALUE_NONE;
Guy Schalnate5a37791996-06-05 15:50:50 -05001056
1057 /* set up filtering buffer, if using this filter */
1058 if (png_ptr->do_filter & PNG_FILTER_SUB)
Guy Schalnat0d580581995-07-20 02:43:20 -05001059 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001060 png_ptr->sub_row = (png_bytep)png_malloc(png_ptr,
Guy Schalnate5a37791996-06-05 15:50:50 -05001061 png_ptr->rowbytes + 1);
Andreas Dilger47a0c421997-05-16 02:46:07 -05001062 png_ptr->sub_row[0] = PNG_FILTER_VALUE_SUB;
Guy Schalnate5a37791996-06-05 15:50:50 -05001063 }
1064
Andreas Dilger47a0c421997-05-16 02:46:07 -05001065 /* We only need to keep the previous row if we are using one of these. */
Guy Schalnate5a37791996-06-05 15:50:50 -05001066 if (png_ptr->do_filter & (PNG_FILTER_AVG | PNG_FILTER_UP | PNG_FILTER_PAETH))
1067 {
1068 /* set up previous row buffer */
Andreas Dilger47a0c421997-05-16 02:46:07 -05001069 png_ptr->prev_row = (png_bytep)png_malloc(png_ptr, buf_size);
1070 png_memset(png_ptr->prev_row, 0, buf_size);
Guy Schalnate5a37791996-06-05 15:50:50 -05001071
1072 if (png_ptr->do_filter & PNG_FILTER_UP)
1073 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001074 png_ptr->up_row = (png_bytep )png_malloc(png_ptr,
Guy Schalnate5a37791996-06-05 15:50:50 -05001075 png_ptr->rowbytes + 1);
Andreas Dilger47a0c421997-05-16 02:46:07 -05001076 png_ptr->up_row[0] = PNG_FILTER_VALUE_UP;
Guy Schalnate5a37791996-06-05 15:50:50 -05001077 }
1078
1079 if (png_ptr->do_filter & PNG_FILTER_AVG)
1080 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001081 png_ptr->avg_row = (png_bytep )png_malloc(png_ptr,
Guy Schalnate5a37791996-06-05 15:50:50 -05001082 png_ptr->rowbytes + 1);
Andreas Dilger47a0c421997-05-16 02:46:07 -05001083 png_ptr->avg_row[0] = PNG_FILTER_VALUE_AVG;
Guy Schalnate5a37791996-06-05 15:50:50 -05001084 }
1085
1086 if (png_ptr->do_filter & PNG_FILTER_PAETH)
1087 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001088 png_ptr->paeth_row = (png_bytep )png_malloc(png_ptr,
Guy Schalnate5a37791996-06-05 15:50:50 -05001089 png_ptr->rowbytes + 1);
Andreas Dilger47a0c421997-05-16 02:46:07 -05001090 png_ptr->paeth_row[0] = PNG_FILTER_VALUE_PAETH;
Guy Schalnate5a37791996-06-05 15:50:50 -05001091 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001092 }
1093
1094 /* if interlaced, we need to set up width and height of pass */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001095 if (png_ptr->interlaced)
Guy Schalnat0d580581995-07-20 02:43:20 -05001096 {
1097 if (!(png_ptr->transformations & PNG_INTERLACE))
1098 {
1099 png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 -
1100 png_pass_ystart[0]) / png_pass_yinc[0];
Andreas Dilger47a0c421997-05-16 02:46:07 -05001101 png_ptr->usr_width = (png_ptr->width + png_pass_inc[0] - 1 -
1102 png_pass_start[0]) / png_pass_inc[0];
Guy Schalnat0d580581995-07-20 02:43:20 -05001103 }
1104 else
1105 {
1106 png_ptr->num_rows = png_ptr->height;
1107 png_ptr->usr_width = png_ptr->width;
1108 }
1109 }
1110 else
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001111 {
Guy Schalnat0d580581995-07-20 02:43:20 -05001112 png_ptr->num_rows = png_ptr->height;
1113 png_ptr->usr_width = png_ptr->width;
1114 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001115 png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
1116 png_ptr->zstream.next_out = png_ptr->zbuf;
Guy Schalnat0d580581995-07-20 02:43:20 -05001117}
1118
Andreas Dilger47a0c421997-05-16 02:46:07 -05001119/* Internal use only. Called when finished processing a row of data. */
Guy Schalnat0d580581995-07-20 02:43:20 -05001120void
Guy Schalnat6d764711995-12-19 03:22:19 -06001121png_write_finish_row(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -05001122{
1123 int ret;
1124
Andreas Dilger47a0c421997-05-16 02:46:07 -05001125 png_debug(1, "in png_write_finish_row\n");
Guy Schalnat0d580581995-07-20 02:43:20 -05001126 /* next row */
1127 png_ptr->row_number++;
Guy Schalnatc21f90c1996-06-17 16:24:45 -05001128
Guy Schalnat0d580581995-07-20 02:43:20 -05001129 /* see if we are done */
Guy Schalnat6d764711995-12-19 03:22:19 -06001130 if (png_ptr->row_number < png_ptr->num_rows)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001131 return;
Guy Schalnat0d580581995-07-20 02:43:20 -05001132
1133 /* if interlaced, go to next pass */
1134 if (png_ptr->interlaced)
1135 {
1136 png_ptr->row_number = 0;
1137 if (png_ptr->transformations & PNG_INTERLACE)
1138 {
1139 png_ptr->pass++;
1140 }
1141 else
1142 {
1143 /* loop until we find a non-zero width or height pass */
1144 do
1145 {
1146 png_ptr->pass++;
1147 if (png_ptr->pass >= 7)
1148 break;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001149 png_ptr->usr_width = (png_ptr->width +
Guy Schalnat0d580581995-07-20 02:43:20 -05001150 png_pass_inc[png_ptr->pass] - 1 -
1151 png_pass_start[png_ptr->pass]) /
1152 png_pass_inc[png_ptr->pass];
1153 png_ptr->num_rows = (png_ptr->height +
1154 png_pass_yinc[png_ptr->pass] - 1 -
1155 png_pass_ystart[png_ptr->pass]) /
1156 png_pass_yinc[png_ptr->pass];
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001157 if (png_ptr->transformations & PNG_INTERLACE)
1158 break;
Guy Schalnat0d580581995-07-20 02:43:20 -05001159 } while (png_ptr->usr_width == 0 || png_ptr->num_rows == 0);
1160
1161 }
1162
Guy Schalnate5a37791996-06-05 15:50:50 -05001163 /* reset the row above the image for the next pass */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001164 if (png_ptr->pass < 7)
Guy Schalnatc21f90c1996-06-17 16:24:45 -05001165 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001166 if (png_ptr->prev_row != NULL)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001167 png_memset(png_ptr->prev_row, 0,
1168 (png_size_t) (((png_uint_32)png_ptr->usr_channels *
Guy Schalnatc21f90c1996-06-17 16:24:45 -05001169 (png_uint_32)png_ptr->usr_bit_depth *
1170 png_ptr->width + 7) >> 3) + 1);
Guy Schalnat0d580581995-07-20 02:43:20 -05001171 return;
Guy Schalnatc21f90c1996-06-17 16:24:45 -05001172 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001173 }
1174
1175 /* if we get here, we've just written the last row, so we need
1176 to flush the compressor */
1177 do
1178 {
1179 /* tell the compressor we are done */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001180 ret = deflate(&png_ptr->zstream, Z_FINISH);
Guy Schalnat0d580581995-07-20 02:43:20 -05001181 /* check for an error */
1182 if (ret != Z_OK && ret != Z_STREAM_END)
1183 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001184 if (png_ptr->zstream.msg != NULL)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001185 png_error(png_ptr, png_ptr->zstream.msg);
Guy Schalnat0d580581995-07-20 02:43:20 -05001186 else
Guy Schalnat6d764711995-12-19 03:22:19 -06001187 png_error(png_ptr, "zlib error");
Guy Schalnat0d580581995-07-20 02:43:20 -05001188 }
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001189 /* check to see if we need more room */
Andreas Dilger47a0c421997-05-16 02:46:07 -05001190 if (!(png_ptr->zstream.avail_out) && ret == Z_OK)
Guy Schalnat0d580581995-07-20 02:43:20 -05001191 {
1192 png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001193 png_ptr->zstream.next_out = png_ptr->zbuf;
1194 png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
Guy Schalnat0d580581995-07-20 02:43:20 -05001195 }
1196 } while (ret != Z_STREAM_END);
1197
1198 /* write any extra space */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001199 if (png_ptr->zstream.avail_out < png_ptr->zbuf_size)
Guy Schalnat0d580581995-07-20 02:43:20 -05001200 {
1201 png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size -
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001202 png_ptr->zstream.avail_out);
Guy Schalnat0d580581995-07-20 02:43:20 -05001203 }
1204
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001205 deflateReset(&png_ptr->zstream);
Guy Schalnat0d580581995-07-20 02:43:20 -05001206}
1207
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001208#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -05001209/* pick out the correct pixels for the interlace pass.
1210
1211 The basic idea here is to go through the row with a source
1212 pointer and a destination pointer (sp and dp), and copy the
1213 correct pixels for the pass. As the row gets compacted,
1214 sp will always be >= dp, so we should never overwrite anything.
1215 See the default: case for the easiest code to understand.
1216 */
1217void
Guy Schalnat6d764711995-12-19 03:22:19 -06001218png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass)
Guy Schalnat0d580581995-07-20 02:43:20 -05001219{
Andreas Dilger47a0c421997-05-16 02:46:07 -05001220 png_debug(1, "in png_do_write_interlace\n");
Guy Schalnat0d580581995-07-20 02:43:20 -05001221 /* we don't have to do anything on the last pass (6) */
Andreas Dilger47a0c421997-05-16 02:46:07 -05001222#if defined(PNG_USELESS_TESTS_SUPPORTED)
1223 if (row != NULL && row_info != NULL && pass < 6)
1224#else
1225 if (pass < 6)
1226#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001227 {
1228 /* each pixel depth is handled seperately */
1229 switch (row_info->pixel_depth)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001230 {
Guy Schalnat0d580581995-07-20 02:43:20 -05001231 case 1:
1232 {
Guy Schalnat6d764711995-12-19 03:22:19 -06001233 png_bytep sp;
1234 png_bytep dp;
Guy Schalnat0d580581995-07-20 02:43:20 -05001235 int shift;
1236 int d;
1237 int value;
1238 png_uint_32 i;
1239
1240 dp = row;
1241 d = 0;
1242 shift = 7;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001243 for (i = png_pass_start[pass]; i < row_info->width;
Guy Schalnat0d580581995-07-20 02:43:20 -05001244 i += png_pass_inc[pass])
1245 {
1246 sp = row + (png_size_t)(i >> 3);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001247 value = (int)(*sp >> (7 - (int)(i & 7))) & 0x1;
Guy Schalnat0d580581995-07-20 02:43:20 -05001248 d |= (value << shift);
1249
1250 if (shift == 0)
1251 {
1252 shift = 7;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001253 *dp++ = (png_byte)d;
Guy Schalnat0d580581995-07-20 02:43:20 -05001254 d = 0;
1255 }
1256 else
1257 shift--;
1258
1259 }
1260 if (shift != 7)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001261 *dp = (png_byte)d;
Guy Schalnat0d580581995-07-20 02:43:20 -05001262 break;
1263 }
1264 case 2:
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001265 {
Guy Schalnat6d764711995-12-19 03:22:19 -06001266 png_bytep sp;
1267 png_bytep dp;
Guy Schalnat0d580581995-07-20 02:43:20 -05001268 int shift;
1269 int d;
1270 int value;
1271 png_uint_32 i;
1272
1273 dp = row;
1274 shift = 6;
1275 d = 0;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001276 for (i = png_pass_start[pass]; i < row_info->width;
Guy Schalnat0d580581995-07-20 02:43:20 -05001277 i += png_pass_inc[pass])
1278 {
1279 sp = row + (png_size_t)(i >> 2);
1280 value = (*sp >> ((3 - (int)(i & 3)) << 1)) & 0x3;
1281 d |= (value << shift);
1282
1283 if (shift == 0)
1284 {
1285 shift = 6;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001286 *dp++ = (png_byte)d;
Guy Schalnat0d580581995-07-20 02:43:20 -05001287 d = 0;
1288 }
1289 else
1290 shift -= 2;
1291 }
1292 if (shift != 6)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001293 *dp = (png_byte)d;
Guy Schalnat0d580581995-07-20 02:43:20 -05001294 break;
1295 }
1296 case 4:
1297 {
Guy Schalnat6d764711995-12-19 03:22:19 -06001298 png_bytep sp;
1299 png_bytep dp;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001300 int shift;
Guy Schalnat0d580581995-07-20 02:43:20 -05001301 int d;
1302 int value;
1303 png_uint_32 i;
1304
1305 dp = row;
1306 shift = 4;
1307 d = 0;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001308 for (i = png_pass_start[pass]; i < row_info->width;
Guy Schalnat0d580581995-07-20 02:43:20 -05001309 i += png_pass_inc[pass])
1310 {
1311 sp = row + (png_size_t)(i >> 1);
1312 value = (*sp >> ((1 - (int)(i & 1)) << 2)) & 0xf;
1313 d |= (value << shift);
1314
1315 if (shift == 0)
1316 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001317 shift = 4;
1318 *dp++ = (png_byte)d;
Guy Schalnat0d580581995-07-20 02:43:20 -05001319 d = 0;
1320 }
1321 else
1322 shift -= 4;
1323 }
1324 if (shift != 4)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001325 *dp = (png_byte)d;
Guy Schalnat0d580581995-07-20 02:43:20 -05001326 break;
1327 }
1328 default:
1329 {
Guy Schalnat6d764711995-12-19 03:22:19 -06001330 png_bytep sp;
1331 png_bytep dp;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001332 png_uint_32 i;
1333 png_size_t pixel_bytes;
Guy Schalnat0d580581995-07-20 02:43:20 -05001334
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001335 /* start at the beginning */
Guy Schalnat0d580581995-07-20 02:43:20 -05001336 dp = row;
1337 /* find out how many bytes each pixel takes up */
1338 pixel_bytes = (row_info->pixel_depth >> 3);
1339 /* loop through the row, only looking at the pixels that
1340 matter */
Andreas Dilger47a0c421997-05-16 02:46:07 -05001341 for (i = png_pass_start[pass]; i < row_info->width;
Guy Schalnat0d580581995-07-20 02:43:20 -05001342 i += png_pass_inc[pass])
1343 {
1344 /* find out where the original pixel is */
Andreas Dilger47a0c421997-05-16 02:46:07 -05001345 sp = row + i * pixel_bytes;
Guy Schalnat0d580581995-07-20 02:43:20 -05001346 /* move the pixel */
1347 if (dp != sp)
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001348 png_memcpy(dp, sp, pixel_bytes);
Guy Schalnat0d580581995-07-20 02:43:20 -05001349 /* next pixel */
1350 dp += pixel_bytes;
1351 }
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001352 break;
Guy Schalnat0d580581995-07-20 02:43:20 -05001353 }
1354 }
1355 /* set new row width */
1356 row_info->width = (row_info->width +
1357 png_pass_inc[pass] - 1 -
1358 png_pass_start[pass]) /
1359 png_pass_inc[pass];
1360 row_info->rowbytes = ((row_info->width *
1361 row_info->pixel_depth + 7) >> 3);
1362
1363 }
1364}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001365#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001366
Andreas Dilger47a0c421997-05-16 02:46:07 -05001367/* This filters the row, chooses which filter to use, if it has not already
1368 * been specified by the application, and then writes the row out with the
1369 * chosen filter. */
1370#define PNG_MAXSUM (~0x0UL >> 1)
1371#define PNG_HISHIFT 10
1372#define PNG_LOMASK 0xffffL
1373#define PNG_HIMASK (~PNG_LOMASK >> PNG_HISHIFT)
Guy Schalnat0d580581995-07-20 02:43:20 -05001374void
Guy Schalnate5a37791996-06-05 15:50:50 -05001375png_write_find_filter(png_structp png_ptr, png_row_infop row_info)
Guy Schalnat0d580581995-07-20 02:43:20 -05001376{
Guy Schalnate5a37791996-06-05 15:50:50 -05001377 png_bytep prev_row, best_row, row_buf;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001378 png_uint_32 mins, bpp;
Guy Schalnat0d580581995-07-20 02:43:20 -05001379
Andreas Dilger47a0c421997-05-16 02:46:07 -05001380 png_debug(1, "in png_write_find_filter\n");
Guy Schalnat0d580581995-07-20 02:43:20 -05001381 /* find out how many bytes offset each pixel is */
1382 bpp = (row_info->pixel_depth + 7) / 8;
Guy Schalnate5a37791996-06-05 15:50:50 -05001383
1384 prev_row = png_ptr->prev_row;
1385 best_row = row_buf = png_ptr->row_buf;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001386 mins = PNG_MAXSUM;
Guy Schalnat0d580581995-07-20 02:43:20 -05001387
Andreas Dilger47a0c421997-05-16 02:46:07 -05001388 /* The prediction method we use is to find which method provides the
1389 * smallest value when summing the absolute values of the distances
1390 * from zero using anything >= 128 as negative numbers. This is known
1391 * as the "minimum sum of absolute differences" heuristic. Other
1392 * heruistics are the "weighted minumum sum of absolute differences"
1393 * (experimental and can in theory improve compression), and the "zlib
1394 * predictive" method (not implemented in libpng 0.95), which does test
1395 * compressions of lines using different filter methods, and then chooses
1396 * the (series of) filter(s) which give minimum compressed data size (VERY
1397 * computationally expensive).
1398 */
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001399
Guy Schalnate5a37791996-06-05 15:50:50 -05001400 /* We don't need to test the 'no filter' case if this is the only filter
Andreas Dilger47a0c421997-05-16 02:46:07 -05001401 * that has been chosen, as it doesn't actually do anything to the data.
1402 */
Guy Schalnate5a37791996-06-05 15:50:50 -05001403 if (png_ptr->do_filter & PNG_FILTER_NONE &&
1404 png_ptr->do_filter != PNG_FILTER_NONE)
Guy Schalnat0d580581995-07-20 02:43:20 -05001405 {
Guy Schalnate5a37791996-06-05 15:50:50 -05001406 png_bytep rp;
1407 png_uint_32 sum = 0;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001408 png_size_t i;
1409 int v;
Guy Schalnat0d580581995-07-20 02:43:20 -05001410
Guy Schalnate5a37791996-06-05 15:50:50 -05001411 for (i = 0, rp = row_buf + 1; i < row_info->rowbytes; i++, rp++)
1412 {
1413 v = *rp;
1414 sum += (v < 128) ? v : 256 - v;
1415 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05001416
1417#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
1418 if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
1419 {
1420 png_uint_32 sumhi, sumlo;
1421 sumlo = sum & PNG_LOMASK;
1422 sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK; /* Gives us some footroom */
1423
1424 /* Reduce the sum if we match any of the previous rows */
1425 for (i = 0; i < png_ptr->num_prev_filters; i++)
1426 {
1427 if (png_ptr->prev_filters[i] == PNG_FILTER_NONE)
1428 {
1429 sumlo = (sumlo * png_ptr->filter_weights[i]) >>
1430 PNG_WEIGHT_SHIFT;
1431 sumhi = (sumhi * png_ptr->filter_weights[i]) >>
1432 PNG_WEIGHT_SHIFT;
1433 }
1434 }
1435
1436 /* Factor in the cost of this filter (this is here for completeness,
1437 * but it makes no sense to have a "cost" for the NONE filter, as
1438 * it has the minimum possible computational cost - none).
1439 */
1440 sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_NONE]) >>
1441 PNG_COST_SHIFT;
1442 sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_NONE]) >>
1443 PNG_COST_SHIFT;
1444
1445 if (sumhi > PNG_HIMASK)
1446 sum = PNG_MAXSUM;
1447 else
1448 sum = (sumhi << PNG_HISHIFT) + sumlo;
1449 }
1450#endif
Guy Schalnate5a37791996-06-05 15:50:50 -05001451 mins = sum;
Guy Schalnat0d580581995-07-20 02:43:20 -05001452 }
1453
Guy Schalnate5a37791996-06-05 15:50:50 -05001454 /* sub filter */
1455 if (png_ptr->do_filter & PNG_FILTER_SUB)
Guy Schalnat0d580581995-07-20 02:43:20 -05001456 {
Guy Schalnate5a37791996-06-05 15:50:50 -05001457 png_bytep rp, dp, lp;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001458 png_uint_32 sum = 0, lmins = mins;
1459 png_size_t i;
1460 int v;
1461
1462#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
1463 /* We temporarily increase the "minumum sum" by the factor we
1464 * would reduce the sum of this filter, so that we can do the
1465 * early exit comparison without scaling the sum each time.
1466 */
1467 if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
1468 {
1469 png_uint_32 lmhi, lmlo;
1470 lmlo = lmins & PNG_LOMASK;
1471 lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;
1472
1473 for (i = 0; i < png_ptr->num_prev_filters; i++)
1474 {
1475 if (png_ptr->prev_filters[i] == PNG_FILTER_VALUE_SUB)
1476 {
1477 lmlo = (lmlo * png_ptr->inv_filter_weights[i]) >>
1478 PNG_WEIGHT_SHIFT;
1479 lmhi = (lmhi * png_ptr->inv_filter_weights[i]) >>
1480 PNG_WEIGHT_SHIFT;
1481 }
1482 }
1483
1484 lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >>
1485 PNG_COST_SHIFT;
1486 lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >>
1487 PNG_COST_SHIFT;
1488
1489 if (lmhi > PNG_HIMASK)
1490 lmins = PNG_MAXSUM;
1491 else
1492 lmins = (lmhi << PNG_HISHIFT) + lmlo;
1493 }
1494#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001495
Guy Schalnate5a37791996-06-05 15:50:50 -05001496 for (i = 0, rp = row_buf + 1, dp = png_ptr->sub_row + 1; i < bpp;
1497 i++, rp++, dp++)
1498 {
1499 v = *dp = *rp;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001500
Guy Schalnate5a37791996-06-05 15:50:50 -05001501 sum += (v < 128) ? v : 256 - v;
1502 }
1503 for (lp = row_buf + 1; i < row_info->rowbytes; i++, rp++, lp++, dp++)
1504 {
1505 v = *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff);
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001506
Guy Schalnate5a37791996-06-05 15:50:50 -05001507 sum += (v < 128) ? v : 256 - v;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001508
1509 if (sum > lmins) /* We are already worse, don't continue. */
1510 break;
Guy Schalnate5a37791996-06-05 15:50:50 -05001511 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05001512
1513#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
1514 if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
1515 {
1516 png_uint_32 sumhi, sumlo;
1517 sumlo = sum & PNG_LOMASK;
1518 sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;
1519
1520 for (i = 0; i < png_ptr->num_prev_filters; i++)
1521 {
1522 if (png_ptr->prev_filters[i] == PNG_FILTER_VALUE_SUB)
1523 {
1524 sumlo = (sumlo * png_ptr->inv_filter_weights[i]) >>
1525 PNG_WEIGHT_SHIFT;
1526 sumhi = (sumhi * png_ptr->inv_filter_weights[i]) >>
1527 PNG_WEIGHT_SHIFT;
1528 }
1529 }
1530
1531 sumlo = (sumlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >>
1532 PNG_COST_SHIFT;
1533 sumhi = (sumhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >>
1534 PNG_COST_SHIFT;
1535
1536 if (sumhi > PNG_HIMASK)
1537 sum = PNG_MAXSUM;
1538 else
1539 sum = (sumhi << PNG_HISHIFT) + sumlo;
1540 }
1541#endif
1542
Guy Schalnate5a37791996-06-05 15:50:50 -05001543 if (sum < mins)
1544 {
1545 mins = sum;
1546 best_row = png_ptr->sub_row;
1547 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001548 }
1549
Guy Schalnate5a37791996-06-05 15:50:50 -05001550 /* up filter */
1551 if (png_ptr->do_filter & PNG_FILTER_UP)
Guy Schalnat0d580581995-07-20 02:43:20 -05001552 {
Guy Schalnate5a37791996-06-05 15:50:50 -05001553 png_bytep rp, dp, pp;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001554 png_uint_32 sum = 0, lmins = mins;
1555 png_size_t i;
1556 int v;
1557
1558#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
1559 if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
1560 {
1561 png_uint_32 lmhi, lmlo;
1562 lmlo = lmins & PNG_LOMASK;
1563 lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;
1564
1565 for (i = 0; i < png_ptr->num_prev_filters; i++)
1566 {
1567 if (png_ptr->prev_filters[i] == PNG_FILTER_VALUE_UP)
1568 {
1569 lmlo = (lmlo * png_ptr->inv_filter_weights[i]) >>
1570 PNG_WEIGHT_SHIFT;
1571 lmhi = (lmhi * png_ptr->inv_filter_weights[i]) >>
1572 PNG_WEIGHT_SHIFT;
1573 }
1574 }
1575
1576 lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_UP]) >>
1577 PNG_COST_SHIFT;
1578 lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_UP]) >>
1579 PNG_COST_SHIFT;
1580
1581 if (lmhi > PNG_HIMASK)
1582 lmins = PNG_MAXSUM;
1583 else
1584 lmins = (lmhi << PNG_HISHIFT) + lmlo;
1585 }
1586#endif
Guy Schalnate5a37791996-06-05 15:50:50 -05001587
1588 for (i = 0, rp = row_buf + 1, dp = png_ptr->up_row + 1,
1589 pp = prev_row + 1; i < row_info->rowbytes; i++, rp++, pp++, dp++)
1590 {
1591 v = *dp = (png_byte)(((int)*rp - (int)*pp) & 0xff);
1592
1593 sum += (v < 128) ? v : 256 - v;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001594
1595 if (sum > lmins) /* We are already worse, don't continue. */
1596 break;
Guy Schalnate5a37791996-06-05 15:50:50 -05001597 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05001598
1599#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
1600 if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
1601 {
1602 png_uint_32 sumhi, sumlo;
1603 sumlo = sum & PNG_LOMASK;
1604 sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;
1605
1606 for (i = 0; i < png_ptr->num_prev_filters; i++)
1607 {
1608 if (png_ptr->prev_filters[i] == PNG_FILTER_UP)
1609 {
1610 sumlo = (sumlo * png_ptr->filter_weights[i]) >>
1611 PNG_WEIGHT_SHIFT;
1612 sumhi = (sumhi * png_ptr->filter_weights[i]) >>
1613 PNG_WEIGHT_SHIFT;
1614 }
1615 }
1616
1617 sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_UP]) >>
1618 PNG_COST_SHIFT;
1619 sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_UP]) >>
1620 PNG_COST_SHIFT;
1621
1622 if (sumhi > PNG_HIMASK)
1623 sum = PNG_MAXSUM;
1624 else
1625 sum = (sumhi << PNG_HISHIFT) + sumlo;
1626 }
1627#endif
1628
Guy Schalnate5a37791996-06-05 15:50:50 -05001629 if (sum < mins)
1630 {
1631 mins = sum;
1632 best_row = png_ptr->up_row;
1633 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001634 }
1635
Guy Schalnate5a37791996-06-05 15:50:50 -05001636 /* avg filter */
1637 if (png_ptr->do_filter & PNG_FILTER_AVG)
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001638 {
Guy Schalnate5a37791996-06-05 15:50:50 -05001639 png_bytep rp, dp, pp, lp;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001640 png_uint_32 sum = 0, lmins = mins;
1641 png_size_t i;
1642 int v;
1643
1644#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
1645 if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
1646 {
1647 png_uint_32 lmhi, lmlo;
1648 lmlo = lmins & PNG_LOMASK;
1649 lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;
1650
1651 for (i = 0; i < png_ptr->num_prev_filters; i++)
1652 {
1653 if (png_ptr->prev_filters[i] == PNG_FILTER_VALUE_AVG)
1654 {
1655 lmlo = (lmlo * png_ptr->inv_filter_weights[i]) >>
1656 PNG_WEIGHT_SHIFT;
1657 lmhi = (lmhi * png_ptr->inv_filter_weights[i]) >>
1658 PNG_WEIGHT_SHIFT;
1659 }
1660 }
1661
1662 lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_AVG]) >>
1663 PNG_COST_SHIFT;
1664 lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_AVG]) >>
1665 PNG_COST_SHIFT;
1666
1667 if (lmhi > PNG_HIMASK)
1668 lmins = PNG_MAXSUM;
1669 else
1670 lmins = (lmhi << PNG_HISHIFT) + lmlo;
1671 }
1672#endif
Guy Schalnate5a37791996-06-05 15:50:50 -05001673
1674 for (i = 0, rp = row_buf + 1, dp = png_ptr->avg_row + 1,
1675 pp = prev_row + 1; i < bpp; i++, rp++, pp++, dp++)
1676 {
1677 v = *dp = (png_byte)(((int)*rp - ((int)*pp / 2)) & 0xff);
1678
1679 sum += (v < 128) ? v : 256 - v;
1680 }
1681 for (lp = row_buf + 1; i < row_info->rowbytes;
1682 i++, rp++, pp++, lp++, dp++)
1683 {
1684 v = *dp = (png_byte)(((int)*rp - (((int)*pp + (int)*lp) / 2)) & 0xff);
1685
1686 sum += (v < 128) ? v : 256 - v;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001687
1688 if (sum > lmins) /* We are already worse, don't continue. */
1689 break;
Guy Schalnate5a37791996-06-05 15:50:50 -05001690 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05001691
1692#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
1693 if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
1694 {
1695 png_uint_32 sumhi, sumlo;
1696 sumlo = sum & PNG_LOMASK;
1697 sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;
1698
1699 for (i = 0; i < png_ptr->num_prev_filters; i++)
1700 {
1701 if (png_ptr->prev_filters[i] == PNG_FILTER_NONE)
1702 {
1703 sumlo = (sumlo * png_ptr->filter_weights[i]) >>
1704 PNG_WEIGHT_SHIFT;
1705 sumhi = (sumhi * png_ptr->filter_weights[i]) >>
1706 PNG_WEIGHT_SHIFT;
1707 }
1708 }
1709
1710 sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_AVG]) >>
1711 PNG_COST_SHIFT;
1712 sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_AVG]) >>
1713 PNG_COST_SHIFT;
1714
1715 if (sumhi > PNG_HIMASK)
1716 sum = PNG_MAXSUM;
1717 else
1718 sum = (sumhi << PNG_HISHIFT) + sumlo;
1719 }
1720#endif
1721
Guy Schalnate5a37791996-06-05 15:50:50 -05001722 if (sum < mins)
1723 {
1724 mins = sum;
1725 best_row = png_ptr->avg_row;
1726 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001727 }
1728
Andreas Dilger47a0c421997-05-16 02:46:07 -05001729 /* Paeth filter */
Guy Schalnate5a37791996-06-05 15:50:50 -05001730 if (png_ptr->do_filter & PNG_FILTER_PAETH)
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001731 {
Guy Schalnate5a37791996-06-05 15:50:50 -05001732 png_bytep rp, dp, pp, cp, lp;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001733 png_uint_32 sum = 0, lmins = mins;
1734 png_size_t i;
1735 int v;
1736
1737#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
1738 if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
1739 {
1740 png_uint_32 lmhi, lmlo;
1741 lmlo = lmins & PNG_LOMASK;
1742 lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;
1743
1744 for (i = 0; i < png_ptr->num_prev_filters; i++)
1745 {
1746 if (png_ptr->prev_filters[i] == PNG_FILTER_VALUE_PAETH)
1747 {
1748 lmlo = (lmlo * png_ptr->inv_filter_weights[i]) >>
1749 PNG_WEIGHT_SHIFT;
1750 lmhi = (lmhi * png_ptr->inv_filter_weights[i]) >>
1751 PNG_WEIGHT_SHIFT;
1752 }
1753 }
1754
1755 lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_PAETH]) >>
1756 PNG_COST_SHIFT;
1757 lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_PAETH]) >>
1758 PNG_COST_SHIFT;
1759
1760 if (lmhi > PNG_HIMASK)
1761 lmins = PNG_MAXSUM;
1762 else
1763 lmins = (lmhi << PNG_HISHIFT) + lmlo;
1764 }
1765#endif
Guy Schalnate5a37791996-06-05 15:50:50 -05001766
1767 for (i = 0, rp = row_buf + 1, dp = png_ptr->paeth_row + 1,
1768 pp = prev_row + 1; i < bpp; i++, rp++, pp++, dp++)
1769 {
1770 v = *dp = (png_byte)(((int)*rp - (int)*pp) & 0xff);
1771
1772 sum += (v < 128) ? v : 256 - v;
1773 }
1774 for (lp = row_buf + 1, cp = prev_row + 1; i < row_info->rowbytes;
1775 i++, rp++, pp++, lp++, dp++, cp++)
1776 {
1777 int a, b, c, pa, pb, pc, p;
1778
1779 b = *pp;
1780 c = *cp;
1781 a = *lp;
1782
1783 p = a + b - c;
1784 pa = abs(p - a);
1785 pb = abs(p - b);
1786 pc = abs(p - c);
1787
1788 if (pa <= pb && pa <= pc)
1789 p = a;
1790 else if (pb <= pc)
1791 p = b;
1792 else
1793 p = c;
1794
1795 v = *dp = (png_byte)(((int)*rp - p) & 0xff);
1796
1797 sum += (v < 128) ? v : 256 - v;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001798
1799 if (sum > lmins) /* We are already worse, don't continue. */
1800 break;
Guy Schalnate5a37791996-06-05 15:50:50 -05001801 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05001802
1803#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
1804 if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
1805 {
1806 png_uint_32 sumhi, sumlo;
1807 sumlo = sum & PNG_LOMASK;
1808 sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;
1809
1810 for (i = 0; i < png_ptr->num_prev_filters; i++)
1811 {
1812 if (png_ptr->prev_filters[i] == PNG_FILTER_PAETH)
1813 {
1814 sumlo = (sumlo * png_ptr->filter_weights[i]) >>
1815 PNG_WEIGHT_SHIFT;
1816 sumhi = (sumhi * png_ptr->filter_weights[i]) >>
1817 PNG_WEIGHT_SHIFT;
1818 }
1819 }
1820
1821 sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_PAETH]) >>
1822 PNG_COST_SHIFT;
1823 sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_PAETH]) >>
1824 PNG_COST_SHIFT;
1825
1826 if (sumhi > PNG_HIMASK)
1827 sum = PNG_MAXSUM;
1828 else
1829 sum = (sumhi << PNG_HISHIFT) + sumlo;
1830 }
1831#endif
1832
Guy Schalnate5a37791996-06-05 15:50:50 -05001833 if (sum < mins)
1834 {
1835 best_row = png_ptr->paeth_row;
1836 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001837 }
1838
Andreas Dilger47a0c421997-05-16 02:46:07 -05001839 /* Do the actual writing of the filtered row data from the chosen filter. */
Guy Schalnate5a37791996-06-05 15:50:50 -05001840 png_write_filtered_row(png_ptr, best_row);
Andreas Dilger47a0c421997-05-16 02:46:07 -05001841
1842#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
1843 /* Save the type of filter we picked this time for future calculations */
1844 if (png_ptr->num_prev_filters > 0)
1845 {
1846 png_byte i;
1847
1848 for (i = 1; i < png_ptr->num_prev_filters; i++)
1849 {
1850 png_ptr->prev_filters[i] = png_ptr->prev_filters[i - 1];
1851 }
1852 png_ptr->prev_filters[i] = best_row[0];
1853 }
1854#endif
Guy Schalnate5a37791996-06-05 15:50:50 -05001855}
1856
1857
Andreas Dilger47a0c421997-05-16 02:46:07 -05001858/* Do the actual writing of a previously filtered row. */
Guy Schalnate5a37791996-06-05 15:50:50 -05001859void
1860png_write_filtered_row(png_structp png_ptr, png_bytep filtered_row)
1861{
Andreas Dilger47a0c421997-05-16 02:46:07 -05001862 png_debug(1, "in png_write_filtered_row\n");
1863 png_debug1(2, "filter = %d\n", filtered_row[0]);
Guy Schalnate5a37791996-06-05 15:50:50 -05001864 /* set up the zlib input buffer */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001865 png_ptr->zstream.next_in = filtered_row;
1866 png_ptr->zstream.avail_in = (uInt)png_ptr->row_info.rowbytes + 1;
Guy Schalnate5a37791996-06-05 15:50:50 -05001867 /* repeat until we have compressed all the data */
1868 do
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001869 {
Guy Schalnate5a37791996-06-05 15:50:50 -05001870 int ret; /* return of zlib */
Guy Schalnat0d580581995-07-20 02:43:20 -05001871
Guy Schalnate5a37791996-06-05 15:50:50 -05001872 /* compress the data */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001873 ret = deflate(&png_ptr->zstream, Z_NO_FLUSH);
Guy Schalnate5a37791996-06-05 15:50:50 -05001874 /* check for compression errors */
1875 if (ret != Z_OK)
1876 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001877 if (png_ptr->zstream.msg != NULL)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001878 png_error(png_ptr, png_ptr->zstream.msg);
Guy Schalnate5a37791996-06-05 15:50:50 -05001879 else
1880 png_error(png_ptr, "zlib error");
1881 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001882
Guy Schalnate5a37791996-06-05 15:50:50 -05001883 /* see if it is time to write another IDAT */
Andreas Dilger47a0c421997-05-16 02:46:07 -05001884 if (!(png_ptr->zstream.avail_out))
Guy Schalnate5a37791996-06-05 15:50:50 -05001885 {
1886 /* write the IDAT and reset the zlib output buffer */
1887 png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001888 png_ptr->zstream.next_out = png_ptr->zbuf;
1889 png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
Guy Schalnate5a37791996-06-05 15:50:50 -05001890 }
1891 /* repeat until all data has been compressed */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001892 } while (png_ptr->zstream.avail_in);
Guy Schalnate5a37791996-06-05 15:50:50 -05001893
Guy Schalnatc21f90c1996-06-17 16:24:45 -05001894 /* swap the current and previous rows */
Andreas Dilger47a0c421997-05-16 02:46:07 -05001895 if (png_ptr->prev_row != NULL)
Guy Schalnatc21f90c1996-06-17 16:24:45 -05001896 {
1897 png_bytep tptr;
1898
1899 tptr = png_ptr->prev_row;
1900 png_ptr->prev_row = png_ptr->row_buf;
1901 png_ptr->row_buf = tptr;
1902 }
1903
Guy Schalnate5a37791996-06-05 15:50:50 -05001904 /* finish row - updates counters and flushes zlib if last row */
1905 png_write_finish_row(png_ptr);
1906
1907#if defined(PNG_WRITE_FLUSH_SUPPORTED)
1908 png_ptr->flush_rows++;
1909
1910 if (png_ptr->flush_dist > 0 &&
1911 png_ptr->flush_rows >= png_ptr->flush_dist)
Guy Schalnat0d580581995-07-20 02:43:20 -05001912 {
Guy Schalnate5a37791996-06-05 15:50:50 -05001913 png_write_flush(png_ptr);
Guy Schalnat0d580581995-07-20 02:43:20 -05001914 }
Guy Schalnate5a37791996-06-05 15:50:50 -05001915#endif /* PNG_WRITE_FLUSH_SUPPORTED */
Guy Schalnat0d580581995-07-20 02:43:20 -05001916}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001917