blob: 5ca26ef8a0423848b871e82da3bdd7071a4f8532 [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++;
915 /* see if we are done */
Guy Schalnat6d764711995-12-19 03:22:19 -0600916 if (png_ptr->row_number < png_ptr->num_rows)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600917 return;
Guy Schalnat0d580581995-07-20 02:43:20 -0500918
919 /* if interlaced, go to next pass */
920 if (png_ptr->interlaced)
921 {
922 png_ptr->row_number = 0;
923 if (png_ptr->transformations & PNG_INTERLACE)
924 {
925 png_ptr->pass++;
926 }
927 else
928 {
929 /* loop until we find a non-zero width or height pass */
930 do
931 {
932 png_ptr->pass++;
933 if (png_ptr->pass >= 7)
934 break;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600935 png_ptr->usr_width = (png_ptr->width +
Guy Schalnat0d580581995-07-20 02:43:20 -0500936 png_pass_inc[png_ptr->pass] - 1 -
937 png_pass_start[png_ptr->pass]) /
938 png_pass_inc[png_ptr->pass];
939 png_ptr->num_rows = (png_ptr->height +
940 png_pass_yinc[png_ptr->pass] - 1 -
941 png_pass_ystart[png_ptr->pass]) /
942 png_pass_yinc[png_ptr->pass];
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500943 if (png_ptr->transformations & PNG_INTERLACE)
944 break;
Guy Schalnat0d580581995-07-20 02:43:20 -0500945 } while (png_ptr->usr_width == 0 || png_ptr->num_rows == 0);
946
947 }
948
Guy Schalnate5a37791996-06-05 15:50:50 -0500949 /* reset the row above the image for the next pass */
Guy Schalnat0d580581995-07-20 02:43:20 -0500950 if (png_ptr->prev_row)
Guy Schalnate5a37791996-06-05 15:50:50 -0500951 png_memset(png_ptr->prev_row, 0, (((png_uint_32)png_ptr->usr_channels *
952 (png_uint_32)png_ptr->usr_bit_depth * png_ptr->width + 7) >> 3) + 1);
953
Guy Schalnat0d580581995-07-20 02:43:20 -0500954 /* if we have more data to get, go get it */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600955 if (png_ptr->pass < 7)
Guy Schalnat0d580581995-07-20 02:43:20 -0500956 return;
957 }
958
959 /* if we get here, we've just written the last row, so we need
960 to flush the compressor */
961 do
962 {
963 /* tell the compressor we are done */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600964 ret = deflate(png_ptr->zstream, Z_FINISH);
Guy Schalnat0d580581995-07-20 02:43:20 -0500965 /* check for an error */
966 if (ret != Z_OK && ret != Z_STREAM_END)
967 {
968 if (png_ptr->zstream->msg)
Guy Schalnat6d764711995-12-19 03:22:19 -0600969 png_error(png_ptr, png_ptr->zstream->msg);
Guy Schalnat0d580581995-07-20 02:43:20 -0500970 else
Guy Schalnat6d764711995-12-19 03:22:19 -0600971 png_error(png_ptr, "zlib error");
Guy Schalnat0d580581995-07-20 02:43:20 -0500972 }
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600973 /* check to see if we need more room */
Guy Schalnat0d580581995-07-20 02:43:20 -0500974 if (!png_ptr->zstream->avail_out && ret == Z_OK)
975 {
976 png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size);
977 png_ptr->zstream->next_out = png_ptr->zbuf;
978 png_ptr->zstream->avail_out = (uInt)png_ptr->zbuf_size;
979 }
980 } while (ret != Z_STREAM_END);
981
982 /* write any extra space */
983 if (png_ptr->zstream->avail_out < png_ptr->zbuf_size)
984 {
985 png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size -
986 png_ptr->zstream->avail_out);
987 }
988
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500989 deflateReset(png_ptr->zstream);
Guy Schalnat0d580581995-07-20 02:43:20 -0500990}
991
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500992#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500993/* pick out the correct pixels for the interlace pass.
994
995 The basic idea here is to go through the row with a source
996 pointer and a destination pointer (sp and dp), and copy the
997 correct pixels for the pass. As the row gets compacted,
998 sp will always be >= dp, so we should never overwrite anything.
999 See the default: case for the easiest code to understand.
1000 */
1001void
Guy Schalnat6d764711995-12-19 03:22:19 -06001002png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass)
Guy Schalnat0d580581995-07-20 02:43:20 -05001003{
1004 /* we don't have to do anything on the last pass (6) */
1005 if (row && row_info && pass < 6)
1006 {
1007 /* each pixel depth is handled seperately */
1008 switch (row_info->pixel_depth)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001009 {
Guy Schalnat0d580581995-07-20 02:43:20 -05001010 case 1:
1011 {
Guy Schalnat6d764711995-12-19 03:22:19 -06001012 png_bytep sp;
1013 png_bytep dp;
Guy Schalnat0d580581995-07-20 02:43:20 -05001014 int shift;
1015 int d;
1016 int value;
1017 png_uint_32 i;
1018
1019 dp = row;
1020 d = 0;
1021 shift = 7;
1022 for (i = png_pass_start[pass];
1023 i < row_info->width;
1024 i += png_pass_inc[pass])
1025 {
1026 sp = row + (png_size_t)(i >> 3);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001027 value = (int)(*sp >> (7 - (int)(i & 7))) & 0x1;
Guy Schalnat0d580581995-07-20 02:43:20 -05001028 d |= (value << shift);
1029
1030 if (shift == 0)
1031 {
1032 shift = 7;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001033 *dp++ = (png_byte)d;
Guy Schalnat0d580581995-07-20 02:43:20 -05001034 d = 0;
1035 }
1036 else
1037 shift--;
1038
1039 }
1040 if (shift != 7)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001041 *dp = (png_byte)d;
Guy Schalnat0d580581995-07-20 02:43:20 -05001042 break;
1043 }
1044 case 2:
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001045 {
Guy Schalnat6d764711995-12-19 03:22:19 -06001046 png_bytep sp;
1047 png_bytep dp;
Guy Schalnat0d580581995-07-20 02:43:20 -05001048 int shift;
1049 int d;
1050 int value;
1051 png_uint_32 i;
1052
1053 dp = row;
1054 shift = 6;
1055 d = 0;
1056 for (i = png_pass_start[pass];
1057 i < row_info->width;
1058 i += png_pass_inc[pass])
1059 {
1060 sp = row + (png_size_t)(i >> 2);
1061 value = (*sp >> ((3 - (int)(i & 3)) << 1)) & 0x3;
1062 d |= (value << shift);
1063
1064 if (shift == 0)
1065 {
1066 shift = 6;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001067 *dp++ = (png_byte)d;
Guy Schalnat0d580581995-07-20 02:43:20 -05001068 d = 0;
1069 }
1070 else
1071 shift -= 2;
1072 }
1073 if (shift != 6)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001074 *dp = (png_byte)d;
Guy Schalnat0d580581995-07-20 02:43:20 -05001075 break;
1076 }
1077 case 4:
1078 {
Guy Schalnat6d764711995-12-19 03:22:19 -06001079 png_bytep sp;
1080 png_bytep dp;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001081 int shift;
Guy Schalnat0d580581995-07-20 02:43:20 -05001082 int d;
1083 int value;
1084 png_uint_32 i;
1085
1086 dp = row;
1087 shift = 4;
1088 d = 0;
1089 for (i = png_pass_start[pass];
1090 i < row_info->width;
1091 i += png_pass_inc[pass])
1092 {
1093 sp = row + (png_size_t)(i >> 1);
1094 value = (*sp >> ((1 - (int)(i & 1)) << 2)) & 0xf;
1095 d |= (value << shift);
1096
1097 if (shift == 0)
1098 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001099 shift = 4;
1100 *dp++ = (png_byte)d;
Guy Schalnat0d580581995-07-20 02:43:20 -05001101 d = 0;
1102 }
1103 else
1104 shift -= 4;
1105 }
1106 if (shift != 4)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001107 *dp = (png_byte)d;
Guy Schalnat0d580581995-07-20 02:43:20 -05001108 break;
1109 }
1110 default:
1111 {
Guy Schalnat6d764711995-12-19 03:22:19 -06001112 png_bytep sp;
1113 png_bytep dp;
Guy Schalnat0d580581995-07-20 02:43:20 -05001114 png_uint_32 i;
1115 int pixel_bytes;
1116
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001117 /* start at the beginning */
Guy Schalnat0d580581995-07-20 02:43:20 -05001118 dp = row;
1119 /* find out how many bytes each pixel takes up */
1120 pixel_bytes = (row_info->pixel_depth >> 3);
1121 /* loop through the row, only looking at the pixels that
1122 matter */
1123 for (i = png_pass_start[pass];
1124 i < row_info->width;
1125 i += png_pass_inc[pass])
1126 {
1127 /* find out where the original pixel is */
1128 sp = row + (png_size_t)(i * pixel_bytes);
1129 /* move the pixel */
1130 if (dp != sp)
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001131 png_memcpy(dp, sp, pixel_bytes);
Guy Schalnat0d580581995-07-20 02:43:20 -05001132 /* next pixel */
1133 dp += pixel_bytes;
1134 }
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001135 break;
Guy Schalnat0d580581995-07-20 02:43:20 -05001136 }
1137 }
1138 /* set new row width */
1139 row_info->width = (row_info->width +
1140 png_pass_inc[pass] - 1 -
1141 png_pass_start[pass]) /
1142 png_pass_inc[pass];
1143 row_info->rowbytes = ((row_info->width *
1144 row_info->pixel_depth + 7) >> 3);
1145
1146 }
1147}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001148#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001149
Guy Schalnate5a37791996-06-05 15:50:50 -05001150/* this filters the row, chooses which filter to use, if it has not already
1151 * been given by the application, and then writes the row out with the
1152 * chosen filter */
Guy Schalnat0d580581995-07-20 02:43:20 -05001153void
Guy Schalnate5a37791996-06-05 15:50:50 -05001154png_write_find_filter(png_structp png_ptr, png_row_infop row_info)
Guy Schalnat0d580581995-07-20 02:43:20 -05001155{
Guy Schalnate5a37791996-06-05 15:50:50 -05001156 png_bytep prev_row, best_row, row_buf;
1157 png_uint_32 mins;
1158 int bpp;
Guy Schalnat0d580581995-07-20 02:43:20 -05001159
1160 /* find out how many bytes offset each pixel is */
1161 bpp = (row_info->pixel_depth + 7) / 8;
Guy Schalnate5a37791996-06-05 15:50:50 -05001162
1163 prev_row = png_ptr->prev_row;
1164 best_row = row_buf = png_ptr->row_buf;
1165 mins = 0xffffffff;
Guy Schalnat0d580581995-07-20 02:43:20 -05001166
1167 /* the prediction method we use is to find which method provides
1168 the smallest value when summing the abs of the distances from
1169 zero using anything >= 128 as negitive numbers. */
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001170
Guy Schalnate5a37791996-06-05 15:50:50 -05001171 /* We don't need to test the 'no filter' case if this is the only filter
1172 * that has been chosen, as it doesn't actually do anything to the data. */
1173 if (png_ptr->do_filter & PNG_FILTER_NONE &&
1174 png_ptr->do_filter != PNG_FILTER_NONE)
Guy Schalnat0d580581995-07-20 02:43:20 -05001175 {
Guy Schalnate5a37791996-06-05 15:50:50 -05001176 png_bytep rp;
1177 png_uint_32 sum = 0;
1178 int i, v;
Guy Schalnat0d580581995-07-20 02:43:20 -05001179
Guy Schalnate5a37791996-06-05 15:50:50 -05001180 for (i = 0, rp = row_buf + 1; i < row_info->rowbytes; i++, rp++)
1181 {
1182 v = *rp;
1183 sum += (v < 128) ? v : 256 - v;
1184 }
1185 mins = sum;
Guy Schalnat0d580581995-07-20 02:43:20 -05001186 }
1187
Guy Schalnate5a37791996-06-05 15:50:50 -05001188 /* sub filter */
1189 if (png_ptr->do_filter & PNG_FILTER_SUB)
Guy Schalnat0d580581995-07-20 02:43:20 -05001190 {
Guy Schalnate5a37791996-06-05 15:50:50 -05001191 png_bytep rp, dp, lp;
1192 png_uint_32 sum = 0;
1193 int i, v;
Guy Schalnat0d580581995-07-20 02:43:20 -05001194
Guy Schalnate5a37791996-06-05 15:50:50 -05001195 for (i = 0, rp = row_buf + 1, dp = png_ptr->sub_row + 1; i < bpp;
1196 i++, rp++, dp++)
1197 {
1198 v = *dp = *rp;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001199
Guy Schalnate5a37791996-06-05 15:50:50 -05001200 sum += (v < 128) ? v : 256 - v;
1201 }
1202 for (lp = row_buf + 1; i < row_info->rowbytes; i++, rp++, lp++, dp++)
1203 {
1204 v = *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff);
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001205
Guy Schalnate5a37791996-06-05 15:50:50 -05001206 sum += (v < 128) ? v : 256 - v;
1207 }
1208 if (sum < mins)
1209 {
1210 mins = sum;
1211 best_row = png_ptr->sub_row;
1212 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001213 }
1214
Guy Schalnate5a37791996-06-05 15:50:50 -05001215 /* up filter */
1216 if (png_ptr->do_filter & PNG_FILTER_UP)
Guy Schalnat0d580581995-07-20 02:43:20 -05001217 {
Guy Schalnate5a37791996-06-05 15:50:50 -05001218 png_bytep rp, dp, pp;
1219 png_uint_32 sum = 0;
1220 int i, v;
1221
1222 for (i = 0, rp = row_buf + 1, dp = png_ptr->up_row + 1,
1223 pp = prev_row + 1; i < row_info->rowbytes; i++, rp++, pp++, dp++)
1224 {
1225 v = *dp = (png_byte)(((int)*rp - (int)*pp) & 0xff);
1226
1227 sum += (v < 128) ? v : 256 - v;
1228 }
1229 if (sum < mins)
1230 {
1231 mins = sum;
1232 best_row = png_ptr->up_row;
1233 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001234 }
1235
Guy Schalnate5a37791996-06-05 15:50:50 -05001236 /* avg filter */
1237 if (png_ptr->do_filter & PNG_FILTER_AVG)
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001238 {
Guy Schalnate5a37791996-06-05 15:50:50 -05001239 png_bytep rp, dp, pp, lp;
1240 png_uint_32 sum = 0;
1241 int i, v;
1242
1243 for (i = 0, rp = row_buf + 1, dp = png_ptr->avg_row + 1,
1244 pp = prev_row + 1; i < bpp; i++, rp++, pp++, dp++)
1245 {
1246 v = *dp = (png_byte)(((int)*rp - ((int)*pp / 2)) & 0xff);
1247
1248 sum += (v < 128) ? v : 256 - v;
1249 }
1250 for (lp = row_buf + 1; i < row_info->rowbytes;
1251 i++, rp++, pp++, lp++, dp++)
1252 {
1253 v = *dp = (png_byte)(((int)*rp - (((int)*pp + (int)*lp) / 2)) & 0xff);
1254
1255 sum += (v < 128) ? v : 256 - v;
1256 }
1257 if (sum < mins)
1258 {
1259 mins = sum;
1260 best_row = png_ptr->avg_row;
1261 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001262 }
1263
Guy Schalnate5a37791996-06-05 15:50:50 -05001264 /* paeth filter */
1265 if (png_ptr->do_filter & PNG_FILTER_PAETH)
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001266 {
Guy Schalnate5a37791996-06-05 15:50:50 -05001267 png_bytep rp, dp, pp, cp, lp;
1268 png_uint_32 sum = 0;
1269 int i, v;
1270
1271 for (i = 0, rp = row_buf + 1, dp = png_ptr->paeth_row + 1,
1272 pp = prev_row + 1; i < bpp; i++, rp++, pp++, dp++)
1273 {
1274 v = *dp = (png_byte)(((int)*rp - (int)*pp) & 0xff);
1275
1276 sum += (v < 128) ? v : 256 - v;
1277 }
1278 for (lp = row_buf + 1, cp = prev_row + 1; i < row_info->rowbytes;
1279 i++, rp++, pp++, lp++, dp++, cp++)
1280 {
1281 int a, b, c, pa, pb, pc, p;
1282
1283 b = *pp;
1284 c = *cp;
1285 a = *lp;
1286
1287 p = a + b - c;
1288 pa = abs(p - a);
1289 pb = abs(p - b);
1290 pc = abs(p - c);
1291
1292 if (pa <= pb && pa <= pc)
1293 p = a;
1294 else if (pb <= pc)
1295 p = b;
1296 else
1297 p = c;
1298
1299 v = *dp = (png_byte)(((int)*rp - p) & 0xff);
1300
1301 sum += (v < 128) ? v : 256 - v;
1302 }
1303 if (sum < mins)
1304 {
1305 best_row = png_ptr->paeth_row;
1306 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001307 }
1308
Guy Schalnate5a37791996-06-05 15:50:50 -05001309 /* Do the actual writing of the filtered row data from the chosen filter */
1310 png_write_filtered_row(png_ptr, best_row);
1311}
1312
1313
1314/* do the actual writing of a filtered row */
1315void
1316png_write_filtered_row(png_structp png_ptr, png_bytep filtered_row)
1317{
1318 /* set up the zlib input buffer */
1319 png_ptr->zstream->next_in = filtered_row;
1320 png_ptr->zstream->avail_in = (uInt)png_ptr->row_info.rowbytes + 1;
1321 /* repeat until we have compressed all the data */
1322 do
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001323 {
Guy Schalnate5a37791996-06-05 15:50:50 -05001324 int ret; /* return of zlib */
Guy Schalnat0d580581995-07-20 02:43:20 -05001325
Guy Schalnate5a37791996-06-05 15:50:50 -05001326 /* compress the data */
1327 ret = deflate(png_ptr->zstream, Z_NO_FLUSH);
1328 /* check for compression errors */
1329 if (ret != Z_OK)
1330 {
1331 if (png_ptr->zstream->msg)
1332 png_error(png_ptr, png_ptr->zstream->msg);
1333 else
1334 png_error(png_ptr, "zlib error");
1335 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001336
Guy Schalnate5a37791996-06-05 15:50:50 -05001337 /* see if it is time to write another IDAT */
1338 if (!png_ptr->zstream->avail_out)
1339 {
1340 /* write the IDAT and reset the zlib output buffer */
1341 png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size);
1342 png_ptr->zstream->next_out = png_ptr->zbuf;
1343 png_ptr->zstream->avail_out = (uInt)png_ptr->zbuf_size;
1344 }
1345 /* repeat until all data has been compressed */
1346 } while (png_ptr->zstream->avail_in);
1347
1348 /* finish row - updates counters and flushes zlib if last row */
1349 png_write_finish_row(png_ptr);
1350
1351#if defined(PNG_WRITE_FLUSH_SUPPORTED)
1352 png_ptr->flush_rows++;
1353
1354 if (png_ptr->flush_dist > 0 &&
1355 png_ptr->flush_rows >= png_ptr->flush_dist)
Guy Schalnat0d580581995-07-20 02:43:20 -05001356 {
Guy Schalnate5a37791996-06-05 15:50:50 -05001357 png_write_flush(png_ptr);
Guy Schalnat0d580581995-07-20 02:43:20 -05001358 }
Guy Schalnate5a37791996-06-05 15:50:50 -05001359#endif /* PNG_WRITE_FLUSH_SUPPORTED */
Guy Schalnat0d580581995-07-20 02:43:20 -05001360}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001361