blob: e455368012f3fddef557bb723cddc88e8af16e15 [file] [log] [blame]
Guy Schalnat0d580581995-07-20 02:43:20 -05001
2/* pngwrite.c - general routines to write a png file
3
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06004 libpng 1.0 beta 4 - version 0.90
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.
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06007 January 10, 1997
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
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060019 info_ptr->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
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060024png_write_info(png_structp png_ptr, png_infop info_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -050025{
26 png_write_sig(png_ptr); /* write PNG signature */
27 /* write IHDR information. */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060028 png_write_IHDR(png_ptr, info_ptr->width, info_ptr->height,
29 info_ptr->bit_depth, info_ptr->color_type, info_ptr->compression_type,
30 info_ptr->filter_type, info_ptr->interlace_type);
Guy Schalnat0d580581995-07-20 02:43:20 -050031 /* 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)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060034 if (info_ptr->valid & PNG_INFO_gAMA)
35 png_write_gAMA(png_ptr, info_ptr->gamma);
Guy Schalnat51f0eb41995-09-26 05:22:39 -050036#endif
37#if defined(PNG_WRITE_sBIT_SUPPORTED)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060038 if (info_ptr->valid & PNG_INFO_sBIT)
39 png_write_sBIT(png_ptr, &(info_ptr->sig_bit), info_ptr->color_type);
Guy Schalnat51f0eb41995-09-26 05:22:39 -050040#endif
41#if defined(PNG_WRITE_cHRM_SUPPORTED)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060042 if (info_ptr->valid & PNG_INFO_cHRM)
Guy Schalnat0d580581995-07-20 02:43:20 -050043 png_write_cHRM(png_ptr,
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060044 info_ptr->x_white, info_ptr->y_white,
45 info_ptr->x_red, info_ptr->y_red,
46 info_ptr->x_green, info_ptr->y_green,
47 info_ptr->x_blue, info_ptr->y_blue);
Guy Schalnat51f0eb41995-09-26 05:22:39 -050048#endif
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060049 if (info_ptr->valid & PNG_INFO_PLTE)
50 png_write_PLTE(png_ptr, info_ptr->palette, info_ptr->num_palette);
51 else if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
Guy Schalnate5a37791996-06-05 15:50:50 -050052 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)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060054 if (info_ptr->valid & PNG_INFO_tRNS)
55 png_write_tRNS(png_ptr, info_ptr->trans, &(info_ptr->trans_values),
56 info_ptr->num_trans, info_ptr->color_type);
Guy Schalnat51f0eb41995-09-26 05:22:39 -050057#endif
58#if defined(PNG_WRITE_bKGD_SUPPORTED)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060059 if (info_ptr->valid & PNG_INFO_bKGD)
60 png_write_bKGD(png_ptr, &(info_ptr->background), info_ptr->color_type);
Guy Schalnat51f0eb41995-09-26 05:22:39 -050061#endif
62#if defined(PNG_WRITE_hIST_SUPPORTED)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060063 if (info_ptr->valid & PNG_INFO_hIST)
64 png_write_hIST(png_ptr, info_ptr->hist, info_ptr->num_palette);
Guy Schalnat51f0eb41995-09-26 05:22:39 -050065#endif
66#if defined(PNG_WRITE_pHYs_SUPPORTED)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060067 if (info_ptr->valid & PNG_INFO_pHYs)
68 png_write_pHYs(png_ptr, info_ptr->x_pixels_per_unit,
69 info_ptr->y_pixels_per_unit, info_ptr->phys_unit_type);
Guy Schalnat51f0eb41995-09-26 05:22:39 -050070#endif
71#if defined(PNG_WRITE_oFFs_SUPPORTED)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060072 if (info_ptr->valid & PNG_INFO_oFFs)
73 png_write_oFFs(png_ptr, info_ptr->x_offset, info_ptr->y_offset,
74 info_ptr->offset_unit_type);
Guy Schalnat51f0eb41995-09-26 05:22:39 -050075#endif
76#if defined(PNG_WRITE_tIME_SUPPORTED)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060077 if (info_ptr->valid & PNG_INFO_tIME)
Guy Schalnate5a37791996-06-05 15:50:50 -050078 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060079 png_write_tIME(png_ptr, &(info_ptr->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 */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060085 if (info_ptr->num_text)
Guy Schalnat0d580581995-07-20 02:43:20 -050086 {
87 int i; /* local counter */
88
89 /* loop through the text chunks */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060090 for (i = 0; i < info_ptr->num_text; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -050091 {
92 /* if chunk is compressed */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060093 if (info_ptr->text[i].compression >= 0)
Guy Schalnat0d580581995-07-20 02:43:20 -050094 {
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 */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060097 png_write_zTXt(png_ptr, info_ptr->text[i].key,
98 info_ptr->text[i].text, info_ptr->text[i].text_length,
99 info_ptr->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 */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600108 png_write_tEXt(png_ptr, info_ptr->text[i].key,
109 info_ptr->text[i].text, info_ptr->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
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600124png_write_end(png_structp png_ptr, png_infop info_ptr)
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 */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600130 if (info_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -0500131 {
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 */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600134 if (info_ptr->valid & PNG_INFO_tIME &&
Guy Schalnate5a37791996-06-05 15:50:50 -0500135 !(png_ptr->flags & PNG_FLAG_WROTE_tIME))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600136 png_write_tIME(png_ptr, &(info_ptr->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 */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600140 if (info_ptr->num_text)
Guy Schalnat0d580581995-07-20 02:43:20 -0500141 {
142 int i; /* local index variable */
143
144 /* loop through comment chunks */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600145 for (i = 0; i < info_ptr->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 */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600149 if (info_ptr->text[i].compression >= 0)
Guy Schalnat0d580581995-07-20 02:43:20 -0500150 {
151 /* write compressed chunk */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600152 png_write_zTXt(png_ptr, info_ptr->text[i].key,
153 info_ptr->text[i].text, info_ptr->text[i].text_length,
154 info_ptr->text[i].compression);
Guy Schalnat0d580581995-07-20 02:43:20 -0500155 }
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 */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600163 png_write_tEXt(png_ptr, info_ptr->text[i].key,
164 info_ptr->text[i].text, info_ptr->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,
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600203 png_error_ptr error_fn, png_error_ptr warn_fn)
Guy Schalnat0d580581995-07-20 02:43:20 -0500204{
Guy Schalnate5a37791996-06-05 15:50:50 -0500205 png_structp png_ptr;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600206#ifdef USE_FAR_KEYWORD
207 jmp_buf jmpbuf;
208#endif
Guy Schalnate5a37791996-06-05 15:50:50 -0500209 if ((png_ptr = (png_structp)png_create_struct(PNG_STRUCT_PNG)) == NULL)
210 {
211 return (png_structp)NULL;
212 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600213#ifdef USE_FAR_KEYWORD
214 if (setjmp(jmpbuf))
215#else
Guy Schalnate5a37791996-06-05 15:50:50 -0500216 if (setjmp(png_ptr->jmpbuf))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600217#endif
Guy Schalnate5a37791996-06-05 15:50:50 -0500218 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600219 png_free(png_ptr, png_ptr->zbuf);
Guy Schalnate5a37791996-06-05 15:50:50 -0500220 png_destroy_struct(png_ptr);
221 return (png_structp)NULL;
222 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600223#ifdef USE_FAR_KEYWORD
224 png_memcpy(png_ptr->jmpbuf,jmpbuf,sizeof(jmp_buf));
225#endif
226 png_set_error_fn(png_ptr, error_ptr, error_fn, warn_fn);
Guy Schalnate5a37791996-06-05 15:50:50 -0500227
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600228 if (user_png_ver == NULL || png_strcmp(user_png_ver, png_libpng_ver))
Guy Schalnate5a37791996-06-05 15:50:50 -0500229 {
230 if (user_png_ver == NULL || user_png_ver[0] != png_libpng_ver[0])
231 {
232 png_error(png_ptr, "Incompatible libpng versions");
233 }
234 else
235 {
236 png_warning(png_ptr, "Different libpng versions");
237 }
238 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500239
240 /* initialize zbuf - compression buffer */
241 png_ptr->zbuf_size = PNG_ZBUF_SIZE;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600242 png_ptr->zbuf = png_malloc(png_ptr, png_ptr->zbuf_size);
Guy Schalnate5a37791996-06-05 15:50:50 -0500243
244 png_set_write_fn(png_ptr, NULL, NULL, NULL);
245
Guy Schalnate5a37791996-06-05 15:50:50 -0500246 return (png_ptr);
247}
248
249
250/* initialize png structure, and allocate any memory needed */
251void
252png_write_init(png_structp png_ptr)
253{
254 jmp_buf tmp_jmp; /* to save current jump buffer */
255
256 /* save jump buffer and error functions */
257 png_memcpy(tmp_jmp, png_ptr->jmpbuf, sizeof (jmp_buf));
258
259 /* reset all variables to 0 */
260 png_memset(png_ptr, 0, sizeof (png_struct));
261
262 /* restore jump buffer */
263 png_memcpy(png_ptr->jmpbuf, tmp_jmp, sizeof (jmp_buf));
264
265 /* initialize zbuf - compression buffer */
266 png_ptr->zbuf_size = PNG_ZBUF_SIZE;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600267 png_ptr->zbuf = png_malloc(png_ptr, png_ptr->zbuf_size);
Guy Schalnate5a37791996-06-05 15:50:50 -0500268 png_set_write_fn(png_ptr, NULL, NULL, NULL);
Guy Schalnat0d580581995-07-20 02:43:20 -0500269}
270
271/* write a few rows of image data. If the image is interlaced,
272 either you will have to write the 7 sub images, or, if you
273 have called png_set_interlace_handling(), you will have to
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600274 "write" the image seven times */
Guy Schalnat0d580581995-07-20 02:43:20 -0500275void
Guy Schalnat6d764711995-12-19 03:22:19 -0600276png_write_rows(png_structp png_ptr, png_bytepp row,
Guy Schalnat0d580581995-07-20 02:43:20 -0500277 png_uint_32 num_rows)
278{
279 png_uint_32 i; /* row counter */
Guy Schalnat6d764711995-12-19 03:22:19 -0600280 png_bytepp rp; /* row pointer */
Guy Schalnat0d580581995-07-20 02:43:20 -0500281
282 /* loop through the rows */
283 for (i = 0, rp = row; i < num_rows; i++, rp++)
284 {
285 png_write_row(png_ptr, *rp);
286 }
287}
288
289/* write the image. You only need to call this function once, even
290 if you are writing an interlaced image. */
291void
Guy Schalnat6d764711995-12-19 03:22:19 -0600292png_write_image(png_structp png_ptr, png_bytepp image)
Guy Schalnat0d580581995-07-20 02:43:20 -0500293{
294 png_uint_32 i; /* row index */
295 int pass, num_pass; /* pass variables */
Guy Schalnat6d764711995-12-19 03:22:19 -0600296 png_bytepp rp; /* points to current row */
Guy Schalnat0d580581995-07-20 02:43:20 -0500297
298 /* intialize interlace handling. If image is not interlaced,
299 this will set pass to 1 */
300 num_pass = png_set_interlace_handling(png_ptr);
301 /* loop through passes */
302 for (pass = 0; pass < num_pass; pass++)
303 {
304 /* loop through image */
305 for (i = 0, rp = image; i < png_ptr->height; i++, rp++)
306 {
307 png_write_row(png_ptr, *rp);
308 }
309 }
310}
311
Guy Schalnate5a37791996-06-05 15:50:50 -0500312/* called by user to write a row of image data */
Guy Schalnat0d580581995-07-20 02:43:20 -0500313void
Guy Schalnat6d764711995-12-19 03:22:19 -0600314png_write_row(png_structp png_ptr, png_bytep row)
Guy Schalnat0d580581995-07-20 02:43:20 -0500315{
316 /* initialize transformations and other stuff if first time */
Guy Schalnat6d764711995-12-19 03:22:19 -0600317 if (png_ptr->row_number == 0 && png_ptr->pass == 0)
Guy Schalnat0d580581995-07-20 02:43:20 -0500318 {
319 png_write_start_row(png_ptr);
320 }
321
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500322#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500323 /* if interlaced and not interested in row, return */
324 if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE))
325 {
326 switch (png_ptr->pass)
327 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600328 case 0:
Guy Schalnat0d580581995-07-20 02:43:20 -0500329 if (png_ptr->row_number & 7)
330 {
331 png_write_finish_row(png_ptr);
332 return;
333 }
334 break;
335 case 1:
336 if ((png_ptr->row_number & 7) || png_ptr->width < 5)
337 {
338 png_write_finish_row(png_ptr);
339 return;
340 }
341 break;
342 case 2:
343 if ((png_ptr->row_number & 7) != 4)
344 {
345 png_write_finish_row(png_ptr);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600346 return;
Guy Schalnat0d580581995-07-20 02:43:20 -0500347 }
348 break;
349 case 3:
350 if ((png_ptr->row_number & 3) || png_ptr->width < 3)
351 {
352 png_write_finish_row(png_ptr);
353 return;
354 }
355 break;
356 case 4:
357 if ((png_ptr->row_number & 3) != 2)
358 {
359 png_write_finish_row(png_ptr);
360 return;
361 }
362 break;
363 case 5:
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600364 if ((png_ptr->row_number & 1) || png_ptr->width < 2)
Guy Schalnat0d580581995-07-20 02:43:20 -0500365 {
366 png_write_finish_row(png_ptr);
367 return;
368 }
369 break;
370 case 6:
371 if (!(png_ptr->row_number & 1))
372 {
373 png_write_finish_row(png_ptr);
374 return;
375 }
376 break;
377 }
378 }
Guy Schalnat6d764711995-12-19 03:22:19 -0600379#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500380
381 /* set up row info for transformations */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600382 png_ptr->row_info.color_type = png_ptr->color_type;
Guy Schalnat0d580581995-07-20 02:43:20 -0500383 png_ptr->row_info.width = png_ptr->usr_width;
384 png_ptr->row_info.channels = png_ptr->usr_channels;
385 png_ptr->row_info.bit_depth = png_ptr->usr_bit_depth;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600386 png_ptr->row_info.pixel_depth = (png_byte)(png_ptr->row_info.bit_depth *
387 png_ptr->row_info.channels);
Guy Schalnat0d580581995-07-20 02:43:20 -0500388 png_ptr->row_info.rowbytes = ((png_ptr->row_info.width *
389 (png_uint_32)png_ptr->row_info.pixel_depth + 7) >> 3);
390
391 /* copy users row into buffer, leaving room for filter byte */
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500392 png_memcpy(png_ptr->row_buf + 1, row, (png_size_t)png_ptr->row_info.rowbytes);
Guy Schalnat0d580581995-07-20 02:43:20 -0500393
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500394#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500395 /* handle interlacing */
396 if (png_ptr->interlaced && png_ptr->pass < 6 &&
397 (png_ptr->transformations & PNG_INTERLACE))
398 {
399 png_do_write_interlace(&(png_ptr->row_info),
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600400 png_ptr->row_buf + 1, png_ptr->pass);
Guy Schalnat0d580581995-07-20 02:43:20 -0500401 /* this should always get caught above, but still ... */
402 if (!(png_ptr->row_info.width))
403 {
404 png_write_finish_row(png_ptr);
405 return;
406 }
407 }
Guy Schalnat6d764711995-12-19 03:22:19 -0600408#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500409
410 /* handle other transformations */
411 if (png_ptr->transformations)
412 png_do_write_transformations(png_ptr);
413
Guy Schalnate5a37791996-06-05 15:50:50 -0500414 /* find a filter if necessary, filter the row and write it out */
415 png_write_find_filter(png_ptr, &(png_ptr->row_info));
Guy Schalnat0d580581995-07-20 02:43:20 -0500416}
417
Guy Schalnat0f716451995-11-28 11:22:13 -0600418#if defined(PNG_WRITE_FLUSH_SUPPORTED)
419/* Set the automatic flush interval or 0 to turn flushing off */
420void
Guy Schalnat4ee97b01996-01-16 01:51:56 -0600421png_set_flush(png_structp png_ptr, int nrows)
Guy Schalnat0f716451995-11-28 11:22:13 -0600422{
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600423 png_ptr->flush_dist = (nrows < 0 ? 0 : nrows);
Guy Schalnat0f716451995-11-28 11:22:13 -0600424}
425
426/* flush the current output buffers now */
427void
Guy Schalnat4ee97b01996-01-16 01:51:56 -0600428png_write_flush(png_structp png_ptr)
Guy Schalnat0f716451995-11-28 11:22:13 -0600429{
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600430 int wrote_IDAT;
Guy Schalnat0f716451995-11-28 11:22:13 -0600431
Guy Schalnate5a37791996-06-05 15:50:50 -0500432 /* We have already written out all of the data */
433 if (png_ptr->row_number >= png_ptr->num_rows)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600434 return;
Guy Schalnat0f716451995-11-28 11:22:13 -0600435
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600436 do
437 {
438 int ret;
Guy Schalnat0f716451995-11-28 11:22:13 -0600439
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600440 /* compress the data */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600441 ret = deflate(&png_ptr->zstream, Z_SYNC_FLUSH);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600442 wrote_IDAT = 0;
Guy Schalnat0f716451995-11-28 11:22:13 -0600443
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600444 /* check for compression errors */
445 if (ret != Z_OK)
446 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600447 if (png_ptr->zstream.msg)
448 png_error(png_ptr, png_ptr->zstream.msg);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600449 else
450 png_error(png_ptr, "zlib error");
451 }
Guy Schalnat0f716451995-11-28 11:22:13 -0600452
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600453 if (!png_ptr->zstream.avail_out)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600454 {
455 /* write the IDAT and reset the zlib output buffer */
456 png_write_IDAT(png_ptr, png_ptr->zbuf,
457 png_ptr->zbuf_size);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600458 png_ptr->zstream.next_out = png_ptr->zbuf;
459 png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600460 wrote_IDAT = 1;
461 }
462 } while(wrote_IDAT == 1);
Guy Schalnat0f716451995-11-28 11:22:13 -0600463
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600464 /* If there is any data left to be output, write it into a new IDAT */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600465 if (png_ptr->zbuf_size != png_ptr->zstream.avail_out)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600466 {
467 /* write the IDAT and reset the zlib output buffer */
468 png_write_IDAT(png_ptr, png_ptr->zbuf,
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600469 png_ptr->zbuf_size - png_ptr->zstream.avail_out);
470 png_ptr->zstream.next_out = png_ptr->zbuf;
471 png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600472 }
473 png_ptr->flush_rows = 0;
474 png_flush(png_ptr);
Guy Schalnat0f716451995-11-28 11:22:13 -0600475}
476#endif /* PNG_WRITE_FLUSH_SUPPORTED */
477
Guy Schalnate5a37791996-06-05 15:50:50 -0500478/* free all memory used by the write */
479void
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600480png_destroy_write_struct(png_structpp png_ptr_ptr, png_infopp info_ptr_ptr)
Guy Schalnate5a37791996-06-05 15:50:50 -0500481{
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600482 png_structp png_ptr = NULL;
483 png_infop info_ptr = NULL;
484
485 if (png_ptr_ptr)
486 png_ptr = *png_ptr_ptr;
487
488 if (info_ptr_ptr)
489 info_ptr = *info_ptr_ptr;
490
491 if (info_ptr)
Guy Schalnate5a37791996-06-05 15:50:50 -0500492 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600493 png_destroy_struct((png_voidp)info_ptr);
494 *info_ptr_ptr = (png_infop)NULL;
Guy Schalnate5a37791996-06-05 15:50:50 -0500495 }
Guy Schalnat6d764711995-12-19 03:22:19 -0600496
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600497 if (png_ptr)
Guy Schalnate5a37791996-06-05 15:50:50 -0500498 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600499 png_write_destroy(png_ptr);
500 png_destroy_struct((png_voidp)png_ptr);
501 *png_ptr_ptr = (png_structp)NULL;
Guy Schalnate5a37791996-06-05 15:50:50 -0500502 }
503}
504
505
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600506/* free any memory used in png struct (old method) */
Guy Schalnat0d580581995-07-20 02:43:20 -0500507void
Guy Schalnat6d764711995-12-19 03:22:19 -0600508png_write_destroy(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -0500509{
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600510 jmp_buf tmp_jmp; /* save jump buffer */
Guy Schalnate5a37791996-06-05 15:50:50 -0500511 png_error_ptr error_fn;
512 png_error_ptr warning_fn;
513 png_voidp error_ptr;
Guy Schalnat0d580581995-07-20 02:43:20 -0500514
515 /* free any memory zlib uses */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600516 deflateEnd(&png_ptr->zstream);
Guy Schalnate5a37791996-06-05 15:50:50 -0500517
Guy Schalnat0d580581995-07-20 02:43:20 -0500518 /* free our memory. png_free checks NULL for us. */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600519 png_free(png_ptr, png_ptr->zbuf);
520 png_free(png_ptr, png_ptr->row_buf);
521 png_free(png_ptr, png_ptr->prev_row);
522 png_free(png_ptr, png_ptr->sub_row);
523 png_free(png_ptr, png_ptr->up_row);
524 png_free(png_ptr, png_ptr->avg_row);
525 png_free(png_ptr, png_ptr->paeth_row);
Guy Schalnate5a37791996-06-05 15:50:50 -0500526
Guy Schalnat0d580581995-07-20 02:43:20 -0500527 /* reset structure */
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500528 png_memcpy(tmp_jmp, png_ptr->jmpbuf, sizeof (jmp_buf));
Guy Schalnate5a37791996-06-05 15:50:50 -0500529
530 error_fn = png_ptr->error_fn;
531 warning_fn = png_ptr->warning_fn;
532 error_ptr = png_ptr->error_ptr;
533
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500534 png_memset(png_ptr, 0, sizeof (png_struct));
Guy Schalnate5a37791996-06-05 15:50:50 -0500535
536 png_ptr->error_fn = error_fn;
537 png_ptr->warning_fn = warning_fn;
538 png_ptr->error_ptr = error_ptr;
539
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500540 png_memcpy(png_ptr->jmpbuf, tmp_jmp, sizeof (jmp_buf));
541}
Guy Schalnate5a37791996-06-05 15:50:50 -0500542
543/* Allow the application to select one or more filters to use */
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500544void
Guy Schalnate5a37791996-06-05 15:50:50 -0500545png_set_filter(png_structp png_ptr, int method, int filters)
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500546{
Guy Schalnate5a37791996-06-05 15:50:50 -0500547 /* We allow 'method' only for future expansion of the base filter method */
548 if (method == 0)
549 {
550 switch (filters & (PNG_ALL_FILTERS | 0x07))
551 {
552 case 5:
553 case 6:
554 case 7: png_warning(png_ptr, "Unknown custom row filter for method 0");
555 case 0: png_ptr->do_filter = PNG_FILTER_NONE; break;
556 case 1: png_ptr->do_filter = PNG_FILTER_SUB; break;
557 case 2: png_ptr->do_filter = PNG_FILTER_UP; break;
558 case 3: png_ptr->do_filter = PNG_FILTER_AVG; break;
559 case 4: png_ptr->do_filter = PNG_FILTER_PAETH; break;
560 default: png_ptr->do_filter = (png_byte)filters; break;
561 }
562
563 /* If we have allocated the row_buf, then we should have also allocated
564 * all of the filter buffers that have been selected.
565 */
566 if (png_ptr->row_buf)
567 {
568 if (png_ptr->do_filter & PNG_FILTER_SUB && !(png_ptr->sub_row))
569 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600570 png_ptr->sub_row = (png_bytep )png_malloc(png_ptr,
Guy Schalnate5a37791996-06-05 15:50:50 -0500571 png_ptr->rowbytes + 1);
572 png_ptr->sub_row[0] = 1; /* Set the row filter type */
573 }
574
575 if (png_ptr->do_filter & PNG_FILTER_UP && !(png_ptr->up_row))
576 {
577 if (!(png_ptr->prev_row))
578 {
579 png_warning(png_ptr, "Can't to add up filter after starting");
580 png_ptr->do_filter &= ~PNG_FILTER_UP;
581 }
582 else
583 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600584 png_ptr->up_row = (png_bytep )png_malloc(png_ptr,
Guy Schalnate5a37791996-06-05 15:50:50 -0500585 png_ptr->rowbytes + 1);
586 png_ptr->up_row[0] = 2; /* Set the row filter type */
587 }
588 }
589
590 if (png_ptr->do_filter & PNG_FILTER_AVG && !(png_ptr->avg_row))
591 {
592 if (!(png_ptr->prev_row))
593 {
594 png_warning(png_ptr, "Can't add average filter after starting");
595 png_ptr->do_filter &= ~PNG_FILTER_AVG;
596 }
597 else
598 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600599 png_ptr->up_row = (png_bytep )png_malloc(png_ptr,
Guy Schalnate5a37791996-06-05 15:50:50 -0500600 png_ptr->rowbytes + 1);
601 png_ptr->up_row[0] = 3; /* Set the row filter type */
602 }
603 }
604
605 if (png_ptr->do_filter & PNG_FILTER_PAETH && !(png_ptr->paeth_row))
606 {
607 if (!(png_ptr->prev_row))
608 {
609 png_warning(png_ptr, "Can't add Paeth filter after starting");
610 png_ptr->do_filter &= ~PNG_FILTER_PAETH;
611 }
612 else
613 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600614 png_ptr->paeth_row = (png_bytep )png_malloc(png_ptr,
Guy Schalnate5a37791996-06-05 15:50:50 -0500615 png_ptr->rowbytes + 1);
616 png_ptr->paeth_row[0] = 4; /* Set the row filter type */
617 }
618 }
619
620 if (png_ptr->do_filter == PNG_NO_FILTERS)
621 png_ptr->do_filter = PNG_FILTER_NONE;
622 }
623 }
624 else
625 png_error(png_ptr, "Unknown custom filter method");
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500626}
627
628void
Guy Schalnat6d764711995-12-19 03:22:19 -0600629png_set_compression_level(png_structp png_ptr, int level)
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500630{
Guy Schalnate5a37791996-06-05 15:50:50 -0500631 png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_LEVEL;
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500632 png_ptr->zlib_level = level;
633}
634
635void
Guy Schalnat6d764711995-12-19 03:22:19 -0600636png_set_compression_mem_level(png_structp png_ptr, int mem_level)
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500637{
Guy Schalnate5a37791996-06-05 15:50:50 -0500638 png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_MEM_LEVEL;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600639 png_ptr->zlib_mem_level = mem_level;
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500640}
641
642void
Guy Schalnat6d764711995-12-19 03:22:19 -0600643png_set_compression_strategy(png_structp png_ptr, int strategy)
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500644{
Guy Schalnate5a37791996-06-05 15:50:50 -0500645 png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_STRATEGY;
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500646 png_ptr->zlib_strategy = strategy;
647}
648
649void
Guy Schalnat6d764711995-12-19 03:22:19 -0600650png_set_compression_window_bits(png_structp png_ptr, int window_bits)
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500651{
Guy Schalnate5a37791996-06-05 15:50:50 -0500652 if (window_bits > 15)
653 png_warning(png_ptr, "Only compression windows <= 32k supported by PNG");
654 png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_WINDOW_BITS;
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500655 png_ptr->zlib_window_bits = window_bits;
656}
657
658void
Guy Schalnat6d764711995-12-19 03:22:19 -0600659png_set_compression_method(png_structp png_ptr, int method)
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500660{
Guy Schalnate5a37791996-06-05 15:50:50 -0500661 if (method != 8)
662 png_warning(png_ptr, "Only compression method 8 is supported by PNG");
663 png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_METHOD;
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500664 png_ptr->zlib_method = method;
Guy Schalnat0d580581995-07-20 02:43:20 -0500665}
666