blob: 2b08369cad9d098cea5c8bb6185801441d2e2786 [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
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06003 *
Glenn Randers-Pehrson074af5e1999-11-28 23:32:18 -06004 * libpng 1.0.5d - November 29, 1999
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06005 * For conditions of distribution and use, see copyright notice in png.h
6 * Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
7 * Copyright (c) 1996, 1997 Andreas Dilger
Glenn Randers-Pehrsonc9442291999-01-06 21:50:16 -06008 * Copyright (c) 1998, 1999 Glenn Randers-Pehrson
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06009 */
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
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -060029 * complement format. If this isn't the case, then this routine needs to
30 * be modified to write data in two's complement format.
31 */
Andreas Dilger47a0c421997-05-16 02:46:07 -050032void
33png_save_int_32(png_bytep buf, png_int_32 i)
34{
35 buf[0] = (png_byte)((i >> 24) & 0xff);
36 buf[1] = (png_byte)((i >> 16) & 0xff);
37 buf[2] = (png_byte)((i >> 8) & 0xff);
38 buf[3] = (png_byte)(i & 0xff);
39}
40#endif
41
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -060042/* Place a 16-bit number into a buffer in PNG byte order.
43 * The parameter is declared unsigned int, not png_uint_16,
44 * just to avoid potential problems on pre-ANSI C compilers.
45 */
Guy Schalnat0d580581995-07-20 02:43:20 -050046void
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -060047png_save_uint_16(png_bytep buf, unsigned int i)
Guy Schalnat0d580581995-07-20 02:43:20 -050048{
49 buf[0] = (png_byte)((i >> 8) & 0xff);
50 buf[1] = (png_byte)(i & 0xff);
51}
52
Andreas Dilger47a0c421997-05-16 02:46:07 -050053/* Write a PNG chunk all at once. The type is an array of ASCII characters
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -060054 * representing the chunk name. The array must be at least 4 bytes in
55 * length, and does not need to be null terminated. To be safe, pass the
56 * pre-defined chunk names here, and if you need a new one, define it
57 * where the others are defined. The length is the length of the data.
58 * All the data must be present. If that is not possible, use the
59 * png_write_chunk_start(), png_write_chunk_data(), and png_write_chunk_end()
60 * functions instead.
61 */
Guy Schalnat0d580581995-07-20 02:43:20 -050062void
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060063png_write_chunk(png_structp png_ptr, png_bytep chunk_name,
Andreas Dilger47a0c421997-05-16 02:46:07 -050064 png_bytep data, png_size_t length)
Guy Schalnat0d580581995-07-20 02:43:20 -050065{
Andreas Dilger47a0c421997-05-16 02:46:07 -050066 png_write_chunk_start(png_ptr, chunk_name, (png_uint_32)length);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060067 png_write_chunk_data(png_ptr, data, length);
68 png_write_chunk_end(png_ptr);
Guy Schalnat0d580581995-07-20 02:43:20 -050069}
70
Andreas Dilger47a0c421997-05-16 02:46:07 -050071/* Write the start of a PNG chunk. The type is the chunk type.
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -060072 * The total_length is the sum of the lengths of all the data you will be
73 * passing in png_write_chunk_data().
74 */
Guy Schalnat0d580581995-07-20 02:43:20 -050075void
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060076png_write_chunk_start(png_structp png_ptr, png_bytep chunk_name,
77 png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -050078{
Andreas Dilger47a0c421997-05-16 02:46:07 -050079 png_byte buf[4];
80 png_debug2(0, "Writing %s chunk (%d bytes)\n", chunk_name, length);
81
Guy Schalnat0d580581995-07-20 02:43:20 -050082 /* write the length */
Andreas Dilger47a0c421997-05-16 02:46:07 -050083 png_save_uint_32(buf, length);
84 png_write_data(png_ptr, buf, (png_size_t)4);
85
Guy Schalnat0d580581995-07-20 02:43:20 -050086 /* write the chunk name */
Andreas Dilger47a0c421997-05-16 02:46:07 -050087 png_write_data(png_ptr, chunk_name, (png_size_t)4);
Guy Schalnat0d580581995-07-20 02:43:20 -050088 /* reset the crc and run it over the chunk name */
89 png_reset_crc(png_ptr);
Andreas Dilger47a0c421997-05-16 02:46:07 -050090 png_calculate_crc(png_ptr, chunk_name, (png_size_t)4);
Guy Schalnat0d580581995-07-20 02:43:20 -050091}
92
Andreas Dilger47a0c421997-05-16 02:46:07 -050093/* Write the data of a PNG chunk started with png_write_chunk_start().
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -060094 * Note that multiple calls to this function are allowed, and that the
95 * sum of the lengths from these calls *must* add up to the total_length
96 * given to png_write_chunk_start().
97 */
Guy Schalnat0d580581995-07-20 02:43:20 -050098void
Andreas Dilger47a0c421997-05-16 02:46:07 -050099png_write_chunk_data(png_structp png_ptr, png_bytep data, png_size_t length)
Guy Schalnat0d580581995-07-20 02:43:20 -0500100{
Andreas Dilger47a0c421997-05-16 02:46:07 -0500101 /* write the data, and run the CRC over it */
102 if (data != NULL && length > 0)
Guy Schalnat0d580581995-07-20 02:43:20 -0500103 {
104 png_calculate_crc(png_ptr, data, length);
Guy Schalnat6d764711995-12-19 03:22:19 -0600105 png_write_data(png_ptr, data, length);
Guy Schalnat0d580581995-07-20 02:43:20 -0500106 }
107}
108
Andreas Dilger47a0c421997-05-16 02:46:07 -0500109/* Finish a chunk started with png_write_chunk_start(). */
Guy Schalnat0d580581995-07-20 02:43:20 -0500110void
Guy Schalnat6d764711995-12-19 03:22:19 -0600111png_write_chunk_end(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -0500112{
Andreas Dilger47a0c421997-05-16 02:46:07 -0500113 png_byte buf[4];
114
Guy Schalnat0d580581995-07-20 02:43:20 -0500115 /* write the crc */
Andreas Dilger47a0c421997-05-16 02:46:07 -0500116 png_save_uint_32(buf, png_ptr->crc);
Andreas Dilger47a0c421997-05-16 02:46:07 -0500117
118 png_write_data(png_ptr, buf, (png_size_t)4);
Guy Schalnat0d580581995-07-20 02:43:20 -0500119}
120
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600121/* Simple function to write the signature. If we have already written
122 * the magic bytes of the signature, or more likely, the PNG stream is
123 * being embedded into another stream and doesn't need its own signature,
124 * we should call png_set_sig_bytes() to tell libpng how many of the
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600125 * bytes have already been written.
126 */
Guy Schalnat0d580581995-07-20 02:43:20 -0500127void
Guy Schalnat6d764711995-12-19 03:22:19 -0600128png_write_sig(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -0500129{
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -0600130 png_byte png_signature[8] = {137, 80, 78, 71, 13, 10, 26, 10};
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600131 /* write the rest of the 8 byte signature */
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -0600132 png_write_data(png_ptr, &png_signature[png_ptr->sig_bytes],
Andreas Dilger47a0c421997-05-16 02:46:07 -0500133 (png_size_t)8 - png_ptr->sig_bytes);
Guy Schalnat0d580581995-07-20 02:43:20 -0500134}
135
136/* Write the IHDR chunk, and update the png_struct with the necessary
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600137 * information. Note that the rest of this code depends upon this
138 * information being correct.
139 */
Guy Schalnat0d580581995-07-20 02:43:20 -0500140void
Guy Schalnat6d764711995-12-19 03:22:19 -0600141png_write_IHDR(png_structp png_ptr, png_uint_32 width, png_uint_32 height,
Guy Schalnat0d580581995-07-20 02:43:20 -0500142 int bit_depth, int color_type, int compression_type, int filter_type,
143 int interlace_type)
144{
Glenn Randers-Pehrson074af5e1999-11-28 23:32:18 -0600145#ifdef PNG_USE_LOCAL_ARRAYS
146 PNG_IHDR;
147#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500148 png_byte buf[13]; /* buffer to store the IHDR info */
149
Andreas Dilger47a0c421997-05-16 02:46:07 -0500150 png_debug(1, "in png_write_IHDR\n");
Guy Schalnate5a37791996-06-05 15:50:50 -0500151 /* Check that we have valid input data from the application info */
152 switch (color_type)
153 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500154 case PNG_COLOR_TYPE_GRAY:
Guy Schalnate5a37791996-06-05 15:50:50 -0500155 switch (bit_depth)
156 {
157 case 1:
158 case 2:
159 case 4:
160 case 8:
161 case 16: png_ptr->channels = 1; break;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500162 default: png_error(png_ptr,"Invalid bit depth for grayscale image");
Guy Schalnate5a37791996-06-05 15:50:50 -0500163 }
164 break;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500165 case PNG_COLOR_TYPE_RGB:
Guy Schalnate5a37791996-06-05 15:50:50 -0500166 if (bit_depth != 8 && bit_depth != 16)
167 png_error(png_ptr, "Invalid bit depth for RGB image");
168 png_ptr->channels = 3;
169 break;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500170 case PNG_COLOR_TYPE_PALETTE:
Guy Schalnate5a37791996-06-05 15:50:50 -0500171 switch (bit_depth)
172 {
173 case 1:
174 case 2:
175 case 4:
176 case 8: png_ptr->channels = 1; break;
177 default: png_error(png_ptr, "Invalid bit depth for paletted image");
178 }
179 break;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500180 case PNG_COLOR_TYPE_GRAY_ALPHA:
Guy Schalnate5a37791996-06-05 15:50:50 -0500181 if (bit_depth != 8 && bit_depth != 16)
182 png_error(png_ptr, "Invalid bit depth for grayscale+alpha image");
183 png_ptr->channels = 2;
184 break;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500185 case PNG_COLOR_TYPE_RGB_ALPHA:
Guy Schalnate5a37791996-06-05 15:50:50 -0500186 if (bit_depth != 8 && bit_depth != 16)
187 png_error(png_ptr, "Invalid bit depth for RGBA image");
188 png_ptr->channels = 4;
189 break;
190 default:
191 png_error(png_ptr, "Invalid image color type specified");
192 }
193
Andreas Dilger47a0c421997-05-16 02:46:07 -0500194 if (compression_type != PNG_COMPRESSION_TYPE_BASE)
Guy Schalnate5a37791996-06-05 15:50:50 -0500195 {
196 png_warning(png_ptr, "Invalid compression type specified");
Andreas Dilger47a0c421997-05-16 02:46:07 -0500197 compression_type = PNG_COMPRESSION_TYPE_BASE;
Guy Schalnate5a37791996-06-05 15:50:50 -0500198 }
199
Andreas Dilger47a0c421997-05-16 02:46:07 -0500200 if (filter_type != PNG_FILTER_TYPE_BASE)
Guy Schalnate5a37791996-06-05 15:50:50 -0500201 {
202 png_warning(png_ptr, "Invalid filter type specified");
Andreas Dilger47a0c421997-05-16 02:46:07 -0500203 filter_type = PNG_FILTER_TYPE_BASE;
Guy Schalnate5a37791996-06-05 15:50:50 -0500204 }
205
Glenn Randers-Pehrson46f61e21998-01-30 21:45:12 -0600206#ifdef PNG_WRITE_INTERLACING_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -0500207 if (interlace_type != PNG_INTERLACE_NONE &&
208 interlace_type != PNG_INTERLACE_ADAM7)
Guy Schalnate5a37791996-06-05 15:50:50 -0500209 {
210 png_warning(png_ptr, "Invalid interlace type specified");
Andreas Dilger47a0c421997-05-16 02:46:07 -0500211 interlace_type = PNG_INTERLACE_ADAM7;
Guy Schalnate5a37791996-06-05 15:50:50 -0500212 }
Glenn Randers-Pehrson46f61e21998-01-30 21:45:12 -0600213#else
214 interlace_type=PNG_INTERLACE_NONE;
215#endif
Guy Schalnate5a37791996-06-05 15:50:50 -0500216
217 /* save off the relevent information */
218 png_ptr->bit_depth = (png_byte)bit_depth;
219 png_ptr->color_type = (png_byte)color_type;
220 png_ptr->interlaced = (png_byte)interlace_type;
221 png_ptr->width = width;
222 png_ptr->height = height;
223
224 png_ptr->pixel_depth = (png_byte)(bit_depth * png_ptr->channels);
Andreas Dilger47a0c421997-05-16 02:46:07 -0500225 png_ptr->rowbytes = ((width * (png_size_t)png_ptr->pixel_depth + 7) >> 3);
Guy Schalnate5a37791996-06-05 15:50:50 -0500226 /* set the usr info, so any transformations can modify it */
227 png_ptr->usr_width = png_ptr->width;
228 png_ptr->usr_bit_depth = png_ptr->bit_depth;
229 png_ptr->usr_channels = png_ptr->channels;
230
Guy Schalnat0d580581995-07-20 02:43:20 -0500231 /* pack the header information into the buffer */
232 png_save_uint_32(buf, width);
233 png_save_uint_32(buf + 4, height);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600234 buf[8] = (png_byte)bit_depth;
235 buf[9] = (png_byte)color_type;
236 buf[10] = (png_byte)compression_type;
237 buf[11] = (png_byte)filter_type;
238 buf[12] = (png_byte)interlace_type;
Guy Schalnat0d580581995-07-20 02:43:20 -0500239
240 /* write the chunk */
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -0600241 png_write_chunk(png_ptr, (png_bytep)png_IHDR, buf, (png_size_t)13);
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500242
Andreas Dilger47a0c421997-05-16 02:46:07 -0500243 /* initialize zlib with PNG info */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600244 png_ptr->zstream.zalloc = png_zalloc;
245 png_ptr->zstream.zfree = png_zfree;
246 png_ptr->zstream.opaque = (voidpf)png_ptr;
Guy Schalnate5a37791996-06-05 15:50:50 -0500247 if (!(png_ptr->do_filter))
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500248 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500249 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE ||
250 png_ptr->bit_depth < 8)
Guy Schalnate5a37791996-06-05 15:50:50 -0500251 png_ptr->do_filter = PNG_FILTER_NONE;
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500252 else
Guy Schalnate5a37791996-06-05 15:50:50 -0500253 png_ptr->do_filter = PNG_ALL_FILTERS;
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500254 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500255 if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_STRATEGY))
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500256 {
Guy Schalnate5a37791996-06-05 15:50:50 -0500257 if (png_ptr->do_filter != PNG_FILTER_NONE)
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500258 png_ptr->zlib_strategy = Z_FILTERED;
259 else
260 png_ptr->zlib_strategy = Z_DEFAULT_STRATEGY;
261 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500262 if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_LEVEL))
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500263 png_ptr->zlib_level = Z_DEFAULT_COMPRESSION;
Guy Schalnate5a37791996-06-05 15:50:50 -0500264 if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_MEM_LEVEL))
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500265 png_ptr->zlib_mem_level = 8;
Guy Schalnate5a37791996-06-05 15:50:50 -0500266 if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_WINDOW_BITS))
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500267 png_ptr->zlib_window_bits = 15;
Guy Schalnate5a37791996-06-05 15:50:50 -0500268 if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_METHOD))
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500269 png_ptr->zlib_method = 8;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600270 deflateInit2(&png_ptr->zstream, png_ptr->zlib_level,
Andreas Dilger47a0c421997-05-16 02:46:07 -0500271 png_ptr->zlib_method, png_ptr->zlib_window_bits,
272 png_ptr->zlib_mem_level, png_ptr->zlib_strategy);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600273 png_ptr->zstream.next_out = png_ptr->zbuf;
274 png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500275
Guy Schalnate5a37791996-06-05 15:50:50 -0500276 png_ptr->mode = PNG_HAVE_IHDR;
Guy Schalnat0d580581995-07-20 02:43:20 -0500277}
278
279/* write the palette. We are careful not to trust png_color to be in the
Glenn Randers-Pehrson345bc271998-06-14 14:43:31 -0500280 * correct order for PNG, so people can redefine it to any convenient
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600281 * structure.
282 */
Guy Schalnat0d580581995-07-20 02:43:20 -0500283void
Andreas Dilger47a0c421997-05-16 02:46:07 -0500284png_write_PLTE(png_structp png_ptr, png_colorp palette, png_uint_32 num_pal)
Guy Schalnat0d580581995-07-20 02:43:20 -0500285{
Glenn Randers-Pehrson074af5e1999-11-28 23:32:18 -0600286#ifdef PNG_USE_LOCAL_ARRAYS
287 PNG_PLTE;
288#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -0500289 png_uint_32 i;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600290 png_colorp pal_ptr;
Guy Schalnat0d580581995-07-20 02:43:20 -0500291 png_byte buf[3];
292
Andreas Dilger47a0c421997-05-16 02:46:07 -0500293 png_debug(1, "in png_write_PLTE\n");
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -0500294 if ((
295#ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
296 !png_ptr->empty_plte_permitted &&
297#endif
298 num_pal == 0) || num_pal > 256)
299 {
300 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
301 {
302 png_error(png_ptr, "Invalid number of colors in palette");
303 }
304 else
305 {
306 png_warning(png_ptr, "Invalid number of colors in palette");
307 return;
308 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500309 }
310
Andreas Dilger47a0c421997-05-16 02:46:07 -0500311 png_ptr->num_palette = (png_uint_16)num_pal;
312 png_debug1(3, "num_palette = %d\n", png_ptr->num_palette);
Guy Schalnate5a37791996-06-05 15:50:50 -0500313
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -0600314 png_write_chunk_start(png_ptr, (png_bytep)png_PLTE, num_pal * 3);
Andreas Dilger47a0c421997-05-16 02:46:07 -0500315 for (i = 0, pal_ptr = palette; i < num_pal; i++, pal_ptr++)
Guy Schalnat0d580581995-07-20 02:43:20 -0500316 {
317 buf[0] = pal_ptr->red;
318 buf[1] = pal_ptr->green;
319 buf[2] = pal_ptr->blue;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500320 png_write_chunk_data(png_ptr, buf, (png_size_t)3);
Guy Schalnat0d580581995-07-20 02:43:20 -0500321 }
322 png_write_chunk_end(png_ptr);
Guy Schalnate5a37791996-06-05 15:50:50 -0500323 png_ptr->mode |= PNG_HAVE_PLTE;
Guy Schalnat0d580581995-07-20 02:43:20 -0500324}
325
326/* write an IDAT chunk */
327void
Andreas Dilger47a0c421997-05-16 02:46:07 -0500328png_write_IDAT(png_structp png_ptr, png_bytep data, png_size_t length)
Guy Schalnat0d580581995-07-20 02:43:20 -0500329{
Glenn Randers-Pehrson074af5e1999-11-28 23:32:18 -0600330#ifdef PNG_USE_LOCAL_ARRAYS
331 PNG_IDAT;
332#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -0500333 png_debug(1, "in png_write_IDAT\n");
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -0600334 png_write_chunk(png_ptr, (png_bytep)png_IDAT, data, length);
Guy Schalnate5a37791996-06-05 15:50:50 -0500335 png_ptr->mode |= PNG_HAVE_IDAT;
Guy Schalnat0d580581995-07-20 02:43:20 -0500336}
337
338/* write an IEND chunk */
339void
Guy Schalnat6d764711995-12-19 03:22:19 -0600340png_write_IEND(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -0500341{
Glenn Randers-Pehrson074af5e1999-11-28 23:32:18 -0600342#ifdef PNG_USE_LOCAL_ARRAYS
343 PNG_IEND;
344#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -0500345 png_debug(1, "in png_write_IEND\n");
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -0600346 png_write_chunk(png_ptr, (png_bytep)png_IEND, NULL, (png_size_t)0);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600347 png_ptr->mode |= PNG_HAVE_IEND;
Guy Schalnat0d580581995-07-20 02:43:20 -0500348}
349
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500350#if defined(PNG_WRITE_gAMA_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500351/* write a gAMA chunk */
352void
Andreas Dilger47a0c421997-05-16 02:46:07 -0500353png_write_gAMA(png_structp png_ptr, double file_gamma)
Guy Schalnat0d580581995-07-20 02:43:20 -0500354{
Glenn Randers-Pehrson074af5e1999-11-28 23:32:18 -0600355#ifdef PNG_USE_LOCAL_ARRAYS
356 PNG_gAMA;
357#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500358 png_uint_32 igamma;
359 png_byte buf[4];
360
Andreas Dilger47a0c421997-05-16 02:46:07 -0500361 png_debug(1, "in png_write_gAMA\n");
Glenn Randers-Pehrson8f8fb6a1998-03-09 23:02:06 -0600362 /* file_gamma is saved in 1/1000000ths */
Glenn Randers-Pehrson397100e1998-03-07 19:45:37 -0600363 igamma = (png_uint_32)(file_gamma * 100000.0 + 0.5);
Guy Schalnat0d580581995-07-20 02:43:20 -0500364 png_save_uint_32(buf, igamma);
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -0600365 png_write_chunk(png_ptr, (png_bytep)png_gAMA, buf, (png_size_t)4);
Guy Schalnat0d580581995-07-20 02:43:20 -0500366}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500367#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500368
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600369#if defined(PNG_WRITE_sRGB_SUPPORTED)
370/* write a sRGB chunk */
371void
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600372png_write_sRGB(png_structp png_ptr, int srgb_intent)
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600373{
Glenn Randers-Pehrson074af5e1999-11-28 23:32:18 -0600374#ifdef PNG_USE_LOCAL_ARRAYS
375 PNG_sRGB;
376#endif
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600377 png_byte buf[1];
378
379 png_debug(1, "in png_write_sRGB\n");
Glenn Randers-Pehrson46f61e21998-01-30 21:45:12 -0600380 if(srgb_intent >= PNG_sRGB_INTENT_LAST)
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600381 png_warning(png_ptr,
382 "Invalid sRGB rendering intent specified");
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600383 buf[0]=(png_byte)srgb_intent;
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -0600384 png_write_chunk(png_ptr, (png_bytep)png_sRGB, buf, (png_size_t)1);
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600385}
386#endif
387
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500388#if defined(PNG_WRITE_sBIT_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500389/* write the sBIT chunk */
390void
Guy Schalnat6d764711995-12-19 03:22:19 -0600391png_write_sBIT(png_structp png_ptr, png_color_8p sbit, int color_type)
Guy Schalnat0d580581995-07-20 02:43:20 -0500392{
Glenn Randers-Pehrson074af5e1999-11-28 23:32:18 -0600393#ifdef PNG_USE_LOCAL_ARRAYS
394 PNG_sBIT;
395#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500396 png_byte buf[4];
Andreas Dilger47a0c421997-05-16 02:46:07 -0500397 png_size_t size;
Guy Schalnat0d580581995-07-20 02:43:20 -0500398
Andreas Dilger47a0c421997-05-16 02:46:07 -0500399 png_debug(1, "in png_write_sBIT\n");
Guy Schalnat6d764711995-12-19 03:22:19 -0600400 /* make sure we don't depend upon the order of PNG_COLOR_8 */
Guy Schalnat0d580581995-07-20 02:43:20 -0500401 if (color_type & PNG_COLOR_MASK_COLOR)
402 {
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -0600403 png_byte maxbits;
Guy Schalnate5a37791996-06-05 15:50:50 -0500404
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -0500405 maxbits = (png_byte)(color_type==PNG_COLOR_TYPE_PALETTE ? 8 :
406 png_ptr->usr_bit_depth);
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600407 if (sbit->red == 0 || sbit->red > maxbits ||
408 sbit->green == 0 || sbit->green > maxbits ||
Guy Schalnate5a37791996-06-05 15:50:50 -0500409 sbit->blue == 0 || sbit->blue > maxbits)
410 {
411 png_warning(png_ptr, "Invalid sBIT depth specified");
412 return;
413 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500414 buf[0] = sbit->red;
415 buf[1] = sbit->green;
416 buf[2] = sbit->blue;
417 size = 3;
418 }
419 else
420 {
Guy Schalnate5a37791996-06-05 15:50:50 -0500421 if (sbit->gray == 0 || sbit->gray > png_ptr->usr_bit_depth)
422 {
423 png_warning(png_ptr, "Invalid sBIT depth specified");
424 return;
425 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500426 buf[0] = sbit->gray;
427 size = 1;
428 }
429
430 if (color_type & PNG_COLOR_MASK_ALPHA)
431 {
Guy Schalnate5a37791996-06-05 15:50:50 -0500432 if (sbit->alpha == 0 || sbit->alpha > png_ptr->usr_bit_depth)
433 {
434 png_warning(png_ptr, "Invalid sBIT depth specified");
435 return;
436 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500437 buf[size++] = sbit->alpha;
438 }
439
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -0600440 png_write_chunk(png_ptr, (png_bytep)png_sBIT, buf, size);
Guy Schalnat0d580581995-07-20 02:43:20 -0500441}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500442#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500443
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500444#if defined(PNG_WRITE_cHRM_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500445/* write the cHRM chunk */
446void
Andreas Dilger47a0c421997-05-16 02:46:07 -0500447png_write_cHRM(png_structp png_ptr, double white_x, double white_y,
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600448 double red_x, double red_y, double green_x, double green_y,
449 double blue_x, double blue_y)
Guy Schalnat0d580581995-07-20 02:43:20 -0500450{
Glenn Randers-Pehrson074af5e1999-11-28 23:32:18 -0600451#ifdef PNG_USE_LOCAL_ARRAYS
452 PNG_cHRM;
453#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500454 png_uint_32 itemp;
455 png_byte buf[32];
456
Andreas Dilger47a0c421997-05-16 02:46:07 -0500457 png_debug(1, "in png_write_cHRM\n");
Glenn Randers-Pehrson8f8fb6a1998-03-09 23:02:06 -0600458 /* each value is saved int 1/1000000ths */
Guy Schalnate5a37791996-06-05 15:50:50 -0500459 if (white_x < 0 || white_x > 0.8 || white_y < 0 || white_y > 0.8 ||
460 white_x + white_y > 1.0)
461 {
462 png_warning(png_ptr, "Invalid cHRM white point specified");
463 return;
464 }
Glenn Randers-Pehrson397100e1998-03-07 19:45:37 -0600465 itemp = (png_uint_32)(white_x * 100000.0 + 0.5);
Guy Schalnat0d580581995-07-20 02:43:20 -0500466 png_save_uint_32(buf, itemp);
Glenn Randers-Pehrson397100e1998-03-07 19:45:37 -0600467 itemp = (png_uint_32)(white_y * 100000.0 + 0.5);
Guy Schalnat0d580581995-07-20 02:43:20 -0500468 png_save_uint_32(buf + 4, itemp);
Guy Schalnate5a37791996-06-05 15:50:50 -0500469
470 if (red_x < 0 || red_x > 0.8 || red_y < 0 || red_y > 0.8 ||
471 red_x + red_y > 1.0)
472 {
473 png_warning(png_ptr, "Invalid cHRM red point specified");
474 return;
475 }
Glenn Randers-Pehrson397100e1998-03-07 19:45:37 -0600476 itemp = (png_uint_32)(red_x * 100000.0 + 0.5);
Guy Schalnat0d580581995-07-20 02:43:20 -0500477 png_save_uint_32(buf + 8, itemp);
Glenn Randers-Pehrson397100e1998-03-07 19:45:37 -0600478 itemp = (png_uint_32)(red_y * 100000.0 + 0.5);
Guy Schalnat0d580581995-07-20 02:43:20 -0500479 png_save_uint_32(buf + 12, itemp);
Guy Schalnate5a37791996-06-05 15:50:50 -0500480
481 if (green_x < 0 || green_x > 0.8 || green_y < 0 || green_y > 0.8 ||
482 green_x + green_y > 1.0)
483 {
484 png_warning(png_ptr, "Invalid cHRM green point specified");
485 return;
486 }
Glenn Randers-Pehrson397100e1998-03-07 19:45:37 -0600487 itemp = (png_uint_32)(green_x * 100000.0 + 0.5);
Guy Schalnat0d580581995-07-20 02:43:20 -0500488 png_save_uint_32(buf + 16, itemp);
Glenn Randers-Pehrson397100e1998-03-07 19:45:37 -0600489 itemp = (png_uint_32)(green_y * 100000.0 + 0.5);
Guy Schalnat0d580581995-07-20 02:43:20 -0500490 png_save_uint_32(buf + 20, itemp);
Guy Schalnate5a37791996-06-05 15:50:50 -0500491
492 if (blue_x < 0 || blue_x > 0.8 || blue_y < 0 || blue_y > 0.8 ||
493 blue_x + blue_y > 1.0)
494 {
495 png_warning(png_ptr, "Invalid cHRM blue point specified");
496 return;
497 }
Glenn Randers-Pehrson397100e1998-03-07 19:45:37 -0600498 itemp = (png_uint_32)(blue_x * 100000.0 + 0.5);
Guy Schalnat0d580581995-07-20 02:43:20 -0500499 png_save_uint_32(buf + 24, itemp);
Glenn Randers-Pehrson397100e1998-03-07 19:45:37 -0600500 itemp = (png_uint_32)(blue_y * 100000.0 + 0.5);
Guy Schalnat0d580581995-07-20 02:43:20 -0500501 png_save_uint_32(buf + 28, itemp);
Guy Schalnate5a37791996-06-05 15:50:50 -0500502
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -0600503 png_write_chunk(png_ptr, (png_bytep)png_cHRM, buf, (png_size_t)32);
Guy Schalnat0d580581995-07-20 02:43:20 -0500504}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500505#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500506
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500507#if defined(PNG_WRITE_tRNS_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500508/* write the tRNS chunk */
509void
Guy Schalnat6d764711995-12-19 03:22:19 -0600510png_write_tRNS(png_structp png_ptr, png_bytep trans, png_color_16p tran,
Guy Schalnat0d580581995-07-20 02:43:20 -0500511 int num_trans, int color_type)
512{
Glenn Randers-Pehrson074af5e1999-11-28 23:32:18 -0600513#ifdef PNG_USE_LOCAL_ARRAYS
514 PNG_tRNS;
515#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500516 png_byte buf[6];
517
Andreas Dilger47a0c421997-05-16 02:46:07 -0500518 png_debug(1, "in png_write_tRNS\n");
Guy Schalnat0d580581995-07-20 02:43:20 -0500519 if (color_type == PNG_COLOR_TYPE_PALETTE)
520 {
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -0600521 if (num_trans <= 0 || num_trans > (int)png_ptr->num_palette)
Guy Schalnate5a37791996-06-05 15:50:50 -0500522 {
523 png_warning(png_ptr,"Invalid number of transparent colors specified");
524 return;
525 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500526 /* write the chunk out as it is */
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -0600527 png_write_chunk(png_ptr, (png_bytep)png_tRNS, trans, (png_size_t)num_trans);
Guy Schalnat0d580581995-07-20 02:43:20 -0500528 }
529 else if (color_type == PNG_COLOR_TYPE_GRAY)
530 {
531 /* one 16 bit value */
532 png_save_uint_16(buf, tran->gray);
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -0600533 png_write_chunk(png_ptr, (png_bytep)png_tRNS, buf, (png_size_t)2);
Guy Schalnat0d580581995-07-20 02:43:20 -0500534 }
535 else if (color_type == PNG_COLOR_TYPE_RGB)
536 {
537 /* three 16 bit values */
538 png_save_uint_16(buf, tran->red);
539 png_save_uint_16(buf + 2, tran->green);
540 png_save_uint_16(buf + 4, tran->blue);
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -0600541 png_write_chunk(png_ptr, (png_bytep)png_tRNS, buf, (png_size_t)6);
Guy Schalnat0d580581995-07-20 02:43:20 -0500542 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500543 else
544 {
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600545 png_warning(png_ptr, "Can't write tRNS with an alpha channel");
Guy Schalnate5a37791996-06-05 15:50:50 -0500546 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500547}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500548#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500549
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500550#if defined(PNG_WRITE_bKGD_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500551/* write the background chunk */
552void
Guy Schalnat6d764711995-12-19 03:22:19 -0600553png_write_bKGD(png_structp png_ptr, png_color_16p back, int color_type)
Guy Schalnat0d580581995-07-20 02:43:20 -0500554{
Glenn Randers-Pehrson074af5e1999-11-28 23:32:18 -0600555#ifdef PNG_USE_LOCAL_ARRAYS
556 PNG_bKGD;
557#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500558 png_byte buf[6];
559
Andreas Dilger47a0c421997-05-16 02:46:07 -0500560 png_debug(1, "in png_write_bKGD\n");
Guy Schalnat0d580581995-07-20 02:43:20 -0500561 if (color_type == PNG_COLOR_TYPE_PALETTE)
562 {
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -0500563 if (
564#ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
565 (!png_ptr->empty_plte_permitted ||
566 (png_ptr->empty_plte_permitted && png_ptr->num_palette)) &&
567#endif
568 back->index > png_ptr->num_palette)
Guy Schalnate5a37791996-06-05 15:50:50 -0500569 {
570 png_warning(png_ptr, "Invalid background palette index");
571 return;
572 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500573 buf[0] = back->index;
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -0600574 png_write_chunk(png_ptr, (png_bytep)png_bKGD, buf, (png_size_t)1);
Guy Schalnat0d580581995-07-20 02:43:20 -0500575 }
576 else if (color_type & PNG_COLOR_MASK_COLOR)
577 {
578 png_save_uint_16(buf, back->red);
579 png_save_uint_16(buf + 2, back->green);
580 png_save_uint_16(buf + 4, back->blue);
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -0600581 png_write_chunk(png_ptr, (png_bytep)png_bKGD, buf, (png_size_t)6);
Guy Schalnat0d580581995-07-20 02:43:20 -0500582 }
583 else
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600584 {
Guy Schalnat0d580581995-07-20 02:43:20 -0500585 png_save_uint_16(buf, back->gray);
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -0600586 png_write_chunk(png_ptr, (png_bytep)png_bKGD, buf, (png_size_t)2);
Guy Schalnat0d580581995-07-20 02:43:20 -0500587 }
588}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500589#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500590
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500591#if defined(PNG_WRITE_hIST_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500592/* write the histogram */
593void
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -0600594png_write_hIST(png_structp png_ptr, png_uint_16p hist, int num_hist)
Guy Schalnat0d580581995-07-20 02:43:20 -0500595{
Glenn Randers-Pehrson074af5e1999-11-28 23:32:18 -0600596#ifdef PNG_USE_LOCAL_ARRAYS
597 PNG_hIST;
598#endif
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -0600599 int i;
Guy Schalnat0d580581995-07-20 02:43:20 -0500600 png_byte buf[3];
601
Andreas Dilger47a0c421997-05-16 02:46:07 -0500602 png_debug(1, "in png_write_hIST\n");
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -0600603 if (num_hist > (int)png_ptr->num_palette)
Guy Schalnate5a37791996-06-05 15:50:50 -0500604 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500605 png_debug2(3, "num_hist = %d, num_palette = %d\n", num_hist,
606 png_ptr->num_palette);
Guy Schalnate5a37791996-06-05 15:50:50 -0500607 png_warning(png_ptr, "Invalid number of histogram entries specified");
608 return;
609 }
610
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -0600611 png_write_chunk_start(png_ptr, (png_bytep)png_hIST, (png_uint_32)(num_hist * 2));
Andreas Dilger47a0c421997-05-16 02:46:07 -0500612 for (i = 0; i < num_hist; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -0500613 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600614 png_save_uint_16(buf, hist[i]);
Andreas Dilger47a0c421997-05-16 02:46:07 -0500615 png_write_chunk_data(png_ptr, buf, (png_size_t)2);
Guy Schalnat0d580581995-07-20 02:43:20 -0500616 }
617 png_write_chunk_end(png_ptr);
618}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500619#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500620
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -0500621#if defined(PNG_WRITE_tEXt_SUPPORTED) || defined(PNG_WRITE_zTXt_SUPPORTED) || \
622 defined(PNG_WRITE_pCAL_SUPPORTED)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600623/* Check that the tEXt or zTXt keyword is valid per PNG 1.0 specification,
624 * and if invalid, correct the keyword rather than discarding the entire
625 * chunk. The PNG 1.0 specification requires keywords 1-79 characters in
626 * length, forbids leading or trailing whitespace, multiple internal spaces,
627 * and the non-break space (0x80) from ISO 8859-1. Returns keyword length.
Andreas Dilger47a0c421997-05-16 02:46:07 -0500628 *
629 * The new_key is allocated to hold the corrected keyword and must be freed
630 * by the calling routine. This avoids problems with trying to write to
631 * static keywords without having to have duplicate copies of the strings.
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600632 */
Andreas Dilger47a0c421997-05-16 02:46:07 -0500633png_size_t
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600634png_check_keyword(png_structp png_ptr, png_charp key, png_charpp new_key)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600635{
Andreas Dilger47a0c421997-05-16 02:46:07 -0500636 png_size_t key_len;
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600637 png_charp kp, dp;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600638 int kflag;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600639
Andreas Dilger47a0c421997-05-16 02:46:07 -0500640 png_debug(1, "in png_check_keyword\n");
641 *new_key = NULL;
642
643 if (key == NULL || (key_len = png_strlen(key)) == 0)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600644 {
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -0600645 png_chunk_warning(png_ptr, "zero length keyword");
Glenn Randers-Pehrsonb2120021998-01-31 20:07:59 -0600646 return ((png_size_t)0);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600647 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600648
Andreas Dilger47a0c421997-05-16 02:46:07 -0500649 png_debug1(2, "Keyword to be checked is '%s'\n", key);
650
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -0600651 *new_key = (png_charp)png_malloc(png_ptr, (png_uint_32)(key_len + 1));
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600652
653 /* Replace non-printing characters with a blank and print a warning */
Andreas Dilger47a0c421997-05-16 02:46:07 -0500654 for (kp = key, dp = *new_key; *kp != '\0'; kp++, dp++)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600655 {
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -0600656 if (*kp < 0x20 || (*kp > 0x7E && (png_byte)*kp < 0xA1))
Andreas Dilger47a0c421997-05-16 02:46:07 -0500657 {
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -0600658#if !defined(PNG_NO_STDIO)
Andreas Dilger47a0c421997-05-16 02:46:07 -0500659 char msg[40];
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600660
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -0600661 sprintf(msg, "invalid keyword character 0x%02X", *kp);
662 png_chunk_warning(png_ptr, msg);
663#else
664 png_chunk_warning(png_ptr, "invalid character in keyword");
665#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -0500666 *dp = ' ';
667 }
668 else
669 {
670 *dp = *kp;
671 }
672 }
673 *dp = '\0';
674
675 /* Remove any trailing white space. */
676 kp = *new_key + key_len - 1;
677 if (*kp == ' ')
678 {
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -0600679 png_chunk_warning(png_ptr, "trailing spaces removed from keyword");
Andreas Dilger47a0c421997-05-16 02:46:07 -0500680
681 while (*kp == ' ')
682 {
683 *(kp--) = '\0';
684 key_len--;
685 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600686 }
687
688 /* Remove any leading white space. */
Andreas Dilger47a0c421997-05-16 02:46:07 -0500689 kp = *new_key;
690 if (*kp == ' ')
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600691 {
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -0600692 png_chunk_warning(png_ptr, "leading spaces removed from keyword");
Andreas Dilger47a0c421997-05-16 02:46:07 -0500693
694 while (*kp == ' ')
695 {
696 kp++;
697 key_len--;
698 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600699 }
700
Andreas Dilger47a0c421997-05-16 02:46:07 -0500701 png_debug1(2, "Checking for multiple internal spaces in '%s'\n", kp);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600702
Andreas Dilger47a0c421997-05-16 02:46:07 -0500703 /* Remove multiple internal spaces. */
704 for (kflag = 0, dp = *new_key; *kp != '\0'; kp++)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600705 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500706 if (*kp == ' ' && kflag == 0)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600707 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500708 *(dp++) = *kp;
709 kflag = 1;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600710 }
Andreas Dilger47a0c421997-05-16 02:46:07 -0500711 else if (*kp == ' ')
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600712 {
713 key_len--;
714 }
715 else
716 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500717 *(dp++) = *kp;
718 kflag = 0;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600719 }
720 }
Andreas Dilger47a0c421997-05-16 02:46:07 -0500721 *dp = '\0';
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600722
723 if (key_len == 0)
Andreas Dilger47a0c421997-05-16 02:46:07 -0500724 {
Glenn Randers-Pehrson6d8f3b01999-10-23 08:39:18 -0500725 png_free(png_ptr, *new_key);
726 *new_key=NULL;
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -0600727 png_chunk_warning(png_ptr, "zero length keyword");
Andreas Dilger47a0c421997-05-16 02:46:07 -0500728 }
729
730 if (key_len > 79)
731 {
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -0600732 png_chunk_warning(png_ptr, "keyword length must be 1 - 79 characters");
Andreas Dilger47a0c421997-05-16 02:46:07 -0500733 new_key[79] = '\0';
734 key_len = 79;
735 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600736
Glenn Randers-Pehrsonb2120021998-01-31 20:07:59 -0600737 return (key_len);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600738}
739#endif
740
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500741#if defined(PNG_WRITE_tEXt_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500742/* write a tEXt chunk */
743void
Guy Schalnat6d764711995-12-19 03:22:19 -0600744png_write_tEXt(png_structp png_ptr, png_charp key, png_charp text,
Andreas Dilger47a0c421997-05-16 02:46:07 -0500745 png_size_t text_len)
Guy Schalnat0d580581995-07-20 02:43:20 -0500746{
Glenn Randers-Pehrson074af5e1999-11-28 23:32:18 -0600747#ifdef PNG_USE_LOCAL_ARRAYS
748 PNG_tEXt;
749#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -0500750 png_size_t key_len;
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600751 png_charp new_key;
Guy Schalnat0d580581995-07-20 02:43:20 -0500752
Andreas Dilger47a0c421997-05-16 02:46:07 -0500753 png_debug(1, "in png_write_tEXt\n");
754 if (key == NULL || (key_len = png_check_keyword(png_ptr, key, &new_key))==0)
755 {
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -0600756 png_warning(png_ptr, "Empty keyword in tEXt chunk");
Guy Schalnate5a37791996-06-05 15:50:50 -0500757 return;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500758 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500759
Andreas Dilger47a0c421997-05-16 02:46:07 -0500760 if (text == NULL || *text == '\0')
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600761 text_len = 0;
762
763 /* make sure we include the 0 after the key */
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -0600764 png_write_chunk_start(png_ptr, (png_bytep)png_tEXt, (png_uint_32)key_len+text_len+1);
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -0500765 /*
766 * We leave it to the application to meet PNG-1.0 requirements on the
767 * contents of the text. PNG-1.0 through PNG-1.2 discourage the use of
768 * any non-Latin-1 characters except for NEWLINE. ISO PNG will forbid them.
769 */
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600770 png_write_chunk_data(png_ptr, (png_bytep)new_key, key_len + 1);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600771 if (text_len)
Andreas Dilger47a0c421997-05-16 02:46:07 -0500772 png_write_chunk_data(png_ptr, (png_bytep)text, text_len);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600773
Guy Schalnat0d580581995-07-20 02:43:20 -0500774 png_write_chunk_end(png_ptr);
Andreas Dilger47a0c421997-05-16 02:46:07 -0500775 png_free(png_ptr, new_key);
Guy Schalnat0d580581995-07-20 02:43:20 -0500776}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500777#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500778
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500779#if defined(PNG_WRITE_zTXt_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -0500780/* write a compressed text chunk */
Guy Schalnat0d580581995-07-20 02:43:20 -0500781void
Guy Schalnat6d764711995-12-19 03:22:19 -0600782png_write_zTXt(png_structp png_ptr, png_charp key, png_charp text,
Andreas Dilger47a0c421997-05-16 02:46:07 -0500783 png_size_t text_len, int compression)
Guy Schalnat0d580581995-07-20 02:43:20 -0500784{
Glenn Randers-Pehrson074af5e1999-11-28 23:32:18 -0600785#ifdef PNG_USE_LOCAL_ARRAYS
786 PNG_zTXt;
787#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -0500788 png_size_t key_len;
Guy Schalnat0d580581995-07-20 02:43:20 -0500789 char buf[1];
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600790 png_charp new_key;
Guy Schalnat0d580581995-07-20 02:43:20 -0500791 int i, ret;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600792 png_charpp output_ptr = NULL; /* array of pointers to output */
Guy Schalnat0d580581995-07-20 02:43:20 -0500793 int num_output_ptr = 0; /* number of output pointers used */
794 int max_output_ptr = 0; /* size of output_ptr */
795
Andreas Dilger47a0c421997-05-16 02:46:07 -0500796 png_debug(1, "in png_write_zTXt\n");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600797
Andreas Dilger47a0c421997-05-16 02:46:07 -0500798 if (key == NULL || (key_len = png_check_keyword(png_ptr, key, &new_key))==0)
Guy Schalnate5a37791996-06-05 15:50:50 -0500799 {
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -0600800 png_warning(png_ptr, "Empty keyword in zTXt chunk");
Andreas Dilger47a0c421997-05-16 02:46:07 -0500801 return;
Guy Schalnate5a37791996-06-05 15:50:50 -0500802 }
803
Andreas Dilger47a0c421997-05-16 02:46:07 -0500804 if (text == NULL || *text == '\0' || compression==PNG_TEXT_COMPRESSION_NONE)
805 {
806 png_write_tEXt(png_ptr, new_key, text, (png_size_t)0);
807 png_free(png_ptr, new_key);
808 return;
809 }
810
811 png_free(png_ptr, new_key);
812
813 if (compression >= PNG_TEXT_COMPRESSION_LAST)
814 {
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -0600815#if !defined(PNG_NO_STDIO)
Andreas Dilger47a0c421997-05-16 02:46:07 -0500816 char msg[50];
817 sprintf(msg, "Unknown zTXt compression type %d", compression);
818 png_warning(png_ptr, msg);
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -0600819#else
820 png_warning(png_ptr, "Unknown zTXt compression type");
821#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -0500822 compression = PNG_TEXT_COMPRESSION_zTXt;
823 }
824
825 /* We can't write the chunk until we find out how much data we have,
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -0500826 * which means we need to run the compressor first and save the
Andreas Dilger47a0c421997-05-16 02:46:07 -0500827 * output. This shouldn't be a problem, as the vast majority of
828 * comments should be reasonable, but we will set up an array of
829 * malloc'd pointers to be sure.
830 *
831 * If we knew the application was well behaved, we could simplify this
832 * greatly by assuming we can always malloc an output buffer large
833 * enough to hold the compressed text ((1001 * text_len / 1000) + 12)
834 * and malloc this directly. The only time this would be a bad idea is
835 * if we can't malloc more than 64K and we have 64K of random input
836 * data, or if the input string is incredibly large (although this
837 * wouldn't cause a failure, just a slowdown due to swapping).
838 */
Guy Schalnat0d580581995-07-20 02:43:20 -0500839
840 /* set up the compression buffers */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600841 png_ptr->zstream.avail_in = (uInt)text_len;
842 png_ptr->zstream.next_in = (Bytef *)text;
843 png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
844 png_ptr->zstream.next_out = (Bytef *)png_ptr->zbuf;
Guy Schalnat0d580581995-07-20 02:43:20 -0500845
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600846 /* this is the same compression loop as in png_write_row() */
Guy Schalnat0d580581995-07-20 02:43:20 -0500847 do
848 {
849 /* compress the data */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600850 ret = deflate(&png_ptr->zstream, Z_NO_FLUSH);
Guy Schalnat0d580581995-07-20 02:43:20 -0500851 if (ret != Z_OK)
852 {
853 /* error */
Andreas Dilger47a0c421997-05-16 02:46:07 -0500854 if (png_ptr->zstream.msg != NULL)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600855 png_error(png_ptr, png_ptr->zstream.msg);
Guy Schalnat0d580581995-07-20 02:43:20 -0500856 else
Guy Schalnat6d764711995-12-19 03:22:19 -0600857 png_error(png_ptr, "zlib error");
Guy Schalnat0d580581995-07-20 02:43:20 -0500858 }
859 /* check to see if we need more room */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600860 if (!png_ptr->zstream.avail_out && png_ptr->zstream.avail_in)
Guy Schalnat0d580581995-07-20 02:43:20 -0500861 {
862 /* make sure the output array has room */
863 if (num_output_ptr >= max_output_ptr)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600864 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500865 int old_max;
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500866
867 old_max = max_output_ptr;
Guy Schalnat0d580581995-07-20 02:43:20 -0500868 max_output_ptr = num_output_ptr + 4;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500869 if (output_ptr != NULL)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600870 {
871 png_charpp old_ptr;
Guy Schalnat4ee97b01996-01-16 01:51:56 -0600872
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600873 old_ptr = output_ptr;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600874 output_ptr = (png_charpp)png_malloc(png_ptr,
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -0600875 (png_uint_32)(max_output_ptr * sizeof (png_charpp)));
Andreas Dilger47a0c421997-05-16 02:46:07 -0500876 png_memcpy(output_ptr, old_ptr, old_max * sizeof (png_charp));
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600877 png_free(png_ptr, old_ptr);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600878 }
879 else
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600880 output_ptr = (png_charpp)png_malloc(png_ptr,
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -0600881 (png_uint_32)(max_output_ptr * sizeof (png_charp)));
Guy Schalnat0d580581995-07-20 02:43:20 -0500882 }
883
884 /* save the data */
Glenn Randers-Pehrson46f61e21998-01-30 21:45:12 -0600885 output_ptr[num_output_ptr] = (png_charp)png_malloc(png_ptr,
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -0600886 (png_uint_32)png_ptr->zbuf_size);
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500887 png_memcpy(output_ptr[num_output_ptr], png_ptr->zbuf,
Andreas Dilger47a0c421997-05-16 02:46:07 -0500888 png_ptr->zbuf_size);
Guy Schalnat0d580581995-07-20 02:43:20 -0500889 num_output_ptr++;
890
891 /* and reset the buffer */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600892 png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
893 png_ptr->zstream.next_out = png_ptr->zbuf;
Guy Schalnat0d580581995-07-20 02:43:20 -0500894 }
Glenn Randers-Pehrson345bc271998-06-14 14:43:31 -0500895 /* continue until we don't have any more to compress */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600896 } while (png_ptr->zstream.avail_in);
Guy Schalnat0d580581995-07-20 02:43:20 -0500897
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600898 /* finish the compression */
Guy Schalnat0d580581995-07-20 02:43:20 -0500899 do
900 {
901 /* tell zlib we are finished */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600902 ret = deflate(&png_ptr->zstream, Z_FINISH);
Guy Schalnat0d580581995-07-20 02:43:20 -0500903 if (ret != Z_OK && ret != Z_STREAM_END)
904 {
905 /* we got an error */
Andreas Dilger47a0c421997-05-16 02:46:07 -0500906 if (png_ptr->zstream.msg != NULL)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600907 png_error(png_ptr, png_ptr->zstream.msg);
Guy Schalnat0d580581995-07-20 02:43:20 -0500908 else
Guy Schalnat6d764711995-12-19 03:22:19 -0600909 png_error(png_ptr, "zlib error");
Guy Schalnat0d580581995-07-20 02:43:20 -0500910 }
911
912 /* check to see if we need more room */
Andreas Dilger47a0c421997-05-16 02:46:07 -0500913 if (!(png_ptr->zstream.avail_out) && ret == Z_OK)
Guy Schalnat0d580581995-07-20 02:43:20 -0500914 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600915 /* check to make sure our output array has room */
916 if (num_output_ptr >= max_output_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -0500917 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500918 int old_max;
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500919
920 old_max = max_output_ptr;
Guy Schalnat0d580581995-07-20 02:43:20 -0500921 max_output_ptr = num_output_ptr + 4;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500922 if (output_ptr != NULL)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600923 {
924 png_charpp old_ptr;
Guy Schalnat0d580581995-07-20 02:43:20 -0500925
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600926 old_ptr = output_ptr;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500927 /* This could be optimized to realloc() */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600928 output_ptr = (png_charpp)png_malloc(png_ptr,
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -0600929 (png_uint_32)(max_output_ptr * sizeof (png_charpp)));
Andreas Dilger47a0c421997-05-16 02:46:07 -0500930 png_memcpy(output_ptr, old_ptr, old_max * sizeof (png_charp));
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600931 png_free(png_ptr, old_ptr);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600932 }
933 else
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600934 output_ptr = (png_charpp)png_malloc(png_ptr,
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -0600935 (png_uint_32)(max_output_ptr * sizeof (png_charp)));
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600936 }
Guy Schalnat4ee97b01996-01-16 01:51:56 -0600937
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600938 /* save off the data */
Glenn Randers-Pehrson46f61e21998-01-30 21:45:12 -0600939 output_ptr[num_output_ptr] = (png_charp)png_malloc(png_ptr,
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -0600940 (png_uint_32)png_ptr->zbuf_size);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600941 png_memcpy(output_ptr[num_output_ptr], png_ptr->zbuf,
Andreas Dilger47a0c421997-05-16 02:46:07 -0500942 png_ptr->zbuf_size);
Guy Schalnat0d580581995-07-20 02:43:20 -0500943 num_output_ptr++;
944
945 /* and reset the buffer pointers */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600946 png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
947 png_ptr->zstream.next_out = png_ptr->zbuf;
Guy Schalnat0d580581995-07-20 02:43:20 -0500948 }
949 } while (ret != Z_STREAM_END);
950
951 /* text length is number of buffers plus last buffer */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600952 text_len = png_ptr->zbuf_size * num_output_ptr;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600953 if (png_ptr->zstream.avail_out < png_ptr->zbuf_size)
Andreas Dilger47a0c421997-05-16 02:46:07 -0500954 text_len += png_ptr->zbuf_size - (png_size_t)png_ptr->zstream.avail_out;
Guy Schalnat0d580581995-07-20 02:43:20 -0500955
956 /* write start of chunk */
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -0600957 png_write_chunk_start(png_ptr, (png_bytep)png_zTXt, (png_uint_32)(key_len+text_len+2));
Guy Schalnat0d580581995-07-20 02:43:20 -0500958 /* write key */
Andreas Dilger47a0c421997-05-16 02:46:07 -0500959 png_write_chunk_data(png_ptr, (png_bytep)key, key_len + 1);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600960 buf[0] = (png_byte)compression;
Guy Schalnat0d580581995-07-20 02:43:20 -0500961 /* write compression */
Andreas Dilger47a0c421997-05-16 02:46:07 -0500962 png_write_chunk_data(png_ptr, (png_bytep)buf, (png_size_t)1);
Guy Schalnat0d580581995-07-20 02:43:20 -0500963
964 /* write saved output buffers, if any */
965 for (i = 0; i < num_output_ptr; i++)
966 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500967 png_write_chunk_data(png_ptr,(png_bytep)output_ptr[i],png_ptr->zbuf_size);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600968 png_free(png_ptr, output_ptr[i]);
Guy Schalnat0d580581995-07-20 02:43:20 -0500969 }
Andreas Dilger47a0c421997-05-16 02:46:07 -0500970 if (max_output_ptr != 0)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600971 png_free(png_ptr, output_ptr);
Guy Schalnat0d580581995-07-20 02:43:20 -0500972 /* write anything left in zbuf */
Andreas Dilger47a0c421997-05-16 02:46:07 -0500973 if (png_ptr->zstream.avail_out < (png_uint_32)png_ptr->zbuf_size)
Guy Schalnat0d580581995-07-20 02:43:20 -0500974 png_write_chunk_data(png_ptr, png_ptr->zbuf,
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600975 png_ptr->zbuf_size - png_ptr->zstream.avail_out);
Guy Schalnat0d580581995-07-20 02:43:20 -0500976 /* close the chunk */
977 png_write_chunk_end(png_ptr);
978
979 /* reset zlib for another zTXt or the image data */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600980 deflateReset(&png_ptr->zstream);
Guy Schalnat0d580581995-07-20 02:43:20 -0500981}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500982#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500983
Andreas Dilger47a0c421997-05-16 02:46:07 -0500984
985#if defined(PNG_WRITE_oFFs_SUPPORTED)
986/* write the oFFs chunk */
987void
988png_write_oFFs(png_structp png_ptr, png_uint_32 x_offset,
989 png_uint_32 y_offset,
990 int unit_type)
991{
Glenn Randers-Pehrson074af5e1999-11-28 23:32:18 -0600992#ifdef PNG_USE_LOCAL_ARRAYS
993 PNG_oFFs;
994#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -0500995 png_byte buf[9];
996
997 png_debug(1, "in png_write_oFFs\n");
998 if (unit_type >= PNG_OFFSET_LAST)
999 png_warning(png_ptr, "Unrecognized unit type for oFFs chunk");
1000
1001 png_save_uint_32(buf, x_offset);
1002 png_save_uint_32(buf + 4, y_offset);
1003 buf[8] = (png_byte)unit_type;
1004
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -06001005 png_write_chunk(png_ptr, (png_bytep)png_oFFs, buf, (png_size_t)9);
Andreas Dilger47a0c421997-05-16 02:46:07 -05001006}
1007#endif
1008
1009#if defined(PNG_WRITE_pCAL_SUPPORTED)
1010/* write the pCAL chunk (png-scivis-19970203) */
1011void
1012png_write_pCAL(png_structp png_ptr, png_charp purpose, png_int_32 X0,
1013 png_int_32 X1, int type, int nparams, png_charp units, png_charpp params)
1014{
Glenn Randers-Pehrson074af5e1999-11-28 23:32:18 -06001015#ifdef PNG_USE_LOCAL_ARRAYS
1016 PNG_pCAL;
1017#endif
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001018 png_size_t purpose_len, units_len, total_len;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001019 png_uint_32p params_len;
1020 png_byte buf[10];
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001021 png_charp new_purpose;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001022 int i;
1023
1024 png_debug1(1, "in png_write_pCAL (%d parameters)\n", nparams);
1025 if (type >= PNG_EQUATION_LAST)
1026 png_warning(png_ptr, "Unrecognized equation type for pCAL chunk");
1027
1028 purpose_len = png_check_keyword(png_ptr, purpose, &new_purpose) + 1;
1029 png_debug1(3, "pCAL purpose length = %d\n", purpose_len);
1030 units_len = png_strlen(units) + (nparams == 0 ? 0 : 1);
1031 png_debug1(3, "pCAL units length = %d\n", units_len);
1032 total_len = purpose_len + units_len + 10;
1033
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06001034 params_len = (png_uint_32p)png_malloc(png_ptr, (png_uint_32)(nparams
1035 *sizeof(png_uint_32)));
Andreas Dilger47a0c421997-05-16 02:46:07 -05001036
1037 /* Find the length of each parameter, making sure we don't count the
1038 null terminator for the last parameter. */
1039 for (i = 0; i < nparams; i++)
1040 {
1041 params_len[i] = png_strlen(params[i]) + (i == nparams - 1 ? 0 : 1);
1042 png_debug2(3, "pCAL parameter %d length = %d\n", i, params_len[i]);
1043 total_len += (png_size_t)params_len[i];
1044 }
1045
1046 png_debug1(3, "pCAL total length = %d\n", total_len);
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -06001047 png_write_chunk_start(png_ptr, (png_bytep)png_pCAL, (png_uint_32)total_len);
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001048 png_write_chunk_data(png_ptr, (png_bytep)new_purpose, purpose_len);
Andreas Dilger47a0c421997-05-16 02:46:07 -05001049 png_save_int_32(buf, X0);
1050 png_save_int_32(buf + 4, X1);
1051 buf[8] = (png_byte)type;
1052 buf[9] = (png_byte)nparams;
1053 png_write_chunk_data(png_ptr, buf, (png_size_t)10);
1054 png_write_chunk_data(png_ptr, (png_bytep)units, (png_size_t)units_len);
1055
1056 png_free(png_ptr, new_purpose);
1057
1058 for (i = 0; i < nparams; i++)
1059 {
1060 png_write_chunk_data(png_ptr, (png_bytep)params[i],
1061 (png_size_t)params_len[i]);
1062 }
1063
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001064 png_free(png_ptr, params_len);
Andreas Dilger47a0c421997-05-16 02:46:07 -05001065 png_write_chunk_end(png_ptr);
1066}
1067#endif
1068
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001069#if defined(PNG_WRITE_pHYs_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -05001070/* write the pHYs chunk */
1071void
Guy Schalnat6d764711995-12-19 03:22:19 -06001072png_write_pHYs(png_structp png_ptr, png_uint_32 x_pixels_per_unit,
Guy Schalnat0d580581995-07-20 02:43:20 -05001073 png_uint_32 y_pixels_per_unit,
1074 int unit_type)
1075{
Glenn Randers-Pehrson074af5e1999-11-28 23:32:18 -06001076#ifdef PNG_USE_LOCAL_ARRAYS
1077 PNG_pHYs;
1078#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001079 png_byte buf[9];
1080
Andreas Dilger47a0c421997-05-16 02:46:07 -05001081 png_debug(1, "in png_write_pHYs\n");
Guy Schalnate5a37791996-06-05 15:50:50 -05001082 if (unit_type >= PNG_RESOLUTION_LAST)
1083 png_warning(png_ptr, "Unrecognized unit type for pHYs chunk");
1084
Guy Schalnat0d580581995-07-20 02:43:20 -05001085 png_save_uint_32(buf, x_pixels_per_unit);
1086 png_save_uint_32(buf + 4, y_pixels_per_unit);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001087 buf[8] = (png_byte)unit_type;
Guy Schalnat0d580581995-07-20 02:43:20 -05001088
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -06001089 png_write_chunk(png_ptr, (png_bytep)png_pHYs, buf, (png_size_t)9);
Guy Schalnat0d580581995-07-20 02:43:20 -05001090}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001091#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001092
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001093#if defined(PNG_WRITE_tIME_SUPPORTED)
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001094/* Write the tIME chunk. Use either png_convert_from_struct_tm()
1095 * or png_convert_from_time_t(), or fill in the structure yourself.
1096 */
Guy Schalnat0d580581995-07-20 02:43:20 -05001097void
Guy Schalnat6d764711995-12-19 03:22:19 -06001098png_write_tIME(png_structp png_ptr, png_timep mod_time)
Guy Schalnat0d580581995-07-20 02:43:20 -05001099{
Glenn Randers-Pehrson074af5e1999-11-28 23:32:18 -06001100#ifdef PNG_USE_LOCAL_ARRAYS
1101 PNG_tIME;
1102#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001103 png_byte buf[7];
1104
Andreas Dilger47a0c421997-05-16 02:46:07 -05001105 png_debug(1, "in png_write_tIME\n");
Guy Schalnate5a37791996-06-05 15:50:50 -05001106 if (mod_time->month > 12 || mod_time->month < 1 ||
1107 mod_time->day > 31 || mod_time->day < 1 ||
1108 mod_time->hour > 23 || mod_time->second > 60)
1109 {
1110 png_warning(png_ptr, "Invalid time specified for tIME chunk");
1111 return;
1112 }
1113
Guy Schalnat0d580581995-07-20 02:43:20 -05001114 png_save_uint_16(buf, mod_time->year);
1115 buf[2] = mod_time->month;
1116 buf[3] = mod_time->day;
1117 buf[4] = mod_time->hour;
1118 buf[5] = mod_time->minute;
1119 buf[6] = mod_time->second;
1120
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -06001121 png_write_chunk(png_ptr, (png_bytep)png_tIME, buf, (png_size_t)7);
Guy Schalnat0d580581995-07-20 02:43:20 -05001122}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001123#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001124
1125/* initializes the row writing capability of libpng */
1126void
Guy Schalnat6d764711995-12-19 03:22:19 -06001127png_write_start_row(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -05001128{
Glenn Randers-Pehrson074af5e1999-11-28 23:32:18 -06001129#ifdef PNG_USE_LOCAL_ARRAYS
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -06001130 /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */
1131
1132 /* start of interlace block */
1133 int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
1134
1135 /* offset to next interlace block */
1136 int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
1137
1138 /* start of interlace block in the y direction */
1139 int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1};
1140
1141 /* offset to next interlace block in the y direction */
1142 int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
Glenn Randers-Pehrson074af5e1999-11-28 23:32:18 -06001143#endif
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -06001144
Andreas Dilger47a0c421997-05-16 02:46:07 -05001145 png_size_t buf_size;
1146
1147 png_debug(1, "in png_write_start_row\n");
1148 buf_size = (png_size_t)(((png_ptr->width * png_ptr->usr_channels *
1149 png_ptr->usr_bit_depth + 7) >> 3) + 1);
1150
Guy Schalnat0d580581995-07-20 02:43:20 -05001151 /* set up row buffer */
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06001152 png_ptr->row_buf = (png_bytep)png_malloc(png_ptr, (png_uint_32)buf_size);
Andreas Dilger47a0c421997-05-16 02:46:07 -05001153 png_ptr->row_buf[0] = PNG_FILTER_VALUE_NONE;
Guy Schalnate5a37791996-06-05 15:50:50 -05001154
1155 /* set up filtering buffer, if using this filter */
1156 if (png_ptr->do_filter & PNG_FILTER_SUB)
Guy Schalnat0d580581995-07-20 02:43:20 -05001157 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001158 png_ptr->sub_row = (png_bytep)png_malloc(png_ptr,
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06001159 (png_ptr->rowbytes + 1));
Andreas Dilger47a0c421997-05-16 02:46:07 -05001160 png_ptr->sub_row[0] = PNG_FILTER_VALUE_SUB;
Guy Schalnate5a37791996-06-05 15:50:50 -05001161 }
1162
Andreas Dilger47a0c421997-05-16 02:46:07 -05001163 /* We only need to keep the previous row if we are using one of these. */
Guy Schalnate5a37791996-06-05 15:50:50 -05001164 if (png_ptr->do_filter & (PNG_FILTER_AVG | PNG_FILTER_UP | PNG_FILTER_PAETH))
1165 {
1166 /* set up previous row buffer */
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06001167 png_ptr->prev_row = (png_bytep)png_malloc(png_ptr, (png_uint_32)buf_size);
Andreas Dilger47a0c421997-05-16 02:46:07 -05001168 png_memset(png_ptr->prev_row, 0, buf_size);
Guy Schalnate5a37791996-06-05 15:50:50 -05001169
1170 if (png_ptr->do_filter & PNG_FILTER_UP)
1171 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001172 png_ptr->up_row = (png_bytep )png_malloc(png_ptr,
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06001173 (png_ptr->rowbytes + 1));
Andreas Dilger47a0c421997-05-16 02:46:07 -05001174 png_ptr->up_row[0] = PNG_FILTER_VALUE_UP;
Guy Schalnate5a37791996-06-05 15:50:50 -05001175 }
1176
1177 if (png_ptr->do_filter & PNG_FILTER_AVG)
1178 {
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06001179 png_ptr->avg_row = (png_bytep)png_malloc(png_ptr,
1180 (png_ptr->rowbytes + 1));
Andreas Dilger47a0c421997-05-16 02:46:07 -05001181 png_ptr->avg_row[0] = PNG_FILTER_VALUE_AVG;
Guy Schalnate5a37791996-06-05 15:50:50 -05001182 }
1183
1184 if (png_ptr->do_filter & PNG_FILTER_PAETH)
1185 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001186 png_ptr->paeth_row = (png_bytep )png_malloc(png_ptr,
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06001187 (png_ptr->rowbytes + 1));
Andreas Dilger47a0c421997-05-16 02:46:07 -05001188 png_ptr->paeth_row[0] = PNG_FILTER_VALUE_PAETH;
Guy Schalnate5a37791996-06-05 15:50:50 -05001189 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001190 }
1191
Glenn Randers-Pehrson46f61e21998-01-30 21:45:12 -06001192#ifdef PNG_WRITE_INTERLACING_SUPPORTED
Guy Schalnat0d580581995-07-20 02:43:20 -05001193 /* if interlaced, we need to set up width and height of pass */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001194 if (png_ptr->interlaced)
Guy Schalnat0d580581995-07-20 02:43:20 -05001195 {
1196 if (!(png_ptr->transformations & PNG_INTERLACE))
1197 {
1198 png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 -
1199 png_pass_ystart[0]) / png_pass_yinc[0];
Andreas Dilger47a0c421997-05-16 02:46:07 -05001200 png_ptr->usr_width = (png_ptr->width + png_pass_inc[0] - 1 -
1201 png_pass_start[0]) / png_pass_inc[0];
Guy Schalnat0d580581995-07-20 02:43:20 -05001202 }
1203 else
1204 {
1205 png_ptr->num_rows = png_ptr->height;
1206 png_ptr->usr_width = png_ptr->width;
1207 }
1208 }
1209 else
Glenn Randers-Pehrson46f61e21998-01-30 21:45:12 -06001210#endif
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001211 {
Guy Schalnat0d580581995-07-20 02:43:20 -05001212 png_ptr->num_rows = png_ptr->height;
1213 png_ptr->usr_width = png_ptr->width;
1214 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001215 png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
1216 png_ptr->zstream.next_out = png_ptr->zbuf;
Guy Schalnat0d580581995-07-20 02:43:20 -05001217}
1218
Andreas Dilger47a0c421997-05-16 02:46:07 -05001219/* Internal use only. Called when finished processing a row of data. */
Guy Schalnat0d580581995-07-20 02:43:20 -05001220void
Guy Schalnat6d764711995-12-19 03:22:19 -06001221png_write_finish_row(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -05001222{
Glenn Randers-Pehrson074af5e1999-11-28 23:32:18 -06001223#ifdef PNG_USE_LOCAL_ARRAYS
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -06001224 /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */
1225
1226 /* start of interlace block */
1227 int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
1228
1229 /* offset to next interlace block */
1230 int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
1231
1232 /* start of interlace block in the y direction */
1233 int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1};
1234
1235 /* offset to next interlace block in the y direction */
1236 int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
Glenn Randers-Pehrson074af5e1999-11-28 23:32:18 -06001237#endif
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -06001238
Guy Schalnat0d580581995-07-20 02:43:20 -05001239 int ret;
1240
Andreas Dilger47a0c421997-05-16 02:46:07 -05001241 png_debug(1, "in png_write_finish_row\n");
Guy Schalnat0d580581995-07-20 02:43:20 -05001242 /* next row */
1243 png_ptr->row_number++;
Guy Schalnatc21f90c1996-06-17 16:24:45 -05001244
Guy Schalnat0d580581995-07-20 02:43:20 -05001245 /* see if we are done */
Guy Schalnat6d764711995-12-19 03:22:19 -06001246 if (png_ptr->row_number < png_ptr->num_rows)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001247 return;
Guy Schalnat0d580581995-07-20 02:43:20 -05001248
Glenn Randers-Pehrson46f61e21998-01-30 21:45:12 -06001249#ifdef PNG_WRITE_INTERLACING_SUPPORTED
Guy Schalnat0d580581995-07-20 02:43:20 -05001250 /* if interlaced, go to next pass */
1251 if (png_ptr->interlaced)
1252 {
1253 png_ptr->row_number = 0;
1254 if (png_ptr->transformations & PNG_INTERLACE)
1255 {
1256 png_ptr->pass++;
1257 }
1258 else
1259 {
1260 /* loop until we find a non-zero width or height pass */
1261 do
1262 {
1263 png_ptr->pass++;
1264 if (png_ptr->pass >= 7)
1265 break;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001266 png_ptr->usr_width = (png_ptr->width +
Guy Schalnat0d580581995-07-20 02:43:20 -05001267 png_pass_inc[png_ptr->pass] - 1 -
1268 png_pass_start[png_ptr->pass]) /
1269 png_pass_inc[png_ptr->pass];
1270 png_ptr->num_rows = (png_ptr->height +
1271 png_pass_yinc[png_ptr->pass] - 1 -
1272 png_pass_ystart[png_ptr->pass]) /
1273 png_pass_yinc[png_ptr->pass];
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001274 if (png_ptr->transformations & PNG_INTERLACE)
1275 break;
Guy Schalnat0d580581995-07-20 02:43:20 -05001276 } while (png_ptr->usr_width == 0 || png_ptr->num_rows == 0);
1277
1278 }
1279
Guy Schalnate5a37791996-06-05 15:50:50 -05001280 /* reset the row above the image for the next pass */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001281 if (png_ptr->pass < 7)
Guy Schalnatc21f90c1996-06-17 16:24:45 -05001282 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001283 if (png_ptr->prev_row != NULL)
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001284 png_memset(png_ptr->prev_row, 0,
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001285 (png_size_t) (((png_uint_32)png_ptr->usr_channels *
Guy Schalnatc21f90c1996-06-17 16:24:45 -05001286 (png_uint_32)png_ptr->usr_bit_depth *
1287 png_ptr->width + 7) >> 3) + 1);
Guy Schalnat0d580581995-07-20 02:43:20 -05001288 return;
Guy Schalnatc21f90c1996-06-17 16:24:45 -05001289 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001290 }
Glenn Randers-Pehrson46f61e21998-01-30 21:45:12 -06001291#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001292
1293 /* if we get here, we've just written the last row, so we need
1294 to flush the compressor */
1295 do
1296 {
1297 /* tell the compressor we are done */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001298 ret = deflate(&png_ptr->zstream, Z_FINISH);
Guy Schalnat0d580581995-07-20 02:43:20 -05001299 /* check for an error */
1300 if (ret != Z_OK && ret != Z_STREAM_END)
1301 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001302 if (png_ptr->zstream.msg != NULL)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001303 png_error(png_ptr, png_ptr->zstream.msg);
Guy Schalnat0d580581995-07-20 02:43:20 -05001304 else
Guy Schalnat6d764711995-12-19 03:22:19 -06001305 png_error(png_ptr, "zlib error");
Guy Schalnat0d580581995-07-20 02:43:20 -05001306 }
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001307 /* check to see if we need more room */
Andreas Dilger47a0c421997-05-16 02:46:07 -05001308 if (!(png_ptr->zstream.avail_out) && ret == Z_OK)
Guy Schalnat0d580581995-07-20 02:43:20 -05001309 {
1310 png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001311 png_ptr->zstream.next_out = png_ptr->zbuf;
1312 png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
Guy Schalnat0d580581995-07-20 02:43:20 -05001313 }
1314 } while (ret != Z_STREAM_END);
1315
1316 /* write any extra space */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001317 if (png_ptr->zstream.avail_out < png_ptr->zbuf_size)
Guy Schalnat0d580581995-07-20 02:43:20 -05001318 {
1319 png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size -
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001320 png_ptr->zstream.avail_out);
Guy Schalnat0d580581995-07-20 02:43:20 -05001321 }
1322
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001323 deflateReset(&png_ptr->zstream);
Guy Schalnat0d580581995-07-20 02:43:20 -05001324}
1325
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001326#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001327/* Pick out the correct pixels for the interlace pass.
1328 * The basic idea here is to go through the row with a source
1329 * pointer and a destination pointer (sp and dp), and copy the
1330 * correct pixels for the pass. As the row gets compacted,
1331 * sp will always be >= dp, so we should never overwrite anything.
1332 * See the default: case for the easiest code to understand.
1333 */
Guy Schalnat0d580581995-07-20 02:43:20 -05001334void
Guy Schalnat6d764711995-12-19 03:22:19 -06001335png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass)
Guy Schalnat0d580581995-07-20 02:43:20 -05001336{
Glenn Randers-Pehrson074af5e1999-11-28 23:32:18 -06001337#ifdef PNG_USE_LOCAL_ARRAYS
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -06001338 /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */
1339
1340 /* start of interlace block */
1341 int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
1342
1343 /* offset to next interlace block */
1344 int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
Glenn Randers-Pehrson074af5e1999-11-28 23:32:18 -06001345#endif
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -06001346
Andreas Dilger47a0c421997-05-16 02:46:07 -05001347 png_debug(1, "in png_do_write_interlace\n");
Guy Schalnat0d580581995-07-20 02:43:20 -05001348 /* we don't have to do anything on the last pass (6) */
Andreas Dilger47a0c421997-05-16 02:46:07 -05001349#if defined(PNG_USELESS_TESTS_SUPPORTED)
1350 if (row != NULL && row_info != NULL && pass < 6)
1351#else
1352 if (pass < 6)
1353#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001354 {
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001355 /* each pixel depth is handled separately */
Guy Schalnat0d580581995-07-20 02:43:20 -05001356 switch (row_info->pixel_depth)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001357 {
Guy Schalnat0d580581995-07-20 02:43:20 -05001358 case 1:
1359 {
Guy Schalnat6d764711995-12-19 03:22:19 -06001360 png_bytep sp;
1361 png_bytep dp;
Guy Schalnat0d580581995-07-20 02:43:20 -05001362 int shift;
1363 int d;
1364 int value;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001365 png_uint_32 i;
1366 png_uint_32 row_width = row_info->width;
Guy Schalnat0d580581995-07-20 02:43:20 -05001367
1368 dp = row;
1369 d = 0;
1370 shift = 7;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001371 for (i = png_pass_start[pass]; i < row_width;
Guy Schalnat0d580581995-07-20 02:43:20 -05001372 i += png_pass_inc[pass])
1373 {
1374 sp = row + (png_size_t)(i >> 3);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001375 value = (int)(*sp >> (7 - (int)(i & 7))) & 0x1;
Guy Schalnat0d580581995-07-20 02:43:20 -05001376 d |= (value << shift);
1377
1378 if (shift == 0)
1379 {
1380 shift = 7;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001381 *dp++ = (png_byte)d;
Guy Schalnat0d580581995-07-20 02:43:20 -05001382 d = 0;
1383 }
1384 else
1385 shift--;
1386
1387 }
1388 if (shift != 7)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001389 *dp = (png_byte)d;
Guy Schalnat0d580581995-07-20 02:43:20 -05001390 break;
1391 }
1392 case 2:
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001393 {
Guy Schalnat6d764711995-12-19 03:22:19 -06001394 png_bytep sp;
1395 png_bytep dp;
Guy Schalnat0d580581995-07-20 02:43:20 -05001396 int shift;
1397 int d;
1398 int value;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001399 png_uint_32 i;
1400 png_uint_32 row_width = row_info->width;
Guy Schalnat0d580581995-07-20 02:43:20 -05001401
1402 dp = row;
1403 shift = 6;
1404 d = 0;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001405 for (i = png_pass_start[pass]; i < row_width;
Guy Schalnat0d580581995-07-20 02:43:20 -05001406 i += png_pass_inc[pass])
1407 {
1408 sp = row + (png_size_t)(i >> 2);
1409 value = (*sp >> ((3 - (int)(i & 3)) << 1)) & 0x3;
1410 d |= (value << shift);
1411
1412 if (shift == 0)
1413 {
1414 shift = 6;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001415 *dp++ = (png_byte)d;
Guy Schalnat0d580581995-07-20 02:43:20 -05001416 d = 0;
1417 }
1418 else
1419 shift -= 2;
1420 }
1421 if (shift != 6)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001422 *dp = (png_byte)d;
Guy Schalnat0d580581995-07-20 02:43:20 -05001423 break;
1424 }
1425 case 4:
1426 {
Guy Schalnat6d764711995-12-19 03:22:19 -06001427 png_bytep sp;
1428 png_bytep dp;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001429 int shift;
Guy Schalnat0d580581995-07-20 02:43:20 -05001430 int d;
1431 int value;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001432 png_uint_32 i;
1433 png_uint_32 row_width = row_info->width;
Guy Schalnat0d580581995-07-20 02:43:20 -05001434
1435 dp = row;
1436 shift = 4;
1437 d = 0;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001438 for (i = png_pass_start[pass]; i < row_width;
Guy Schalnat0d580581995-07-20 02:43:20 -05001439 i += png_pass_inc[pass])
1440 {
1441 sp = row + (png_size_t)(i >> 1);
1442 value = (*sp >> ((1 - (int)(i & 1)) << 2)) & 0xf;
1443 d |= (value << shift);
1444
1445 if (shift == 0)
1446 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001447 shift = 4;
1448 *dp++ = (png_byte)d;
Guy Schalnat0d580581995-07-20 02:43:20 -05001449 d = 0;
1450 }
1451 else
1452 shift -= 4;
1453 }
1454 if (shift != 4)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001455 *dp = (png_byte)d;
Guy Schalnat0d580581995-07-20 02:43:20 -05001456 break;
1457 }
1458 default:
1459 {
Guy Schalnat6d764711995-12-19 03:22:19 -06001460 png_bytep sp;
1461 png_bytep dp;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001462 png_uint_32 i;
1463 png_uint_32 row_width = row_info->width;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001464 png_size_t pixel_bytes;
Guy Schalnat0d580581995-07-20 02:43:20 -05001465
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001466 /* start at the beginning */
Guy Schalnat0d580581995-07-20 02:43:20 -05001467 dp = row;
1468 /* find out how many bytes each pixel takes up */
1469 pixel_bytes = (row_info->pixel_depth >> 3);
1470 /* loop through the row, only looking at the pixels that
1471 matter */
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001472 for (i = png_pass_start[pass]; i < row_width;
Guy Schalnat0d580581995-07-20 02:43:20 -05001473 i += png_pass_inc[pass])
1474 {
1475 /* find out where the original pixel is */
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001476 sp = row + (png_size_t)i * pixel_bytes;
Guy Schalnat0d580581995-07-20 02:43:20 -05001477 /* move the pixel */
1478 if (dp != sp)
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001479 png_memcpy(dp, sp, pixel_bytes);
Guy Schalnat0d580581995-07-20 02:43:20 -05001480 /* next pixel */
1481 dp += pixel_bytes;
1482 }
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001483 break;
Guy Schalnat0d580581995-07-20 02:43:20 -05001484 }
1485 }
1486 /* set new row width */
1487 row_info->width = (row_info->width +
1488 png_pass_inc[pass] - 1 -
1489 png_pass_start[pass]) /
1490 png_pass_inc[pass];
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06001491 row_info->rowbytes = ((row_info->width *
1492 row_info->pixel_depth + 7) >> 3);
Guy Schalnat0d580581995-07-20 02:43:20 -05001493 }
1494}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001495#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001496
Andreas Dilger47a0c421997-05-16 02:46:07 -05001497/* This filters the row, chooses which filter to use, if it has not already
1498 * been specified by the application, and then writes the row out with the
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001499 * chosen filter.
1500 */
Glenn Randers-Pehrsonea3bcd71998-03-07 14:33:00 -06001501#define PNG_MAXSUM (~((png_uint_32)0) >> 1)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001502#define PNG_HISHIFT 10
Glenn Randers-Pehrsonea3bcd71998-03-07 14:33:00 -06001503#define PNG_LOMASK ((png_uint_32)0xffffL)
1504#define PNG_HIMASK ((png_uint_32)(~PNG_LOMASK >> PNG_HISHIFT))
Guy Schalnat0d580581995-07-20 02:43:20 -05001505void
Guy Schalnate5a37791996-06-05 15:50:50 -05001506png_write_find_filter(png_structp png_ptr, png_row_infop row_info)
Guy Schalnat0d580581995-07-20 02:43:20 -05001507{
Guy Schalnate5a37791996-06-05 15:50:50 -05001508 png_bytep prev_row, best_row, row_buf;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001509 png_uint_32 mins, bpp;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001510 png_byte filter_to_do = png_ptr->do_filter;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001511 png_uint_32 row_bytes = row_info->rowbytes;
1512#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
1513 int num_p_filters = (int)png_ptr->num_prev_filters;
1514#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001515
Andreas Dilger47a0c421997-05-16 02:46:07 -05001516 png_debug(1, "in png_write_find_filter\n");
Guy Schalnat0d580581995-07-20 02:43:20 -05001517 /* find out how many bytes offset each pixel is */
1518 bpp = (row_info->pixel_depth + 7) / 8;
Guy Schalnate5a37791996-06-05 15:50:50 -05001519
1520 prev_row = png_ptr->prev_row;
1521 best_row = row_buf = png_ptr->row_buf;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001522 mins = PNG_MAXSUM;
Guy Schalnat0d580581995-07-20 02:43:20 -05001523
Andreas Dilger47a0c421997-05-16 02:46:07 -05001524 /* The prediction method we use is to find which method provides the
1525 * smallest value when summing the absolute values of the distances
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05001526 * from zero, using anything >= 128 as negative numbers. This is known
Andreas Dilger47a0c421997-05-16 02:46:07 -05001527 * as the "minimum sum of absolute differences" heuristic. Other
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001528 * heuristics are the "weighted minimum sum of absolute differences"
Andreas Dilger47a0c421997-05-16 02:46:07 -05001529 * (experimental and can in theory improve compression), and the "zlib
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05001530 * predictive" method (not implemented yet), which does test compressions
1531 * of lines using different filter methods, and then chooses the
1532 * (series of) filter(s) that give minimum compressed data size (VERY
Andreas Dilger47a0c421997-05-16 02:46:07 -05001533 * computationally expensive).
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05001534 *
1535 * GRR 980525: consider also
1536 * (1) minimum sum of absolute differences from running average (i.e.,
1537 * keep running sum of non-absolute differences & count of bytes)
1538 * [track dispersion, too? restart average if dispersion too large?]
1539 * (1b) minimum sum of absolute differences from sliding average, probably
1540 * with window size <= deflate window (usually 32K)
1541 * (2) minimum sum of squared differences from zero or running average
1542 * (i.e., ~ root-mean-square approach)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001543 */
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001544
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001545
Guy Schalnate5a37791996-06-05 15:50:50 -05001546 /* We don't need to test the 'no filter' case if this is the only filter
Andreas Dilger47a0c421997-05-16 02:46:07 -05001547 * that has been chosen, as it doesn't actually do anything to the data.
1548 */
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001549 if (filter_to_do & PNG_FILTER_NONE &&
1550 filter_to_do != PNG_FILTER_NONE)
Guy Schalnat0d580581995-07-20 02:43:20 -05001551 {
Guy Schalnate5a37791996-06-05 15:50:50 -05001552 png_bytep rp;
1553 png_uint_32 sum = 0;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001554 png_uint_32 i;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001555 int v;
Guy Schalnat0d580581995-07-20 02:43:20 -05001556
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001557 for (i = 0, rp = row_buf + 1; i < row_bytes; i++, rp++)
Guy Schalnate5a37791996-06-05 15:50:50 -05001558 {
1559 v = *rp;
1560 sum += (v < 128) ? v : 256 - v;
1561 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05001562
1563#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
1564 if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
1565 {
1566 png_uint_32 sumhi, sumlo;
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001567 int j;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001568 sumlo = sum & PNG_LOMASK;
1569 sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK; /* Gives us some footroom */
1570
1571 /* Reduce the sum if we match any of the previous rows */
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001572 for (j = 0; j < num_p_filters; j++)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001573 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001574 if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_NONE)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001575 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001576 sumlo = (sumlo * png_ptr->filter_weights[j]) >>
Andreas Dilger47a0c421997-05-16 02:46:07 -05001577 PNG_WEIGHT_SHIFT;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001578 sumhi = (sumhi * png_ptr->filter_weights[j]) >>
Andreas Dilger47a0c421997-05-16 02:46:07 -05001579 PNG_WEIGHT_SHIFT;
1580 }
1581 }
1582
1583 /* Factor in the cost of this filter (this is here for completeness,
1584 * but it makes no sense to have a "cost" for the NONE filter, as
1585 * it has the minimum possible computational cost - none).
1586 */
1587 sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_NONE]) >>
1588 PNG_COST_SHIFT;
1589 sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_NONE]) >>
1590 PNG_COST_SHIFT;
1591
1592 if (sumhi > PNG_HIMASK)
1593 sum = PNG_MAXSUM;
1594 else
1595 sum = (sumhi << PNG_HISHIFT) + sumlo;
1596 }
1597#endif
Guy Schalnate5a37791996-06-05 15:50:50 -05001598 mins = sum;
Guy Schalnat0d580581995-07-20 02:43:20 -05001599 }
1600
Guy Schalnate5a37791996-06-05 15:50:50 -05001601 /* sub filter */
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001602 if (filter_to_do == PNG_FILTER_SUB)
1603 /* it's the only filter so no testing is needed */
1604 {
1605 png_bytep rp, lp, dp;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001606 png_uint_32 i;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001607 for (i = 0, rp = row_buf + 1, dp = png_ptr->sub_row + 1; i < bpp;
1608 i++, rp++, dp++)
1609 {
1610 *dp = *rp;
1611 }
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001612 for (lp = row_buf + 1; i < row_bytes;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001613 i++, rp++, lp++, dp++)
1614 {
1615 *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff);
1616 }
1617 best_row = png_ptr->sub_row;
1618 }
1619
1620 else if (filter_to_do & PNG_FILTER_SUB)
Guy Schalnat0d580581995-07-20 02:43:20 -05001621 {
Guy Schalnate5a37791996-06-05 15:50:50 -05001622 png_bytep rp, dp, lp;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001623 png_uint_32 sum = 0, lmins = mins;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001624 png_uint_32 i;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001625 int v;
1626
1627#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001628 /* We temporarily increase the "minimum sum" by the factor we
Andreas Dilger47a0c421997-05-16 02:46:07 -05001629 * would reduce the sum of this filter, so that we can do the
1630 * early exit comparison without scaling the sum each time.
1631 */
1632 if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
1633 {
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001634 int j;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001635 png_uint_32 lmhi, lmlo;
1636 lmlo = lmins & PNG_LOMASK;
1637 lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;
1638
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001639 for (j = 0; j < num_p_filters; j++)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001640 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001641 if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_SUB)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001642 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001643 lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
Andreas Dilger47a0c421997-05-16 02:46:07 -05001644 PNG_WEIGHT_SHIFT;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001645 lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
Andreas Dilger47a0c421997-05-16 02:46:07 -05001646 PNG_WEIGHT_SHIFT;
1647 }
1648 }
1649
1650 lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >>
1651 PNG_COST_SHIFT;
1652 lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >>
1653 PNG_COST_SHIFT;
1654
1655 if (lmhi > PNG_HIMASK)
1656 lmins = PNG_MAXSUM;
1657 else
1658 lmins = (lmhi << PNG_HISHIFT) + lmlo;
1659 }
1660#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001661
Guy Schalnate5a37791996-06-05 15:50:50 -05001662 for (i = 0, rp = row_buf + 1, dp = png_ptr->sub_row + 1; i < bpp;
1663 i++, rp++, dp++)
1664 {
1665 v = *dp = *rp;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001666
Guy Schalnate5a37791996-06-05 15:50:50 -05001667 sum += (v < 128) ? v : 256 - v;
1668 }
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06001669 for (lp = row_buf + 1; i < row_info->rowbytes;
1670 i++, rp++, lp++, dp++)
Guy Schalnate5a37791996-06-05 15:50:50 -05001671 {
1672 v = *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff);
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001673
Guy Schalnate5a37791996-06-05 15:50:50 -05001674 sum += (v < 128) ? v : 256 - v;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001675
1676 if (sum > lmins) /* We are already worse, don't continue. */
1677 break;
Guy Schalnate5a37791996-06-05 15:50:50 -05001678 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05001679
1680#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
1681 if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
1682 {
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001683 int j;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001684 png_uint_32 sumhi, sumlo;
1685 sumlo = sum & PNG_LOMASK;
1686 sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;
1687
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001688 for (j = 0; j < num_p_filters; j++)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001689 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001690 if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_SUB)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001691 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001692 sumlo = (sumlo * png_ptr->inv_filter_weights[j]) >>
Andreas Dilger47a0c421997-05-16 02:46:07 -05001693 PNG_WEIGHT_SHIFT;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001694 sumhi = (sumhi * png_ptr->inv_filter_weights[j]) >>
Andreas Dilger47a0c421997-05-16 02:46:07 -05001695 PNG_WEIGHT_SHIFT;
1696 }
1697 }
1698
1699 sumlo = (sumlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >>
1700 PNG_COST_SHIFT;
1701 sumhi = (sumhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >>
1702 PNG_COST_SHIFT;
1703
1704 if (sumhi > PNG_HIMASK)
1705 sum = PNG_MAXSUM;
1706 else
1707 sum = (sumhi << PNG_HISHIFT) + sumlo;
1708 }
1709#endif
1710
Guy Schalnate5a37791996-06-05 15:50:50 -05001711 if (sum < mins)
1712 {
1713 mins = sum;
1714 best_row = png_ptr->sub_row;
1715 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001716 }
1717
Guy Schalnate5a37791996-06-05 15:50:50 -05001718 /* up filter */
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001719 if (filter_to_do == PNG_FILTER_UP)
1720 {
1721 png_bytep rp, dp, pp;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001722 png_uint_32 i;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001723
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001724 for (i = 0, rp = row_buf + 1, dp = png_ptr->up_row + 1,
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001725 pp = prev_row + 1; i < row_bytes;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001726 i++, rp++, pp++, dp++)
1727 {
1728 *dp = (png_byte)(((int)*rp - (int)*pp) & 0xff);
1729 }
1730 best_row = png_ptr->up_row;
1731 }
1732
1733 else if (filter_to_do & PNG_FILTER_UP)
Guy Schalnat0d580581995-07-20 02:43:20 -05001734 {
Guy Schalnate5a37791996-06-05 15:50:50 -05001735 png_bytep rp, dp, pp;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001736 png_uint_32 sum = 0, lmins = mins;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001737 png_uint_32 i;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001738 int v;
1739
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001740
Andreas Dilger47a0c421997-05-16 02:46:07 -05001741#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
1742 if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
1743 {
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001744 int j;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001745 png_uint_32 lmhi, lmlo;
1746 lmlo = lmins & PNG_LOMASK;
1747 lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;
1748
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001749 for (j = 0; j < num_p_filters; j++)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001750 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001751 if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_UP)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001752 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001753 lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
Andreas Dilger47a0c421997-05-16 02:46:07 -05001754 PNG_WEIGHT_SHIFT;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001755 lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
Andreas Dilger47a0c421997-05-16 02:46:07 -05001756 PNG_WEIGHT_SHIFT;
1757 }
1758 }
1759
1760 lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_UP]) >>
1761 PNG_COST_SHIFT;
1762 lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_UP]) >>
1763 PNG_COST_SHIFT;
1764
1765 if (lmhi > PNG_HIMASK)
1766 lmins = PNG_MAXSUM;
1767 else
1768 lmins = (lmhi << PNG_HISHIFT) + lmlo;
1769 }
1770#endif
Guy Schalnate5a37791996-06-05 15:50:50 -05001771
1772 for (i = 0, rp = row_buf + 1, dp = png_ptr->up_row + 1,
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001773 pp = prev_row + 1; i < row_bytes; i++)
Guy Schalnate5a37791996-06-05 15:50:50 -05001774 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001775 v = *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff);
Guy Schalnate5a37791996-06-05 15:50:50 -05001776
1777 sum += (v < 128) ? v : 256 - v;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001778
1779 if (sum > lmins) /* We are already worse, don't continue. */
1780 break;
Guy Schalnate5a37791996-06-05 15:50:50 -05001781 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05001782
1783#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
1784 if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
1785 {
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001786 int j;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001787 png_uint_32 sumhi, sumlo;
1788 sumlo = sum & PNG_LOMASK;
1789 sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;
1790
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001791 for (j = 0; j < num_p_filters; j++)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001792 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001793 if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_UP)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001794 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001795 sumlo = (sumlo * png_ptr->filter_weights[j]) >>
Andreas Dilger47a0c421997-05-16 02:46:07 -05001796 PNG_WEIGHT_SHIFT;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001797 sumhi = (sumhi * png_ptr->filter_weights[j]) >>
Andreas Dilger47a0c421997-05-16 02:46:07 -05001798 PNG_WEIGHT_SHIFT;
1799 }
1800 }
1801
1802 sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_UP]) >>
1803 PNG_COST_SHIFT;
1804 sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_UP]) >>
1805 PNG_COST_SHIFT;
1806
1807 if (sumhi > PNG_HIMASK)
1808 sum = PNG_MAXSUM;
1809 else
1810 sum = (sumhi << PNG_HISHIFT) + sumlo;
1811 }
1812#endif
1813
Guy Schalnate5a37791996-06-05 15:50:50 -05001814 if (sum < mins)
1815 {
1816 mins = sum;
1817 best_row = png_ptr->up_row;
1818 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001819 }
1820
Guy Schalnate5a37791996-06-05 15:50:50 -05001821 /* avg filter */
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001822 if (filter_to_do == PNG_FILTER_AVG)
1823 {
1824 png_bytep rp, dp, pp, lp;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001825 png_uint_32 i;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001826 for (i = 0, rp = row_buf + 1, dp = png_ptr->avg_row + 1,
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001827 pp = prev_row + 1; i < bpp; i++)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001828 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001829 *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001830 }
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001831 for (lp = row_buf + 1; i < row_bytes; i++)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001832 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001833 *dp++ = (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2))
1834 & 0xff);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001835 }
1836 best_row = png_ptr->avg_row;
1837 }
1838
1839 else if (filter_to_do & PNG_FILTER_AVG)
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001840 {
Guy Schalnate5a37791996-06-05 15:50:50 -05001841 png_bytep rp, dp, pp, lp;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001842 png_uint_32 sum = 0, lmins = mins;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001843 png_uint_32 i;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001844 int v;
1845
1846#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
1847 if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
1848 {
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001849 int j;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001850 png_uint_32 lmhi, lmlo;
1851 lmlo = lmins & PNG_LOMASK;
1852 lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;
1853
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001854 for (j = 0; j < num_p_filters; j++)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001855 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001856 if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_AVG)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001857 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001858 lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
Andreas Dilger47a0c421997-05-16 02:46:07 -05001859 PNG_WEIGHT_SHIFT;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001860 lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
Andreas Dilger47a0c421997-05-16 02:46:07 -05001861 PNG_WEIGHT_SHIFT;
1862 }
1863 }
1864
1865 lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_AVG]) >>
1866 PNG_COST_SHIFT;
1867 lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_AVG]) >>
1868 PNG_COST_SHIFT;
1869
1870 if (lmhi > PNG_HIMASK)
1871 lmins = PNG_MAXSUM;
1872 else
1873 lmins = (lmhi << PNG_HISHIFT) + lmlo;
1874 }
1875#endif
Guy Schalnate5a37791996-06-05 15:50:50 -05001876
1877 for (i = 0, rp = row_buf + 1, dp = png_ptr->avg_row + 1,
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001878 pp = prev_row + 1; i < bpp; i++)
Guy Schalnate5a37791996-06-05 15:50:50 -05001879 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001880 v = *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff);
Guy Schalnate5a37791996-06-05 15:50:50 -05001881
1882 sum += (v < 128) ? v : 256 - v;
1883 }
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001884 for (lp = row_buf + 1; i < row_bytes; i++)
Guy Schalnate5a37791996-06-05 15:50:50 -05001885 {
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001886 v = *dp++ =
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001887 (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2)) & 0xff);
Guy Schalnate5a37791996-06-05 15:50:50 -05001888
1889 sum += (v < 128) ? v : 256 - v;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001890
1891 if (sum > lmins) /* We are already worse, don't continue. */
1892 break;
Guy Schalnate5a37791996-06-05 15:50:50 -05001893 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05001894
1895#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
1896 if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
1897 {
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001898 int j;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001899 png_uint_32 sumhi, sumlo;
1900 sumlo = sum & PNG_LOMASK;
1901 sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;
1902
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001903 for (j = 0; j < num_p_filters; j++)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001904 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001905 if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_NONE)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001906 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001907 sumlo = (sumlo * png_ptr->filter_weights[j]) >>
Andreas Dilger47a0c421997-05-16 02:46:07 -05001908 PNG_WEIGHT_SHIFT;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001909 sumhi = (sumhi * png_ptr->filter_weights[j]) >>
Andreas Dilger47a0c421997-05-16 02:46:07 -05001910 PNG_WEIGHT_SHIFT;
1911 }
1912 }
1913
1914 sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_AVG]) >>
1915 PNG_COST_SHIFT;
1916 sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_AVG]) >>
1917 PNG_COST_SHIFT;
1918
1919 if (sumhi > PNG_HIMASK)
1920 sum = PNG_MAXSUM;
1921 else
1922 sum = (sumhi << PNG_HISHIFT) + sumlo;
1923 }
1924#endif
1925
Guy Schalnate5a37791996-06-05 15:50:50 -05001926 if (sum < mins)
1927 {
1928 mins = sum;
1929 best_row = png_ptr->avg_row;
1930 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001931 }
1932
Andreas Dilger47a0c421997-05-16 02:46:07 -05001933 /* Paeth filter */
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001934 if (filter_to_do == PNG_FILTER_PAETH)
1935 {
1936 png_bytep rp, dp, pp, cp, lp;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001937 png_uint_32 i;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001938 for (i = 0, rp = row_buf + 1, dp = png_ptr->paeth_row + 1,
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001939 pp = prev_row + 1; i < bpp; i++)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001940 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001941 *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001942 }
1943
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001944 for (lp = row_buf + 1, cp = prev_row + 1; i < row_bytes; i++)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001945 {
1946 int a, b, c, pa, pb, pc, p;
1947
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001948 b = *pp++;
1949 c = *cp++;
1950 a = *lp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001951
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001952 p = b - c;
1953 pc = a - c;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001954
1955#ifdef PNG_USE_ABS
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001956 pa = abs(p);
1957 pb = abs(pc);
1958 pc = abs(p + pc);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001959#else
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001960 pa = p < 0 ? -p : p;
1961 pb = pc < 0 ? -pc : pc;
1962 pc = (p + pc) < 0 ? -(p + pc) : p + pc;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001963#endif
1964
1965 p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c;
1966
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001967 *dp++ = (png_byte)(((int)*rp++ - p) & 0xff);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001968 }
1969 best_row = png_ptr->paeth_row;
1970 }
1971
1972 else if (filter_to_do & PNG_FILTER_PAETH)
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001973 {
Guy Schalnate5a37791996-06-05 15:50:50 -05001974 png_bytep rp, dp, pp, cp, lp;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001975 png_uint_32 sum = 0, lmins = mins;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001976 png_uint_32 i;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001977 int v;
1978
1979#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
1980 if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
1981 {
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05001982 int j;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001983 png_uint_32 lmhi, lmlo;
1984 lmlo = lmins & PNG_LOMASK;
1985 lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;
1986
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001987 for (j = 0; j < num_p_filters; j++)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001988 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001989 if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_PAETH)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001990 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001991 lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
Andreas Dilger47a0c421997-05-16 02:46:07 -05001992 PNG_WEIGHT_SHIFT;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05001993 lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
Andreas Dilger47a0c421997-05-16 02:46:07 -05001994 PNG_WEIGHT_SHIFT;
1995 }
1996 }
1997
1998 lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_PAETH]) >>
1999 PNG_COST_SHIFT;
2000 lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_PAETH]) >>
2001 PNG_COST_SHIFT;
2002
2003 if (lmhi > PNG_HIMASK)
2004 lmins = PNG_MAXSUM;
2005 else
2006 lmins = (lmhi << PNG_HISHIFT) + lmlo;
2007 }
2008#endif
Guy Schalnate5a37791996-06-05 15:50:50 -05002009
2010 for (i = 0, rp = row_buf + 1, dp = png_ptr->paeth_row + 1,
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002011 pp = prev_row + 1; i < bpp; i++)
Guy Schalnate5a37791996-06-05 15:50:50 -05002012 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002013 v = *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff);
Guy Schalnate5a37791996-06-05 15:50:50 -05002014
2015 sum += (v < 128) ? v : 256 - v;
2016 }
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002017
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002018 for (lp = row_buf + 1, cp = prev_row + 1; i < row_bytes; i++)
Guy Schalnate5a37791996-06-05 15:50:50 -05002019 {
2020 int a, b, c, pa, pb, pc, p;
2021
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002022 b = *pp++;
2023 c = *cp++;
2024 a = *lp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002025
2026#ifndef PNG_SLOW_PAETH
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002027 p = b - c;
2028 pc = a - c;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002029#ifdef PNG_USE_ABS
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002030 pa = abs(p);
2031 pb = abs(pc);
2032 pc = abs(p + pc);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002033#else
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002034 pa = p < 0 ? -p : p;
2035 pb = pc < 0 ? -pc : pc;
2036 pc = (p + pc) < 0 ? -(p + pc) : p + pc;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002037#endif
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002038 p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c;
2039#else /* PNG_SLOW_PAETH */
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002040 p = a + b - c;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002041 pa = abs(p - a);
2042 pb = abs(p - b);
2043 pc = abs(p - c);
Guy Schalnate5a37791996-06-05 15:50:50 -05002044 if (pa <= pb && pa <= pc)
2045 p = a;
2046 else if (pb <= pc)
2047 p = b;
2048 else
2049 p = c;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002050#endif /* PNG_SLOW_PAETH */
Guy Schalnate5a37791996-06-05 15:50:50 -05002051
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002052 v = *dp++ = (png_byte)(((int)*rp++ - p) & 0xff);
Guy Schalnate5a37791996-06-05 15:50:50 -05002053
2054 sum += (v < 128) ? v : 256 - v;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002055
2056 if (sum > lmins) /* We are already worse, don't continue. */
2057 break;
Guy Schalnate5a37791996-06-05 15:50:50 -05002058 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05002059
2060#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
2061 if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
2062 {
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05002063 int j;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002064 png_uint_32 sumhi, sumlo;
2065 sumlo = sum & PNG_LOMASK;
2066 sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;
2067
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002068 for (j = 0; j < num_p_filters; j++)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002069 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002070 if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_PAETH)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002071 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002072 sumlo = (sumlo * png_ptr->filter_weights[j]) >>
Andreas Dilger47a0c421997-05-16 02:46:07 -05002073 PNG_WEIGHT_SHIFT;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002074 sumhi = (sumhi * png_ptr->filter_weights[j]) >>
Andreas Dilger47a0c421997-05-16 02:46:07 -05002075 PNG_WEIGHT_SHIFT;
2076 }
2077 }
2078
2079 sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_PAETH]) >>
2080 PNG_COST_SHIFT;
2081 sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_PAETH]) >>
2082 PNG_COST_SHIFT;
2083
2084 if (sumhi > PNG_HIMASK)
2085 sum = PNG_MAXSUM;
2086 else
2087 sum = (sumhi << PNG_HISHIFT) + sumlo;
2088 }
2089#endif
2090
Guy Schalnate5a37791996-06-05 15:50:50 -05002091 if (sum < mins)
2092 {
2093 best_row = png_ptr->paeth_row;
2094 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002095 }
2096
Andreas Dilger47a0c421997-05-16 02:46:07 -05002097 /* Do the actual writing of the filtered row data from the chosen filter. */
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002098
Guy Schalnate5a37791996-06-05 15:50:50 -05002099 png_write_filtered_row(png_ptr, best_row);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002100
2101#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
2102 /* Save the type of filter we picked this time for future calculations */
2103 if (png_ptr->num_prev_filters > 0)
2104 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002105 int j;
2106 for (j = 1; j < num_p_filters; j++)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002107 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002108 png_ptr->prev_filters[j] = png_ptr->prev_filters[j - 1];
Andreas Dilger47a0c421997-05-16 02:46:07 -05002109 }
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002110 png_ptr->prev_filters[j] = best_row[0];
Andreas Dilger47a0c421997-05-16 02:46:07 -05002111 }
2112#endif
Guy Schalnate5a37791996-06-05 15:50:50 -05002113}
2114
2115
Andreas Dilger47a0c421997-05-16 02:46:07 -05002116/* Do the actual writing of a previously filtered row. */
Guy Schalnate5a37791996-06-05 15:50:50 -05002117void
2118png_write_filtered_row(png_structp png_ptr, png_bytep filtered_row)
2119{
Andreas Dilger47a0c421997-05-16 02:46:07 -05002120 png_debug(1, "in png_write_filtered_row\n");
2121 png_debug1(2, "filter = %d\n", filtered_row[0]);
Guy Schalnate5a37791996-06-05 15:50:50 -05002122 /* set up the zlib input buffer */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002123 png_ptr->zstream.next_in = filtered_row;
2124 png_ptr->zstream.avail_in = (uInt)png_ptr->row_info.rowbytes + 1;
Guy Schalnate5a37791996-06-05 15:50:50 -05002125 /* repeat until we have compressed all the data */
2126 do
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002127 {
Guy Schalnate5a37791996-06-05 15:50:50 -05002128 int ret; /* return of zlib */
Guy Schalnat0d580581995-07-20 02:43:20 -05002129
Guy Schalnate5a37791996-06-05 15:50:50 -05002130 /* compress the data */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002131 ret = deflate(&png_ptr->zstream, Z_NO_FLUSH);
Guy Schalnate5a37791996-06-05 15:50:50 -05002132 /* check for compression errors */
2133 if (ret != Z_OK)
2134 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002135 if (png_ptr->zstream.msg != NULL)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002136 png_error(png_ptr, png_ptr->zstream.msg);
Guy Schalnate5a37791996-06-05 15:50:50 -05002137 else
2138 png_error(png_ptr, "zlib error");
2139 }
Guy Schalnat0d580581995-07-20 02:43:20 -05002140
Guy Schalnate5a37791996-06-05 15:50:50 -05002141 /* see if it is time to write another IDAT */
Andreas Dilger47a0c421997-05-16 02:46:07 -05002142 if (!(png_ptr->zstream.avail_out))
Guy Schalnate5a37791996-06-05 15:50:50 -05002143 {
2144 /* write the IDAT and reset the zlib output buffer */
2145 png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002146 png_ptr->zstream.next_out = png_ptr->zbuf;
2147 png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
Guy Schalnate5a37791996-06-05 15:50:50 -05002148 }
2149 /* repeat until all data has been compressed */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002150 } while (png_ptr->zstream.avail_in);
Guy Schalnate5a37791996-06-05 15:50:50 -05002151
Guy Schalnatc21f90c1996-06-17 16:24:45 -05002152 /* swap the current and previous rows */
Andreas Dilger47a0c421997-05-16 02:46:07 -05002153 if (png_ptr->prev_row != NULL)
Guy Schalnatc21f90c1996-06-17 16:24:45 -05002154 {
2155 png_bytep tptr;
2156
2157 tptr = png_ptr->prev_row;
2158 png_ptr->prev_row = png_ptr->row_buf;
2159 png_ptr->row_buf = tptr;
2160 }
2161
Guy Schalnate5a37791996-06-05 15:50:50 -05002162 /* finish row - updates counters and flushes zlib if last row */
2163 png_write_finish_row(png_ptr);
2164
2165#if defined(PNG_WRITE_FLUSH_SUPPORTED)
2166 png_ptr->flush_rows++;
2167
2168 if (png_ptr->flush_dist > 0 &&
2169 png_ptr->flush_rows >= png_ptr->flush_dist)
Guy Schalnat0d580581995-07-20 02:43:20 -05002170 {
Guy Schalnate5a37791996-06-05 15:50:50 -05002171 png_write_flush(png_ptr);
Guy Schalnat0d580581995-07-20 02:43:20 -05002172 }
Guy Schalnate5a37791996-06-05 15:50:50 -05002173#endif /* PNG_WRITE_FLUSH_SUPPORTED */
Guy Schalnat0d580581995-07-20 02:43:20 -05002174}