blob: e6d590fa1c457063fe6160af0718c1d858b53ae8 [file] [log] [blame]
Guy Schalnat0d580581995-07-20 02:43:20 -05001
2/* pngwrite.c - general routines to write a png file
3
Guy Schalnat4ee97b01996-01-16 01:51:56 -06004 libpng 1.0 beta 2 - version 0.87
Guy Schalnat0d580581995-07-20 02:43:20 -05005 For conditions of distribution and use, see copyright notice in png.h
Guy Schalnat69b14481996-01-10 02:56:49 -06006 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
Guy Schalnat4ee97b01996-01-16 01:51:56 -06007 January 15, 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 Schalnat6d764711995-12-19 03:22:19 -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 Schalnat51f0eb41995-09-26 05:22:39 -050051#if defined(PNG_WRITE_tRNS_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -050052 if (info->valid & PNG_INFO_tRNS)
53 png_write_tRNS(png_ptr, info->trans, &(info->trans_values),
54 info->num_trans, info->color_type);
Guy Schalnat51f0eb41995-09-26 05:22:39 -050055#endif
56#if defined(PNG_WRITE_bKGD_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -050057 if (info->valid & PNG_INFO_bKGD)
58 png_write_bKGD(png_ptr, &(info->background), info->color_type);
Guy Schalnat51f0eb41995-09-26 05:22:39 -050059#endif
60#if defined(PNG_WRITE_hIST_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -050061 if (info->valid & PNG_INFO_hIST)
62 png_write_hIST(png_ptr, info->hist, info->num_palette);
Guy Schalnat51f0eb41995-09-26 05:22:39 -050063#endif
64#if defined(PNG_WRITE_pHYs_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -050065 if (info->valid & PNG_INFO_pHYs)
66 png_write_pHYs(png_ptr, info->x_pixels_per_unit,
67 info->y_pixels_per_unit, info->phys_unit_type);
Guy Schalnat51f0eb41995-09-26 05:22:39 -050068#endif
69#if defined(PNG_WRITE_oFFs_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -050070 if (info->valid & PNG_INFO_oFFs)
71 png_write_oFFs(png_ptr, info->x_offset, info->y_offset,
72 info->offset_unit_type);
Guy Schalnat51f0eb41995-09-26 05:22:39 -050073#endif
74#if defined(PNG_WRITE_tIME_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -050075 if (info->valid & PNG_INFO_tIME)
76 png_write_tIME(png_ptr, &(info->mod_time));
77 /* Check to see if we need to write text chunks */
Guy Schalnat51f0eb41995-09-26 05:22:39 -050078#endif
79#if defined(PNG_WRITE_tEXt_SUPPORTED) || defined(PNG_WRITE_zTXt_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -050080 if (info->num_text)
81 {
82 int i; /* local counter */
83
84 /* loop through the text chunks */
85 for (i = 0; i < info->num_text; i++)
86 {
87 /* if chunk is compressed */
88 if (info->text[i].compression >= 0)
89 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -050090#if defined(PNG_WRITE_zTXt_SUPPORTED)
Guy Schalnat6d764711995-12-19 03:22:19 -060091 /* write compressed chunk */
Guy Schalnat0d580581995-07-20 02:43:20 -050092 png_write_zTXt(png_ptr, info->text[i].key,
93 info->text[i].text, info->text[i].text_length,
94 info->text[i].compression);
Guy Schalnat51f0eb41995-09-26 05:22:39 -050095#endif
Guy Schalnat0d580581995-07-20 02:43:20 -050096 }
97 else
98 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -050099#if defined(PNG_WRITE_tEXt_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500100 /* write uncompressed chunk */
101 png_write_tEXt(png_ptr, info->text[i].key,
Guy Schalnat6d764711995-12-19 03:22:19 -0600102 info->text[i].text, info->text[i].text_length);
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500103#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500104 }
105 }
106 }
Guy Schalnat6d764711995-12-19 03:22:19 -0600107#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500108}
109
110/* writes the end of the png file. If you don't want to write comments or
111 time information, you can pass NULL for info. If you already wrote these
112 in png_write_info(), do not write them again here. If you have long
113 comments, I suggest writing them here, and compressing them. */
114void
Guy Schalnat6d764711995-12-19 03:22:19 -0600115png_write_end(png_structp png_ptr, png_infop info)
Guy Schalnat0d580581995-07-20 02:43:20 -0500116{
Guy Schalnat69b14481996-01-10 02:56:49 -0600117 /* see if user wants us to write information chunks */
Guy Schalnat0d580581995-07-20 02:43:20 -0500118 if (info)
119 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500120#if defined(PNG_WRITE_tIME_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500121 /* check to see if user has supplied a time chunk */
122 if (info->valid & PNG_INFO_tIME)
123 png_write_tIME(png_ptr, &(info->mod_time));
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500124#endif
125#if defined(PNG_WRITE_tEXt_SUPPORTED) || defined(PNG_WRITE_zTXt_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500126 /* check to see if we need to write comment chunks */
127 if (info->num_text)
128 {
129 int i; /* local index variable */
130
131 /* loop through comment chunks */
132 for (i = 0; i < info->num_text; i++)
Guy Schalnat6d764711995-12-19 03:22:19 -0600133 {
Guy Schalnat0d580581995-07-20 02:43:20 -0500134 /* check to see if comment is to be compressed */
135 if (info->text[i].compression >= 0)
136 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500137#if defined(PNG_WRITE_zTXt_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500138 /* write compressed chunk */
139 png_write_zTXt(png_ptr, info->text[i].key,
140 info->text[i].text, info->text[i].text_length,
141 info->text[i].compression);
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500142#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500143 }
144 else
145 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500146#if defined(PNG_WRITE_tEXt_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500147 /* write uncompressed chunk */
148 png_write_tEXt(png_ptr, info->text[i].key,
149 info->text[i].text, info->text[i].text_length);
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500150#endif
Guy Schalnat6d764711995-12-19 03:22:19 -0600151 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500152 }
153 }
Guy Schalnat6d764711995-12-19 03:22:19 -0600154#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500155 }
156 /* write end of png file */
157 png_write_IEND(png_ptr);
158}
159
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500160#if defined(PNG_WRITE_tIME_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500161void
Guy Schalnat6d764711995-12-19 03:22:19 -0600162png_convert_from_struct_tm(png_timep ptime, struct tm FAR * ttime)
Guy Schalnat0d580581995-07-20 02:43:20 -0500163{
Guy Schalnat4ee97b01996-01-16 01:51:56 -0600164 ptime->year = (png_uint_16)(1900 + ttime->tm_year);
165 ptime->month = (png_byte)(ttime->tm_mon + 1);
166 ptime->day = (png_byte)ttime->tm_mday;
167 ptime->hour = (png_byte)ttime->tm_hour;
168 ptime->minute = (png_byte)ttime->tm_min;
169 ptime->second = (png_byte)ttime->tm_sec;
Guy Schalnat0d580581995-07-20 02:43:20 -0500170}
171
172void
Guy Schalnat6d764711995-12-19 03:22:19 -0600173png_convert_from_time_t(png_timep ptime, time_t ttime)
Guy Schalnat0d580581995-07-20 02:43:20 -0500174{
175 struct tm *tbuf;
176
177 tbuf = gmtime(&ttime);
178 png_convert_from_struct_tm(ptime, tbuf);
179}
Guy Schalnat6d764711995-12-19 03:22:19 -0600180#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500181
182/* initialize png structure, and allocate any memory needed */
183void
Guy Schalnat6d764711995-12-19 03:22:19 -0600184png_write_init(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -0500185{
186 jmp_buf tmp_jmp; /* to save current jump buffer */
Guy Schalnat6d764711995-12-19 03:22:19 -0600187 png_msg_ptr error_fn;
188 png_msg_ptr warning_fn;
189 png_voidp msg_ptr;
Guy Schalnat0d580581995-07-20 02:43:20 -0500190
Guy Schalnat6d764711995-12-19 03:22:19 -0600191 /* save jump buffer and error functions */
192 png_memcpy(tmp_jmp, png_ptr->jmpbuf, sizeof (jmp_buf));
193 error_fn = png_ptr->error_fn;
194 warning_fn = png_ptr->warning_fn;
195 msg_ptr = png_ptr->msg_ptr;
196
197 /* reset all variables to 0 */
198 png_memset(png_ptr, 0, sizeof (png_struct));
199 /* restore jump buffer and error functions */
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500200 png_memcpy(png_ptr->jmpbuf, tmp_jmp, sizeof (jmp_buf));
Guy Schalnat6d764711995-12-19 03:22:19 -0600201 png_ptr->error_fn = error_fn;
202 png_ptr->warning_fn = warning_fn;
203 png_ptr->msg_ptr = msg_ptr;
Guy Schalnat0d580581995-07-20 02:43:20 -0500204
205 /* initialize zbuf - compression buffer */
206 png_ptr->zbuf_size = PNG_ZBUF_SIZE;
207 png_ptr->zbuf = png_large_malloc(png_ptr, png_ptr->zbuf_size);
Guy Schalnat0d580581995-07-20 02:43:20 -0500208}
209
210/* write a few rows of image data. If the image is interlaced,
211 either you will have to write the 7 sub images, or, if you
212 have called png_set_interlace_handling(), you will have to
Guy Schalnat6d764711995-12-19 03:22:19 -0600213 "write" the image seven times */
Guy Schalnat0d580581995-07-20 02:43:20 -0500214void
Guy Schalnat6d764711995-12-19 03:22:19 -0600215png_write_rows(png_structp png_ptr, png_bytepp row,
Guy Schalnat0d580581995-07-20 02:43:20 -0500216 png_uint_32 num_rows)
217{
218 png_uint_32 i; /* row counter */
Guy Schalnat6d764711995-12-19 03:22:19 -0600219 png_bytepp rp; /* row pointer */
Guy Schalnat0d580581995-07-20 02:43:20 -0500220
221 /* loop through the rows */
222 for (i = 0, rp = row; i < num_rows; i++, rp++)
223 {
224 png_write_row(png_ptr, *rp);
225 }
226}
227
228/* write the image. You only need to call this function once, even
229 if you are writing an interlaced image. */
230void
Guy Schalnat6d764711995-12-19 03:22:19 -0600231png_write_image(png_structp png_ptr, png_bytepp image)
Guy Schalnat0d580581995-07-20 02:43:20 -0500232{
233 png_uint_32 i; /* row index */
234 int pass, num_pass; /* pass variables */
Guy Schalnat6d764711995-12-19 03:22:19 -0600235 png_bytepp rp; /* points to current row */
Guy Schalnat0d580581995-07-20 02:43:20 -0500236
237 /* intialize interlace handling. If image is not interlaced,
238 this will set pass to 1 */
239 num_pass = png_set_interlace_handling(png_ptr);
240 /* loop through passes */
241 for (pass = 0; pass < num_pass; pass++)
242 {
243 /* loop through image */
244 for (i = 0, rp = image; i < png_ptr->height; i++, rp++)
245 {
246 png_write_row(png_ptr, *rp);
247 }
248 }
249}
250
251/* write a row of image data */
252void
Guy Schalnat6d764711995-12-19 03:22:19 -0600253png_write_row(png_structp png_ptr, png_bytep row)
Guy Schalnat0d580581995-07-20 02:43:20 -0500254{
255 /* initialize transformations and other stuff if first time */
Guy Schalnat6d764711995-12-19 03:22:19 -0600256 if (png_ptr->row_number == 0 && png_ptr->pass == 0)
Guy Schalnat0d580581995-07-20 02:43:20 -0500257 {
258 png_write_start_row(png_ptr);
259 }
260
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500261#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500262 /* if interlaced and not interested in row, return */
263 if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE))
264 {
265 switch (png_ptr->pass)
266 {
Guy Schalnat6d764711995-12-19 03:22:19 -0600267 case 0:
Guy Schalnat0d580581995-07-20 02:43:20 -0500268 if (png_ptr->row_number & 7)
269 {
270 png_write_finish_row(png_ptr);
271 return;
272 }
273 break;
274 case 1:
275 if ((png_ptr->row_number & 7) || png_ptr->width < 5)
276 {
277 png_write_finish_row(png_ptr);
278 return;
279 }
280 break;
281 case 2:
282 if ((png_ptr->row_number & 7) != 4)
283 {
284 png_write_finish_row(png_ptr);
Guy Schalnat6d764711995-12-19 03:22:19 -0600285 return;
Guy Schalnat0d580581995-07-20 02:43:20 -0500286 }
287 break;
288 case 3:
289 if ((png_ptr->row_number & 3) || png_ptr->width < 3)
290 {
291 png_write_finish_row(png_ptr);
292 return;
293 }
294 break;
295 case 4:
296 if ((png_ptr->row_number & 3) != 2)
297 {
298 png_write_finish_row(png_ptr);
299 return;
300 }
301 break;
302 case 5:
Guy Schalnat6d764711995-12-19 03:22:19 -0600303 if ((png_ptr->row_number & 1) || png_ptr->width < 2)
Guy Schalnat0d580581995-07-20 02:43:20 -0500304 {
305 png_write_finish_row(png_ptr);
306 return;
307 }
308 break;
309 case 6:
310 if (!(png_ptr->row_number & 1))
311 {
312 png_write_finish_row(png_ptr);
313 return;
314 }
315 break;
316 }
317 }
Guy Schalnat6d764711995-12-19 03:22:19 -0600318#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500319
320 /* set up row info for transformations */
Guy Schalnat6d764711995-12-19 03:22:19 -0600321 png_ptr->row_info.color_type = png_ptr->color_type;
Guy Schalnat0d580581995-07-20 02:43:20 -0500322 png_ptr->row_info.width = png_ptr->usr_width;
323 png_ptr->row_info.channels = png_ptr->usr_channels;
324 png_ptr->row_info.bit_depth = png_ptr->usr_bit_depth;
Guy Schalnat4ee97b01996-01-16 01:51:56 -0600325 png_ptr->row_info.pixel_depth = (png_byte)(png_ptr->row_info.bit_depth *
326 png_ptr->row_info.channels);
Guy Schalnat0d580581995-07-20 02:43:20 -0500327 png_ptr->row_info.rowbytes = ((png_ptr->row_info.width *
328 (png_uint_32)png_ptr->row_info.pixel_depth + 7) >> 3);
329
330 /* copy users row into buffer, leaving room for filter byte */
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500331 png_memcpy(png_ptr->row_buf + 1, row, (png_size_t)png_ptr->row_info.rowbytes);
Guy Schalnat0d580581995-07-20 02:43:20 -0500332
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500333#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500334 /* handle interlacing */
335 if (png_ptr->interlaced && png_ptr->pass < 6 &&
336 (png_ptr->transformations & PNG_INTERLACE))
337 {
338 png_do_write_interlace(&(png_ptr->row_info),
Guy Schalnat6d764711995-12-19 03:22:19 -0600339 png_ptr->row_buf + 1, png_ptr->pass);
Guy Schalnat0d580581995-07-20 02:43:20 -0500340 /* this should always get caught above, but still ... */
341 if (!(png_ptr->row_info.width))
342 {
343 png_write_finish_row(png_ptr);
344 return;
345 }
346 }
Guy Schalnat6d764711995-12-19 03:22:19 -0600347#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500348
349 /* handle other transformations */
350 if (png_ptr->transformations)
351 png_do_write_transformations(png_ptr);
352
353 /* filter rows that have been proved to help */
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500354 if (png_ptr->do_filter)
Guy Schalnat0d580581995-07-20 02:43:20 -0500355 {
356 /* save row to previous row */
Guy Schalnat6d764711995-12-19 03:22:19 -0600357 png_memcpy(png_ptr->save_row, png_ptr->row_buf,
Guy Schalnat0d580581995-07-20 02:43:20 -0500358 (png_size_t)png_ptr->row_info.rowbytes + 1);
359
360 /* filter row */
361 png_write_filter_row(&(png_ptr->row_info), png_ptr->row_buf,
362 png_ptr->prev_row);
363
364 /* trade saved pointer and prev pointer so next row references are correctly */
365 { /* scope limiter */
Guy Schalnat6d764711995-12-19 03:22:19 -0600366 png_bytep tptr;
Guy Schalnat0d580581995-07-20 02:43:20 -0500367
368 tptr = png_ptr->prev_row;
369 png_ptr->prev_row = png_ptr->save_row;
370 png_ptr->save_row = tptr;
371 }
372 }
373 else
374 /* set filter row to "none" */
Guy Schalnat6d764711995-12-19 03:22:19 -0600375 png_ptr->row_buf[0] = 0;
Guy Schalnat0d580581995-07-20 02:43:20 -0500376
377 /* set up the zlib input buffer */
378 png_ptr->zstream->next_in = png_ptr->row_buf;
379 png_ptr->zstream->avail_in = (uInt)png_ptr->row_info.rowbytes + 1;
Guy Schalnat0d580581995-07-20 02:43:20 -0500380 /* repeat until we have compressed all the data */
381 do
382 {
383 int ret; /* return of zlib */
384
385 /* compress the data */
386 ret = deflate(png_ptr->zstream, Z_NO_FLUSH);
387 /* check for compression errors */
388 if (ret != Z_OK)
389 {
390 if (png_ptr->zstream->msg)
Guy Schalnat6d764711995-12-19 03:22:19 -0600391 png_error(png_ptr, png_ptr->zstream->msg);
392 else
393 png_error(png_ptr, "zlib error");
Guy Schalnat0d580581995-07-20 02:43:20 -0500394 }
395
396 /* see if it is time to write another IDAT */
397 if (!png_ptr->zstream->avail_out)
398 {
399 /* write the IDAT and reset the zlib output buffer */
400 png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size);
401 png_ptr->zstream->next_out = png_ptr->zbuf;
402 png_ptr->zstream->avail_out = (uInt)png_ptr->zbuf_size;
403 }
404 /* repeat until all data has been compressed */
405 } while (png_ptr->zstream->avail_in);
406
Guy Schalnat6d764711995-12-19 03:22:19 -0600407 /* finish row - updates counters and flushes zlib if last row */
408 png_write_finish_row(png_ptr);
Guy Schalnat0f716451995-11-28 11:22:13 -0600409
410#if defined(PNG_WRITE_FLUSH_SUPPORTED)
Guy Schalnat6d764711995-12-19 03:22:19 -0600411 png_ptr->flush_rows++;
Guy Schalnat0f716451995-11-28 11:22:13 -0600412
Guy Schalnat6d764711995-12-19 03:22:19 -0600413 if (png_ptr->flush_dist > 0 &&
414 png_ptr->flush_rows >= png_ptr->flush_dist)
415 {
416 png_write_flush(png_ptr);
417 }
Guy Schalnat0f716451995-11-28 11:22:13 -0600418#endif /* PNG_WRITE_FLUSH_SUPPORTED */
Guy Schalnat0d580581995-07-20 02:43:20 -0500419}
420
Guy Schalnat0f716451995-11-28 11:22:13 -0600421#if defined(PNG_WRITE_FLUSH_SUPPORTED)
422/* Set the automatic flush interval or 0 to turn flushing off */
423void
Guy Schalnat4ee97b01996-01-16 01:51:56 -0600424png_set_flush(png_structp png_ptr, int nrows)
Guy Schalnat0f716451995-11-28 11:22:13 -0600425{
Guy Schalnat6d764711995-12-19 03:22:19 -0600426 png_ptr->flush_dist = (nrows < 0 ? 0 : nrows);
Guy Schalnat0f716451995-11-28 11:22:13 -0600427}
428
429/* flush the current output buffers now */
430void
Guy Schalnat4ee97b01996-01-16 01:51:56 -0600431png_write_flush(png_structp png_ptr)
Guy Schalnat0f716451995-11-28 11:22:13 -0600432{
Guy Schalnat6d764711995-12-19 03:22:19 -0600433 int wrote_IDAT;
Guy Schalnat0f716451995-11-28 11:22:13 -0600434
Guy Schalnat6d764711995-12-19 03:22:19 -0600435 if (png_ptr->mode != PNG_HAVE_IDAT)
436 return;
Guy Schalnat0f716451995-11-28 11:22:13 -0600437
Guy Schalnat6d764711995-12-19 03:22:19 -0600438 do
439 {
440 int ret;
Guy Schalnat0f716451995-11-28 11:22:13 -0600441
Guy Schalnat6d764711995-12-19 03:22:19 -0600442 /* compress the data */
443 ret = deflate(png_ptr->zstream, Z_SYNC_FLUSH);
444 wrote_IDAT = 0;
Guy Schalnat0f716451995-11-28 11:22:13 -0600445
Guy Schalnat6d764711995-12-19 03:22:19 -0600446 /* check for compression errors */
447 if (ret != Z_OK)
448 {
449 if (png_ptr->zstream->msg)
450 png_error(png_ptr, png_ptr->zstream->msg);
451 else
452 png_error(png_ptr, "zlib error");
453 }
Guy Schalnat0f716451995-11-28 11:22:13 -0600454
Guy Schalnat6d764711995-12-19 03:22:19 -0600455 if (!png_ptr->zstream->avail_out)
456 {
457 /* write the IDAT and reset the zlib output buffer */
458 png_write_IDAT(png_ptr, png_ptr->zbuf,
459 png_ptr->zbuf_size);
460 png_ptr->zstream->next_out = png_ptr->zbuf;
461 png_ptr->zstream->avail_out = (uInt)png_ptr->zbuf_size;
462 wrote_IDAT = 1;
463 }
464 } while(wrote_IDAT == 1);
Guy Schalnat0f716451995-11-28 11:22:13 -0600465
Guy Schalnat6d764711995-12-19 03:22:19 -0600466 /* If there is any data left to be output, write it into a new IDAT */
467 if (png_ptr->zbuf_size != png_ptr->zstream->avail_out)
468 {
469 /* write the IDAT and reset the zlib output buffer */
470 png_write_IDAT(png_ptr, png_ptr->zbuf,
471 png_ptr->zbuf_size - png_ptr->zstream->avail_out);
472 png_ptr->zstream->next_out = png_ptr->zbuf;
473 png_ptr->zstream->avail_out = (uInt)png_ptr->zbuf_size;
474 }
475 png_ptr->flush_rows = 0;
476 png_flush(png_ptr);
Guy Schalnat0f716451995-11-28 11:22:13 -0600477}
478#endif /* PNG_WRITE_FLUSH_SUPPORTED */
479
Guy Schalnat6d764711995-12-19 03:22:19 -0600480
Guy Schalnat0d580581995-07-20 02:43:20 -0500481/* free any memory used in png struct */
482void
Guy Schalnat6d764711995-12-19 03:22:19 -0600483png_write_destroy(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -0500484{
Guy Schalnat6d764711995-12-19 03:22:19 -0600485 jmp_buf tmp_jmp; /* save jump buffer */
Guy Schalnat0d580581995-07-20 02:43:20 -0500486
487 /* free any memory zlib uses */
Guy Schalnat6d764711995-12-19 03:22:19 -0600488 deflateEnd(png_ptr->zstream);
489 png_free(png_ptr, png_ptr->zstream);
Guy Schalnat0d580581995-07-20 02:43:20 -0500490 /* free our memory. png_free checks NULL for us. */
491 png_large_free(png_ptr, png_ptr->zbuf);
492 png_large_free(png_ptr, png_ptr->row_buf);
493 png_large_free(png_ptr, png_ptr->prev_row);
494 png_large_free(png_ptr, png_ptr->save_row);
495 /* reset structure */
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500496 png_memcpy(tmp_jmp, png_ptr->jmpbuf, sizeof (jmp_buf));
497 png_memset(png_ptr, 0, sizeof (png_struct));
498 png_memcpy(png_ptr->jmpbuf, tmp_jmp, sizeof (jmp_buf));
499}
500void
Guy Schalnat6d764711995-12-19 03:22:19 -0600501png_set_filtering(png_structp png_ptr, int filter)
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500502{
503 png_ptr->do_custom_filter = 1;
Guy Schalnat4ee97b01996-01-16 01:51:56 -0600504 png_ptr->do_filter = (png_byte)filter;
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500505}
506
507void
Guy Schalnat6d764711995-12-19 03:22:19 -0600508png_set_compression_level(png_structp png_ptr, int level)
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500509{
510 png_ptr->zlib_custom_level = 1;
511 png_ptr->zlib_level = level;
512}
513
514void
Guy Schalnat6d764711995-12-19 03:22:19 -0600515png_set_compression_mem_level(png_structp png_ptr, int mem_level)
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500516{
517 png_ptr->zlib_custom_mem_level = 1;
Guy Schalnat6d764711995-12-19 03:22:19 -0600518 png_ptr->zlib_mem_level = mem_level;
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500519}
520
521void
Guy Schalnat6d764711995-12-19 03:22:19 -0600522png_set_compression_strategy(png_structp png_ptr, int strategy)
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500523{
524 png_ptr->zlib_custom_strategy = 1;
525 png_ptr->zlib_strategy = strategy;
526}
527
528void
Guy Schalnat6d764711995-12-19 03:22:19 -0600529png_set_compression_window_bits(png_structp png_ptr, int window_bits)
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500530{
531 png_ptr->zlib_custom_window_bits = 1;
532 png_ptr->zlib_window_bits = window_bits;
533}
534
535void
Guy Schalnat6d764711995-12-19 03:22:19 -0600536png_set_compression_method(png_structp png_ptr, int method)
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500537{
538 png_ptr->zlib_custom_method = 1;
539 png_ptr->zlib_method = method;
Guy Schalnat0d580581995-07-20 02:43:20 -0500540}
541