blob: c9821bc858ef4028d915a5b8f86e74da7db809ae [file] [log] [blame]
Guy Schalnat0d580581995-07-20 02:43:20 -05001
2/* pngwutil.c - utilities to write a png file
3
Guy Schalnate5a37791996-06-05 15:50:50 -05004 libpng 1.0 beta 3 - version 0.89
Guy Schalnat0d580581995-07-20 02:43:20 -05005 For conditions of distribution and use, see copyright notice in png.h
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06006 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
Guy Schalnate5a37791996-06-05 15:50:50 -05007 May 25, 1996
Guy Schalnat0d580581995-07-20 02:43:20 -05008 */
9#define PNG_INTERNAL
10#include "png.h"
11
12/* place a 32 bit number into a buffer in png byte order. We work
13 with unsigned numbers for convenience, you may have to cast
14 signed numbers (if you use any, most png data is unsigned). */
15void
Guy Schalnat6d764711995-12-19 03:22:19 -060016png_save_uint_32(png_bytep buf, png_uint_32 i)
Guy Schalnat0d580581995-07-20 02:43:20 -050017{
18 buf[0] = (png_byte)((i >> 24) & 0xff);
19 buf[1] = (png_byte)((i >> 16) & 0xff);
20 buf[2] = (png_byte)((i >> 8) & 0xff);
21 buf[3] = (png_byte)(i & 0xff);
22}
23
24/* place a 16 bit number into a buffer in png byte order */
25void
Guy Schalnat6d764711995-12-19 03:22:19 -060026png_save_uint_16(png_bytep buf, png_uint_16 i)
Guy Schalnat0d580581995-07-20 02:43:20 -050027{
28 buf[0] = (png_byte)((i >> 8) & 0xff);
29 buf[1] = (png_byte)(i & 0xff);
30}
31
32/* write a 32 bit number */
33void
Guy Schalnat6d764711995-12-19 03:22:19 -060034png_write_uint_32(png_structp png_ptr, png_uint_32 i)
Guy Schalnat0d580581995-07-20 02:43:20 -050035{
36 png_byte buf[4];
37
38 buf[0] = (png_byte)((i >> 24) & 0xff);
39 buf[1] = (png_byte)((i >> 16) & 0xff);
40 buf[2] = (png_byte)((i >> 8) & 0xff);
41 buf[3] = (png_byte)(i & 0xff);
Guy Schalnat6d764711995-12-19 03:22:19 -060042 png_write_data(png_ptr, buf, 4);
Guy Schalnat0d580581995-07-20 02:43:20 -050043}
44
45/* write a 16 bit number */
46void
Guy Schalnat6d764711995-12-19 03:22:19 -060047png_write_uint_16(png_structp png_ptr, png_uint_16 i)
Guy Schalnat0d580581995-07-20 02:43:20 -050048{
49 png_byte buf[2];
50
51 buf[0] = (png_byte)((i >> 8) & 0xff);
52 buf[1] = (png_byte)(i & 0xff);
Guy Schalnat6d764711995-12-19 03:22:19 -060053 png_write_data(png_ptr, buf, 2);
Guy Schalnat0d580581995-07-20 02:43:20 -050054}
55
56/* Write a png chunk all at once. The type is an array of ASCII characters
57 representing the chunk name. The array must be at least 4 bytes in
58 length, and does not need to be null terminated. To be safe, pass the
59 pre-defined chunk names here, and if you need a new one, define it
60 where the others are defined. The length is the length of the data.
61 All the data must be present. If that is not possible, use the
62 png_write_chunk_start(), png_write_chunk_data(), and png_write_chunk_end()
63 functions instead. */
64void
Guy Schalnat6d764711995-12-19 03:22:19 -060065png_write_chunk(png_structp png_ptr, png_bytep type,
66 png_bytep data, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -050067{
68 /* write length */
69 png_write_uint_32(png_ptr, length);
70 /* write chunk name */
Guy Schalnat6d764711995-12-19 03:22:19 -060071 png_write_data(png_ptr, type, (png_uint_32)4);
Guy Schalnat0d580581995-07-20 02:43:20 -050072 /* reset the crc and run the chunk name over it */
73 png_reset_crc(png_ptr);
74 png_calculate_crc(png_ptr, type, (png_uint_32)4);
75 /* write the data and update the crc */
76 if (length)
77 {
78 png_calculate_crc(png_ptr, data, length);
Guy Schalnat6d764711995-12-19 03:22:19 -060079 png_write_data(png_ptr, data, length);
Guy Schalnat0d580581995-07-20 02:43:20 -050080 }
81 /* write the crc */
82 png_write_uint_32(png_ptr, ~png_ptr->crc);
83}
84
85/* Write the start of a png chunk. The type is the chunk type.
86 The total_length is the sum of the lengths of all the data you will be
87 passing in png_write_chunk_data() */
88void
Guy Schalnat6d764711995-12-19 03:22:19 -060089png_write_chunk_start(png_structp png_ptr, png_bytep type,
Guy Schalnat0d580581995-07-20 02:43:20 -050090 png_uint_32 total_length)
91{
92 /* write the length */
93 png_write_uint_32(png_ptr, total_length);
94 /* write the chunk name */
Guy Schalnat6d764711995-12-19 03:22:19 -060095 png_write_data(png_ptr, type, (png_uint_32)4);
Guy Schalnat0d580581995-07-20 02:43:20 -050096 /* reset the crc and run it over the chunk name */
97 png_reset_crc(png_ptr);
98 png_calculate_crc(png_ptr, type, (png_uint_32)4);
99}
100
101/* write the data of a png chunk started with png_write_chunk_start().
102 Note that multiple calls to this function are allowed, and that the
103 sum of the lengths from these calls *must* add up to the total_length
104 given to png_write_chunk_start() */
105void
Guy Schalnat6d764711995-12-19 03:22:19 -0600106png_write_chunk_data(png_structp png_ptr, png_bytep data, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -0500107{
108 /* write the data, and run the crc over it */
109 if (length)
110 {
111 png_calculate_crc(png_ptr, data, length);
Guy Schalnat6d764711995-12-19 03:22:19 -0600112 png_write_data(png_ptr, data, length);
Guy Schalnat0d580581995-07-20 02:43:20 -0500113 }
114}
115
116/* finish a chunk started with png_write_chunk_start() */
117void
Guy Schalnat6d764711995-12-19 03:22:19 -0600118png_write_chunk_end(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -0500119{
120 /* write the crc */
121 png_write_uint_32(png_ptr, ~png_ptr->crc);
122}
123
124/* simple function to write the signature */
125void
Guy Schalnat6d764711995-12-19 03:22:19 -0600126png_write_sig(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -0500127{
128 /* write the 8 byte signature */
Guy Schalnat6d764711995-12-19 03:22:19 -0600129 png_write_data(png_ptr, png_sig, (png_uint_32)8);
Guy Schalnat0d580581995-07-20 02:43:20 -0500130}
131
132/* Write the IHDR chunk, and update the png_struct with the necessary
133 information. Note that the rest of this code depends upon this
134 information being correct. */
135void
Guy Schalnat6d764711995-12-19 03:22:19 -0600136png_write_IHDR(png_structp png_ptr, png_uint_32 width, png_uint_32 height,
Guy Schalnat0d580581995-07-20 02:43:20 -0500137 int bit_depth, int color_type, int compression_type, int filter_type,
138 int interlace_type)
139{
140 png_byte buf[13]; /* buffer to store the IHDR info */
141
Guy Schalnate5a37791996-06-05 15:50:50 -0500142 /* Check that we have valid input data from the application info */
143 switch (color_type)
144 {
145 case 0:
146 switch (bit_depth)
147 {
148 case 1:
149 case 2:
150 case 4:
151 case 8:
152 case 16: png_ptr->channels = 1; break;
153 default: png_error(png_ptr, "Invalid bit depth for grayscale image");
154 }
155 break;
156 case 2:
157 if (bit_depth != 8 && bit_depth != 16)
158 png_error(png_ptr, "Invalid bit depth for RGB image");
159 png_ptr->channels = 3;
160 break;
161 case 3:
162 switch (bit_depth)
163 {
164 case 1:
165 case 2:
166 case 4:
167 case 8: png_ptr->channels = 1; break;
168 default: png_error(png_ptr, "Invalid bit depth for paletted image");
169 }
170 break;
171 case 4:
172 if (bit_depth != 8 && bit_depth != 16)
173 png_error(png_ptr, "Invalid bit depth for grayscale+alpha image");
174 png_ptr->channels = 2;
175 break;
176 case 6:
177 if (bit_depth != 8 && bit_depth != 16)
178 png_error(png_ptr, "Invalid bit depth for RGBA image");
179 png_ptr->channels = 4;
180 break;
181 default:
182 png_error(png_ptr, "Invalid image color type specified");
183 }
184
185 if (compression_type != 0)
186 {
187 png_warning(png_ptr, "Invalid compression type specified");
188 compression_type = 0;
189 }
190
191 if (filter_type != 0)
192 {
193 png_warning(png_ptr, "Invalid filter type specified");
194 filter_type = 0;
195 }
196
197 if (interlace_type != 0 && interlace_type != 1)
198 {
199 png_warning(png_ptr, "Invalid interlace type specified");
200 interlace_type = 1;
201 }
202
203 /* save off the relevent information */
204 png_ptr->bit_depth = (png_byte)bit_depth;
205 png_ptr->color_type = (png_byte)color_type;
206 png_ptr->interlaced = (png_byte)interlace_type;
207 png_ptr->width = width;
208 png_ptr->height = height;
209
210 png_ptr->pixel_depth = (png_byte)(bit_depth * png_ptr->channels);
211 png_ptr->rowbytes = ((width * (png_uint_32)png_ptr->pixel_depth + 7) >> 3);
212 /* set the usr info, so any transformations can modify it */
213 png_ptr->usr_width = png_ptr->width;
214 png_ptr->usr_bit_depth = png_ptr->bit_depth;
215 png_ptr->usr_channels = png_ptr->channels;
216
Guy Schalnat0d580581995-07-20 02:43:20 -0500217 /* pack the header information into the buffer */
218 png_save_uint_32(buf, width);
219 png_save_uint_32(buf + 4, height);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600220 buf[8] = (png_byte)bit_depth;
221 buf[9] = (png_byte)color_type;
222 buf[10] = (png_byte)compression_type;
223 buf[11] = (png_byte)filter_type;
224 buf[12] = (png_byte)interlace_type;
Guy Schalnat0d580581995-07-20 02:43:20 -0500225
226 /* write the chunk */
Guy Schalnate5a37791996-06-05 15:50:50 -0500227 png_write_chunk(png_ptr, png_IHDR, buf, (png_uint_32)13);
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500228
229 /* initialize zlib with png info */
Guy Schalnat6d764711995-12-19 03:22:19 -0600230 png_ptr->zstream = (z_stream *)png_malloc(png_ptr, sizeof (z_stream));
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500231 png_ptr->zstream->zalloc = png_zalloc;
232 png_ptr->zstream->zfree = png_zfree;
Guy Schalnat4ee97b01996-01-16 01:51:56 -0600233 png_ptr->zstream->opaque = (voidpf)png_ptr;
Guy Schalnate5a37791996-06-05 15:50:50 -0500234 if (!(png_ptr->do_filter))
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500235 {
236 if (png_ptr->color_type == 3 || png_ptr->bit_depth < 8)
Guy Schalnate5a37791996-06-05 15:50:50 -0500237 png_ptr->do_filter = PNG_FILTER_NONE;
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500238 else
Guy Schalnate5a37791996-06-05 15:50:50 -0500239 png_ptr->do_filter = PNG_ALL_FILTERS;
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500240 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500241 if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_STRATEGY))
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500242 {
Guy Schalnate5a37791996-06-05 15:50:50 -0500243 if (png_ptr->do_filter != PNG_FILTER_NONE)
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500244 png_ptr->zlib_strategy = Z_FILTERED;
245 else
246 png_ptr->zlib_strategy = Z_DEFAULT_STRATEGY;
247 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500248 if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_LEVEL))
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500249 png_ptr->zlib_level = Z_DEFAULT_COMPRESSION;
Guy Schalnate5a37791996-06-05 15:50:50 -0500250 if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_MEM_LEVEL))
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500251 png_ptr->zlib_mem_level = 8;
Guy Schalnate5a37791996-06-05 15:50:50 -0500252 if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_WINDOW_BITS))
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500253 png_ptr->zlib_window_bits = 15;
Guy Schalnate5a37791996-06-05 15:50:50 -0500254 if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_METHOD))
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500255 png_ptr->zlib_method = 8;
256 deflateInit2(png_ptr->zstream, png_ptr->zlib_level,
257 png_ptr->zlib_method,
258 png_ptr->zlib_window_bits,
259 png_ptr->zlib_mem_level,
260 png_ptr->zlib_strategy);
261 png_ptr->zstream->next_out = png_ptr->zbuf;
262 png_ptr->zstream->avail_out = (uInt)png_ptr->zbuf_size;
263
Guy Schalnate5a37791996-06-05 15:50:50 -0500264 png_ptr->mode = PNG_HAVE_IHDR;
Guy Schalnat0d580581995-07-20 02:43:20 -0500265}
266
267/* write the palette. We are careful not to trust png_color to be in the
268 correct order for PNG, so people can redefine it to any convient
269 structure. */
270void
Guy Schalnat6d764711995-12-19 03:22:19 -0600271png_write_PLTE(png_structp png_ptr, png_colorp palette, int number)
Guy Schalnat0d580581995-07-20 02:43:20 -0500272{
273 int i;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600274 png_colorp pal_ptr;
Guy Schalnat0d580581995-07-20 02:43:20 -0500275 png_byte buf[3];
276
Guy Schalnate5a37791996-06-05 15:50:50 -0500277 if (number == 0 || number > 256)
278 {
279 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
280 {
281 png_error(png_ptr, "Invalid number of colors in palette");
282 }
283 else
284 {
285 png_warning(png_ptr, "Invalid number of colors in palette");
286 return;
287 }
288 }
289
290 png_ptr->num_palette = number;
291
Guy Schalnat0d580581995-07-20 02:43:20 -0500292 png_write_chunk_start(png_ptr, png_PLTE, number * 3);
293 for (i = 0, pal_ptr = palette;
294 i < number;
295 i++, pal_ptr++)
296 {
297 buf[0] = pal_ptr->red;
298 buf[1] = pal_ptr->green;
299 buf[2] = pal_ptr->blue;
300 png_write_chunk_data(png_ptr, buf, (png_uint_32)3);
301 }
302 png_write_chunk_end(png_ptr);
Guy Schalnate5a37791996-06-05 15:50:50 -0500303 png_ptr->mode |= PNG_HAVE_PLTE;
Guy Schalnat0d580581995-07-20 02:43:20 -0500304}
305
306/* write an IDAT chunk */
307void
Guy Schalnat6d764711995-12-19 03:22:19 -0600308png_write_IDAT(png_structp png_ptr, png_bytep data, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -0500309{
Guy Schalnat0d580581995-07-20 02:43:20 -0500310 png_write_chunk(png_ptr, png_IDAT, data, length);
Guy Schalnate5a37791996-06-05 15:50:50 -0500311 png_ptr->mode |= PNG_HAVE_IDAT;
Guy Schalnat0d580581995-07-20 02:43:20 -0500312}
313
314/* write an IEND chunk */
315void
Guy Schalnat6d764711995-12-19 03:22:19 -0600316png_write_IEND(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -0500317{
318 png_write_chunk(png_ptr, png_IEND, NULL, (png_uint_32)0);
Guy Schalnate5a37791996-06-05 15:50:50 -0500319 png_ptr->mode |= PNG_AFTER_IEND;
Guy Schalnat0d580581995-07-20 02:43:20 -0500320}
321
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500322#if defined(PNG_WRITE_gAMA_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500323/* write a gAMA chunk */
324void
Guy Schalnat6d764711995-12-19 03:22:19 -0600325png_write_gAMA(png_structp png_ptr, double gamma)
Guy Schalnat0d580581995-07-20 02:43:20 -0500326{
327 png_uint_32 igamma;
328 png_byte buf[4];
329
330 /* gamma is saved in 1/100,000ths */
331 igamma = (png_uint_32)(gamma * 100000.0 + 0.5);
332 png_save_uint_32(buf, igamma);
333 png_write_chunk(png_ptr, png_gAMA, buf, (png_uint_32)4);
334}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500335#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500336
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500337#if defined(PNG_WRITE_sBIT_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500338/* write the sBIT chunk */
339void
Guy Schalnat6d764711995-12-19 03:22:19 -0600340png_write_sBIT(png_structp png_ptr, png_color_8p sbit, int color_type)
Guy Schalnat0d580581995-07-20 02:43:20 -0500341{
342 png_byte buf[4];
343 int size;
344
Guy Schalnat6d764711995-12-19 03:22:19 -0600345 /* make sure we don't depend upon the order of PNG_COLOR_8 */
Guy Schalnat0d580581995-07-20 02:43:20 -0500346 if (color_type & PNG_COLOR_MASK_COLOR)
347 {
Guy Schalnate5a37791996-06-05 15:50:50 -0500348 int maxbits;
349
350 maxbits = color_type==PNG_COLOR_TYPE_PALETTE ? 8:png_ptr->usr_bit_depth;
351 if (sbit->red == 0 || sbit->red > maxbits ||
352 sbit->green == 0 || sbit->green > maxbits ||
353 sbit->blue == 0 || sbit->blue > maxbits)
354 {
355 png_warning(png_ptr, "Invalid sBIT depth specified");
356 return;
357 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500358 buf[0] = sbit->red;
359 buf[1] = sbit->green;
360 buf[2] = sbit->blue;
361 size = 3;
362 }
363 else
364 {
Guy Schalnate5a37791996-06-05 15:50:50 -0500365 if (sbit->gray == 0 || sbit->gray > png_ptr->usr_bit_depth)
366 {
367 png_warning(png_ptr, "Invalid sBIT depth specified");
368 return;
369 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500370 buf[0] = sbit->gray;
371 size = 1;
372 }
373
374 if (color_type & PNG_COLOR_MASK_ALPHA)
375 {
Guy Schalnate5a37791996-06-05 15:50:50 -0500376 if (sbit->alpha == 0 || sbit->alpha > png_ptr->usr_bit_depth)
377 {
378 png_warning(png_ptr, "Invalid sBIT depth specified");
379 return;
380 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500381 buf[size++] = sbit->alpha;
382 }
383
384 png_write_chunk(png_ptr, png_sBIT, buf, (png_uint_32)size);
385}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500386#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500387
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500388#if defined(PNG_WRITE_cHRM_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500389/* write the cHRM chunk */
390void
Guy Schalnat6d764711995-12-19 03:22:19 -0600391png_write_cHRM ( png_structp png_ptr, double white_x, double white_y,
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600392 double red_x, double red_y, double green_x, double green_y,
393 double blue_x, double blue_y)
Guy Schalnat0d580581995-07-20 02:43:20 -0500394{
395 png_uint_32 itemp;
396 png_byte buf[32];
397
398 /* each value is saved int 1/100,000ths */
Guy Schalnate5a37791996-06-05 15:50:50 -0500399 if (white_x < 0 || white_x > 0.8 || white_y < 0 || white_y > 0.8 ||
400 white_x + white_y > 1.0)
401 {
402 png_warning(png_ptr, "Invalid cHRM white point specified");
403 return;
404 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500405 itemp = (png_uint_32)(white_x * 100000.0 + 0.5);
406 png_save_uint_32(buf, itemp);
407 itemp = (png_uint_32)(white_y * 100000.0 + 0.5);
408 png_save_uint_32(buf + 4, itemp);
Guy Schalnate5a37791996-06-05 15:50:50 -0500409
410 if (red_x < 0 || red_x > 0.8 || red_y < 0 || red_y > 0.8 ||
411 red_x + red_y > 1.0)
412 {
413 png_warning(png_ptr, "Invalid cHRM red point specified");
414 return;
415 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500416 itemp = (png_uint_32)(red_x * 100000.0 + 0.5);
417 png_save_uint_32(buf + 8, itemp);
418 itemp = (png_uint_32)(red_y * 100000.0 + 0.5);
419 png_save_uint_32(buf + 12, itemp);
Guy Schalnate5a37791996-06-05 15:50:50 -0500420
421 if (green_x < 0 || green_x > 0.8 || green_y < 0 || green_y > 0.8 ||
422 green_x + green_y > 1.0)
423 {
424 png_warning(png_ptr, "Invalid cHRM green point specified");
425 return;
426 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500427 itemp = (png_uint_32)(green_x * 100000.0 + 0.5);
428 png_save_uint_32(buf + 16, itemp);
429 itemp = (png_uint_32)(green_y * 100000.0 + 0.5);
430 png_save_uint_32(buf + 20, itemp);
Guy Schalnate5a37791996-06-05 15:50:50 -0500431
432 if (blue_x < 0 || blue_x > 0.8 || blue_y < 0 || blue_y > 0.8 ||
433 blue_x + blue_y > 1.0)
434 {
435 png_warning(png_ptr, "Invalid cHRM blue point specified");
436 return;
437 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500438 itemp = (png_uint_32)(blue_x * 100000.0 + 0.5);
439 png_save_uint_32(buf + 24, itemp);
440 itemp = (png_uint_32)(blue_y * 100000.0 + 0.5);
441 png_save_uint_32(buf + 28, itemp);
Guy Schalnate5a37791996-06-05 15:50:50 -0500442
Guy Schalnat0d580581995-07-20 02:43:20 -0500443 png_write_chunk(png_ptr, png_cHRM, buf, (png_uint_32)32);
444}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500445#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500446
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500447#if defined(PNG_WRITE_tRNS_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500448/* write the tRNS chunk */
449void
Guy Schalnat6d764711995-12-19 03:22:19 -0600450png_write_tRNS(png_structp png_ptr, png_bytep trans, png_color_16p tran,
Guy Schalnat0d580581995-07-20 02:43:20 -0500451 int num_trans, int color_type)
452{
453 png_byte buf[6];
454
455 if (color_type == PNG_COLOR_TYPE_PALETTE)
456 {
Guy Schalnate5a37791996-06-05 15:50:50 -0500457 if (num_trans <= 0 || num_trans > png_ptr->num_palette)
458 {
459 png_warning(png_ptr,"Invalid number of transparent colors specified");
460 return;
461 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500462 /* write the chunk out as it is */
463 png_write_chunk(png_ptr, png_tRNS, trans, (png_uint_32)num_trans);
464 }
465 else if (color_type == PNG_COLOR_TYPE_GRAY)
466 {
467 /* one 16 bit value */
468 png_save_uint_16(buf, tran->gray);
469 png_write_chunk(png_ptr, png_tRNS, buf, (png_uint_32)2);
470 }
471 else if (color_type == PNG_COLOR_TYPE_RGB)
472 {
473 /* three 16 bit values */
474 png_save_uint_16(buf, tran->red);
475 png_save_uint_16(buf + 2, tran->green);
476 png_save_uint_16(buf + 4, tran->blue);
477 png_write_chunk(png_ptr, png_tRNS, buf, (png_uint_32)6);
478 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500479 else
480 {
481 png_warning(png_ptr, "Can't write tRNS with and alpha channel");
482 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500483}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500484#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500485
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500486#if defined(PNG_WRITE_bKGD_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500487/* write the background chunk */
488void
Guy Schalnat6d764711995-12-19 03:22:19 -0600489png_write_bKGD(png_structp png_ptr, png_color_16p back, int color_type)
Guy Schalnat0d580581995-07-20 02:43:20 -0500490{
491 png_byte buf[6];
492
493 if (color_type == PNG_COLOR_TYPE_PALETTE)
494 {
Guy Schalnate5a37791996-06-05 15:50:50 -0500495 if (back->index > png_ptr->num_palette)
496 {
497 png_warning(png_ptr, "Invalid background palette index");
498 return;
499 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500500 buf[0] = back->index;
501 png_write_chunk(png_ptr, png_bKGD, buf, (png_uint_32)1);
502 }
503 else if (color_type & PNG_COLOR_MASK_COLOR)
504 {
505 png_save_uint_16(buf, back->red);
506 png_save_uint_16(buf + 2, back->green);
507 png_save_uint_16(buf + 4, back->blue);
508 png_write_chunk(png_ptr, png_bKGD, buf, (png_uint_32)6);
509 }
510 else
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600511 {
Guy Schalnat0d580581995-07-20 02:43:20 -0500512 png_save_uint_16(buf, back->gray);
513 png_write_chunk(png_ptr, png_bKGD, buf, (png_uint_32)2);
514 }
515}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500516#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500517
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500518#if defined(PNG_WRITE_hIST_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500519/* write the histogram */
520void
Guy Schalnat6d764711995-12-19 03:22:19 -0600521png_write_hIST(png_structp png_ptr, png_uint_16p hist, int number)
Guy Schalnat0d580581995-07-20 02:43:20 -0500522{
523 int i;
524 png_byte buf[3];
525
Guy Schalnate5a37791996-06-05 15:50:50 -0500526 if (number <= 0 || number > png_ptr->num_palette)
527 {
528 png_warning(png_ptr, "Invalid number of histogram entries specified");
529 return;
530 }
531
Guy Schalnat0d580581995-07-20 02:43:20 -0500532 png_write_chunk_start(png_ptr, png_hIST, (png_uint_32)(number * 2));
533 for (i = 0; i < number; i++)
534 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600535 png_save_uint_16(buf, hist[i]);
Guy Schalnat0d580581995-07-20 02:43:20 -0500536 png_write_chunk_data(png_ptr, buf, (png_uint_32)2);
537 }
538 png_write_chunk_end(png_ptr);
539}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500540#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500541
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500542#if defined(PNG_WRITE_tEXt_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500543/* write a tEXt chunk */
544void
Guy Schalnat6d764711995-12-19 03:22:19 -0600545png_write_tEXt(png_structp png_ptr, png_charp key, png_charp text,
Guy Schalnat0d580581995-07-20 02:43:20 -0500546 png_uint_32 text_len)
547{
548 int key_len;
549
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500550 key_len = png_strlen(key);
Guy Schalnate5a37791996-06-05 15:50:50 -0500551
552 if (key_len == 0)
553 {
554 png_warning(png_ptr, "Invalid text keyword length");
555 return;
556 }
557 else if (key_len > 80)
558 {
559 png_warning(png_ptr, "Text keyword length restricted to 80 characters\n");
560 key[80] = '\0';
561 key_len = 80;
562 }
563
Guy Schalnat0d580581995-07-20 02:43:20 -0500564 /* make sure we count the 0 after the key */
565 png_write_chunk_start(png_ptr, png_tEXt,
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600566 (png_uint_32)(key_len + text_len + 1));
Guy Schalnat0d580581995-07-20 02:43:20 -0500567 /* key has an 0 at the end. How nice */
Guy Schalnat6d764711995-12-19 03:22:19 -0600568 png_write_chunk_data(png_ptr, (png_bytep )key, (png_uint_32)(key_len + 1));
Guy Schalnat0d580581995-07-20 02:43:20 -0500569 if (text && text_len)
Guy Schalnat6d764711995-12-19 03:22:19 -0600570 png_write_chunk_data(png_ptr, (png_bytep )text, (png_uint_32)text_len);
Guy Schalnat0d580581995-07-20 02:43:20 -0500571 png_write_chunk_end(png_ptr);
572}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500573#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500574
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500575#if defined(PNG_WRITE_zTXt_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500576/* write a compressed chunk */
577void
Guy Schalnat6d764711995-12-19 03:22:19 -0600578png_write_zTXt(png_structp png_ptr, png_charp key, png_charp text,
Guy Schalnat0d580581995-07-20 02:43:20 -0500579 png_uint_32 text_len, int compression)
580{
581 int key_len;
582 char buf[1];
583 int i, ret;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600584 png_charpp output_ptr = NULL; /* array of pointers to output */
Guy Schalnat0d580581995-07-20 02:43:20 -0500585 int num_output_ptr = 0; /* number of output pointers used */
586 int max_output_ptr = 0; /* size of output_ptr */
587
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500588 key_len = png_strlen(key);
Guy Schalnat0d580581995-07-20 02:43:20 -0500589
Guy Schalnate5a37791996-06-05 15:50:50 -0500590 if (key_len == 0)
591 {
592 png_warning(png_ptr, "Invalid text keyword length");
593 return;
594 }
595 else if (key_len > 80)
596 {
597 png_warning(png_ptr, "Text keyword length restricted to 80 characters\n");
598 key[80] = '\0';
599 key_len = 80;
600 }
601
602 if (compression != 0)
603 {
604 png_warning(png_ptr, "Only type 0 compression allowed for text\n");
605 compression = 0;
606 }
607
Guy Schalnat0d580581995-07-20 02:43:20 -0500608 /* we can't write the chunk until we find out how much data we have,
609 which means we need to run the compresser first, and save the
610 output. This shouldn't be a problem, as the vast majority of
611 comments should be reasonable, but we will set up an array of
612 malloced pointers to be sure. */
613
614 /* set up the compression buffers */
615 png_ptr->zstream->avail_in = (uInt)text_len;
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500616 png_ptr->zstream->next_in = (Bytef *)text;
Guy Schalnat0d580581995-07-20 02:43:20 -0500617 png_ptr->zstream->avail_out = (uInt)png_ptr->zbuf_size;
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500618 png_ptr->zstream->next_out = (Bytef *)png_ptr->zbuf;
Guy Schalnat0d580581995-07-20 02:43:20 -0500619
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600620 /* this is the same compression loop as in png_write_row() */
Guy Schalnat0d580581995-07-20 02:43:20 -0500621 do
622 {
623 /* compress the data */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600624 ret = deflate(png_ptr->zstream, Z_NO_FLUSH);
Guy Schalnat0d580581995-07-20 02:43:20 -0500625 if (ret != Z_OK)
626 {
627 /* error */
628 if (png_ptr->zstream->msg)
Guy Schalnat6d764711995-12-19 03:22:19 -0600629 png_error(png_ptr, png_ptr->zstream->msg);
Guy Schalnat0d580581995-07-20 02:43:20 -0500630 else
Guy Schalnat6d764711995-12-19 03:22:19 -0600631 png_error(png_ptr, "zlib error");
Guy Schalnat0d580581995-07-20 02:43:20 -0500632 }
633 /* check to see if we need more room */
634 if (!png_ptr->zstream->avail_out && png_ptr->zstream->avail_in)
635 {
636 /* make sure the output array has room */
637 if (num_output_ptr >= max_output_ptr)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600638 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500639 png_uint_32 old_max;
640
641 old_max = max_output_ptr;
Guy Schalnat0d580581995-07-20 02:43:20 -0500642 max_output_ptr = num_output_ptr + 4;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600643 if (output_ptr)
644 {
645 png_charpp old_ptr;
Guy Schalnat4ee97b01996-01-16 01:51:56 -0600646
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600647 old_ptr = output_ptr;
648 output_ptr = (png_charpp)png_large_malloc(png_ptr,
649 max_output_ptr * sizeof (png_charpp));
650 png_memcpy(output_ptr, old_ptr,
651 (png_size_t)(old_max * sizeof (png_charp)));
652 png_large_free(png_ptr, old_ptr);
653 }
654 else
655 output_ptr = (png_charpp)png_large_malloc(png_ptr,
656 max_output_ptr * sizeof (png_charp));
Guy Schalnat0d580581995-07-20 02:43:20 -0500657 }
658
659 /* save the data */
660 output_ptr[num_output_ptr] = png_large_malloc(png_ptr,
661 png_ptr->zbuf_size);
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500662 png_memcpy(output_ptr[num_output_ptr], png_ptr->zbuf,
Guy Schalnat0d580581995-07-20 02:43:20 -0500663 (png_size_t)png_ptr->zbuf_size);
664 num_output_ptr++;
665
666 /* and reset the buffer */
667 png_ptr->zstream->avail_out = (uInt)png_ptr->zbuf_size;
668 png_ptr->zstream->next_out = png_ptr->zbuf;
669 }
670 /* continue until we don't have anymore to compress */
671 } while (png_ptr->zstream->avail_in);
672
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600673 /* finish the compression */
Guy Schalnat0d580581995-07-20 02:43:20 -0500674 do
675 {
676 /* tell zlib we are finished */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600677 ret = deflate(png_ptr->zstream, Z_FINISH);
Guy Schalnat0d580581995-07-20 02:43:20 -0500678 if (ret != Z_OK && ret != Z_STREAM_END)
679 {
680 /* we got an error */
681 if (png_ptr->zstream->msg)
Guy Schalnat6d764711995-12-19 03:22:19 -0600682 png_error(png_ptr, png_ptr->zstream->msg);
Guy Schalnat0d580581995-07-20 02:43:20 -0500683 else
Guy Schalnat6d764711995-12-19 03:22:19 -0600684 png_error(png_ptr, "zlib error");
Guy Schalnat0d580581995-07-20 02:43:20 -0500685 }
686
687 /* check to see if we need more room */
688 if (!png_ptr->zstream->avail_out && ret == Z_OK)
689 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600690 /* check to make sure our output array has room */
691 if (num_output_ptr >= max_output_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -0500692 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500693 png_uint_32 old_max;
694
695 old_max = max_output_ptr;
Guy Schalnat0d580581995-07-20 02:43:20 -0500696 max_output_ptr = num_output_ptr + 4;
697 if (output_ptr)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600698 {
699 png_charpp old_ptr;
Guy Schalnat0d580581995-07-20 02:43:20 -0500700
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600701 old_ptr = output_ptr;
702 output_ptr = (png_charpp)png_large_malloc(png_ptr,
703 max_output_ptr * sizeof (png_charpp));
704 png_memcpy(output_ptr, old_ptr,
705 (png_size_t)(old_max * sizeof (png_charp)));
706 png_large_free(png_ptr, old_ptr);
707 }
708 else
709 output_ptr = (png_charpp)png_large_malloc(png_ptr,
710 max_output_ptr * sizeof (png_charp));
711 }
Guy Schalnat4ee97b01996-01-16 01:51:56 -0600712
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600713 /* save off the data */
714 output_ptr[num_output_ptr] = png_large_malloc(png_ptr,
715 png_ptr->zbuf_size);
716 png_memcpy(output_ptr[num_output_ptr], png_ptr->zbuf,
Guy Schalnat0d580581995-07-20 02:43:20 -0500717 (png_size_t)png_ptr->zbuf_size);
718 num_output_ptr++;
719
720 /* and reset the buffer pointers */
721 png_ptr->zstream->avail_out = (uInt)png_ptr->zbuf_size;
722 png_ptr->zstream->next_out = png_ptr->zbuf;
723 }
724 } while (ret != Z_STREAM_END);
725
726 /* text length is number of buffers plus last buffer */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600727 text_len = png_ptr->zbuf_size * num_output_ptr;
Guy Schalnat0d580581995-07-20 02:43:20 -0500728 if (png_ptr->zstream->avail_out < png_ptr->zbuf_size)
729 text_len += (png_uint_32)(png_ptr->zbuf_size -
730 png_ptr->zstream->avail_out);
731
732 /* write start of chunk */
733 png_write_chunk_start(png_ptr, png_zTXt,
734 (png_uint_32)(key_len + text_len + 2));
735 /* write key */
Guy Schalnat6d764711995-12-19 03:22:19 -0600736 png_write_chunk_data(png_ptr, (png_bytep )key, (png_uint_32)(key_len + 1));
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600737 buf[0] = (png_byte)compression;
Guy Schalnat0d580581995-07-20 02:43:20 -0500738 /* write compression */
Guy Schalnat6d764711995-12-19 03:22:19 -0600739 png_write_chunk_data(png_ptr, (png_bytep )buf, (png_uint_32)1);
Guy Schalnat0d580581995-07-20 02:43:20 -0500740
741 /* write saved output buffers, if any */
742 for (i = 0; i < num_output_ptr; i++)
743 {
Guy Schalnat6d764711995-12-19 03:22:19 -0600744 png_write_chunk_data(png_ptr, (png_bytep )output_ptr[i], png_ptr->zbuf_size);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600745 png_large_free(png_ptr, output_ptr[i]);
Guy Schalnat0d580581995-07-20 02:43:20 -0500746 }
747 if (max_output_ptr)
Guy Schalnat4ee97b01996-01-16 01:51:56 -0600748 png_large_free(png_ptr, output_ptr);
Guy Schalnat0d580581995-07-20 02:43:20 -0500749 /* write anything left in zbuf */
750 if (png_ptr->zstream->avail_out < png_ptr->zbuf_size)
751 png_write_chunk_data(png_ptr, png_ptr->zbuf,
752 png_ptr->zbuf_size - png_ptr->zstream->avail_out);
753 /* close the chunk */
754 png_write_chunk_end(png_ptr);
755
756 /* reset zlib for another zTXt or the image data */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600757 deflateReset(png_ptr->zstream);
Guy Schalnat0d580581995-07-20 02:43:20 -0500758}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500759#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500760
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500761#if defined(PNG_WRITE_pHYs_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500762/* write the pHYs chunk */
763void
Guy Schalnat6d764711995-12-19 03:22:19 -0600764png_write_pHYs(png_structp png_ptr, png_uint_32 x_pixels_per_unit,
Guy Schalnat0d580581995-07-20 02:43:20 -0500765 png_uint_32 y_pixels_per_unit,
766 int unit_type)
767{
768 png_byte buf[9];
769
Guy Schalnate5a37791996-06-05 15:50:50 -0500770 if (unit_type >= PNG_RESOLUTION_LAST)
771 png_warning(png_ptr, "Unrecognized unit type for pHYs chunk");
772
Guy Schalnat0d580581995-07-20 02:43:20 -0500773 png_save_uint_32(buf, x_pixels_per_unit);
774 png_save_uint_32(buf + 4, y_pixels_per_unit);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600775 buf[8] = (png_byte)unit_type;
Guy Schalnat0d580581995-07-20 02:43:20 -0500776
777 png_write_chunk(png_ptr, png_pHYs, buf, (png_uint_32)9);
778}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500779#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500780
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500781#if defined(PNG_WRITE_oFFs_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500782/* write the oFFs chunk */
783void
Guy Schalnat6d764711995-12-19 03:22:19 -0600784png_write_oFFs(png_structp png_ptr, png_uint_32 x_offset,
Guy Schalnat0d580581995-07-20 02:43:20 -0500785 png_uint_32 y_offset,
786 int unit_type)
787{
788 png_byte buf[9];
789
Guy Schalnate5a37791996-06-05 15:50:50 -0500790 if (unit_type >= PNG_OFFSET_LAST)
791 png_warning(png_ptr, "Unrecognized unit type for oFFs chunk");
792
Guy Schalnat0d580581995-07-20 02:43:20 -0500793 png_save_uint_32(buf, x_offset);
794 png_save_uint_32(buf + 4, y_offset);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600795 buf[8] = (png_byte)unit_type;
Guy Schalnat0d580581995-07-20 02:43:20 -0500796
797 png_write_chunk(png_ptr, png_oFFs, buf, (png_uint_32)9);
798}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500799#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500800
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500801#if defined(PNG_WRITE_tIME_SUPPORTED)
802/* write the tIME chunk. Use either png_convert_from_struct_tm()
803 or png_convert_from_time_t(), or fill in the structure yourself */
Guy Schalnat0d580581995-07-20 02:43:20 -0500804void
Guy Schalnat6d764711995-12-19 03:22:19 -0600805png_write_tIME(png_structp png_ptr, png_timep mod_time)
Guy Schalnat0d580581995-07-20 02:43:20 -0500806{
807 png_byte buf[7];
808
Guy Schalnate5a37791996-06-05 15:50:50 -0500809 if (mod_time->month > 12 || mod_time->month < 1 ||
810 mod_time->day > 31 || mod_time->day < 1 ||
811 mod_time->hour > 23 || mod_time->second > 60)
812 {
813 png_warning(png_ptr, "Invalid time specified for tIME chunk");
814 return;
815 }
816
Guy Schalnat0d580581995-07-20 02:43:20 -0500817 png_save_uint_16(buf, mod_time->year);
818 buf[2] = mod_time->month;
819 buf[3] = mod_time->day;
820 buf[4] = mod_time->hour;
821 buf[5] = mod_time->minute;
822 buf[6] = mod_time->second;
823
824 png_write_chunk(png_ptr, png_tIME, buf, (png_uint_32)7);
825}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500826#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500827
828/* initializes the row writing capability of libpng */
829void
Guy Schalnat6d764711995-12-19 03:22:19 -0600830png_write_start_row(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -0500831{
832 /* set up row buffer */
Guy Schalnat6d764711995-12-19 03:22:19 -0600833 png_ptr->row_buf = (png_bytep )png_large_malloc(png_ptr,
Guy Schalnat0d580581995-07-20 02:43:20 -0500834 (((png_uint_32)png_ptr->usr_channels *
835 (png_uint_32)png_ptr->usr_bit_depth *
Guy Schalnat6d764711995-12-19 03:22:19 -0600836 png_ptr->width + 7) >> 3) + 1);
Guy Schalnate5a37791996-06-05 15:50:50 -0500837 png_ptr->row_buf[0] = 0;
838
839 /* set up filtering buffer, if using this filter */
840 if (png_ptr->do_filter & PNG_FILTER_SUB)
Guy Schalnat0d580581995-07-20 02:43:20 -0500841 {
Guy Schalnate5a37791996-06-05 15:50:50 -0500842 png_ptr->sub_row = (png_bytep )png_large_malloc(png_ptr,
843 png_ptr->rowbytes + 1);
844 png_ptr->sub_row[0] = 1; /* Set the row filter type */
845 }
846
847 /* We only need to keep the previous row if we are using one of these */
848 if (png_ptr->do_filter & (PNG_FILTER_AVG | PNG_FILTER_UP | PNG_FILTER_PAETH))
849 {
850 /* set up previous row buffer */
Guy Schalnat6d764711995-12-19 03:22:19 -0600851 png_ptr->prev_row = (png_bytep )png_large_malloc(png_ptr,
Guy Schalnate5a37791996-06-05 15:50:50 -0500852 (((png_uint_32)png_ptr->usr_channels *
853 (png_uint_32)png_ptr->usr_bit_depth *
854 png_ptr->width + 7) >> 3) + 1);
855 png_memset(png_ptr->prev_row, 0, (((png_uint_32)png_ptr->usr_channels *
856 (png_uint_32)png_ptr->usr_bit_depth * png_ptr->width + 7) >> 3) + 1);
857
858 if (png_ptr->do_filter & PNG_FILTER_UP)
859 {
860 png_ptr->up_row = (png_bytep )png_large_malloc(png_ptr,
861 png_ptr->rowbytes + 1);
862 png_ptr->up_row[0] = 2; /* Set the row filter type */
863 }
864
865 if (png_ptr->do_filter & PNG_FILTER_AVG)
866 {
867 png_ptr->avg_row = (png_bytep )png_large_malloc(png_ptr,
868 png_ptr->rowbytes + 1);
869 png_ptr->avg_row[0] = 3; /* Set the row filter type */
870 }
871
872 if (png_ptr->do_filter & PNG_FILTER_PAETH)
873 {
874 png_ptr->paeth_row = (png_bytep )png_large_malloc(png_ptr,
875 png_ptr->rowbytes + 1);
876 png_ptr->paeth_row[0] = 4; /* Set the row filter type */
877 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500878 }
879
880 /* if interlaced, we need to set up width and height of pass */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600881 if (png_ptr->interlaced)
Guy Schalnat0d580581995-07-20 02:43:20 -0500882 {
883 if (!(png_ptr->transformations & PNG_INTERLACE))
884 {
885 png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 -
886 png_pass_ystart[0]) / png_pass_yinc[0];
887 png_ptr->usr_width = (png_ptr->width +
888 png_pass_inc[0] - 1 -
889 png_pass_start[0]) /
890 png_pass_inc[0];
891 }
892 else
893 {
894 png_ptr->num_rows = png_ptr->height;
895 png_ptr->usr_width = png_ptr->width;
896 }
897 }
898 else
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600899 {
Guy Schalnat0d580581995-07-20 02:43:20 -0500900 png_ptr->num_rows = png_ptr->height;
901 png_ptr->usr_width = png_ptr->width;
902 }
903 png_ptr->zstream->avail_out = (uInt)png_ptr->zbuf_size;
904 png_ptr->zstream->next_out = png_ptr->zbuf;
905}
906
907/* Internal use only. Called when finished processing a row of data */
908void
Guy Schalnat6d764711995-12-19 03:22:19 -0600909png_write_finish_row(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -0500910{
911 int ret;
912
913 /* next row */
914 png_ptr->row_number++;
Guy Schalnatc21f90c1996-06-17 16:24:45 -0500915
Guy Schalnat0d580581995-07-20 02:43:20 -0500916 /* see if we are done */
Guy Schalnat6d764711995-12-19 03:22:19 -0600917 if (png_ptr->row_number < png_ptr->num_rows)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600918 return;
Guy Schalnat0d580581995-07-20 02:43:20 -0500919
920 /* if interlaced, go to next pass */
921 if (png_ptr->interlaced)
922 {
923 png_ptr->row_number = 0;
924 if (png_ptr->transformations & PNG_INTERLACE)
925 {
926 png_ptr->pass++;
927 }
928 else
929 {
930 /* loop until we find a non-zero width or height pass */
931 do
932 {
933 png_ptr->pass++;
934 if (png_ptr->pass >= 7)
935 break;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600936 png_ptr->usr_width = (png_ptr->width +
Guy Schalnat0d580581995-07-20 02:43:20 -0500937 png_pass_inc[png_ptr->pass] - 1 -
938 png_pass_start[png_ptr->pass]) /
939 png_pass_inc[png_ptr->pass];
940 png_ptr->num_rows = (png_ptr->height +
941 png_pass_yinc[png_ptr->pass] - 1 -
942 png_pass_ystart[png_ptr->pass]) /
943 png_pass_yinc[png_ptr->pass];
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500944 if (png_ptr->transformations & PNG_INTERLACE)
945 break;
Guy Schalnat0d580581995-07-20 02:43:20 -0500946 } while (png_ptr->usr_width == 0 || png_ptr->num_rows == 0);
947
948 }
949
Guy Schalnate5a37791996-06-05 15:50:50 -0500950 /* reset the row above the image for the next pass */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600951 if (png_ptr->pass < 7)
Guy Schalnatc21f90c1996-06-17 16:24:45 -0500952 {
953 if (png_ptr->prev_row)
954 png_memset(png_ptr->prev_row, 0,
955 (((png_uint_32)png_ptr->usr_channels *
956 (png_uint_32)png_ptr->usr_bit_depth *
957 png_ptr->width + 7) >> 3) + 1);
Guy Schalnat0d580581995-07-20 02:43:20 -0500958 return;
Guy Schalnatc21f90c1996-06-17 16:24:45 -0500959 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500960 }
961
962 /* if we get here, we've just written the last row, so we need
963 to flush the compressor */
964 do
965 {
966 /* tell the compressor we are done */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600967 ret = deflate(png_ptr->zstream, Z_FINISH);
Guy Schalnat0d580581995-07-20 02:43:20 -0500968 /* check for an error */
969 if (ret != Z_OK && ret != Z_STREAM_END)
970 {
971 if (png_ptr->zstream->msg)
Guy Schalnat6d764711995-12-19 03:22:19 -0600972 png_error(png_ptr, png_ptr->zstream->msg);
Guy Schalnat0d580581995-07-20 02:43:20 -0500973 else
Guy Schalnat6d764711995-12-19 03:22:19 -0600974 png_error(png_ptr, "zlib error");
Guy Schalnat0d580581995-07-20 02:43:20 -0500975 }
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600976 /* check to see if we need more room */
Guy Schalnat0d580581995-07-20 02:43:20 -0500977 if (!png_ptr->zstream->avail_out && ret == Z_OK)
978 {
979 png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size);
980 png_ptr->zstream->next_out = png_ptr->zbuf;
981 png_ptr->zstream->avail_out = (uInt)png_ptr->zbuf_size;
982 }
983 } while (ret != Z_STREAM_END);
984
985 /* write any extra space */
986 if (png_ptr->zstream->avail_out < png_ptr->zbuf_size)
987 {
988 png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size -
989 png_ptr->zstream->avail_out);
990 }
991
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500992 deflateReset(png_ptr->zstream);
Guy Schalnat0d580581995-07-20 02:43:20 -0500993}
994
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500995#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500996/* pick out the correct pixels for the interlace pass.
997
998 The basic idea here is to go through the row with a source
999 pointer and a destination pointer (sp and dp), and copy the
1000 correct pixels for the pass. As the row gets compacted,
1001 sp will always be >= dp, so we should never overwrite anything.
1002 See the default: case for the easiest code to understand.
1003 */
1004void
Guy Schalnat6d764711995-12-19 03:22:19 -06001005png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass)
Guy Schalnat0d580581995-07-20 02:43:20 -05001006{
1007 /* we don't have to do anything on the last pass (6) */
1008 if (row && row_info && pass < 6)
1009 {
1010 /* each pixel depth is handled seperately */
1011 switch (row_info->pixel_depth)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001012 {
Guy Schalnat0d580581995-07-20 02:43:20 -05001013 case 1:
1014 {
Guy Schalnat6d764711995-12-19 03:22:19 -06001015 png_bytep sp;
1016 png_bytep dp;
Guy Schalnat0d580581995-07-20 02:43:20 -05001017 int shift;
1018 int d;
1019 int value;
1020 png_uint_32 i;
1021
1022 dp = row;
1023 d = 0;
1024 shift = 7;
1025 for (i = png_pass_start[pass];
1026 i < row_info->width;
1027 i += png_pass_inc[pass])
1028 {
1029 sp = row + (png_size_t)(i >> 3);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001030 value = (int)(*sp >> (7 - (int)(i & 7))) & 0x1;
Guy Schalnat0d580581995-07-20 02:43:20 -05001031 d |= (value << shift);
1032
1033 if (shift == 0)
1034 {
1035 shift = 7;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001036 *dp++ = (png_byte)d;
Guy Schalnat0d580581995-07-20 02:43:20 -05001037 d = 0;
1038 }
1039 else
1040 shift--;
1041
1042 }
1043 if (shift != 7)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001044 *dp = (png_byte)d;
Guy Schalnat0d580581995-07-20 02:43:20 -05001045 break;
1046 }
1047 case 2:
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001048 {
Guy Schalnat6d764711995-12-19 03:22:19 -06001049 png_bytep sp;
1050 png_bytep dp;
Guy Schalnat0d580581995-07-20 02:43:20 -05001051 int shift;
1052 int d;
1053 int value;
1054 png_uint_32 i;
1055
1056 dp = row;
1057 shift = 6;
1058 d = 0;
1059 for (i = png_pass_start[pass];
1060 i < row_info->width;
1061 i += png_pass_inc[pass])
1062 {
1063 sp = row + (png_size_t)(i >> 2);
1064 value = (*sp >> ((3 - (int)(i & 3)) << 1)) & 0x3;
1065 d |= (value << shift);
1066
1067 if (shift == 0)
1068 {
1069 shift = 6;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001070 *dp++ = (png_byte)d;
Guy Schalnat0d580581995-07-20 02:43:20 -05001071 d = 0;
1072 }
1073 else
1074 shift -= 2;
1075 }
1076 if (shift != 6)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001077 *dp = (png_byte)d;
Guy Schalnat0d580581995-07-20 02:43:20 -05001078 break;
1079 }
1080 case 4:
1081 {
Guy Schalnat6d764711995-12-19 03:22:19 -06001082 png_bytep sp;
1083 png_bytep dp;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001084 int shift;
Guy Schalnat0d580581995-07-20 02:43:20 -05001085 int d;
1086 int value;
1087 png_uint_32 i;
1088
1089 dp = row;
1090 shift = 4;
1091 d = 0;
1092 for (i = png_pass_start[pass];
1093 i < row_info->width;
1094 i += png_pass_inc[pass])
1095 {
1096 sp = row + (png_size_t)(i >> 1);
1097 value = (*sp >> ((1 - (int)(i & 1)) << 2)) & 0xf;
1098 d |= (value << shift);
1099
1100 if (shift == 0)
1101 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001102 shift = 4;
1103 *dp++ = (png_byte)d;
Guy Schalnat0d580581995-07-20 02:43:20 -05001104 d = 0;
1105 }
1106 else
1107 shift -= 4;
1108 }
1109 if (shift != 4)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001110 *dp = (png_byte)d;
Guy Schalnat0d580581995-07-20 02:43:20 -05001111 break;
1112 }
1113 default:
1114 {
Guy Schalnat6d764711995-12-19 03:22:19 -06001115 png_bytep sp;
1116 png_bytep dp;
Guy Schalnat0d580581995-07-20 02:43:20 -05001117 png_uint_32 i;
1118 int pixel_bytes;
1119
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001120 /* start at the beginning */
Guy Schalnat0d580581995-07-20 02:43:20 -05001121 dp = row;
1122 /* find out how many bytes each pixel takes up */
1123 pixel_bytes = (row_info->pixel_depth >> 3);
1124 /* loop through the row, only looking at the pixels that
1125 matter */
1126 for (i = png_pass_start[pass];
1127 i < row_info->width;
1128 i += png_pass_inc[pass])
1129 {
1130 /* find out where the original pixel is */
1131 sp = row + (png_size_t)(i * pixel_bytes);
1132 /* move the pixel */
1133 if (dp != sp)
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001134 png_memcpy(dp, sp, pixel_bytes);
Guy Schalnat0d580581995-07-20 02:43:20 -05001135 /* next pixel */
1136 dp += pixel_bytes;
1137 }
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001138 break;
Guy Schalnat0d580581995-07-20 02:43:20 -05001139 }
1140 }
1141 /* set new row width */
1142 row_info->width = (row_info->width +
1143 png_pass_inc[pass] - 1 -
1144 png_pass_start[pass]) /
1145 png_pass_inc[pass];
1146 row_info->rowbytes = ((row_info->width *
1147 row_info->pixel_depth + 7) >> 3);
1148
1149 }
1150}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001151#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001152
Guy Schalnate5a37791996-06-05 15:50:50 -05001153/* this filters the row, chooses which filter to use, if it has not already
1154 * been given by the application, and then writes the row out with the
1155 * chosen filter */
Guy Schalnat0d580581995-07-20 02:43:20 -05001156void
Guy Schalnate5a37791996-06-05 15:50:50 -05001157png_write_find_filter(png_structp png_ptr, png_row_infop row_info)
Guy Schalnat0d580581995-07-20 02:43:20 -05001158{
Guy Schalnate5a37791996-06-05 15:50:50 -05001159 png_bytep prev_row, best_row, row_buf;
1160 png_uint_32 mins;
1161 int bpp;
Guy Schalnat0d580581995-07-20 02:43:20 -05001162
1163 /* find out how many bytes offset each pixel is */
1164 bpp = (row_info->pixel_depth + 7) / 8;
Guy Schalnate5a37791996-06-05 15:50:50 -05001165
1166 prev_row = png_ptr->prev_row;
1167 best_row = row_buf = png_ptr->row_buf;
1168 mins = 0xffffffff;
Guy Schalnat0d580581995-07-20 02:43:20 -05001169
1170 /* the prediction method we use is to find which method provides
1171 the smallest value when summing the abs of the distances from
1172 zero using anything >= 128 as negitive numbers. */
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001173
Guy Schalnate5a37791996-06-05 15:50:50 -05001174 /* We don't need to test the 'no filter' case if this is the only filter
1175 * that has been chosen, as it doesn't actually do anything to the data. */
1176 if (png_ptr->do_filter & PNG_FILTER_NONE &&
1177 png_ptr->do_filter != PNG_FILTER_NONE)
Guy Schalnat0d580581995-07-20 02:43:20 -05001178 {
Guy Schalnate5a37791996-06-05 15:50:50 -05001179 png_bytep rp;
1180 png_uint_32 sum = 0;
1181 int i, v;
Guy Schalnat0d580581995-07-20 02:43:20 -05001182
Guy Schalnate5a37791996-06-05 15:50:50 -05001183 for (i = 0, rp = row_buf + 1; i < row_info->rowbytes; i++, rp++)
1184 {
1185 v = *rp;
1186 sum += (v < 128) ? v : 256 - v;
1187 }
1188 mins = sum;
Guy Schalnat0d580581995-07-20 02:43:20 -05001189 }
1190
Guy Schalnate5a37791996-06-05 15:50:50 -05001191 /* sub filter */
1192 if (png_ptr->do_filter & PNG_FILTER_SUB)
Guy Schalnat0d580581995-07-20 02:43:20 -05001193 {
Guy Schalnate5a37791996-06-05 15:50:50 -05001194 png_bytep rp, dp, lp;
1195 png_uint_32 sum = 0;
1196 int i, v;
Guy Schalnat0d580581995-07-20 02:43:20 -05001197
Guy Schalnate5a37791996-06-05 15:50:50 -05001198 for (i = 0, rp = row_buf + 1, dp = png_ptr->sub_row + 1; i < bpp;
1199 i++, rp++, dp++)
1200 {
1201 v = *dp = *rp;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001202
Guy Schalnate5a37791996-06-05 15:50:50 -05001203 sum += (v < 128) ? v : 256 - v;
1204 }
1205 for (lp = row_buf + 1; i < row_info->rowbytes; i++, rp++, lp++, dp++)
1206 {
1207 v = *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff);
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001208
Guy Schalnate5a37791996-06-05 15:50:50 -05001209 sum += (v < 128) ? v : 256 - v;
1210 }
1211 if (sum < mins)
1212 {
1213 mins = sum;
1214 best_row = png_ptr->sub_row;
1215 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001216 }
1217
Guy Schalnate5a37791996-06-05 15:50:50 -05001218 /* up filter */
1219 if (png_ptr->do_filter & PNG_FILTER_UP)
Guy Schalnat0d580581995-07-20 02:43:20 -05001220 {
Guy Schalnate5a37791996-06-05 15:50:50 -05001221 png_bytep rp, dp, pp;
1222 png_uint_32 sum = 0;
1223 int i, v;
1224
1225 for (i = 0, rp = row_buf + 1, dp = png_ptr->up_row + 1,
1226 pp = prev_row + 1; i < row_info->rowbytes; i++, rp++, pp++, dp++)
1227 {
1228 v = *dp = (png_byte)(((int)*rp - (int)*pp) & 0xff);
1229
1230 sum += (v < 128) ? v : 256 - v;
1231 }
1232 if (sum < mins)
1233 {
1234 mins = sum;
1235 best_row = png_ptr->up_row;
1236 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001237 }
1238
Guy Schalnate5a37791996-06-05 15:50:50 -05001239 /* avg filter */
1240 if (png_ptr->do_filter & PNG_FILTER_AVG)
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001241 {
Guy Schalnate5a37791996-06-05 15:50:50 -05001242 png_bytep rp, dp, pp, lp;
1243 png_uint_32 sum = 0;
1244 int i, v;
1245
1246 for (i = 0, rp = row_buf + 1, dp = png_ptr->avg_row + 1,
1247 pp = prev_row + 1; i < bpp; i++, rp++, pp++, dp++)
1248 {
1249 v = *dp = (png_byte)(((int)*rp - ((int)*pp / 2)) & 0xff);
1250
1251 sum += (v < 128) ? v : 256 - v;
1252 }
1253 for (lp = row_buf + 1; i < row_info->rowbytes;
1254 i++, rp++, pp++, lp++, dp++)
1255 {
1256 v = *dp = (png_byte)(((int)*rp - (((int)*pp + (int)*lp) / 2)) & 0xff);
1257
1258 sum += (v < 128) ? v : 256 - v;
1259 }
1260 if (sum < mins)
1261 {
1262 mins = sum;
1263 best_row = png_ptr->avg_row;
1264 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001265 }
1266
Guy Schalnate5a37791996-06-05 15:50:50 -05001267 /* paeth filter */
1268 if (png_ptr->do_filter & PNG_FILTER_PAETH)
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001269 {
Guy Schalnate5a37791996-06-05 15:50:50 -05001270 png_bytep rp, dp, pp, cp, lp;
1271 png_uint_32 sum = 0;
1272 int i, v;
1273
1274 for (i = 0, rp = row_buf + 1, dp = png_ptr->paeth_row + 1,
1275 pp = prev_row + 1; i < bpp; i++, rp++, pp++, dp++)
1276 {
1277 v = *dp = (png_byte)(((int)*rp - (int)*pp) & 0xff);
1278
1279 sum += (v < 128) ? v : 256 - v;
1280 }
1281 for (lp = row_buf + 1, cp = prev_row + 1; i < row_info->rowbytes;
1282 i++, rp++, pp++, lp++, dp++, cp++)
1283 {
1284 int a, b, c, pa, pb, pc, p;
1285
1286 b = *pp;
1287 c = *cp;
1288 a = *lp;
1289
1290 p = a + b - c;
1291 pa = abs(p - a);
1292 pb = abs(p - b);
1293 pc = abs(p - c);
1294
1295 if (pa <= pb && pa <= pc)
1296 p = a;
1297 else if (pb <= pc)
1298 p = b;
1299 else
1300 p = c;
1301
1302 v = *dp = (png_byte)(((int)*rp - p) & 0xff);
1303
1304 sum += (v < 128) ? v : 256 - v;
1305 }
1306 if (sum < mins)
1307 {
1308 best_row = png_ptr->paeth_row;
1309 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001310 }
1311
Guy Schalnate5a37791996-06-05 15:50:50 -05001312 /* Do the actual writing of the filtered row data from the chosen filter */
1313 png_write_filtered_row(png_ptr, best_row);
1314}
1315
1316
1317/* do the actual writing of a filtered row */
1318void
1319png_write_filtered_row(png_structp png_ptr, png_bytep filtered_row)
1320{
1321 /* set up the zlib input buffer */
1322 png_ptr->zstream->next_in = filtered_row;
1323 png_ptr->zstream->avail_in = (uInt)png_ptr->row_info.rowbytes + 1;
1324 /* repeat until we have compressed all the data */
1325 do
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001326 {
Guy Schalnate5a37791996-06-05 15:50:50 -05001327 int ret; /* return of zlib */
Guy Schalnat0d580581995-07-20 02:43:20 -05001328
Guy Schalnate5a37791996-06-05 15:50:50 -05001329 /* compress the data */
1330 ret = deflate(png_ptr->zstream, Z_NO_FLUSH);
1331 /* check for compression errors */
1332 if (ret != Z_OK)
1333 {
1334 if (png_ptr->zstream->msg)
1335 png_error(png_ptr, png_ptr->zstream->msg);
1336 else
1337 png_error(png_ptr, "zlib error");
1338 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001339
Guy Schalnate5a37791996-06-05 15:50:50 -05001340 /* see if it is time to write another IDAT */
1341 if (!png_ptr->zstream->avail_out)
1342 {
1343 /* write the IDAT and reset the zlib output buffer */
1344 png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size);
1345 png_ptr->zstream->next_out = png_ptr->zbuf;
1346 png_ptr->zstream->avail_out = (uInt)png_ptr->zbuf_size;
1347 }
1348 /* repeat until all data has been compressed */
1349 } while (png_ptr->zstream->avail_in);
1350
Guy Schalnatc21f90c1996-06-17 16:24:45 -05001351 /* swap the current and previous rows */
1352 if (png_ptr->prev_row)
1353 {
1354 png_bytep tptr;
1355
1356 tptr = png_ptr->prev_row;
1357 png_ptr->prev_row = png_ptr->row_buf;
1358 png_ptr->row_buf = tptr;
1359 }
1360
Guy Schalnate5a37791996-06-05 15:50:50 -05001361 /* finish row - updates counters and flushes zlib if last row */
1362 png_write_finish_row(png_ptr);
1363
1364#if defined(PNG_WRITE_FLUSH_SUPPORTED)
1365 png_ptr->flush_rows++;
1366
1367 if (png_ptr->flush_dist > 0 &&
1368 png_ptr->flush_rows >= png_ptr->flush_dist)
Guy Schalnat0d580581995-07-20 02:43:20 -05001369 {
Guy Schalnate5a37791996-06-05 15:50:50 -05001370 png_write_flush(png_ptr);
Guy Schalnat0d580581995-07-20 02:43:20 -05001371 }
Guy Schalnate5a37791996-06-05 15:50:50 -05001372#endif /* PNG_WRITE_FLUSH_SUPPORTED */
Guy Schalnat0d580581995-07-20 02:43:20 -05001373}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001374