blob: fd68e7a2ab41b79efb0288b28a01e9f748906bcf [file] [log] [blame]
Guy Schalnat0d580581995-07-20 02:43:20 -05001
2/* pngwrite.c - general routines 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
10/* get internal access to png.h */
11#define PNG_INTERNAL
12#include "png.h"
13
14/* Writes all the png information. This is the suggested way to use
15 the library. If you have a new chunk to add, make a function to
16 write it, and put it in the correct location here. If you want
17 the chunk written after the image data, put it in png_write_end().
18 I strongly encurage you to supply a PNG_INFO_ flag, and check
Guy Schalnatb2e01bd1996-01-26 01:38:47 -060019 info->valid before writing the chunk, as that will keep the code
Guy Schalnat0d580581995-07-20 02:43:20 -050020 from breaking if you want to just write a plain png file.
21 If you have long comments, I suggest writing them in png_write_end(),
22 and compressing them. */
23void
Guy Schalnat6d764711995-12-19 03:22:19 -060024png_write_info(png_structp png_ptr, png_infop info)
Guy Schalnat0d580581995-07-20 02:43:20 -050025{
26 png_write_sig(png_ptr); /* write PNG signature */
27 /* write IHDR information. */
28 png_write_IHDR(png_ptr, info->width, info->height, info->bit_depth,
29 info->color_type, info->compression_type, info->filter_type,
30 info->interlace_type);
31 /* the rest of these check to see if the valid field has the appropriate
32 flag set, and if it does, writes the chunk. */
Guy Schalnat51f0eb41995-09-26 05:22:39 -050033#if defined(PNG_WRITE_gAMA_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -050034 if (info->valid & PNG_INFO_gAMA)
35 png_write_gAMA(png_ptr, info->gamma);
Guy Schalnat51f0eb41995-09-26 05:22:39 -050036#endif
37#if defined(PNG_WRITE_sBIT_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -050038 if (info->valid & PNG_INFO_sBIT)
39 png_write_sBIT(png_ptr, &(info->sig_bit), info->color_type);
Guy Schalnat51f0eb41995-09-26 05:22:39 -050040#endif
41#if defined(PNG_WRITE_cHRM_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -050042 if (info->valid & PNG_INFO_cHRM)
43 png_write_cHRM(png_ptr,
44 info->x_white, info->y_white,
45 info->x_red, info->y_red,
46 info->x_green, info->y_green,
47 info->x_blue, info->y_blue);
Guy Schalnat51f0eb41995-09-26 05:22:39 -050048#endif
Guy Schalnat0d580581995-07-20 02:43:20 -050049 if (info->valid & PNG_INFO_PLTE)
50 png_write_PLTE(png_ptr, info->palette, info->num_palette);
Guy Schalnate5a37791996-06-05 15:50:50 -050051 else if (info->color_type == PNG_COLOR_TYPE_PALETTE)
52 png_error(png_ptr, "Valid palette required for paletted images\n");
Guy Schalnat51f0eb41995-09-26 05:22:39 -050053#if defined(PNG_WRITE_tRNS_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -050054 if (info->valid & PNG_INFO_tRNS)
55 png_write_tRNS(png_ptr, info->trans, &(info->trans_values),
56 info->num_trans, info->color_type);
Guy Schalnat51f0eb41995-09-26 05:22:39 -050057#endif
58#if defined(PNG_WRITE_bKGD_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -050059 if (info->valid & PNG_INFO_bKGD)
60 png_write_bKGD(png_ptr, &(info->background), info->color_type);
Guy Schalnat51f0eb41995-09-26 05:22:39 -050061#endif
62#if defined(PNG_WRITE_hIST_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -050063 if (info->valid & PNG_INFO_hIST)
64 png_write_hIST(png_ptr, info->hist, info->num_palette);
Guy Schalnat51f0eb41995-09-26 05:22:39 -050065#endif
66#if defined(PNG_WRITE_pHYs_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -050067 if (info->valid & PNG_INFO_pHYs)
68 png_write_pHYs(png_ptr, info->x_pixels_per_unit,
69 info->y_pixels_per_unit, info->phys_unit_type);
Guy Schalnat51f0eb41995-09-26 05:22:39 -050070#endif
71#if defined(PNG_WRITE_oFFs_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -050072 if (info->valid & PNG_INFO_oFFs)
73 png_write_oFFs(png_ptr, info->x_offset, info->y_offset,
74 info->offset_unit_type);
Guy Schalnat51f0eb41995-09-26 05:22:39 -050075#endif
76#if defined(PNG_WRITE_tIME_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -050077 if (info->valid & PNG_INFO_tIME)
Guy Schalnate5a37791996-06-05 15:50:50 -050078 {
Guy Schalnat0d580581995-07-20 02:43:20 -050079 png_write_tIME(png_ptr, &(info->mod_time));
Guy Schalnate5a37791996-06-05 15:50:50 -050080 png_ptr->flags |= PNG_FLAG_WROTE_tIME;
81 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -050082#endif
83#if defined(PNG_WRITE_tEXt_SUPPORTED) || defined(PNG_WRITE_zTXt_SUPPORTED)
Guy Schalnate5a37791996-06-05 15:50:50 -050084 /* Check to see if we need to write text chunks */
Guy Schalnat0d580581995-07-20 02:43:20 -050085 if (info->num_text)
86 {
87 int i; /* local counter */
88
89 /* loop through the text chunks */
90 for (i = 0; i < info->num_text; i++)
91 {
92 /* if chunk is compressed */
93 if (info->text[i].compression >= 0)
94 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -050095#if defined(PNG_WRITE_zTXt_SUPPORTED)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -060096 /* write compressed chunk */
Guy Schalnat0d580581995-07-20 02:43:20 -050097 png_write_zTXt(png_ptr, info->text[i].key,
98 info->text[i].text, info->text[i].text_length,
99 info->text[i].compression);
Guy Schalnate5a37791996-06-05 15:50:50 -0500100#else
101 png_warning(png_ptr, "Unable to write compressed text\n");
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500102#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500103 }
104 else
105 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500106#if defined(PNG_WRITE_tEXt_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500107 /* write uncompressed chunk */
108 png_write_tEXt(png_ptr, info->text[i].key,
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600109 info->text[i].text, info->text[i].text_length);
Guy Schalnate5a37791996-06-05 15:50:50 -0500110#else
111 png_warning(png_ptr, "Unable to write uncompressed text\n");
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500112#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500113 }
114 }
115 }
Guy Schalnat6d764711995-12-19 03:22:19 -0600116#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500117}
118
119/* writes the end of the png file. If you don't want to write comments or
120 time information, you can pass NULL for info. If you already wrote these
121 in png_write_info(), do not write them again here. If you have long
122 comments, I suggest writing them here, and compressing them. */
123void
Guy Schalnat6d764711995-12-19 03:22:19 -0600124png_write_end(png_structp png_ptr, png_infop info)
Guy Schalnat0d580581995-07-20 02:43:20 -0500125{
Guy Schalnate5a37791996-06-05 15:50:50 -0500126 if (!(png_ptr->mode & PNG_HAVE_IDAT))
127 png_error(png_ptr, "No IDATs written into file");
128
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600129 /* see if user wants us to write information chunks */
Guy Schalnat0d580581995-07-20 02:43:20 -0500130 if (info)
131 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500132#if defined(PNG_WRITE_tIME_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500133 /* check to see if user has supplied a time chunk */
Guy Schalnate5a37791996-06-05 15:50:50 -0500134 if (info->valid & PNG_INFO_tIME &&
135 !(png_ptr->flags & PNG_FLAG_WROTE_tIME))
Guy Schalnat0d580581995-07-20 02:43:20 -0500136 png_write_tIME(png_ptr, &(info->mod_time));
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500137#endif
138#if defined(PNG_WRITE_tEXt_SUPPORTED) || defined(PNG_WRITE_zTXt_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500139 /* check to see if we need to write comment chunks */
140 if (info->num_text)
141 {
142 int i; /* local index variable */
143
144 /* loop through comment chunks */
145 for (i = 0; i < info->num_text; i++)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600146 {
Guy Schalnate5a37791996-06-05 15:50:50 -0500147#if defined(PNG_WRITE_zTXt_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500148 /* check to see if comment is to be compressed */
149 if (info->text[i].compression >= 0)
150 {
151 /* write compressed chunk */
152 png_write_zTXt(png_ptr, info->text[i].key,
153 info->text[i].text, info->text[i].text_length,
154 info->text[i].compression);
155 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500156#if defined(PNG_WRITE_tEXt_SUPPORTED)
Guy Schalnate5a37791996-06-05 15:50:50 -0500157 else
158#endif
159#endif
160#if defined(PNG_WRITE_tEXt_SUPPORTED)
161 {
Guy Schalnat0d580581995-07-20 02:43:20 -0500162 /* write uncompressed chunk */
163 png_write_tEXt(png_ptr, info->text[i].key,
164 info->text[i].text, info->text[i].text_length);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600165 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500166#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500167 }
168 }
Guy Schalnat6d764711995-12-19 03:22:19 -0600169#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500170 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500171
172 png_ptr->mode |= PNG_AFTER_IDAT;
173
Guy Schalnat0d580581995-07-20 02:43:20 -0500174 /* write end of png file */
175 png_write_IEND(png_ptr);
176}
177
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500178#if defined(PNG_WRITE_tIME_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500179void
Guy Schalnat6d764711995-12-19 03:22:19 -0600180png_convert_from_struct_tm(png_timep ptime, struct tm FAR * ttime)
Guy Schalnat0d580581995-07-20 02:43:20 -0500181{
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600182 ptime->year = (png_uint_16)(1900 + ttime->tm_year);
183 ptime->month = (png_byte)(ttime->tm_mon + 1);
184 ptime->day = (png_byte)ttime->tm_mday;
185 ptime->hour = (png_byte)ttime->tm_hour;
186 ptime->minute = (png_byte)ttime->tm_min;
187 ptime->second = (png_byte)ttime->tm_sec;
Guy Schalnat0d580581995-07-20 02:43:20 -0500188}
189
190void
Guy Schalnat6d764711995-12-19 03:22:19 -0600191png_convert_from_time_t(png_timep ptime, time_t ttime)
Guy Schalnat0d580581995-07-20 02:43:20 -0500192{
193 struct tm *tbuf;
194
195 tbuf = gmtime(&ttime);
196 png_convert_from_struct_tm(ptime, tbuf);
197}
Guy Schalnat6d764711995-12-19 03:22:19 -0600198#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500199
200/* initialize png structure, and allocate any memory needed */
Guy Schalnate5a37791996-06-05 15:50:50 -0500201png_structp
202png_create_write_struct(png_const_charp user_png_ver, voidp error_ptr,
203 png_error_ptr warn_fn, png_error_ptr error_fn)
Guy Schalnat0d580581995-07-20 02:43:20 -0500204{
Guy Schalnate5a37791996-06-05 15:50:50 -0500205 png_structp png_ptr;
Guy Schalnat0d580581995-07-20 02:43:20 -0500206
Guy Schalnate5a37791996-06-05 15:50:50 -0500207 if ((png_ptr = (png_structp)png_create_struct(PNG_STRUCT_PNG)) == NULL)
208 {
209 return (png_structp)NULL;
210 }
Guy Schalnat6d764711995-12-19 03:22:19 -0600211
Guy Schalnate5a37791996-06-05 15:50:50 -0500212 if (setjmp(png_ptr->jmpbuf))
213 {
214 png_large_free(png_ptr, png_ptr->zbuf);
215 png_free(png_ptr, png_ptr->zstream);
216 png_destroy_struct(png_ptr);
217 return (png_structp)NULL;
218 }
219
220 png_set_error_fn(png_ptr, error_ptr, warn_fn, error_fn);
221
222 if (user_png_ver == NULL || strcmp(user_png_ver, png_libpng_ver))
223 {
224 if (user_png_ver == NULL || user_png_ver[0] != png_libpng_ver[0])
225 {
226 png_error(png_ptr, "Incompatible libpng versions");
227 }
228 else
229 {
230 png_warning(png_ptr, "Different libpng versions");
231 }
232 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500233
234 /* initialize zbuf - compression buffer */
235 png_ptr->zbuf_size = PNG_ZBUF_SIZE;
236 png_ptr->zbuf = png_large_malloc(png_ptr, png_ptr->zbuf_size);
Guy Schalnate5a37791996-06-05 15:50:50 -0500237
238 png_set_write_fn(png_ptr, NULL, NULL, NULL);
239
240 png_ptr->do_free |= PNG_FREE_STRUCT;
241
242 return (png_ptr);
243}
244
245
246/* initialize png structure, and allocate any memory needed */
247void
248png_write_init(png_structp png_ptr)
249{
250 jmp_buf tmp_jmp; /* to save current jump buffer */
251
252 /* save jump buffer and error functions */
253 png_memcpy(tmp_jmp, png_ptr->jmpbuf, sizeof (jmp_buf));
254
255 /* reset all variables to 0 */
256 png_memset(png_ptr, 0, sizeof (png_struct));
257
258 /* restore jump buffer */
259 png_memcpy(png_ptr->jmpbuf, tmp_jmp, sizeof (jmp_buf));
260
261 /* initialize zbuf - compression buffer */
262 png_ptr->zbuf_size = PNG_ZBUF_SIZE;
263 png_ptr->zbuf = png_large_malloc(png_ptr, png_ptr->zbuf_size);
264 png_set_write_fn(png_ptr, NULL, NULL, NULL);
Guy Schalnat0d580581995-07-20 02:43:20 -0500265}
266
267/* write a few rows of image data. If the image is interlaced,
268 either you will have to write the 7 sub images, or, if you
269 have called png_set_interlace_handling(), you will have to
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600270 "write" the image seven times */
Guy Schalnat0d580581995-07-20 02:43:20 -0500271void
Guy Schalnat6d764711995-12-19 03:22:19 -0600272png_write_rows(png_structp png_ptr, png_bytepp row,
Guy Schalnat0d580581995-07-20 02:43:20 -0500273 png_uint_32 num_rows)
274{
275 png_uint_32 i; /* row counter */
Guy Schalnat6d764711995-12-19 03:22:19 -0600276 png_bytepp rp; /* row pointer */
Guy Schalnat0d580581995-07-20 02:43:20 -0500277
278 /* loop through the rows */
279 for (i = 0, rp = row; i < num_rows; i++, rp++)
280 {
281 png_write_row(png_ptr, *rp);
282 }
283}
284
285/* write the image. You only need to call this function once, even
286 if you are writing an interlaced image. */
287void
Guy Schalnat6d764711995-12-19 03:22:19 -0600288png_write_image(png_structp png_ptr, png_bytepp image)
Guy Schalnat0d580581995-07-20 02:43:20 -0500289{
290 png_uint_32 i; /* row index */
291 int pass, num_pass; /* pass variables */
Guy Schalnat6d764711995-12-19 03:22:19 -0600292 png_bytepp rp; /* points to current row */
Guy Schalnat0d580581995-07-20 02:43:20 -0500293
294 /* intialize interlace handling. If image is not interlaced,
295 this will set pass to 1 */
296 num_pass = png_set_interlace_handling(png_ptr);
297 /* loop through passes */
298 for (pass = 0; pass < num_pass; pass++)
299 {
300 /* loop through image */
301 for (i = 0, rp = image; i < png_ptr->height; i++, rp++)
302 {
303 png_write_row(png_ptr, *rp);
304 }
305 }
306}
307
Guy Schalnate5a37791996-06-05 15:50:50 -0500308/* called by user to write a row of image data */
Guy Schalnat0d580581995-07-20 02:43:20 -0500309void
Guy Schalnat6d764711995-12-19 03:22:19 -0600310png_write_row(png_structp png_ptr, png_bytep row)
Guy Schalnat0d580581995-07-20 02:43:20 -0500311{
312 /* initialize transformations and other stuff if first time */
Guy Schalnat6d764711995-12-19 03:22:19 -0600313 if (png_ptr->row_number == 0 && png_ptr->pass == 0)
Guy Schalnat0d580581995-07-20 02:43:20 -0500314 {
315 png_write_start_row(png_ptr);
316 }
317
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500318#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500319 /* if interlaced and not interested in row, return */
320 if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE))
321 {
322 switch (png_ptr->pass)
323 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600324 case 0:
Guy Schalnat0d580581995-07-20 02:43:20 -0500325 if (png_ptr->row_number & 7)
326 {
327 png_write_finish_row(png_ptr);
328 return;
329 }
330 break;
331 case 1:
332 if ((png_ptr->row_number & 7) || png_ptr->width < 5)
333 {
334 png_write_finish_row(png_ptr);
335 return;
336 }
337 break;
338 case 2:
339 if ((png_ptr->row_number & 7) != 4)
340 {
341 png_write_finish_row(png_ptr);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600342 return;
Guy Schalnat0d580581995-07-20 02:43:20 -0500343 }
344 break;
345 case 3:
346 if ((png_ptr->row_number & 3) || png_ptr->width < 3)
347 {
348 png_write_finish_row(png_ptr);
349 return;
350 }
351 break;
352 case 4:
353 if ((png_ptr->row_number & 3) != 2)
354 {
355 png_write_finish_row(png_ptr);
356 return;
357 }
358 break;
359 case 5:
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600360 if ((png_ptr->row_number & 1) || png_ptr->width < 2)
Guy Schalnat0d580581995-07-20 02:43:20 -0500361 {
362 png_write_finish_row(png_ptr);
363 return;
364 }
365 break;
366 case 6:
367 if (!(png_ptr->row_number & 1))
368 {
369 png_write_finish_row(png_ptr);
370 return;
371 }
372 break;
373 }
374 }
Guy Schalnat6d764711995-12-19 03:22:19 -0600375#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500376
377 /* set up row info for transformations */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600378 png_ptr->row_info.color_type = png_ptr->color_type;
Guy Schalnat0d580581995-07-20 02:43:20 -0500379 png_ptr->row_info.width = png_ptr->usr_width;
380 png_ptr->row_info.channels = png_ptr->usr_channels;
381 png_ptr->row_info.bit_depth = png_ptr->usr_bit_depth;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600382 png_ptr->row_info.pixel_depth = (png_byte)(png_ptr->row_info.bit_depth *
383 png_ptr->row_info.channels);
Guy Schalnat0d580581995-07-20 02:43:20 -0500384 png_ptr->row_info.rowbytes = ((png_ptr->row_info.width *
385 (png_uint_32)png_ptr->row_info.pixel_depth + 7) >> 3);
386
387 /* copy users row into buffer, leaving room for filter byte */
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500388 png_memcpy(png_ptr->row_buf + 1, row, (png_size_t)png_ptr->row_info.rowbytes);
Guy Schalnat0d580581995-07-20 02:43:20 -0500389
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500390#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500391 /* handle interlacing */
392 if (png_ptr->interlaced && png_ptr->pass < 6 &&
393 (png_ptr->transformations & PNG_INTERLACE))
394 {
395 png_do_write_interlace(&(png_ptr->row_info),
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600396 png_ptr->row_buf + 1, png_ptr->pass);
Guy Schalnat0d580581995-07-20 02:43:20 -0500397 /* this should always get caught above, but still ... */
398 if (!(png_ptr->row_info.width))
399 {
400 png_write_finish_row(png_ptr);
401 return;
402 }
403 }
Guy Schalnat6d764711995-12-19 03:22:19 -0600404#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500405
406 /* handle other transformations */
407 if (png_ptr->transformations)
408 png_do_write_transformations(png_ptr);
409
Guy Schalnate5a37791996-06-05 15:50:50 -0500410 /* find a filter if necessary, filter the row and write it out */
411 png_write_find_filter(png_ptr, &(png_ptr->row_info));
412
413 /* trade current and prev rows so next filter references are correct */
414 if (png_ptr->prev_row)
Guy Schalnat0d580581995-07-20 02:43:20 -0500415 {
Guy Schalnate5a37791996-06-05 15:50:50 -0500416 png_bytep tptr;
Guy Schalnat0d580581995-07-20 02:43:20 -0500417
Guy Schalnate5a37791996-06-05 15:50:50 -0500418 tptr = png_ptr->prev_row;
419 png_ptr->prev_row = png_ptr->row_buf;
420 png_ptr->row_buf = tptr;
Guy Schalnat0d580581995-07-20 02:43:20 -0500421 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500422}
423
Guy Schalnat0f716451995-11-28 11:22:13 -0600424#if defined(PNG_WRITE_FLUSH_SUPPORTED)
425/* Set the automatic flush interval or 0 to turn flushing off */
426void
Guy Schalnat4ee97b01996-01-16 01:51:56 -0600427png_set_flush(png_structp png_ptr, int nrows)
Guy Schalnat0f716451995-11-28 11:22:13 -0600428{
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600429 png_ptr->flush_dist = (nrows < 0 ? 0 : nrows);
Guy Schalnat0f716451995-11-28 11:22:13 -0600430}
431
432/* flush the current output buffers now */
433void
Guy Schalnat4ee97b01996-01-16 01:51:56 -0600434png_write_flush(png_structp png_ptr)
Guy Schalnat0f716451995-11-28 11:22:13 -0600435{
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600436 int wrote_IDAT;
Guy Schalnat0f716451995-11-28 11:22:13 -0600437
Guy Schalnate5a37791996-06-05 15:50:50 -0500438 /* We have already written out all of the data */
439 if (png_ptr->row_number >= png_ptr->num_rows)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600440 return;
Guy Schalnat0f716451995-11-28 11:22:13 -0600441
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600442 do
443 {
444 int ret;
Guy Schalnat0f716451995-11-28 11:22:13 -0600445
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600446 /* compress the data */
447 ret = deflate(png_ptr->zstream, Z_SYNC_FLUSH);
448 wrote_IDAT = 0;
Guy Schalnat0f716451995-11-28 11:22:13 -0600449
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600450 /* check for compression errors */
451 if (ret != Z_OK)
452 {
453 if (png_ptr->zstream->msg)
454 png_error(png_ptr, png_ptr->zstream->msg);
455 else
456 png_error(png_ptr, "zlib error");
457 }
Guy Schalnat0f716451995-11-28 11:22:13 -0600458
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600459 if (!png_ptr->zstream->avail_out)
460 {
461 /* write the IDAT and reset the zlib output buffer */
462 png_write_IDAT(png_ptr, png_ptr->zbuf,
463 png_ptr->zbuf_size);
464 png_ptr->zstream->next_out = png_ptr->zbuf;
465 png_ptr->zstream->avail_out = (uInt)png_ptr->zbuf_size;
466 wrote_IDAT = 1;
467 }
468 } while(wrote_IDAT == 1);
Guy Schalnat0f716451995-11-28 11:22:13 -0600469
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600470 /* If there is any data left to be output, write it into a new IDAT */
471 if (png_ptr->zbuf_size != png_ptr->zstream->avail_out)
472 {
473 /* write the IDAT and reset the zlib output buffer */
474 png_write_IDAT(png_ptr, png_ptr->zbuf,
475 png_ptr->zbuf_size - png_ptr->zstream->avail_out);
476 png_ptr->zstream->next_out = png_ptr->zbuf;
477 png_ptr->zstream->avail_out = (uInt)png_ptr->zbuf_size;
478 }
479 png_ptr->flush_rows = 0;
480 png_flush(png_ptr);
Guy Schalnat0f716451995-11-28 11:22:13 -0600481}
482#endif /* PNG_WRITE_FLUSH_SUPPORTED */
483
Guy Schalnate5a37791996-06-05 15:50:50 -0500484/* free all memory used by the write */
485void
486png_destroy_write_struct(png_structpp png_ptr, png_infopp info_ptr)
487{
488 if (info_ptr && *info_ptr)
489 {
490 png_destroy_struct((voidp)*info_ptr);
491 *info_ptr = (png_infop)NULL;
492 }
Guy Schalnat6d764711995-12-19 03:22:19 -0600493
Guy Schalnate5a37791996-06-05 15:50:50 -0500494 if (png_ptr && *png_ptr)
495 {
496 png_write_destroy(*png_ptr);
497 png_destroy_struct((voidp)*png_ptr);
498 *png_ptr = (png_structp)NULL;
499 }
500}
501
502
503/* free any memory used in png struct (old) */
Guy Schalnat0d580581995-07-20 02:43:20 -0500504void
Guy Schalnat6d764711995-12-19 03:22:19 -0600505png_write_destroy(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -0500506{
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600507 jmp_buf tmp_jmp; /* save jump buffer */
Guy Schalnate5a37791996-06-05 15:50:50 -0500508 png_error_ptr error_fn;
509 png_error_ptr warning_fn;
510 png_voidp error_ptr;
Guy Schalnat0d580581995-07-20 02:43:20 -0500511
512 /* free any memory zlib uses */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600513 deflateEnd(png_ptr->zstream);
Guy Schalnat6d764711995-12-19 03:22:19 -0600514 png_free(png_ptr, png_ptr->zstream);
Guy Schalnate5a37791996-06-05 15:50:50 -0500515
Guy Schalnat0d580581995-07-20 02:43:20 -0500516 /* free our memory. png_free checks NULL for us. */
517 png_large_free(png_ptr, png_ptr->zbuf);
518 png_large_free(png_ptr, png_ptr->row_buf);
519 png_large_free(png_ptr, png_ptr->prev_row);
Guy Schalnate5a37791996-06-05 15:50:50 -0500520 png_large_free(png_ptr, png_ptr->sub_row);
521 png_large_free(png_ptr, png_ptr->up_row);
522 png_large_free(png_ptr, png_ptr->avg_row);
523 png_large_free(png_ptr, png_ptr->paeth_row);
524
Guy Schalnat0d580581995-07-20 02:43:20 -0500525 /* reset structure */
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500526 png_memcpy(tmp_jmp, png_ptr->jmpbuf, sizeof (jmp_buf));
Guy Schalnate5a37791996-06-05 15:50:50 -0500527
528 error_fn = png_ptr->error_fn;
529 warning_fn = png_ptr->warning_fn;
530 error_ptr = png_ptr->error_ptr;
531
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500532 png_memset(png_ptr, 0, sizeof (png_struct));
Guy Schalnate5a37791996-06-05 15:50:50 -0500533
534 png_ptr->error_fn = error_fn;
535 png_ptr->warning_fn = warning_fn;
536 png_ptr->error_ptr = error_ptr;
537
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500538 png_memcpy(png_ptr->jmpbuf, tmp_jmp, sizeof (jmp_buf));
539}
Guy Schalnate5a37791996-06-05 15:50:50 -0500540
541/* Allow the application to select one or more filters to use */
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500542void
Guy Schalnate5a37791996-06-05 15:50:50 -0500543png_set_filter(png_structp png_ptr, int method, int filters)
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500544{
Guy Schalnate5a37791996-06-05 15:50:50 -0500545 /* We allow 'method' only for future expansion of the base filter method */
546 if (method == 0)
547 {
548 switch (filters & (PNG_ALL_FILTERS | 0x07))
549 {
550 case 5:
551 case 6:
552 case 7: png_warning(png_ptr, "Unknown custom row filter for method 0");
553 case 0: png_ptr->do_filter = PNG_FILTER_NONE; break;
554 case 1: png_ptr->do_filter = PNG_FILTER_SUB; break;
555 case 2: png_ptr->do_filter = PNG_FILTER_UP; break;
556 case 3: png_ptr->do_filter = PNG_FILTER_AVG; break;
557 case 4: png_ptr->do_filter = PNG_FILTER_PAETH; break;
558 default: png_ptr->do_filter = (png_byte)filters; break;
559 }
560
561 /* If we have allocated the row_buf, then we should have also allocated
562 * all of the filter buffers that have been selected.
563 */
564 if (png_ptr->row_buf)
565 {
566 if (png_ptr->do_filter & PNG_FILTER_SUB && !(png_ptr->sub_row))
567 {
568 png_ptr->sub_row = (png_bytep )png_large_malloc(png_ptr,
569 png_ptr->rowbytes + 1);
570 png_ptr->sub_row[0] = 1; /* Set the row filter type */
571 }
572
573 if (png_ptr->do_filter & PNG_FILTER_UP && !(png_ptr->up_row))
574 {
575 if (!(png_ptr->prev_row))
576 {
577 png_warning(png_ptr, "Can't to add up filter after starting");
578 png_ptr->do_filter &= ~PNG_FILTER_UP;
579 }
580 else
581 {
582 png_ptr->up_row = (png_bytep )png_large_malloc(png_ptr,
583 png_ptr->rowbytes + 1);
584 png_ptr->up_row[0] = 2; /* Set the row filter type */
585 }
586 }
587
588 if (png_ptr->do_filter & PNG_FILTER_AVG && !(png_ptr->avg_row))
589 {
590 if (!(png_ptr->prev_row))
591 {
592 png_warning(png_ptr, "Can't add average filter after starting");
593 png_ptr->do_filter &= ~PNG_FILTER_AVG;
594 }
595 else
596 {
597 png_ptr->up_row = (png_bytep )png_large_malloc(png_ptr,
598 png_ptr->rowbytes + 1);
599 png_ptr->up_row[0] = 3; /* Set the row filter type */
600 }
601 }
602
603 if (png_ptr->do_filter & PNG_FILTER_PAETH && !(png_ptr->paeth_row))
604 {
605 if (!(png_ptr->prev_row))
606 {
607 png_warning(png_ptr, "Can't add Paeth filter after starting");
608 png_ptr->do_filter &= ~PNG_FILTER_PAETH;
609 }
610 else
611 {
612 png_ptr->paeth_row = (png_bytep )png_large_malloc(png_ptr,
613 png_ptr->rowbytes + 1);
614 png_ptr->paeth_row[0] = 4; /* Set the row filter type */
615 }
616 }
617
618 if (png_ptr->do_filter == PNG_NO_FILTERS)
619 png_ptr->do_filter = PNG_FILTER_NONE;
620 }
621 }
622 else
623 png_error(png_ptr, "Unknown custom filter method");
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500624}
625
626void
Guy Schalnat6d764711995-12-19 03:22:19 -0600627png_set_compression_level(png_structp png_ptr, int level)
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500628{
Guy Schalnate5a37791996-06-05 15:50:50 -0500629 png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_LEVEL;
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500630 png_ptr->zlib_level = level;
631}
632
633void
Guy Schalnat6d764711995-12-19 03:22:19 -0600634png_set_compression_mem_level(png_structp png_ptr, int mem_level)
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500635{
Guy Schalnate5a37791996-06-05 15:50:50 -0500636 png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_MEM_LEVEL;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600637 png_ptr->zlib_mem_level = mem_level;
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500638}
639
640void
Guy Schalnat6d764711995-12-19 03:22:19 -0600641png_set_compression_strategy(png_structp png_ptr, int strategy)
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500642{
Guy Schalnate5a37791996-06-05 15:50:50 -0500643 png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_STRATEGY;
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500644 png_ptr->zlib_strategy = strategy;
645}
646
647void
Guy Schalnat6d764711995-12-19 03:22:19 -0600648png_set_compression_window_bits(png_structp png_ptr, int window_bits)
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500649{
Guy Schalnate5a37791996-06-05 15:50:50 -0500650 if (window_bits > 15)
651 png_warning(png_ptr, "Only compression windows <= 32k supported by PNG");
652 png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_WINDOW_BITS;
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500653 png_ptr->zlib_window_bits = window_bits;
654}
655
656void
Guy Schalnat6d764711995-12-19 03:22:19 -0600657png_set_compression_method(png_structp png_ptr, int method)
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500658{
Guy Schalnate5a37791996-06-05 15:50:50 -0500659 if (method != 8)
660 png_warning(png_ptr, "Only compression method 8 is supported by PNG");
661 png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_METHOD;
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500662 png_ptr->zlib_method = method;
Guy Schalnat0d580581995-07-20 02:43:20 -0500663}
664