blob: 9acaf08e60f1f5731b1c37eccb16bb6216b1bf25 [file] [log] [blame]
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06001
Andreas Dilger47a0c421997-05-16 02:46:07 -05002/* pngwrite.c - general routines to write a PNG file
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06003 *
Glenn Randers-Pehrson76546822009-05-16 07:25:42 -05004 * Last changed in libpng 1.4.0 [May 16, 2009]
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06005 * For conditions of distribution and use, see copyright notice in png.h
Glenn Randers-Pehrson79134c62009-02-14 10:32:18 -06006 * Copyright (c) 1998-2009 Glenn Randers-Pehrson
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05007 * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
8 * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06009 */
Guy Schalnat0d580581995-07-20 02:43:20 -050010
11/* get internal access to png.h */
Guy Schalnat0d580581995-07-20 02:43:20 -050012#include "png.h"
Glenn Randers-Pehrson19095602001-03-14 07:08:39 -060013#ifdef PNG_WRITE_SUPPORTED
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -050014#include "pngpriv.h"
Guy Schalnat0d580581995-07-20 02:43:20 -050015
Andreas Dilger47a0c421997-05-16 02:46:07 -050016/* Writes all the PNG information. This is the suggested way to use the
17 * library. If you have a new chunk to add, make a function to write it,
18 * and put it in the correct location here. If you want the chunk written
Glenn Randers-Pehrson345bc271998-06-14 14:43:31 -050019 * after the image data, put it in png_write_end(). I strongly encourage
Andreas Dilger47a0c421997-05-16 02:46:07 -050020 * you to supply a PNG_INFO_ flag, and check info_ptr->valid before writing
21 * the chunk, as that will keep the code from breaking if you want to just
22 * write a plain PNG file. If you have long comments, I suggest writing
23 * them in png_write_end(), and compressing them.
24 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -050025void PNGAPI
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -060026png_write_info_before_PLTE(png_structp png_ptr, png_infop info_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -050027{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -050028 png_debug(1, "in png_write_info_before_PLTE");
Glenn Randers-Pehrson170b70c2006-03-10 10:19:04 -060029 if (png_ptr == NULL || info_ptr == NULL)
30 return;
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -060031 if (!(png_ptr->mode & PNG_WROTE_INFO_BEFORE_PLTE))
32 {
Guy Schalnat0d580581995-07-20 02:43:20 -050033 png_write_sig(png_ptr); /* write PNG signature */
Glenn Randers-Pehrson408b4212000-12-18 09:33:57 -060034#if defined(PNG_MNG_FEATURES_SUPPORTED)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -050035 if ((png_ptr->mode&PNG_HAVE_PNG_SIGNATURE)&&(png_ptr->mng_features_permitted))
Glenn Randers-Pehrson408b4212000-12-18 09:33:57 -060036 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -050037 png_warning(png_ptr, "MNG features are not allowed in a PNG datastream");
Glenn Randers-Pehrson408b4212000-12-18 09:33:57 -060038 png_ptr->mng_features_permitted=0;
39 }
40#endif
Guy Schalnat0d580581995-07-20 02:43:20 -050041 /* write IHDR information. */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060042 png_write_IHDR(png_ptr, info_ptr->width, info_ptr->height,
43 info_ptr->bit_depth, info_ptr->color_type, info_ptr->compression_type,
Glenn Randers-Pehrson46f61e21998-01-30 21:45:12 -060044 info_ptr->filter_type,
45#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
46 info_ptr->interlace_type);
47#else
48 0);
49#endif
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -050050 /* The rest of these check to see if the valid field has the appropriate
51 * flag set, and if it does, writes the chunk.
52 */
Guy Schalnat51f0eb41995-09-26 05:22:39 -050053#if defined(PNG_WRITE_gAMA_SUPPORTED)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060054 if (info_ptr->valid & PNG_INFO_gAMA)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -060055 {
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -060056# ifdef PNG_FLOATING_POINT_SUPPORTED
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060057 png_write_gAMA(png_ptr, info_ptr->gamma);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -060058#else
59#ifdef PNG_FIXED_POINT_SUPPORTED
60 png_write_gAMA_fixed(png_ptr, info_ptr->int_gamma);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -060061# endif
62#endif
63 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -050064#endif
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -060065#if defined(PNG_WRITE_sRGB_SUPPORTED)
66 if (info_ptr->valid & PNG_INFO_sRGB)
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -060067 png_write_sRGB(png_ptr, (int)info_ptr->srgb_intent);
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -060068#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -060069#if defined(PNG_WRITE_iCCP_SUPPORTED)
70 if (info_ptr->valid & PNG_INFO_iCCP)
Glenn Randers-Pehrson76e5fd62000-12-28 07:50:05 -060071 png_write_iCCP(png_ptr, info_ptr->iccp_name, PNG_COMPRESSION_TYPE_BASE,
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -060072 info_ptr->iccp_profile, (int)info_ptr->iccp_proflen);
73#endif
Guy Schalnat51f0eb41995-09-26 05:22:39 -050074#if defined(PNG_WRITE_sBIT_SUPPORTED)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060075 if (info_ptr->valid & PNG_INFO_sBIT)
76 png_write_sBIT(png_ptr, &(info_ptr->sig_bit), info_ptr->color_type);
Guy Schalnat51f0eb41995-09-26 05:22:39 -050077#endif
78#if defined(PNG_WRITE_cHRM_SUPPORTED)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060079 if (info_ptr->valid & PNG_INFO_cHRM)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -060080 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -060081#ifdef PNG_FLOATING_POINT_SUPPORTED
Guy Schalnat0d580581995-07-20 02:43:20 -050082 png_write_cHRM(png_ptr,
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060083 info_ptr->x_white, info_ptr->y_white,
84 info_ptr->x_red, info_ptr->y_red,
85 info_ptr->x_green, info_ptr->y_green,
86 info_ptr->x_blue, info_ptr->y_blue);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -060087#else
88# ifdef PNG_FIXED_POINT_SUPPORTED
89 png_write_cHRM_fixed(png_ptr,
90 info_ptr->int_x_white, info_ptr->int_y_white,
91 info_ptr->int_x_red, info_ptr->int_y_red,
92 info_ptr->int_x_green, info_ptr->int_y_green,
93 info_ptr->int_x_blue, info_ptr->int_y_blue);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -060094# endif
95#endif
96 }
97#endif
98#if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED)
99 if (info_ptr->unknown_chunks_num)
100 {
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500101 png_unknown_chunk *up;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600102
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500103 png_debug(5, "writing extra chunks");
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600104
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500105 for (up = info_ptr->unknown_chunks;
106 up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num;
107 up++)
108 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600109 int keep=png_handle_as_unknown(png_ptr, up->name);
Glenn Randers-Pehrsondff799e2004-08-07 21:42:49 -0500110 if (keep != PNG_HANDLE_CHUNK_NEVER &&
Glenn Randers-Pehrson5b5dcf82004-07-17 22:45:44 -0500111 up->location && !(up->location & PNG_HAVE_PLTE) &&
112 !(up->location & PNG_HAVE_IDAT) &&
Glenn Randers-Pehrsondff799e2004-08-07 21:42:49 -0500113 ((up->name[3] & 0x20) || keep == PNG_HANDLE_CHUNK_ALWAYS ||
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600114 (png_ptr->flags & PNG_FLAG_KEEP_UNSAFE_CHUNKS)))
115 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500116 if (up->size == 0)
117 png_warning(png_ptr, "Writing zero-length unknown chunk");
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600118 png_write_chunk(png_ptr, up->name, up->data, up->size);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600119 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500120 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600121 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500122#endif
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -0600123 png_ptr->mode |= PNG_WROTE_INFO_BEFORE_PLTE;
124 }
125}
126
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500127void PNGAPI
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -0600128png_write_info(png_structp png_ptr, png_infop info_ptr)
129{
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600130#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED)
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -0600131 int i;
132#endif
133
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500134 png_debug(1, "in png_write_info");
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -0600135
Glenn Randers-Pehrson170b70c2006-03-10 10:19:04 -0600136 if (png_ptr == NULL || info_ptr == NULL)
137 return;
138
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -0600139 png_write_info_before_PLTE(png_ptr, info_ptr);
140
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600141 if (info_ptr->valid & PNG_INFO_PLTE)
Andreas Dilger47a0c421997-05-16 02:46:07 -0500142 png_write_PLTE(png_ptr, info_ptr->palette,
143 (png_uint_32)info_ptr->num_palette);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600144 else if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
Glenn Randers-Pehrsonc3d51c12006-03-02 07:23:18 -0600145 png_error(png_ptr, "Valid palette required for paletted images");
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600146
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500147#if defined(PNG_WRITE_tRNS_SUPPORTED)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600148 if (info_ptr->valid & PNG_INFO_tRNS)
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500149 {
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600150#if defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED)
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500151 /* invert the alpha channel (in tRNS) */
152 if ((png_ptr->transformations & PNG_INVERT_ALPHA) &&
153 info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
154 {
155 int j;
156 for (j=0; j<(int)info_ptr->num_trans; j++)
157 info_ptr->trans[j] = (png_byte)(255 - info_ptr->trans[j]);
158 }
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600159#endif
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -0500160 png_write_tRNS(png_ptr, info_ptr->trans, &(info_ptr->trans_color),
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600161 info_ptr->num_trans, info_ptr->color_type);
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500162 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500163#endif
164#if defined(PNG_WRITE_bKGD_SUPPORTED)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600165 if (info_ptr->valid & PNG_INFO_bKGD)
166 png_write_bKGD(png_ptr, &(info_ptr->background), info_ptr->color_type);
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500167#endif
168#if defined(PNG_WRITE_hIST_SUPPORTED)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600169 if (info_ptr->valid & PNG_INFO_hIST)
170 png_write_hIST(png_ptr, info_ptr->hist, info_ptr->num_palette);
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500171#endif
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500172#if defined(PNG_WRITE_oFFs_SUPPORTED)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600173 if (info_ptr->valid & PNG_INFO_oFFs)
174 png_write_oFFs(png_ptr, info_ptr->x_offset, info_ptr->y_offset,
175 info_ptr->offset_unit_type);
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500176#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -0500177#if defined(PNG_WRITE_pCAL_SUPPORTED)
178 if (info_ptr->valid & PNG_INFO_pCAL)
179 png_write_pCAL(png_ptr, info_ptr->pcal_purpose, info_ptr->pcal_X0,
180 info_ptr->pcal_X1, info_ptr->pcal_type, info_ptr->pcal_nparams,
181 info_ptr->pcal_units, info_ptr->pcal_params);
182#endif
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500183#if defined(PNG_sCAL_SUPPORTED)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600184 if (info_ptr->valid & PNG_INFO_sCAL)
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500185#if defined(PNG_WRITE_sCAL_SUPPORTED)
Glenn Randers-Pehrson68ea2432000-04-01 21:10:05 -0600186#if defined(PNG_FLOATING_POINT_SUPPORTED) && !defined(PNG_NO_STDIO)
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600187 png_write_sCAL(png_ptr, (int)info_ptr->scal_unit,
188 info_ptr->scal_pixel_width, info_ptr->scal_pixel_height);
189#else
190#ifdef PNG_FIXED_POINT_SUPPORTED
191 png_write_sCAL_s(png_ptr, (int)info_ptr->scal_unit,
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600192 info_ptr->scal_s_width, info_ptr->scal_s_height);
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500193#endif /* FIXED_POINT */
194#endif /* FLOATING_POINT */
195#else /* WRITE_sCAL */
Glenn Randers-Pehrson68ea2432000-04-01 21:10:05 -0600196 png_warning(png_ptr,
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -0500197 "png_write_sCAL not supported; sCAL chunk not written");
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500198#endif /* WRITE_sCAL */
199#endif /* sCAL */
200
Andreas Dilger47a0c421997-05-16 02:46:07 -0500201#if defined(PNG_WRITE_pHYs_SUPPORTED)
202 if (info_ptr->valid & PNG_INFO_pHYs)
203 png_write_pHYs(png_ptr, info_ptr->x_pixels_per_unit,
204 info_ptr->y_pixels_per_unit, info_ptr->phys_unit_type);
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500205#endif /* pHYs */
206
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500207#if defined(PNG_WRITE_tIME_SUPPORTED)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600208 if (info_ptr->valid & PNG_INFO_tIME)
Guy Schalnate5a37791996-06-05 15:50:50 -0500209 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600210 png_write_tIME(png_ptr, &(info_ptr->mod_time));
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -0600211 png_ptr->mode |= PNG_WROTE_tIME;
Guy Schalnate5a37791996-06-05 15:50:50 -0500212 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500213#endif /* tIME */
214
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600215#if defined(PNG_WRITE_sPLT_SUPPORTED)
216 if (info_ptr->valid & PNG_INFO_sPLT)
217 for (i = 0; i < (int)info_ptr->splt_palettes_num; i++)
218 png_write_sPLT(png_ptr, info_ptr->splt_palettes + i);
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500219#endif /* sPLT */
220
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600221#if defined(PNG_WRITE_TEXT_SUPPORTED)
Guy Schalnate5a37791996-06-05 15:50:50 -0500222 /* Check to see if we need to write text chunks */
Andreas Dilger47a0c421997-05-16 02:46:07 -0500223 for (i = 0; i < info_ptr->num_text; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -0500224 {
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500225 png_debug2(2, "Writing header text chunk %d, type %d", i,
Andreas Dilger47a0c421997-05-16 02:46:07 -0500226 info_ptr->text[i].compression);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600227 /* an internationalized chunk? */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600228 if (info_ptr->text[i].compression > 0)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600229 {
230#if defined(PNG_WRITE_iTXt_SUPPORTED)
231 /* write international chunk */
232 png_write_iTXt(png_ptr,
233 info_ptr->text[i].compression,
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600234 info_ptr->text[i].key,
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600235 info_ptr->text[i].lang,
236 info_ptr->text[i].lang_key,
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600237 info_ptr->text[i].text);
238#else
Glenn Randers-Pehrsonc3d51c12006-03-02 07:23:18 -0600239 png_warning(png_ptr, "Unable to write international text");
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600240#endif
241 /* Mark this chunk as written */
242 info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;
243 }
Andreas Dilger47a0c421997-05-16 02:46:07 -0500244 /* If we want a compressed text chunk */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600245 else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_zTXt)
Andreas Dilger47a0c421997-05-16 02:46:07 -0500246 {
247#if defined(PNG_WRITE_zTXt_SUPPORTED)
248 /* write compressed chunk */
249 png_write_zTXt(png_ptr, info_ptr->text[i].key,
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600250 info_ptr->text[i].text, 0,
Andreas Dilger47a0c421997-05-16 02:46:07 -0500251 info_ptr->text[i].compression);
252#else
Glenn Randers-Pehrsonc3d51c12006-03-02 07:23:18 -0600253 png_warning(png_ptr, "Unable to write compressed text");
Andreas Dilger47a0c421997-05-16 02:46:07 -0500254#endif
255 /* Mark this chunk as written */
256 info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR;
257 }
258 else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE)
259 {
260#if defined(PNG_WRITE_tEXt_SUPPORTED)
261 /* write uncompressed chunk */
262 png_write_tEXt(png_ptr, info_ptr->text[i].key,
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600263 info_ptr->text[i].text,
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600264 0);
Andreas Dilger47a0c421997-05-16 02:46:07 -0500265 /* Mark this chunk as written */
266 info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500267#else
268 /* Can't get here */
269 png_warning(png_ptr, "Unable to write uncompressed text");
270#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -0500271 }
272 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500273#endif /* tEXt */
274
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600275#if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED)
276 if (info_ptr->unknown_chunks_num)
277 {
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500278 png_unknown_chunk *up;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600279
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500280 png_debug(5, "writing extra chunks");
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600281
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500282 for (up = info_ptr->unknown_chunks;
283 up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num;
284 up++)
285 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600286 int keep=png_handle_as_unknown(png_ptr, up->name);
Glenn Randers-Pehrsondff799e2004-08-07 21:42:49 -0500287 if (keep != PNG_HANDLE_CHUNK_NEVER &&
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600288 up->location && (up->location & PNG_HAVE_PLTE) &&
289 !(up->location & PNG_HAVE_IDAT) &&
Glenn Randers-Pehrsondff799e2004-08-07 21:42:49 -0500290 ((up->name[3] & 0x20) || keep == PNG_HANDLE_CHUNK_ALWAYS ||
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600291 (png_ptr->flags & PNG_FLAG_KEEP_UNSAFE_CHUNKS)))
292 {
293 png_write_chunk(png_ptr, up->name, up->data, up->size);
294 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500295 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600296 }
297#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -0500298}
Guy Schalnat0d580581995-07-20 02:43:20 -0500299
Andreas Dilger47a0c421997-05-16 02:46:07 -0500300/* Writes the end of the PNG file. If you don't want to write comments or
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600301 * time information, you can pass NULL for info. If you already wrote these
302 * in png_write_info(), do not write them again here. If you have long
303 * comments, I suggest writing them here, and compressing them.
304 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500305void PNGAPI
Andreas Dilger47a0c421997-05-16 02:46:07 -0500306png_write_end(png_structp png_ptr, png_infop info_ptr)
307{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500308 png_debug(1, "in png_write_end");
Glenn Randers-Pehrson170b70c2006-03-10 10:19:04 -0600309 if (png_ptr == NULL)
310 return;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500311 if (!(png_ptr->mode & PNG_HAVE_IDAT))
312 png_error(png_ptr, "No IDATs written into file");
313
314 /* see if user wants us to write information chunks */
315 if (info_ptr != NULL)
316 {
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600317#if defined(PNG_WRITE_TEXT_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -0500318 int i; /* local index variable */
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -0600319#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -0500320#if defined(PNG_WRITE_tIME_SUPPORTED)
321 /* check to see if user has supplied a time chunk */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600322 if ((info_ptr->valid & PNG_INFO_tIME) &&
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -0600323 !(png_ptr->mode & PNG_WROTE_tIME))
Andreas Dilger47a0c421997-05-16 02:46:07 -0500324 png_write_tIME(png_ptr, &(info_ptr->mod_time));
325#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600326#if defined(PNG_WRITE_TEXT_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -0500327 /* loop through comment chunks */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600328 for (i = 0; i < info_ptr->num_text; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -0500329 {
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500330 png_debug2(2, "Writing trailer text chunk %d, type %d", i,
Andreas Dilger47a0c421997-05-16 02:46:07 -0500331 info_ptr->text[i].compression);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600332 /* an internationalized chunk? */
333 if (info_ptr->text[i].compression > 0)
334 {
335#if defined(PNG_WRITE_iTXt_SUPPORTED)
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500336 /* write international chunk */
337 png_write_iTXt(png_ptr,
338 info_ptr->text[i].compression,
339 info_ptr->text[i].key,
340 info_ptr->text[i].lang,
341 info_ptr->text[i].lang_key,
342 info_ptr->text[i].text);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600343#else
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500344 png_warning(png_ptr, "Unable to write international text");
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600345#endif
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500346 /* Mark this chunk as written */
347 info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600348 }
349 else if (info_ptr->text[i].compression >= PNG_TEXT_COMPRESSION_zTXt)
Guy Schalnat0d580581995-07-20 02:43:20 -0500350 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500351#if defined(PNG_WRITE_zTXt_SUPPORTED)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600352 /* write compressed chunk */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600353 png_write_zTXt(png_ptr, info_ptr->text[i].key,
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600354 info_ptr->text[i].text, 0,
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600355 info_ptr->text[i].compression);
Guy Schalnate5a37791996-06-05 15:50:50 -0500356#else
Glenn Randers-Pehrsonc3d51c12006-03-02 07:23:18 -0600357 png_warning(png_ptr, "Unable to write compressed text");
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500358#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -0500359 /* Mark this chunk as written */
360 info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR;
Guy Schalnat0d580581995-07-20 02:43:20 -0500361 }
Andreas Dilger47a0c421997-05-16 02:46:07 -0500362 else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE)
Guy Schalnat0d580581995-07-20 02:43:20 -0500363 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500364#if defined(PNG_WRITE_tEXt_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500365 /* write uncompressed chunk */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600366 png_write_tEXt(png_ptr, info_ptr->text[i].key,
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600367 info_ptr->text[i].text, 0);
Guy Schalnate5a37791996-06-05 15:50:50 -0500368#else
Glenn Randers-Pehrsonc3d51c12006-03-02 07:23:18 -0600369 png_warning(png_ptr, "Unable to write uncompressed text");
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500370#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500371
Andreas Dilger47a0c421997-05-16 02:46:07 -0500372 /* Mark this chunk as written */
373 info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;
Guy Schalnat0d580581995-07-20 02:43:20 -0500374 }
375 }
Guy Schalnat6d764711995-12-19 03:22:19 -0600376#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600377#if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED)
378 if (info_ptr->unknown_chunks_num)
379 {
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500380 png_unknown_chunk *up;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600381
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500382 png_debug(5, "writing extra chunks");
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600383
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500384 for (up = info_ptr->unknown_chunks;
385 up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num;
386 up++)
387 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600388 int keep=png_handle_as_unknown(png_ptr, up->name);
Glenn Randers-Pehrsondff799e2004-08-07 21:42:49 -0500389 if (keep != PNG_HANDLE_CHUNK_NEVER &&
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600390 up->location && (up->location & PNG_AFTER_IDAT) &&
Glenn Randers-Pehrsondff799e2004-08-07 21:42:49 -0500391 ((up->name[3] & 0x20) || keep == PNG_HANDLE_CHUNK_ALWAYS ||
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600392 (png_ptr->flags & PNG_FLAG_KEEP_UNSAFE_CHUNKS)))
393 {
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600394 png_write_chunk(png_ptr, up->name, up->data, up->size);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600395 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500396 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600397 }
398#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500399 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500400
401 png_ptr->mode |= PNG_AFTER_IDAT;
402
Andreas Dilger47a0c421997-05-16 02:46:07 -0500403 /* write end of PNG file */
Guy Schalnat0d580581995-07-20 02:43:20 -0500404 png_write_IEND(png_ptr);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500405 /* This flush, added in libpng-1.0.8, removed from libpng-1.0.9beta03,
406 * and restored again in libpng-1.2.30, may cause some applications that
407 * do not set png_ptr->output_flush_fn to crash. If your application
Glenn Randers-Pehrson79134c62009-02-14 10:32:18 -0600408 * experiences a problem, please report the event to
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500409 * png-mng-implement at lists.sf.net .
410 */
Glenn Randers-Pehrsondbed41f2008-08-19 18:20:52 -0500411#if defined(PNG_WRITE_FLUSH_SUPPORTED)
Glenn Randers-Pehrson32fc5ce2000-07-24 06:34:14 -0500412 png_flush(png_ptr);
Glenn Randers-Pehrsondbed41f2008-08-19 18:20:52 -0500413#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500414}
415
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500416#if defined(PNG_WRITE_tIME_SUPPORTED)
Glenn Randers-Pehrson316f97a2000-07-08 13:19:41 -0500417/* "time.h" functions are not supported on WindowsCE */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500418void PNGAPI
Guy Schalnat6d764711995-12-19 03:22:19 -0600419png_convert_from_struct_tm(png_timep ptime, struct tm FAR * ttime)
Guy Schalnat0d580581995-07-20 02:43:20 -0500420{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500421 png_debug(1, "in png_convert_from_struct_tm");
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600422 ptime->year = (png_uint_16)(1900 + ttime->tm_year);
423 ptime->month = (png_byte)(ttime->tm_mon + 1);
424 ptime->day = (png_byte)ttime->tm_mday;
425 ptime->hour = (png_byte)ttime->tm_hour;
426 ptime->minute = (png_byte)ttime->tm_min;
427 ptime->second = (png_byte)ttime->tm_sec;
Guy Schalnat0d580581995-07-20 02:43:20 -0500428}
429
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500430void PNGAPI
Guy Schalnat6d764711995-12-19 03:22:19 -0600431png_convert_from_time_t(png_timep ptime, time_t ttime)
Guy Schalnat0d580581995-07-20 02:43:20 -0500432{
433 struct tm *tbuf;
434
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500435 png_debug(1, "in png_convert_from_time_t");
Guy Schalnat0d580581995-07-20 02:43:20 -0500436 tbuf = gmtime(&ttime);
437 png_convert_from_struct_tm(ptime, tbuf);
438}
Guy Schalnat6d764711995-12-19 03:22:19 -0600439#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500440
Glenn Randers-Pehrsona93c9422009-04-13 11:41:33 -0500441
Andreas Dilger47a0c421997-05-16 02:46:07 -0500442/* Initialize png_ptr structure, and allocate any memory needed */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500443png_structp PNGAPI
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -0500444png_create_write_struct(png_const_charp user_png_ver, png_voidp error_ptr,
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600445 png_error_ptr error_fn, png_error_ptr warn_fn)
Guy Schalnat0d580581995-07-20 02:43:20 -0500446{
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -0500447#ifdef PNG_USER_MEM_SUPPORTED
448 return (png_create_write_struct_2(user_png_ver, error_ptr, error_fn,
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -0500449 warn_fn, NULL, NULL, NULL));
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -0500450}
451
452/* Alternate initialize png_ptr structure, and allocate any memory needed */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500453png_structp PNGAPI
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -0500454png_create_write_struct_2(png_const_charp user_png_ver, png_voidp error_ptr,
455 png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr,
456 png_malloc_ptr malloc_fn, png_free_ptr free_fn)
457{
458#endif /* PNG_USER_MEM_SUPPORTED */
Glenn Randers-Pehrsona93c9422009-04-13 11:41:33 -0500459 int png_cleanup_needed = 0;
Glenn Randers-Pehrson79134c62009-02-14 10:32:18 -0600460#ifdef PNG_SETJMP_SUPPORTED
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500461 volatile
Glenn Randers-Pehrson79134c62009-02-14 10:32:18 -0600462#endif
Glenn Randers-Pehrsonf0a8fe02009-04-14 08:28:15 -0500463 png_structp png_ptr;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600464#ifdef PNG_SETJMP_SUPPORTED
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600465#ifdef USE_FAR_KEYWORD
466 jmp_buf jmpbuf;
467#endif
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600468#endif
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500469 int i;
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500470 png_debug(1, "in png_create_write_struct");
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -0500471#ifdef PNG_USER_MEM_SUPPORTED
Glenn Randers-Pehrson9c0f0942002-02-21 23:14:23 -0600472 png_ptr = (png_structp)png_create_struct_2(PNG_STRUCT_PNG,
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500473 (png_malloc_ptr)malloc_fn, (png_voidp)mem_ptr);
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -0500474#else
Glenn Randers-Pehrson9c0f0942002-02-21 23:14:23 -0600475 png_ptr = (png_structp)png_create_struct(PNG_STRUCT_PNG);
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -0500476#endif /* PNG_USER_MEM_SUPPORTED */
Glenn Randers-Pehrson9c0f0942002-02-21 23:14:23 -0600477 if (png_ptr == NULL)
Glenn Randers-Pehrson3f549252001-10-27 07:35:13 -0500478 return (NULL);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600479
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -0500480 /* added at libpng-1.2.6 */
481#ifdef PNG_SET_USER_LIMITS_SUPPORTED
482 png_ptr->user_width_max=PNG_USER_WIDTH_MAX;
483 png_ptr->user_height_max=PNG_USER_HEIGHT_MAX;
484#endif
485
Glenn Randers-Pehrsonf0a8fe02009-04-14 08:28:15 -0500486#ifdef PNG_SETJMP_SUPPORTED
487/* Applications that neglect to set up their own setjmp() and then
488 encounter a png_error() will longjmp here. Since the jmpbuf is
489 then meaningless we abort instead of returning. */
490#ifdef USE_FAR_KEYWORD
491 if (setjmp(jmpbuf))
492#else
493 if (setjmp(png_ptr->jmpbuf))
494#endif
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500495 PNG_ABORT();
Glenn Randers-Pehrsonf0a8fe02009-04-14 08:28:15 -0500496#endif
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600497
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -0500498#ifdef PNG_USER_MEM_SUPPORTED
499 png_set_mem_fn(png_ptr, mem_ptr, malloc_fn, free_fn);
500#endif /* PNG_USER_MEM_SUPPORTED */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600501 png_set_error_fn(png_ptr, error_ptr, error_fn, warn_fn);
Guy Schalnate5a37791996-06-05 15:50:50 -0500502
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500503 if (user_png_ver)
Guy Schalnate5a37791996-06-05 15:50:50 -0500504 {
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500505 i=0;
506 do
507 {
508 if (user_png_ver[i] != png_libpng_ver[i])
509 png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH;
510 } while (png_libpng_ver[i++]);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500511 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500512
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500513 if (png_ptr->flags & PNG_FLAG_LIBRARY_MISMATCH)
Glenn Randers-Pehrson98c9d732000-05-03 21:06:11 -0500514 {
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500515 /* Libpng 0.90 and later are binary incompatible with libpng 0.89, so
516 * we must recompile any applications that use any older library version.
517 * For versions after libpng 1.0, we will be compatible, so we need
518 * only check the first digit.
519 */
520 if (user_png_ver == NULL || user_png_ver[0] != png_libpng_ver[0] ||
Glenn Randers-Pehrson8b6a8892001-05-18 04:54:50 -0500521 (user_png_ver[0] == '1' && user_png_ver[2] != png_libpng_ver[2]) ||
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500522 (user_png_ver[0] == '0' && user_png_ver[2] < '9'))
523 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500524#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE)
Glenn Randers-Pehrsonb1828932001-06-23 08:03:17 -0500525 char msg[80];
526 if (user_png_ver)
527 {
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500528 png_snprintf(msg, 80,
529 "Application was compiled with png.h from libpng-%.20s",
530 user_png_ver);
531 png_warning(png_ptr, msg);
Glenn Randers-Pehrsonb1828932001-06-23 08:03:17 -0500532 }
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500533 png_snprintf(msg, 80,
534 "Application is running with png.c from libpng-%.20s",
Glenn Randers-Pehrsonb1828932001-06-23 08:03:17 -0500535 png_libpng_ver);
536 png_warning(png_ptr, msg);
537#endif
538#ifdef PNG_ERROR_NUMBERS_SUPPORTED
539 png_ptr->flags=0;
540#endif
Glenn Randers-Pehrsona93c9422009-04-13 11:41:33 -0500541 png_warning(png_ptr,
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500542 "Incompatible libpng version in application and library");
Glenn Randers-Pehrsona93c9422009-04-13 11:41:33 -0500543 png_cleanup_needed = 1;
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500544 }
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500545 }
Glenn Randers-Pehrson98c9d732000-05-03 21:06:11 -0500546
Guy Schalnat0d580581995-07-20 02:43:20 -0500547 /* initialize zbuf - compression buffer */
548 png_ptr->zbuf_size = PNG_ZBUF_SIZE;
Glenn Randers-Pehrsona93c9422009-04-13 11:41:33 -0500549 if (!png_cleanup_needed)
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500550 {
551 png_ptr->zbuf = (png_bytep)png_malloc_warn(png_ptr,
552 png_ptr->zbuf_size);
553 if (png_ptr->zbuf == NULL)
554 png_cleanup_needed = 1;
555 }
Glenn Randers-Pehrsona93c9422009-04-13 11:41:33 -0500556 if (png_cleanup_needed)
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500557 {
558 /* Clean up PNG structure and deallocate any memory. */
559 png_free(png_ptr, png_ptr->zbuf);
560 png_ptr->zbuf = NULL;
Glenn Randers-Pehrsona93c9422009-04-13 11:41:33 -0500561#ifdef PNG_USER_MEM_SUPPORTED
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500562 png_destroy_struct_2((png_voidp)png_ptr,
563 (png_free_ptr)free_fn, (png_voidp)mem_ptr);
Glenn Randers-Pehrsona93c9422009-04-13 11:41:33 -0500564#else
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500565 png_destroy_struct((png_voidp)png_ptr);
Glenn Randers-Pehrsona93c9422009-04-13 11:41:33 -0500566#endif
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500567 return (NULL);
568 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500569
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -0500570 png_set_write_fn(png_ptr, NULL, NULL, NULL);
Guy Schalnate5a37791996-06-05 15:50:50 -0500571
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600572#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
573 png_set_filter_heuristics(png_ptr, PNG_FILTER_HEURISTIC_DEFAULT,
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -0500574 1, NULL, NULL);
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600575#endif
576
Glenn Randers-Pehrson03008a02002-04-27 10:11:25 -0500577 return (png_ptr);
Guy Schalnate5a37791996-06-05 15:50:50 -0500578}
579
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500580
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600581/* Write a few rows of image data. If the image is interlaced,
582 * either you will have to write the 7 sub images, or, if you
583 * have called png_set_interlace_handling(), you will have to
584 * "write" the image seven times.
585 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500586void PNGAPI
Guy Schalnat6d764711995-12-19 03:22:19 -0600587png_write_rows(png_structp png_ptr, png_bytepp row,
Guy Schalnat0d580581995-07-20 02:43:20 -0500588 png_uint_32 num_rows)
589{
590 png_uint_32 i; /* row counter */
Guy Schalnat6d764711995-12-19 03:22:19 -0600591 png_bytepp rp; /* row pointer */
Guy Schalnat0d580581995-07-20 02:43:20 -0500592
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500593 png_debug(1, "in png_write_rows");
Glenn Randers-Pehrson170b70c2006-03-10 10:19:04 -0600594
595 if (png_ptr == NULL)
596 return;
597
Guy Schalnat0d580581995-07-20 02:43:20 -0500598 /* loop through the rows */
599 for (i = 0, rp = row; i < num_rows; i++, rp++)
600 {
601 png_write_row(png_ptr, *rp);
602 }
603}
604
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600605/* Write the image. You only need to call this function once, even
606 * if you are writing an interlaced image.
607 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500608void PNGAPI
Guy Schalnat6d764711995-12-19 03:22:19 -0600609png_write_image(png_structp png_ptr, png_bytepp image)
Guy Schalnat0d580581995-07-20 02:43:20 -0500610{
611 png_uint_32 i; /* row index */
612 int pass, num_pass; /* pass variables */
Guy Schalnat6d764711995-12-19 03:22:19 -0600613 png_bytepp rp; /* points to current row */
Guy Schalnat0d580581995-07-20 02:43:20 -0500614
Glenn Randers-Pehrson170b70c2006-03-10 10:19:04 -0600615 if (png_ptr == NULL)
616 return;
617
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500618 png_debug(1, "in png_write_image");
Glenn Randers-Pehrson46f61e21998-01-30 21:45:12 -0600619#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500620 /* intialize interlace handling. If image is not interlaced,
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500621 * this will set pass to 1
622 */
Guy Schalnat0d580581995-07-20 02:43:20 -0500623 num_pass = png_set_interlace_handling(png_ptr);
Glenn Randers-Pehrson46f61e21998-01-30 21:45:12 -0600624#else
625 num_pass = 1;
626#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500627 /* loop through passes */
628 for (pass = 0; pass < num_pass; pass++)
629 {
630 /* loop through image */
631 for (i = 0, rp = image; i < png_ptr->height; i++, rp++)
632 {
633 png_write_row(png_ptr, *rp);
634 }
635 }
636}
637
Guy Schalnate5a37791996-06-05 15:50:50 -0500638/* called by user to write a row of image data */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500639void PNGAPI
Guy Schalnat6d764711995-12-19 03:22:19 -0600640png_write_row(png_structp png_ptr, png_bytep row)
Guy Schalnat0d580581995-07-20 02:43:20 -0500641{
Glenn Randers-Pehrson170b70c2006-03-10 10:19:04 -0600642 if (png_ptr == NULL)
643 return;
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500644 png_debug2(1, "in png_write_row (row %ld, pass %d)",
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600645 png_ptr->row_number, png_ptr->pass);
Glenn Randers-Pehrson170b70c2006-03-10 10:19:04 -0600646
Guy Schalnat0d580581995-07-20 02:43:20 -0500647 /* initialize transformations and other stuff if first time */
Guy Schalnat6d764711995-12-19 03:22:19 -0600648 if (png_ptr->row_number == 0 && png_ptr->pass == 0)
Guy Schalnat0d580581995-07-20 02:43:20 -0500649 {
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500650 /* make sure we wrote the header info */
651 if (!(png_ptr->mode & PNG_WROTE_INFO_BEFORE_PLTE))
652 png_error(png_ptr,
653 "png_write_info was never called before png_write_row");
Glenn Randers-Pehrson5cded0b2001-11-07 07:10:08 -0600654
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500655 /* check for transforms that have been set but were defined out */
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500656#if !defined(PNG_WRITE_INVERT_SUPPORTED) && defined(PNG_READ_INVERT_SUPPORTED)
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500657 if (png_ptr->transformations & PNG_INVERT_MONO)
658 png_warning(png_ptr, "PNG_WRITE_INVERT_SUPPORTED is not defined");
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500659#endif
660#if !defined(PNG_WRITE_FILLER_SUPPORTED) && defined(PNG_READ_FILLER_SUPPORTED)
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500661 if (png_ptr->transformations & PNG_FILLER)
662 png_warning(png_ptr, "PNG_WRITE_FILLER_SUPPORTED is not defined");
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500663#endif
664#if !defined(PNG_WRITE_PACKSWAP_SUPPORTED) && defined(PNG_READ_PACKSWAP_SUPPORTED)
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500665 if (png_ptr->transformations & PNG_PACKSWAP)
666 png_warning(png_ptr, "PNG_WRITE_PACKSWAP_SUPPORTED is not defined");
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500667#endif
668#if !defined(PNG_WRITE_PACK_SUPPORTED) && defined(PNG_READ_PACK_SUPPORTED)
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500669 if (png_ptr->transformations & PNG_PACK)
670 png_warning(png_ptr, "PNG_WRITE_PACK_SUPPORTED is not defined");
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500671#endif
672#if !defined(PNG_WRITE_SHIFT_SUPPORTED) && defined(PNG_READ_SHIFT_SUPPORTED)
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500673 if (png_ptr->transformations & PNG_SHIFT)
674 png_warning(png_ptr, "PNG_WRITE_SHIFT_SUPPORTED is not defined");
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500675#endif
676#if !defined(PNG_WRITE_BGR_SUPPORTED) && defined(PNG_READ_BGR_SUPPORTED)
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500677 if (png_ptr->transformations & PNG_BGR)
678 png_warning(png_ptr, "PNG_WRITE_BGR_SUPPORTED is not defined");
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500679#endif
680#if !defined(PNG_WRITE_SWAP_SUPPORTED) && defined(PNG_READ_SWAP_SUPPORTED)
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500681 if (png_ptr->transformations & PNG_SWAP_BYTES)
682 png_warning(png_ptr, "PNG_WRITE_SWAP_SUPPORTED is not defined");
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500683#endif
684
Guy Schalnat0d580581995-07-20 02:43:20 -0500685 png_write_start_row(png_ptr);
686 }
687
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500688#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500689 /* if interlaced and not interested in row, return */
690 if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE))
691 {
692 switch (png_ptr->pass)
693 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600694 case 0:
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600695 if (png_ptr->row_number & 0x07)
Guy Schalnat0d580581995-07-20 02:43:20 -0500696 {
697 png_write_finish_row(png_ptr);
698 return;
699 }
700 break;
701 case 1:
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600702 if ((png_ptr->row_number & 0x07) || png_ptr->width < 5)
Guy Schalnat0d580581995-07-20 02:43:20 -0500703 {
704 png_write_finish_row(png_ptr);
705 return;
706 }
707 break;
708 case 2:
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600709 if ((png_ptr->row_number & 0x07) != 4)
Guy Schalnat0d580581995-07-20 02:43:20 -0500710 {
711 png_write_finish_row(png_ptr);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600712 return;
Guy Schalnat0d580581995-07-20 02:43:20 -0500713 }
714 break;
715 case 3:
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600716 if ((png_ptr->row_number & 0x03) || png_ptr->width < 3)
Guy Schalnat0d580581995-07-20 02:43:20 -0500717 {
718 png_write_finish_row(png_ptr);
719 return;
720 }
721 break;
722 case 4:
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600723 if ((png_ptr->row_number & 0x03) != 2)
Guy Schalnat0d580581995-07-20 02:43:20 -0500724 {
725 png_write_finish_row(png_ptr);
726 return;
727 }
728 break;
729 case 5:
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600730 if ((png_ptr->row_number & 0x01) || png_ptr->width < 2)
Guy Schalnat0d580581995-07-20 02:43:20 -0500731 {
732 png_write_finish_row(png_ptr);
733 return;
734 }
735 break;
736 case 6:
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600737 if (!(png_ptr->row_number & 0x01))
Guy Schalnat0d580581995-07-20 02:43:20 -0500738 {
739 png_write_finish_row(png_ptr);
740 return;
741 }
742 break;
743 }
744 }
Guy Schalnat6d764711995-12-19 03:22:19 -0600745#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500746
747 /* set up row info for transformations */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600748 png_ptr->row_info.color_type = png_ptr->color_type;
Guy Schalnat0d580581995-07-20 02:43:20 -0500749 png_ptr->row_info.width = png_ptr->usr_width;
750 png_ptr->row_info.channels = png_ptr->usr_channels;
751 png_ptr->row_info.bit_depth = png_ptr->usr_bit_depth;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600752 png_ptr->row_info.pixel_depth = (png_byte)(png_ptr->row_info.bit_depth *
753 png_ptr->row_info.channels);
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -0600754
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -0500755 png_ptr->row_info.rowbytes = PNG_ROWBYTES(png_ptr->row_info.pixel_depth,
756 png_ptr->row_info.width);
Guy Schalnat0d580581995-07-20 02:43:20 -0500757
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500758 png_debug1(3, "row_info->color_type = %d", png_ptr->row_info.color_type);
759 png_debug1(3, "row_info->width = %lu", png_ptr->row_info.width);
760 png_debug1(3, "row_info->channels = %d", png_ptr->row_info.channels);
761 png_debug1(3, "row_info->bit_depth = %d", png_ptr->row_info.bit_depth);
762 png_debug1(3, "row_info->pixel_depth = %d", png_ptr->row_info.pixel_depth);
763 png_debug1(3, "row_info->rowbytes = %lu", png_ptr->row_info.rowbytes);
Andreas Dilger47a0c421997-05-16 02:46:07 -0500764
765 /* Copy user's row into buffer, leaving room for filter byte. */
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -0500766 png_memcpy(png_ptr->row_buf + 1, row, png_ptr->row_info.rowbytes);
Guy Schalnat0d580581995-07-20 02:43:20 -0500767
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500768#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500769 /* Handle interlacing */
Guy Schalnat0d580581995-07-20 02:43:20 -0500770 if (png_ptr->interlaced && png_ptr->pass < 6 &&
771 (png_ptr->transformations & PNG_INTERLACE))
772 {
773 png_do_write_interlace(&(png_ptr->row_info),
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600774 png_ptr->row_buf + 1, png_ptr->pass);
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500775 /* This should always get caught above, but still ... */
Guy Schalnat0d580581995-07-20 02:43:20 -0500776 if (!(png_ptr->row_info.width))
777 {
778 png_write_finish_row(png_ptr);
779 return;
780 }
781 }
Guy Schalnat6d764711995-12-19 03:22:19 -0600782#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500783
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500784 /* Handle other transformations */
Guy Schalnat0d580581995-07-20 02:43:20 -0500785 if (png_ptr->transformations)
786 png_do_write_transformations(png_ptr);
787
Glenn Randers-Pehrson2ad31ae2000-12-15 08:54:42 -0600788#if defined(PNG_MNG_FEATURES_SUPPORTED)
Glenn Randers-Pehrson408b4212000-12-18 09:33:57 -0600789 /* Write filter_method 64 (intrapixel differencing) only if
790 * 1. Libpng was compiled with PNG_MNG_FEATURES_SUPPORTED and
791 * 2. Libpng did not write a PNG signature (this filter_method is only
792 * used in PNG datastreams that are embedded in MNG datastreams) and
793 * 3. The application called png_permit_mng_features with a mask that
794 * included PNG_FLAG_MNG_FILTER_64 and
795 * 4. The filter_method is 64 and
796 * 5. The color_type is RGB or RGBA
797 */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500798 if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) &&
Glenn Randers-Pehrson2ad31ae2000-12-15 08:54:42 -0600799 (png_ptr->filter_type == PNG_INTRAPIXEL_DIFFERENCING))
800 {
801 /* Intrapixel differencing */
802 png_do_write_intrapixel(&(png_ptr->row_info), png_ptr->row_buf + 1);
803 }
804#endif
805
Andreas Dilger47a0c421997-05-16 02:46:07 -0500806 /* Find a filter if necessary, filter the row and write it out. */
Guy Schalnate5a37791996-06-05 15:50:50 -0500807 png_write_find_filter(png_ptr, &(png_ptr->row_info));
Glenn Randers-Pehrson08a33431998-03-07 06:06:55 -0600808
809 if (png_ptr->write_row_fn != NULL)
810 (*(png_ptr->write_row_fn))(png_ptr, png_ptr->row_number, png_ptr->pass);
Guy Schalnat0d580581995-07-20 02:43:20 -0500811}
812
Guy Schalnat0f716451995-11-28 11:22:13 -0600813#if defined(PNG_WRITE_FLUSH_SUPPORTED)
814/* Set the automatic flush interval or 0 to turn flushing off */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500815void PNGAPI
Guy Schalnat4ee97b01996-01-16 01:51:56 -0600816png_set_flush(png_structp png_ptr, int nrows)
Guy Schalnat0f716451995-11-28 11:22:13 -0600817{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500818 png_debug(1, "in png_set_flush");
Glenn Randers-Pehrson170b70c2006-03-10 10:19:04 -0600819 if (png_ptr == NULL)
820 return;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600821 png_ptr->flush_dist = (nrows < 0 ? 0 : nrows);
Guy Schalnat0f716451995-11-28 11:22:13 -0600822}
823
824/* flush the current output buffers now */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500825void PNGAPI
Guy Schalnat4ee97b01996-01-16 01:51:56 -0600826png_write_flush(png_structp png_ptr)
Guy Schalnat0f716451995-11-28 11:22:13 -0600827{
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600828 int wrote_IDAT;
Guy Schalnat0f716451995-11-28 11:22:13 -0600829
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500830 png_debug(1, "in png_write_flush");
Glenn Randers-Pehrson170b70c2006-03-10 10:19:04 -0600831 if (png_ptr == NULL)
832 return;
Guy Schalnate5a37791996-06-05 15:50:50 -0500833 /* We have already written out all of the data */
834 if (png_ptr->row_number >= png_ptr->num_rows)
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500835 return;
Guy Schalnat0f716451995-11-28 11:22:13 -0600836
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600837 do
838 {
839 int ret;
Guy Schalnat0f716451995-11-28 11:22:13 -0600840
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600841 /* compress the data */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600842 ret = deflate(&png_ptr->zstream, Z_SYNC_FLUSH);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600843 wrote_IDAT = 0;
Guy Schalnat0f716451995-11-28 11:22:13 -0600844
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600845 /* check for compression errors */
846 if (ret != Z_OK)
847 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500848 if (png_ptr->zstream.msg != NULL)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600849 png_error(png_ptr, png_ptr->zstream.msg);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600850 else
851 png_error(png_ptr, "zlib error");
852 }
Guy Schalnat0f716451995-11-28 11:22:13 -0600853
Andreas Dilger47a0c421997-05-16 02:46:07 -0500854 if (!(png_ptr->zstream.avail_out))
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600855 {
856 /* write the IDAT and reset the zlib output buffer */
857 png_write_IDAT(png_ptr, png_ptr->zbuf,
858 png_ptr->zbuf_size);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600859 png_ptr->zstream.next_out = png_ptr->zbuf;
860 png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600861 wrote_IDAT = 1;
862 }
863 } while(wrote_IDAT == 1);
Guy Schalnat0f716451995-11-28 11:22:13 -0600864
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600865 /* If there is any data left to be output, write it into a new IDAT */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600866 if (png_ptr->zbuf_size != png_ptr->zstream.avail_out)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600867 {
868 /* write the IDAT and reset the zlib output buffer */
869 png_write_IDAT(png_ptr, png_ptr->zbuf,
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600870 png_ptr->zbuf_size - png_ptr->zstream.avail_out);
871 png_ptr->zstream.next_out = png_ptr->zbuf;
872 png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600873 }
874 png_ptr->flush_rows = 0;
875 png_flush(png_ptr);
Guy Schalnat0f716451995-11-28 11:22:13 -0600876}
877#endif /* PNG_WRITE_FLUSH_SUPPORTED */
878
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500879/* Free all memory used by the write */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500880void PNGAPI
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600881png_destroy_write_struct(png_structpp png_ptr_ptr, png_infopp info_ptr_ptr)
Guy Schalnate5a37791996-06-05 15:50:50 -0500882{
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600883 png_structp png_ptr = NULL;
884 png_infop info_ptr = NULL;
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -0500885#ifdef PNG_USER_MEM_SUPPORTED
886 png_free_ptr free_fn = NULL;
Glenn Randers-Pehrson8b6a8892001-05-18 04:54:50 -0500887 png_voidp mem_ptr = NULL;
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -0500888#endif
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600889
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500890 png_debug(1, "in png_destroy_write_struct");
Andreas Dilger47a0c421997-05-16 02:46:07 -0500891 if (png_ptr_ptr != NULL)
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -0500892 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600893 png_ptr = *png_ptr_ptr;
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -0500894#ifdef PNG_USER_MEM_SUPPORTED
895 free_fn = png_ptr->free_fn;
Glenn Randers-Pehrsonfcbd7872002-04-07 16:35:38 -0500896 mem_ptr = png_ptr->mem_ptr;
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -0500897#endif
898 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600899
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500900#ifdef PNG_USER_MEM_SUPPORTED
901 if (png_ptr != NULL)
902 {
903 free_fn = png_ptr->free_fn;
904 mem_ptr = png_ptr->mem_ptr;
905 }
906#endif
907
Andreas Dilger47a0c421997-05-16 02:46:07 -0500908 if (info_ptr_ptr != NULL)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600909 info_ptr = *info_ptr_ptr;
910
Andreas Dilger47a0c421997-05-16 02:46:07 -0500911 if (info_ptr != NULL)
Guy Schalnate5a37791996-06-05 15:50:50 -0500912 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500913 if (png_ptr != NULL)
914 {
915 png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1);
Glenn Randers-Pehrsona77ef622000-02-18 13:48:52 -0600916
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -0500917#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500918 if (png_ptr->num_chunk_list)
919 {
920 png_free(png_ptr, png_ptr->chunk_list);
Glenn Randers-Pehrson895a9c92008-07-25 08:51:18 -0500921 png_ptr->num_chunk_list = 0;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500922 }
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -0500923#endif
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500924 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600925
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -0500926#ifdef PNG_USER_MEM_SUPPORTED
Glenn Randers-Pehrson8b6a8892001-05-18 04:54:50 -0500927 png_destroy_struct_2((png_voidp)info_ptr, (png_free_ptr)free_fn,
928 (png_voidp)mem_ptr);
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -0500929#else
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600930 png_destroy_struct((png_voidp)info_ptr);
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -0500931#endif
Glenn Randers-Pehrson3f549252001-10-27 07:35:13 -0500932 *info_ptr_ptr = NULL;
Guy Schalnate5a37791996-06-05 15:50:50 -0500933 }
Guy Schalnat6d764711995-12-19 03:22:19 -0600934
Andreas Dilger47a0c421997-05-16 02:46:07 -0500935 if (png_ptr != NULL)
Guy Schalnate5a37791996-06-05 15:50:50 -0500936 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600937 png_write_destroy(png_ptr);
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -0500938#ifdef PNG_USER_MEM_SUPPORTED
Glenn Randers-Pehrson8b6a8892001-05-18 04:54:50 -0500939 png_destroy_struct_2((png_voidp)png_ptr, (png_free_ptr)free_fn,
940 (png_voidp)mem_ptr);
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -0500941#else
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600942 png_destroy_struct((png_voidp)png_ptr);
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -0500943#endif
Glenn Randers-Pehrson3f549252001-10-27 07:35:13 -0500944 *png_ptr_ptr = NULL;
Guy Schalnate5a37791996-06-05 15:50:50 -0500945 }
946}
947
948
Andreas Dilger47a0c421997-05-16 02:46:07 -0500949/* Free any memory used in png_ptr struct (old method) */
Glenn Randers-Pehrsonf64a06f2001-04-11 07:38:00 -0500950void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -0600951png_write_destroy(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -0500952{
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600953#ifdef PNG_SETJMP_SUPPORTED
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600954 jmp_buf tmp_jmp; /* save jump buffer */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600955#endif
Guy Schalnate5a37791996-06-05 15:50:50 -0500956 png_error_ptr error_fn;
957 png_error_ptr warning_fn;
958 png_voidp error_ptr;
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -0500959#ifdef PNG_USER_MEM_SUPPORTED
960 png_free_ptr free_fn;
961#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500962
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500963 png_debug(1, "in png_write_destroy");
Guy Schalnat0d580581995-07-20 02:43:20 -0500964 /* free any memory zlib uses */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600965 deflateEnd(&png_ptr->zstream);
Guy Schalnate5a37791996-06-05 15:50:50 -0500966
Guy Schalnat0d580581995-07-20 02:43:20 -0500967 /* free our memory. png_free checks NULL for us. */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600968 png_free(png_ptr, png_ptr->zbuf);
969 png_free(png_ptr, png_ptr->row_buf);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500970#ifndef PNG_NO_WRITE_FILTER
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600971 png_free(png_ptr, png_ptr->prev_row);
972 png_free(png_ptr, png_ptr->sub_row);
973 png_free(png_ptr, png_ptr->up_row);
974 png_free(png_ptr, png_ptr->avg_row);
975 png_free(png_ptr, png_ptr->paeth_row);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500976#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600977
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600978#if defined(PNG_TIME_RFC1123_SUPPORTED)
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600979 png_free(png_ptr, png_ptr->time_buffer);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600980#endif
981
Andreas Dilger47a0c421997-05-16 02:46:07 -0500982#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
983 png_free(png_ptr, png_ptr->prev_filters);
984 png_free(png_ptr, png_ptr->filter_weights);
985 png_free(png_ptr, png_ptr->inv_filter_weights);
986 png_free(png_ptr, png_ptr->filter_costs);
987 png_free(png_ptr, png_ptr->inv_filter_costs);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600988#endif
Guy Schalnate5a37791996-06-05 15:50:50 -0500989
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600990#ifdef PNG_SETJMP_SUPPORTED
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500991 /* Reset structure */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500992 png_memcpy(tmp_jmp, png_ptr->jmpbuf, png_sizeof(jmp_buf));
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600993#endif
Guy Schalnate5a37791996-06-05 15:50:50 -0500994
995 error_fn = png_ptr->error_fn;
996 warning_fn = png_ptr->warning_fn;
997 error_ptr = png_ptr->error_ptr;
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -0500998#ifdef PNG_USER_MEM_SUPPORTED
999 free_fn = png_ptr->free_fn;
1000#endif
Guy Schalnate5a37791996-06-05 15:50:50 -05001001
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001002 png_memset(png_ptr, 0, png_sizeof(png_struct));
Guy Schalnate5a37791996-06-05 15:50:50 -05001003
1004 png_ptr->error_fn = error_fn;
1005 png_ptr->warning_fn = warning_fn;
1006 png_ptr->error_ptr = error_ptr;
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -05001007#ifdef PNG_USER_MEM_SUPPORTED
1008 png_ptr->free_fn = free_fn;
1009#endif
Guy Schalnate5a37791996-06-05 15:50:50 -05001010
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001011#ifdef PNG_SETJMP_SUPPORTED
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001012 png_memcpy(png_ptr->jmpbuf, tmp_jmp, png_sizeof(jmp_buf));
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001013#endif
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001014}
Guy Schalnate5a37791996-06-05 15:50:50 -05001015
Andreas Dilger47a0c421997-05-16 02:46:07 -05001016/* Allow the application to select one or more row filters to use. */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001017void PNGAPI
Guy Schalnate5a37791996-06-05 15:50:50 -05001018png_set_filter(png_structp png_ptr, int method, int filters)
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001019{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001020 png_debug(1, "in png_set_filter");
Glenn Randers-Pehrson170b70c2006-03-10 10:19:04 -06001021 if (png_ptr == NULL)
1022 return;
Glenn Randers-Pehrson408b4212000-12-18 09:33:57 -06001023#if defined(PNG_MNG_FEATURES_SUPPORTED)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001024 if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) &&
Glenn Randers-Pehrson408b4212000-12-18 09:33:57 -06001025 (method == PNG_INTRAPIXEL_DIFFERENCING))
1026 method = PNG_FILTER_TYPE_BASE;
1027#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -05001028 if (method == PNG_FILTER_TYPE_BASE)
Guy Schalnate5a37791996-06-05 15:50:50 -05001029 {
1030 switch (filters & (PNG_ALL_FILTERS | 0x07))
1031 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001032#ifndef PNG_NO_WRITE_FILTER
Guy Schalnate5a37791996-06-05 15:50:50 -05001033 case 5:
1034 case 6:
Andreas Dilger47a0c421997-05-16 02:46:07 -05001035 case 7: png_warning(png_ptr, "Unknown row filter for method 0");
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001036#endif /* PNG_NO_WRITE_FILTER */
1037 case PNG_FILTER_VALUE_NONE:
1038 png_ptr->do_filter=PNG_FILTER_NONE; break;
1039#ifndef PNG_NO_WRITE_FILTER
1040 case PNG_FILTER_VALUE_SUB:
1041 png_ptr->do_filter=PNG_FILTER_SUB; break;
1042 case PNG_FILTER_VALUE_UP:
1043 png_ptr->do_filter=PNG_FILTER_UP; break;
1044 case PNG_FILTER_VALUE_AVG:
1045 png_ptr->do_filter=PNG_FILTER_AVG; break;
1046 case PNG_FILTER_VALUE_PAETH:
1047 png_ptr->do_filter=PNG_FILTER_PAETH; break;
Guy Schalnate5a37791996-06-05 15:50:50 -05001048 default: png_ptr->do_filter = (png_byte)filters; break;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001049#else
1050 default: png_warning(png_ptr, "Unknown row filter for method 0");
1051#endif /* PNG_NO_WRITE_FILTER */
Guy Schalnate5a37791996-06-05 15:50:50 -05001052 }
1053
Andreas Dilger47a0c421997-05-16 02:46:07 -05001054 /* If we have allocated the row_buf, this means we have already started
1055 * with the image and we should have allocated all of the filter buffers
1056 * that have been selected. If prev_row isn't already allocated, then
1057 * it is too late to start using the filters that need it, since we
1058 * will be missing the data in the previous row. If an application
1059 * wants to start and stop using particular filters during compression,
1060 * it should start out with all of the filters, and then add and
1061 * remove them after the start of compression.
Guy Schalnate5a37791996-06-05 15:50:50 -05001062 */
Andreas Dilger47a0c421997-05-16 02:46:07 -05001063 if (png_ptr->row_buf != NULL)
Guy Schalnate5a37791996-06-05 15:50:50 -05001064 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001065#ifndef PNG_NO_WRITE_FILTER
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001066 if ((png_ptr->do_filter & PNG_FILTER_SUB) && png_ptr->sub_row == NULL)
Guy Schalnate5a37791996-06-05 15:50:50 -05001067 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001068 png_ptr->sub_row = (png_bytep)png_malloc(png_ptr,
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06001069 (png_ptr->rowbytes + 1));
Andreas Dilger47a0c421997-05-16 02:46:07 -05001070 png_ptr->sub_row[0] = PNG_FILTER_VALUE_SUB;
Guy Schalnate5a37791996-06-05 15:50:50 -05001071 }
1072
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001073 if ((png_ptr->do_filter & PNG_FILTER_UP) && png_ptr->up_row == NULL)
Guy Schalnate5a37791996-06-05 15:50:50 -05001074 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001075 if (png_ptr->prev_row == NULL)
Guy Schalnate5a37791996-06-05 15:50:50 -05001076 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001077 png_warning(png_ptr, "Can't add Up filter after starting");
Guy Schalnate5a37791996-06-05 15:50:50 -05001078 png_ptr->do_filter &= ~PNG_FILTER_UP;
1079 }
1080 else
1081 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001082 png_ptr->up_row = (png_bytep)png_malloc(png_ptr,
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06001083 (png_ptr->rowbytes + 1));
Andreas Dilger47a0c421997-05-16 02:46:07 -05001084 png_ptr->up_row[0] = PNG_FILTER_VALUE_UP;
Guy Schalnate5a37791996-06-05 15:50:50 -05001085 }
1086 }
1087
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001088 if ((png_ptr->do_filter & PNG_FILTER_AVG) && png_ptr->avg_row == NULL)
Guy Schalnate5a37791996-06-05 15:50:50 -05001089 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001090 if (png_ptr->prev_row == NULL)
Guy Schalnate5a37791996-06-05 15:50:50 -05001091 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001092 png_warning(png_ptr, "Can't add Average filter after starting");
Guy Schalnate5a37791996-06-05 15:50:50 -05001093 png_ptr->do_filter &= ~PNG_FILTER_AVG;
1094 }
1095 else
1096 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001097 png_ptr->avg_row = (png_bytep)png_malloc(png_ptr,
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06001098 (png_ptr->rowbytes + 1));
Andreas Dilger47a0c421997-05-16 02:46:07 -05001099 png_ptr->avg_row[0] = PNG_FILTER_VALUE_AVG;
Guy Schalnate5a37791996-06-05 15:50:50 -05001100 }
1101 }
1102
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001103 if ((png_ptr->do_filter & PNG_FILTER_PAETH) &&
Andreas Dilger47a0c421997-05-16 02:46:07 -05001104 png_ptr->paeth_row == NULL)
Guy Schalnate5a37791996-06-05 15:50:50 -05001105 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001106 if (png_ptr->prev_row == NULL)
Guy Schalnate5a37791996-06-05 15:50:50 -05001107 {
1108 png_warning(png_ptr, "Can't add Paeth filter after starting");
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05001109 png_ptr->do_filter &= (png_byte)(~PNG_FILTER_PAETH);
Guy Schalnate5a37791996-06-05 15:50:50 -05001110 }
1111 else
1112 {
Glenn Randers-Pehrson46f61e21998-01-30 21:45:12 -06001113 png_ptr->paeth_row = (png_bytep)png_malloc(png_ptr,
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06001114 (png_ptr->rowbytes + 1));
Andreas Dilger47a0c421997-05-16 02:46:07 -05001115 png_ptr->paeth_row[0] = PNG_FILTER_VALUE_PAETH;
Guy Schalnate5a37791996-06-05 15:50:50 -05001116 }
1117 }
1118
1119 if (png_ptr->do_filter == PNG_NO_FILTERS)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001120#endif /* PNG_NO_WRITE_FILTER */
Guy Schalnate5a37791996-06-05 15:50:50 -05001121 png_ptr->do_filter = PNG_FILTER_NONE;
1122 }
1123 }
1124 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05001125 png_error(png_ptr, "Unknown custom filter method");
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001126}
1127
Andreas Dilger47a0c421997-05-16 02:46:07 -05001128/* This allows us to influence the way in which libpng chooses the "best"
1129 * filter for the current scanline. While the "minimum-sum-of-absolute-
1130 * differences metric is relatively fast and effective, there is some
1131 * question as to whether it can be improved upon by trying to keep the
1132 * filtered data going to zlib more consistent, hopefully resulting in
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001133 * better compression.
1134 */
Andreas Dilger47a0c421997-05-16 02:46:07 -05001135#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) /* GRR 970116 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001136void PNGAPI
Andreas Dilger47a0c421997-05-16 02:46:07 -05001137png_set_filter_heuristics(png_structp png_ptr, int heuristic_method,
1138 int num_weights, png_doublep filter_weights,
1139 png_doublep filter_costs)
1140{
1141 int i;
1142
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001143 png_debug(1, "in png_set_filter_heuristics");
Glenn Randers-Pehrson170b70c2006-03-10 10:19:04 -06001144 if (png_ptr == NULL)
1145 return;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001146 if (heuristic_method >= PNG_FILTER_HEURISTIC_LAST)
1147 {
1148 png_warning(png_ptr, "Unknown filter heuristic method");
1149 return;
1150 }
1151
1152 if (heuristic_method == PNG_FILTER_HEURISTIC_DEFAULT)
1153 {
1154 heuristic_method = PNG_FILTER_HEURISTIC_UNWEIGHTED;
1155 }
1156
1157 if (num_weights < 0 || filter_weights == NULL ||
1158 heuristic_method == PNG_FILTER_HEURISTIC_UNWEIGHTED)
1159 {
1160 num_weights = 0;
1161 }
1162
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -05001163 png_ptr->num_prev_filters = (png_byte)num_weights;
1164 png_ptr->heuristic_method = (png_byte)heuristic_method;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001165
1166 if (num_weights > 0)
1167 {
1168 if (png_ptr->prev_filters == NULL)
1169 {
1170 png_ptr->prev_filters = (png_bytep)png_malloc(png_ptr,
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001171 (png_uint_32)(png_sizeof(png_byte) * num_weights));
Andreas Dilger47a0c421997-05-16 02:46:07 -05001172
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05001173 /* To make sure that the weighting starts out fairly */
1174 for (i = 0; i < num_weights; i++)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001175 {
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05001176 png_ptr->prev_filters[i] = 255;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001177 }
1178 }
1179
1180 if (png_ptr->filter_weights == NULL)
1181 {
Glenn Randers-Pehrson87c6bc92001-04-03 22:43:19 -05001182 png_ptr->filter_weights = (png_uint_16p)png_malloc(png_ptr,
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001183 (png_uint_32)(png_sizeof(png_uint_16) * num_weights));
Andreas Dilger47a0c421997-05-16 02:46:07 -05001184
Glenn Randers-Pehrson87c6bc92001-04-03 22:43:19 -05001185 png_ptr->inv_filter_weights = (png_uint_16p)png_malloc(png_ptr,
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001186 (png_uint_32)(png_sizeof(png_uint_16) * num_weights));
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05001187 for (i = 0; i < num_weights; i++)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001188 {
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05001189 png_ptr->inv_filter_weights[i] =
1190 png_ptr->filter_weights[i] = PNG_WEIGHT_FACTOR;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001191 }
1192 }
1193
1194 for (i = 0; i < num_weights; i++)
1195 {
1196 if (filter_weights[i] < 0.0)
1197 {
1198 png_ptr->inv_filter_weights[i] =
1199 png_ptr->filter_weights[i] = PNG_WEIGHT_FACTOR;
1200 }
1201 else
1202 {
1203 png_ptr->inv_filter_weights[i] =
1204 (png_uint_16)((double)PNG_WEIGHT_FACTOR*filter_weights[i]+0.5);
1205 png_ptr->filter_weights[i] =
1206 (png_uint_16)((double)PNG_WEIGHT_FACTOR/filter_weights[i]+0.5);
1207 }
1208 }
1209 }
1210
1211 /* If, in the future, there are other filter methods, this would
1212 * need to be based on png_ptr->filter.
1213 */
1214 if (png_ptr->filter_costs == NULL)
1215 {
Glenn Randers-Pehrson87c6bc92001-04-03 22:43:19 -05001216 png_ptr->filter_costs = (png_uint_16p)png_malloc(png_ptr,
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001217 (png_uint_32)(png_sizeof(png_uint_16) * PNG_FILTER_VALUE_LAST));
Andreas Dilger47a0c421997-05-16 02:46:07 -05001218
Glenn Randers-Pehrson87c6bc92001-04-03 22:43:19 -05001219 png_ptr->inv_filter_costs = (png_uint_16p)png_malloc(png_ptr,
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001220 (png_uint_32)(png_sizeof(png_uint_16) * PNG_FILTER_VALUE_LAST));
Andreas Dilger47a0c421997-05-16 02:46:07 -05001221
1222 for (i = 0; i < PNG_FILTER_VALUE_LAST; i++)
1223 {
1224 png_ptr->inv_filter_costs[i] =
1225 png_ptr->filter_costs[i] = PNG_COST_FACTOR;
1226 }
1227 }
1228
1229 /* Here is where we set the relative costs of the different filters. We
1230 * should take the desired compression level into account when setting
1231 * the costs, so that Paeth, for instance, has a high relative cost at low
1232 * compression levels, while it has a lower relative cost at higher
1233 * compression settings. The filter types are in order of increasing
1234 * relative cost, so it would be possible to do this with an algorithm.
1235 */
1236 for (i = 0; i < PNG_FILTER_VALUE_LAST; i++)
1237 {
1238 if (filter_costs == NULL || filter_costs[i] < 0.0)
1239 {
1240 png_ptr->inv_filter_costs[i] =
1241 png_ptr->filter_costs[i] = PNG_COST_FACTOR;
1242 }
1243 else if (filter_costs[i] >= 1.0)
1244 {
1245 png_ptr->inv_filter_costs[i] =
1246 (png_uint_16)((double)PNG_COST_FACTOR / filter_costs[i] + 0.5);
1247 png_ptr->filter_costs[i] =
1248 (png_uint_16)((double)PNG_COST_FACTOR * filter_costs[i] + 0.5);
1249 }
1250 }
1251}
1252#endif /* PNG_WRITE_WEIGHTED_FILTER_SUPPORTED */
1253
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001254void PNGAPI
Guy Schalnat6d764711995-12-19 03:22:19 -06001255png_set_compression_level(png_structp png_ptr, int level)
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001256{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001257 png_debug(1, "in png_set_compression_level");
Glenn Randers-Pehrson170b70c2006-03-10 10:19:04 -06001258 if (png_ptr == NULL)
1259 return;
Guy Schalnate5a37791996-06-05 15:50:50 -05001260 png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_LEVEL;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001261 png_ptr->zlib_level = level;
1262}
1263
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001264void PNGAPI
Guy Schalnat6d764711995-12-19 03:22:19 -06001265png_set_compression_mem_level(png_structp png_ptr, int mem_level)
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001266{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001267 png_debug(1, "in png_set_compression_mem_level");
Glenn Randers-Pehrson170b70c2006-03-10 10:19:04 -06001268 if (png_ptr == NULL)
1269 return;
Guy Schalnate5a37791996-06-05 15:50:50 -05001270 png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_MEM_LEVEL;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001271 png_ptr->zlib_mem_level = mem_level;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001272}
1273
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001274void PNGAPI
Guy Schalnat6d764711995-12-19 03:22:19 -06001275png_set_compression_strategy(png_structp png_ptr, int strategy)
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001276{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001277 png_debug(1, "in png_set_compression_strategy");
Glenn Randers-Pehrson170b70c2006-03-10 10:19:04 -06001278 if (png_ptr == NULL)
1279 return;
Guy Schalnate5a37791996-06-05 15:50:50 -05001280 png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_STRATEGY;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001281 png_ptr->zlib_strategy = strategy;
1282}
1283
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001284void PNGAPI
Guy Schalnat6d764711995-12-19 03:22:19 -06001285png_set_compression_window_bits(png_structp png_ptr, int window_bits)
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001286{
Glenn Randers-Pehrson170b70c2006-03-10 10:19:04 -06001287 if (png_ptr == NULL)
1288 return;
Guy Schalnate5a37791996-06-05 15:50:50 -05001289 if (window_bits > 15)
1290 png_warning(png_ptr, "Only compression windows <= 32k supported by PNG");
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001291 else if (window_bits < 8)
1292 png_warning(png_ptr, "Only compression windows >= 256 supported by PNG");
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001293#ifndef WBITS_8_OK
1294 /* avoid libpng bug with 256-byte windows */
1295 if (window_bits == 8)
1296 {
1297 png_warning(png_ptr, "Compression window is being reset to 512");
1298 window_bits=9;
1299 }
1300#endif
Guy Schalnate5a37791996-06-05 15:50:50 -05001301 png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_WINDOW_BITS;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001302 png_ptr->zlib_window_bits = window_bits;
1303}
1304
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001305void PNGAPI
Guy Schalnat6d764711995-12-19 03:22:19 -06001306png_set_compression_method(png_structp png_ptr, int method)
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001307{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001308 png_debug(1, "in png_set_compression_method");
Glenn Randers-Pehrson170b70c2006-03-10 10:19:04 -06001309 if (png_ptr == NULL)
1310 return;
Guy Schalnate5a37791996-06-05 15:50:50 -05001311 if (method != 8)
1312 png_warning(png_ptr, "Only compression method 8 is supported by PNG");
1313 png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_METHOD;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001314 png_ptr->zlib_method = method;
Guy Schalnat0d580581995-07-20 02:43:20 -05001315}
1316
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001317void PNGAPI
Glenn Randers-Pehrson08a33431998-03-07 06:06:55 -06001318png_set_write_status_fn(png_structp png_ptr, png_write_status_ptr write_row_fn)
1319{
Glenn Randers-Pehrson170b70c2006-03-10 10:19:04 -06001320 if (png_ptr == NULL)
1321 return;
Glenn Randers-Pehrson08a33431998-03-07 06:06:55 -06001322 png_ptr->write_row_fn = write_row_fn;
1323}
1324
1325#if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001326void PNGAPI
Glenn Randers-Pehrson08a33431998-03-07 06:06:55 -06001327png_set_write_user_transform_fn(png_structp png_ptr, png_user_transform_ptr
1328 write_user_transform_fn)
1329{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001330 png_debug(1, "in png_set_write_user_transform_fn");
Glenn Randers-Pehrson170b70c2006-03-10 10:19:04 -06001331 if (png_ptr == NULL)
1332 return;
Glenn Randers-Pehrson08a33431998-03-07 06:06:55 -06001333 png_ptr->transformations |= PNG_USER_TRANSFORM;
1334 png_ptr->write_user_transform_fn = write_user_transform_fn;
1335}
1336#endif
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001337
1338
1339#if defined(PNG_INFO_IMAGE_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001340void PNGAPI
1341png_write_png(png_structp png_ptr, png_infop info_ptr,
Glenn Randers-Pehrson1ef65b62000-05-12 06:19:53 -05001342 int transforms, voidp params)
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001343{
Glenn Randers-Pehrson170b70c2006-03-10 10:19:04 -06001344 if (png_ptr == NULL || info_ptr == NULL)
1345 return;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001346#if defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED)
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05001347 /* Invert the alpha channel from opacity to transparency */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001348 if (transforms & PNG_TRANSFORM_INVERT_ALPHA)
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05001349 png_set_invert_alpha(png_ptr);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001350#endif
1351
1352 /* Write the file header information. */
1353 png_write_info(png_ptr, info_ptr);
1354
1355 /* ------ these transformations don't touch the info structure ------- */
1356
1357#if defined(PNG_WRITE_INVERT_SUPPORTED)
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05001358 /* Invert monochrome pixels */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001359 if (transforms & PNG_TRANSFORM_INVERT_MONO)
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05001360 png_set_invert_mono(png_ptr);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001361#endif
1362
1363#if defined(PNG_WRITE_SHIFT_SUPPORTED)
1364 /* Shift the pixels up to a legal bit depth and fill in
1365 * as appropriate to correctly scale the image.
1366 */
1367 if ((transforms & PNG_TRANSFORM_SHIFT)
1368 && (info_ptr->valid & PNG_INFO_sBIT))
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05001369 png_set_shift(png_ptr, &info_ptr->sig_bit);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001370#endif
1371
1372#if defined(PNG_WRITE_PACK_SUPPORTED)
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05001373 /* Pack pixels into bytes */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001374 if (transforms & PNG_TRANSFORM_PACKING)
1375 png_set_packing(png_ptr);
1376#endif
1377
1378#if defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED)
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05001379 /* Swap location of alpha bytes from ARGB to RGBA */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001380 if (transforms & PNG_TRANSFORM_SWAP_ALPHA)
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05001381 png_set_swap_alpha(png_ptr);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001382#endif
1383
1384#if defined(PNG_WRITE_FILLER_SUPPORTED)
Glenn Randers-Pehrson4a82d692008-12-15 16:25:05 -06001385 /* Pack XRGB/RGBX/ARGB/RGBA into * RGB (4 channels -> 3 channels) */
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05001386 if (transforms & PNG_TRANSFORM_STRIP_FILLER_AFTER)
Glenn Randers-Pehrson1eb14e92008-12-10 07:14:45 -06001387 png_set_filler(png_ptr, 0, PNG_FILLER_AFTER);
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05001388 else if (transforms & PNG_TRANSFORM_STRIP_FILLER_BEFORE)
Glenn Randers-Pehrson1eb14e92008-12-10 07:14:45 -06001389 png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001390#endif
1391
1392#if defined(PNG_WRITE_BGR_SUPPORTED)
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05001393 /* Flip BGR pixels to RGB */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001394 if (transforms & PNG_TRANSFORM_BGR)
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05001395 png_set_bgr(png_ptr);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001396#endif
1397
1398#if defined(PNG_WRITE_SWAP_SUPPORTED)
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05001399 /* Swap bytes of 16-bit files to most significant byte first */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001400 if (transforms & PNG_TRANSFORM_SWAP_ENDIAN)
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05001401 png_set_swap(png_ptr);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001402#endif
1403
1404#if defined(PNG_WRITE_PACKSWAP_SUPPORTED)
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05001405 /* Swap bits of 1, 2, 4 bit packed pixel formats */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001406 if (transforms & PNG_TRANSFORM_PACKSWAP)
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05001407 png_set_packswap(png_ptr);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001408#endif
1409
1410 /* ----------------------- end of transformations ------------------- */
1411
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -05001412 /* Write the bits */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001413 if (info_ptr->valid & PNG_INFO_IDAT)
1414 png_write_image(png_ptr, info_ptr->row_pointers);
1415
1416 /* It is REQUIRED to call this to finish writing the rest of the file */
1417 png_write_end(png_ptr, info_ptr);
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06001418
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001419 transforms = transforms; /* quiet compiler warnings */
1420 params = params;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001421}
1422#endif
Glenn Randers-Pehrson19095602001-03-14 07:08:39 -06001423#endif /* PNG_WRITE_SUPPORTED */