annotate lib/libpng/pngwrite.c @ 2296:6e178010fc29

libpng
author Ritor1
date Mon, 17 Mar 2014 01:21:55 +0600
parents
children
rev   line source
2296
Ritor1
parents:
diff changeset
1
Ritor1
parents:
diff changeset
2 /* pngwrite.c - general routines to write a PNG file
Ritor1
parents:
diff changeset
3 *
Ritor1
parents:
diff changeset
4 * Last changed in libpng 1.6.10 [March 6, 2014]
Ritor1
parents:
diff changeset
5 * Copyright (c) 1998-2014 Glenn Randers-Pehrson
Ritor1
parents:
diff changeset
6 * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
Ritor1
parents:
diff changeset
7 * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
Ritor1
parents:
diff changeset
8 *
Ritor1
parents:
diff changeset
9 * This code is released under the libpng license.
Ritor1
parents:
diff changeset
10 * For conditions of distribution and use, see the disclaimer
Ritor1
parents:
diff changeset
11 * and license in png.h
Ritor1
parents:
diff changeset
12 */
Ritor1
parents:
diff changeset
13
Ritor1
parents:
diff changeset
14 #include "pngpriv.h"
Ritor1
parents:
diff changeset
15 #if defined(PNG_SIMPLIFIED_WRITE_SUPPORTED) && defined(PNG_STDIO_SUPPORTED)
Ritor1
parents:
diff changeset
16 # include <errno.h>
Ritor1
parents:
diff changeset
17 #endif
Ritor1
parents:
diff changeset
18
Ritor1
parents:
diff changeset
19 #ifdef PNG_WRITE_SUPPORTED
Ritor1
parents:
diff changeset
20
Ritor1
parents:
diff changeset
21 #ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
Ritor1
parents:
diff changeset
22 /* Write out all the unknown chunks for the current given location */
Ritor1
parents:
diff changeset
23 static void
Ritor1
parents:
diff changeset
24 write_unknown_chunks(png_structrp png_ptr, png_const_inforp info_ptr,
Ritor1
parents:
diff changeset
25 unsigned int where)
Ritor1
parents:
diff changeset
26 {
Ritor1
parents:
diff changeset
27 if (info_ptr->unknown_chunks_num)
Ritor1
parents:
diff changeset
28 {
Ritor1
parents:
diff changeset
29 png_const_unknown_chunkp up;
Ritor1
parents:
diff changeset
30
Ritor1
parents:
diff changeset
31 png_debug(5, "writing extra chunks");
Ritor1
parents:
diff changeset
32
Ritor1
parents:
diff changeset
33 for (up = info_ptr->unknown_chunks;
Ritor1
parents:
diff changeset
34 up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num;
Ritor1
parents:
diff changeset
35 ++up)
Ritor1
parents:
diff changeset
36 if (up->location & where)
Ritor1
parents:
diff changeset
37 {
Ritor1
parents:
diff changeset
38 /* If per-chunk unknown chunk handling is enabled use it, otherwise
Ritor1
parents:
diff changeset
39 * just write the chunks the application has set.
Ritor1
parents:
diff changeset
40 */
Ritor1
parents:
diff changeset
41 #ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED
Ritor1
parents:
diff changeset
42 int keep = png_handle_as_unknown(png_ptr, up->name);
Ritor1
parents:
diff changeset
43
Ritor1
parents:
diff changeset
44 /* NOTE: this code is radically different from the read side in the
Ritor1
parents:
diff changeset
45 * matter of handling an ancillary unknown chunk. In the read side
Ritor1
parents:
diff changeset
46 * the default behavior is to discard it, in the code below the default
Ritor1
parents:
diff changeset
47 * behavior is to write it. Critical chunks are, however, only
Ritor1
parents:
diff changeset
48 * written if explicitly listed or if the default is set to write all
Ritor1
parents:
diff changeset
49 * unknown chunks.
Ritor1
parents:
diff changeset
50 *
Ritor1
parents:
diff changeset
51 * The default handling is also slightly weird - it is not possible to
Ritor1
parents:
diff changeset
52 * stop the writing of all unsafe-to-copy chunks!
Ritor1
parents:
diff changeset
53 *
Ritor1
parents:
diff changeset
54 * TODO: REVIEW: this would seem to be a bug.
Ritor1
parents:
diff changeset
55 */
Ritor1
parents:
diff changeset
56 if (keep != PNG_HANDLE_CHUNK_NEVER &&
Ritor1
parents:
diff changeset
57 ((up->name[3] & 0x20) /* safe-to-copy overrides everything */ ||
Ritor1
parents:
diff changeset
58 keep == PNG_HANDLE_CHUNK_ALWAYS ||
Ritor1
parents:
diff changeset
59 (keep == PNG_HANDLE_CHUNK_AS_DEFAULT &&
Ritor1
parents:
diff changeset
60 png_ptr->unknown_default == PNG_HANDLE_CHUNK_ALWAYS)))
Ritor1
parents:
diff changeset
61 #endif
Ritor1
parents:
diff changeset
62 {
Ritor1
parents:
diff changeset
63 /* TODO: review, what is wrong with a zero length unknown chunk? */
Ritor1
parents:
diff changeset
64 if (up->size == 0)
Ritor1
parents:
diff changeset
65 png_warning(png_ptr, "Writing zero-length unknown chunk");
Ritor1
parents:
diff changeset
66
Ritor1
parents:
diff changeset
67 png_write_chunk(png_ptr, up->name, up->data, up->size);
Ritor1
parents:
diff changeset
68 }
Ritor1
parents:
diff changeset
69 }
Ritor1
parents:
diff changeset
70 }
Ritor1
parents:
diff changeset
71 }
Ritor1
parents:
diff changeset
72 #endif /* PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED */
Ritor1
parents:
diff changeset
73
Ritor1
parents:
diff changeset
74 /* Writes all the PNG information. This is the suggested way to use the
Ritor1
parents:
diff changeset
75 * library. If you have a new chunk to add, make a function to write it,
Ritor1
parents:
diff changeset
76 * and put it in the correct location here. If you want the chunk written
Ritor1
parents:
diff changeset
77 * after the image data, put it in png_write_end(). I strongly encourage
Ritor1
parents:
diff changeset
78 * you to supply a PNG_INFO_ flag, and check info_ptr->valid before writing
Ritor1
parents:
diff changeset
79 * the chunk, as that will keep the code from breaking if you want to just
Ritor1
parents:
diff changeset
80 * write a plain PNG file. If you have long comments, I suggest writing
Ritor1
parents:
diff changeset
81 * them in png_write_end(), and compressing them.
Ritor1
parents:
diff changeset
82 */
Ritor1
parents:
diff changeset
83 void PNGAPI
Ritor1
parents:
diff changeset
84 png_write_info_before_PLTE(png_structrp png_ptr, png_const_inforp info_ptr)
Ritor1
parents:
diff changeset
85 {
Ritor1
parents:
diff changeset
86 png_debug(1, "in png_write_info_before_PLTE");
Ritor1
parents:
diff changeset
87
Ritor1
parents:
diff changeset
88 if (png_ptr == NULL || info_ptr == NULL)
Ritor1
parents:
diff changeset
89 return;
Ritor1
parents:
diff changeset
90
Ritor1
parents:
diff changeset
91 if (!(png_ptr->mode & PNG_WROTE_INFO_BEFORE_PLTE))
Ritor1
parents:
diff changeset
92 {
Ritor1
parents:
diff changeset
93 /* Write PNG signature */
Ritor1
parents:
diff changeset
94 png_write_sig(png_ptr);
Ritor1
parents:
diff changeset
95
Ritor1
parents:
diff changeset
96 #ifdef PNG_MNG_FEATURES_SUPPORTED
Ritor1
parents:
diff changeset
97 if ((png_ptr->mode&PNG_HAVE_PNG_SIGNATURE) && \
Ritor1
parents:
diff changeset
98 (png_ptr->mng_features_permitted))
Ritor1
parents:
diff changeset
99 {
Ritor1
parents:
diff changeset
100 png_warning(png_ptr, "MNG features are not allowed in a PNG datastream");
Ritor1
parents:
diff changeset
101 png_ptr->mng_features_permitted = 0;
Ritor1
parents:
diff changeset
102 }
Ritor1
parents:
diff changeset
103 #endif
Ritor1
parents:
diff changeset
104
Ritor1
parents:
diff changeset
105 /* Write IHDR information. */
Ritor1
parents:
diff changeset
106 png_write_IHDR(png_ptr, info_ptr->width, info_ptr->height,
Ritor1
parents:
diff changeset
107 info_ptr->bit_depth, info_ptr->color_type, info_ptr->compression_type,
Ritor1
parents:
diff changeset
108 info_ptr->filter_type,
Ritor1
parents:
diff changeset
109 #ifdef PNG_WRITE_INTERLACING_SUPPORTED
Ritor1
parents:
diff changeset
110 info_ptr->interlace_type
Ritor1
parents:
diff changeset
111 #else
Ritor1
parents:
diff changeset
112 0
Ritor1
parents:
diff changeset
113 #endif
Ritor1
parents:
diff changeset
114 );
Ritor1
parents:
diff changeset
115
Ritor1
parents:
diff changeset
116 /* The rest of these check to see if the valid field has the appropriate
Ritor1
parents:
diff changeset
117 * flag set, and if it does, writes the chunk.
Ritor1
parents:
diff changeset
118 *
Ritor1
parents:
diff changeset
119 * 1.6.0: COLORSPACE support controls the writing of these chunks too, and
Ritor1
parents:
diff changeset
120 * the chunks will be written if the WRITE routine is there and information
Ritor1
parents:
diff changeset
121 * is available in the COLORSPACE. (See png_colorspace_sync_info in png.c
Ritor1
parents:
diff changeset
122 * for where the valid flags get set.)
Ritor1
parents:
diff changeset
123 *
Ritor1
parents:
diff changeset
124 * Under certain circumstances the colorspace can be invalidated without
Ritor1
parents:
diff changeset
125 * syncing the info_struct 'valid' flags; this happens if libpng detects and
Ritor1
parents:
diff changeset
126 * error and calls png_error while the color space is being set, yet the
Ritor1
parents:
diff changeset
127 * application continues writing the PNG. So check the 'invalid' flag here
Ritor1
parents:
diff changeset
128 * too.
Ritor1
parents:
diff changeset
129 */
Ritor1
parents:
diff changeset
130 #ifdef PNG_GAMMA_SUPPORTED
Ritor1
parents:
diff changeset
131 # ifdef PNG_WRITE_gAMA_SUPPORTED
Ritor1
parents:
diff changeset
132 if (!(info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) &&
Ritor1
parents:
diff changeset
133 (info_ptr->colorspace.flags & PNG_COLORSPACE_FROM_gAMA) &&
Ritor1
parents:
diff changeset
134 (info_ptr->valid & PNG_INFO_gAMA))
Ritor1
parents:
diff changeset
135 png_write_gAMA_fixed(png_ptr, info_ptr->colorspace.gamma);
Ritor1
parents:
diff changeset
136 # endif
Ritor1
parents:
diff changeset
137 #endif
Ritor1
parents:
diff changeset
138
Ritor1
parents:
diff changeset
139 #ifdef PNG_COLORSPACE_SUPPORTED
Ritor1
parents:
diff changeset
140 /* Write only one of sRGB or an ICC profile. If a profile was supplied
Ritor1
parents:
diff changeset
141 * and it matches one of the known sRGB ones issue a warning.
Ritor1
parents:
diff changeset
142 */
Ritor1
parents:
diff changeset
143 # ifdef PNG_WRITE_iCCP_SUPPORTED
Ritor1
parents:
diff changeset
144 if (!(info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) &&
Ritor1
parents:
diff changeset
145 (info_ptr->valid & PNG_INFO_iCCP))
Ritor1
parents:
diff changeset
146 {
Ritor1
parents:
diff changeset
147 # ifdef PNG_WRITE_sRGB_SUPPORTED
Ritor1
parents:
diff changeset
148 if (info_ptr->valid & PNG_INFO_sRGB)
Ritor1
parents:
diff changeset
149 png_app_warning(png_ptr,
Ritor1
parents:
diff changeset
150 "profile matches sRGB but writing iCCP instead");
Ritor1
parents:
diff changeset
151 # endif
Ritor1
parents:
diff changeset
152
Ritor1
parents:
diff changeset
153 png_write_iCCP(png_ptr, info_ptr->iccp_name,
Ritor1
parents:
diff changeset
154 info_ptr->iccp_profile);
Ritor1
parents:
diff changeset
155 }
Ritor1
parents:
diff changeset
156 # ifdef PNG_WRITE_sRGB_SUPPORTED
Ritor1
parents:
diff changeset
157 else
Ritor1
parents:
diff changeset
158 # endif
Ritor1
parents:
diff changeset
159 # endif
Ritor1
parents:
diff changeset
160
Ritor1
parents:
diff changeset
161 # ifdef PNG_WRITE_sRGB_SUPPORTED
Ritor1
parents:
diff changeset
162 if (!(info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) &&
Ritor1
parents:
diff changeset
163 (info_ptr->valid & PNG_INFO_sRGB))
Ritor1
parents:
diff changeset
164 png_write_sRGB(png_ptr, info_ptr->colorspace.rendering_intent);
Ritor1
parents:
diff changeset
165 # endif /* WRITE_sRGB */
Ritor1
parents:
diff changeset
166 #endif /* COLORSPACE */
Ritor1
parents:
diff changeset
167
Ritor1
parents:
diff changeset
168 #ifdef PNG_WRITE_sBIT_SUPPORTED
Ritor1
parents:
diff changeset
169 if (info_ptr->valid & PNG_INFO_sBIT)
Ritor1
parents:
diff changeset
170 png_write_sBIT(png_ptr, &(info_ptr->sig_bit), info_ptr->color_type);
Ritor1
parents:
diff changeset
171 #endif
Ritor1
parents:
diff changeset
172
Ritor1
parents:
diff changeset
173 #ifdef PNG_COLORSPACE_SUPPORTED
Ritor1
parents:
diff changeset
174 # ifdef PNG_WRITE_cHRM_SUPPORTED
Ritor1
parents:
diff changeset
175 if (!(info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) &&
Ritor1
parents:
diff changeset
176 (info_ptr->colorspace.flags & PNG_COLORSPACE_FROM_cHRM) &&
Ritor1
parents:
diff changeset
177 (info_ptr->valid & PNG_INFO_cHRM))
Ritor1
parents:
diff changeset
178 png_write_cHRM_fixed(png_ptr, &info_ptr->colorspace.end_points_xy);
Ritor1
parents:
diff changeset
179 # endif
Ritor1
parents:
diff changeset
180 #endif
Ritor1
parents:
diff changeset
181
Ritor1
parents:
diff changeset
182 #ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
Ritor1
parents:
diff changeset
183 write_unknown_chunks(png_ptr, info_ptr, PNG_HAVE_IHDR);
Ritor1
parents:
diff changeset
184 #endif
Ritor1
parents:
diff changeset
185
Ritor1
parents:
diff changeset
186 png_ptr->mode |= PNG_WROTE_INFO_BEFORE_PLTE;
Ritor1
parents:
diff changeset
187 }
Ritor1
parents:
diff changeset
188 }
Ritor1
parents:
diff changeset
189
Ritor1
parents:
diff changeset
190 void PNGAPI
Ritor1
parents:
diff changeset
191 png_write_info(png_structrp png_ptr, png_const_inforp info_ptr)
Ritor1
parents:
diff changeset
192 {
Ritor1
parents:
diff changeset
193 #if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED)
Ritor1
parents:
diff changeset
194 int i;
Ritor1
parents:
diff changeset
195 #endif
Ritor1
parents:
diff changeset
196
Ritor1
parents:
diff changeset
197 png_debug(1, "in png_write_info");
Ritor1
parents:
diff changeset
198
Ritor1
parents:
diff changeset
199 if (png_ptr == NULL || info_ptr == NULL)
Ritor1
parents:
diff changeset
200 return;
Ritor1
parents:
diff changeset
201
Ritor1
parents:
diff changeset
202 png_write_info_before_PLTE(png_ptr, info_ptr);
Ritor1
parents:
diff changeset
203
Ritor1
parents:
diff changeset
204 if (info_ptr->valid & PNG_INFO_PLTE)
Ritor1
parents:
diff changeset
205 png_write_PLTE(png_ptr, info_ptr->palette,
Ritor1
parents:
diff changeset
206 (png_uint_32)info_ptr->num_palette);
Ritor1
parents:
diff changeset
207
Ritor1
parents:
diff changeset
208 else if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
Ritor1
parents:
diff changeset
209 png_error(png_ptr, "Valid palette required for paletted images");
Ritor1
parents:
diff changeset
210
Ritor1
parents:
diff changeset
211 #ifdef PNG_WRITE_tRNS_SUPPORTED
Ritor1
parents:
diff changeset
212 if (info_ptr->valid & PNG_INFO_tRNS)
Ritor1
parents:
diff changeset
213 {
Ritor1
parents:
diff changeset
214 #ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED
Ritor1
parents:
diff changeset
215 /* Invert the alpha channel (in tRNS) */
Ritor1
parents:
diff changeset
216 if ((png_ptr->transformations & PNG_INVERT_ALPHA) &&
Ritor1
parents:
diff changeset
217 info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
Ritor1
parents:
diff changeset
218 {
Ritor1
parents:
diff changeset
219 int j;
Ritor1
parents:
diff changeset
220 for (j = 0; j<(int)info_ptr->num_trans; j++)
Ritor1
parents:
diff changeset
221 info_ptr->trans_alpha[j] =
Ritor1
parents:
diff changeset
222 (png_byte)(255 - info_ptr->trans_alpha[j]);
Ritor1
parents:
diff changeset
223 }
Ritor1
parents:
diff changeset
224 #endif
Ritor1
parents:
diff changeset
225 png_write_tRNS(png_ptr, info_ptr->trans_alpha, &(info_ptr->trans_color),
Ritor1
parents:
diff changeset
226 info_ptr->num_trans, info_ptr->color_type);
Ritor1
parents:
diff changeset
227 }
Ritor1
parents:
diff changeset
228 #endif
Ritor1
parents:
diff changeset
229 #ifdef PNG_WRITE_bKGD_SUPPORTED
Ritor1
parents:
diff changeset
230 if (info_ptr->valid & PNG_INFO_bKGD)
Ritor1
parents:
diff changeset
231 png_write_bKGD(png_ptr, &(info_ptr->background), info_ptr->color_type);
Ritor1
parents:
diff changeset
232 #endif
Ritor1
parents:
diff changeset
233
Ritor1
parents:
diff changeset
234 #ifdef PNG_WRITE_hIST_SUPPORTED
Ritor1
parents:
diff changeset
235 if (info_ptr->valid & PNG_INFO_hIST)
Ritor1
parents:
diff changeset
236 png_write_hIST(png_ptr, info_ptr->hist, info_ptr->num_palette);
Ritor1
parents:
diff changeset
237 #endif
Ritor1
parents:
diff changeset
238
Ritor1
parents:
diff changeset
239 #ifdef PNG_WRITE_oFFs_SUPPORTED
Ritor1
parents:
diff changeset
240 if (info_ptr->valid & PNG_INFO_oFFs)
Ritor1
parents:
diff changeset
241 png_write_oFFs(png_ptr, info_ptr->x_offset, info_ptr->y_offset,
Ritor1
parents:
diff changeset
242 info_ptr->offset_unit_type);
Ritor1
parents:
diff changeset
243 #endif
Ritor1
parents:
diff changeset
244
Ritor1
parents:
diff changeset
245 #ifdef PNG_WRITE_pCAL_SUPPORTED
Ritor1
parents:
diff changeset
246 if (info_ptr->valid & PNG_INFO_pCAL)
Ritor1
parents:
diff changeset
247 png_write_pCAL(png_ptr, info_ptr->pcal_purpose, info_ptr->pcal_X0,
Ritor1
parents:
diff changeset
248 info_ptr->pcal_X1, info_ptr->pcal_type, info_ptr->pcal_nparams,
Ritor1
parents:
diff changeset
249 info_ptr->pcal_units, info_ptr->pcal_params);
Ritor1
parents:
diff changeset
250 #endif
Ritor1
parents:
diff changeset
251
Ritor1
parents:
diff changeset
252 #ifdef PNG_WRITE_sCAL_SUPPORTED
Ritor1
parents:
diff changeset
253 if (info_ptr->valid & PNG_INFO_sCAL)
Ritor1
parents:
diff changeset
254 png_write_sCAL_s(png_ptr, (int)info_ptr->scal_unit,
Ritor1
parents:
diff changeset
255 info_ptr->scal_s_width, info_ptr->scal_s_height);
Ritor1
parents:
diff changeset
256 #endif /* sCAL */
Ritor1
parents:
diff changeset
257
Ritor1
parents:
diff changeset
258 #ifdef PNG_WRITE_pHYs_SUPPORTED
Ritor1
parents:
diff changeset
259 if (info_ptr->valid & PNG_INFO_pHYs)
Ritor1
parents:
diff changeset
260 png_write_pHYs(png_ptr, info_ptr->x_pixels_per_unit,
Ritor1
parents:
diff changeset
261 info_ptr->y_pixels_per_unit, info_ptr->phys_unit_type);
Ritor1
parents:
diff changeset
262 #endif /* pHYs */
Ritor1
parents:
diff changeset
263
Ritor1
parents:
diff changeset
264 #ifdef PNG_WRITE_tIME_SUPPORTED
Ritor1
parents:
diff changeset
265 if (info_ptr->valid & PNG_INFO_tIME)
Ritor1
parents:
diff changeset
266 {
Ritor1
parents:
diff changeset
267 png_write_tIME(png_ptr, &(info_ptr->mod_time));
Ritor1
parents:
diff changeset
268 png_ptr->mode |= PNG_WROTE_tIME;
Ritor1
parents:
diff changeset
269 }
Ritor1
parents:
diff changeset
270 #endif /* tIME */
Ritor1
parents:
diff changeset
271
Ritor1
parents:
diff changeset
272 #ifdef PNG_WRITE_sPLT_SUPPORTED
Ritor1
parents:
diff changeset
273 if (info_ptr->valid & PNG_INFO_sPLT)
Ritor1
parents:
diff changeset
274 for (i = 0; i < (int)info_ptr->splt_palettes_num; i++)
Ritor1
parents:
diff changeset
275 png_write_sPLT(png_ptr, info_ptr->splt_palettes + i);
Ritor1
parents:
diff changeset
276 #endif /* sPLT */
Ritor1
parents:
diff changeset
277
Ritor1
parents:
diff changeset
278 #ifdef PNG_WRITE_TEXT_SUPPORTED
Ritor1
parents:
diff changeset
279 /* Check to see if we need to write text chunks */
Ritor1
parents:
diff changeset
280 for (i = 0; i < info_ptr->num_text; i++)
Ritor1
parents:
diff changeset
281 {
Ritor1
parents:
diff changeset
282 png_debug2(2, "Writing header text chunk %d, type %d", i,
Ritor1
parents:
diff changeset
283 info_ptr->text[i].compression);
Ritor1
parents:
diff changeset
284 /* An internationalized chunk? */
Ritor1
parents:
diff changeset
285 if (info_ptr->text[i].compression > 0)
Ritor1
parents:
diff changeset
286 {
Ritor1
parents:
diff changeset
287 #ifdef PNG_WRITE_iTXt_SUPPORTED
Ritor1
parents:
diff changeset
288 /* Write international chunk */
Ritor1
parents:
diff changeset
289 png_write_iTXt(png_ptr,
Ritor1
parents:
diff changeset
290 info_ptr->text[i].compression,
Ritor1
parents:
diff changeset
291 info_ptr->text[i].key,
Ritor1
parents:
diff changeset
292 info_ptr->text[i].lang,
Ritor1
parents:
diff changeset
293 info_ptr->text[i].lang_key,
Ritor1
parents:
diff changeset
294 info_ptr->text[i].text);
Ritor1
parents:
diff changeset
295 #else
Ritor1
parents:
diff changeset
296 png_warning(png_ptr, "Unable to write international text");
Ritor1
parents:
diff changeset
297 #endif
Ritor1
parents:
diff changeset
298 /* Mark this chunk as written */
Ritor1
parents:
diff changeset
299 info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;
Ritor1
parents:
diff changeset
300 }
Ritor1
parents:
diff changeset
301
Ritor1
parents:
diff changeset
302 /* If we want a compressed text chunk */
Ritor1
parents:
diff changeset
303 else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_zTXt)
Ritor1
parents:
diff changeset
304 {
Ritor1
parents:
diff changeset
305 #ifdef PNG_WRITE_zTXt_SUPPORTED
Ritor1
parents:
diff changeset
306 /* Write compressed chunk */
Ritor1
parents:
diff changeset
307 png_write_zTXt(png_ptr, info_ptr->text[i].key,
Ritor1
parents:
diff changeset
308 info_ptr->text[i].text, 0,
Ritor1
parents:
diff changeset
309 info_ptr->text[i].compression);
Ritor1
parents:
diff changeset
310 #else
Ritor1
parents:
diff changeset
311 png_warning(png_ptr, "Unable to write compressed text");
Ritor1
parents:
diff changeset
312 #endif
Ritor1
parents:
diff changeset
313 /* Mark this chunk as written */
Ritor1
parents:
diff changeset
314 info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR;
Ritor1
parents:
diff changeset
315 }
Ritor1
parents:
diff changeset
316
Ritor1
parents:
diff changeset
317 else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE)
Ritor1
parents:
diff changeset
318 {
Ritor1
parents:
diff changeset
319 #ifdef PNG_WRITE_tEXt_SUPPORTED
Ritor1
parents:
diff changeset
320 /* Write uncompressed chunk */
Ritor1
parents:
diff changeset
321 png_write_tEXt(png_ptr, info_ptr->text[i].key,
Ritor1
parents:
diff changeset
322 info_ptr->text[i].text,
Ritor1
parents:
diff changeset
323 0);
Ritor1
parents:
diff changeset
324 /* Mark this chunk as written */
Ritor1
parents:
diff changeset
325 info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;
Ritor1
parents:
diff changeset
326 #else
Ritor1
parents:
diff changeset
327 /* Can't get here */
Ritor1
parents:
diff changeset
328 png_warning(png_ptr, "Unable to write uncompressed text");
Ritor1
parents:
diff changeset
329 #endif
Ritor1
parents:
diff changeset
330 }
Ritor1
parents:
diff changeset
331 }
Ritor1
parents:
diff changeset
332 #endif /* tEXt */
Ritor1
parents:
diff changeset
333
Ritor1
parents:
diff changeset
334 #ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
Ritor1
parents:
diff changeset
335 write_unknown_chunks(png_ptr, info_ptr, PNG_HAVE_PLTE);
Ritor1
parents:
diff changeset
336 #endif
Ritor1
parents:
diff changeset
337 }
Ritor1
parents:
diff changeset
338
Ritor1
parents:
diff changeset
339 /* Writes the end of the PNG file. If you don't want to write comments or
Ritor1
parents:
diff changeset
340 * time information, you can pass NULL for info. If you already wrote these
Ritor1
parents:
diff changeset
341 * in png_write_info(), do not write them again here. If you have long
Ritor1
parents:
diff changeset
342 * comments, I suggest writing them here, and compressing them.
Ritor1
parents:
diff changeset
343 */
Ritor1
parents:
diff changeset
344 void PNGAPI
Ritor1
parents:
diff changeset
345 png_write_end(png_structrp png_ptr, png_inforp info_ptr)
Ritor1
parents:
diff changeset
346 {
Ritor1
parents:
diff changeset
347 png_debug(1, "in png_write_end");
Ritor1
parents:
diff changeset
348
Ritor1
parents:
diff changeset
349 if (png_ptr == NULL)
Ritor1
parents:
diff changeset
350 return;
Ritor1
parents:
diff changeset
351
Ritor1
parents:
diff changeset
352 if (!(png_ptr->mode & PNG_HAVE_IDAT))
Ritor1
parents:
diff changeset
353 png_error(png_ptr, "No IDATs written into file");
Ritor1
parents:
diff changeset
354
Ritor1
parents:
diff changeset
355 #ifdef PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED
Ritor1
parents:
diff changeset
356 if (png_ptr->num_palette_max > png_ptr->num_palette)
Ritor1
parents:
diff changeset
357 png_benign_error(png_ptr, "Wrote palette index exceeding num_palette");
Ritor1
parents:
diff changeset
358 #endif
Ritor1
parents:
diff changeset
359
Ritor1
parents:
diff changeset
360 /* See if user wants us to write information chunks */
Ritor1
parents:
diff changeset
361 if (info_ptr != NULL)
Ritor1
parents:
diff changeset
362 {
Ritor1
parents:
diff changeset
363 #ifdef PNG_WRITE_TEXT_SUPPORTED
Ritor1
parents:
diff changeset
364 int i; /* local index variable */
Ritor1
parents:
diff changeset
365 #endif
Ritor1
parents:
diff changeset
366 #ifdef PNG_WRITE_tIME_SUPPORTED
Ritor1
parents:
diff changeset
367 /* Check to see if user has supplied a time chunk */
Ritor1
parents:
diff changeset
368 if ((info_ptr->valid & PNG_INFO_tIME) &&
Ritor1
parents:
diff changeset
369 !(png_ptr->mode & PNG_WROTE_tIME))
Ritor1
parents:
diff changeset
370 png_write_tIME(png_ptr, &(info_ptr->mod_time));
Ritor1
parents:
diff changeset
371
Ritor1
parents:
diff changeset
372 #endif
Ritor1
parents:
diff changeset
373 #ifdef PNG_WRITE_TEXT_SUPPORTED
Ritor1
parents:
diff changeset
374 /* Loop through comment chunks */
Ritor1
parents:
diff changeset
375 for (i = 0; i < info_ptr->num_text; i++)
Ritor1
parents:
diff changeset
376 {
Ritor1
parents:
diff changeset
377 png_debug2(2, "Writing trailer text chunk %d, type %d", i,
Ritor1
parents:
diff changeset
378 info_ptr->text[i].compression);
Ritor1
parents:
diff changeset
379 /* An internationalized chunk? */
Ritor1
parents:
diff changeset
380 if (info_ptr->text[i].compression > 0)
Ritor1
parents:
diff changeset
381 {
Ritor1
parents:
diff changeset
382 #ifdef PNG_WRITE_iTXt_SUPPORTED
Ritor1
parents:
diff changeset
383 /* Write international chunk */
Ritor1
parents:
diff changeset
384 png_write_iTXt(png_ptr,
Ritor1
parents:
diff changeset
385 info_ptr->text[i].compression,
Ritor1
parents:
diff changeset
386 info_ptr->text[i].key,
Ritor1
parents:
diff changeset
387 info_ptr->text[i].lang,
Ritor1
parents:
diff changeset
388 info_ptr->text[i].lang_key,
Ritor1
parents:
diff changeset
389 info_ptr->text[i].text);
Ritor1
parents:
diff changeset
390 #else
Ritor1
parents:
diff changeset
391 png_warning(png_ptr, "Unable to write international text");
Ritor1
parents:
diff changeset
392 #endif
Ritor1
parents:
diff changeset
393 /* Mark this chunk as written */
Ritor1
parents:
diff changeset
394 info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;
Ritor1
parents:
diff changeset
395 }
Ritor1
parents:
diff changeset
396
Ritor1
parents:
diff changeset
397 else if (info_ptr->text[i].compression >= PNG_TEXT_COMPRESSION_zTXt)
Ritor1
parents:
diff changeset
398 {
Ritor1
parents:
diff changeset
399 #ifdef PNG_WRITE_zTXt_SUPPORTED
Ritor1
parents:
diff changeset
400 /* Write compressed chunk */
Ritor1
parents:
diff changeset
401 png_write_zTXt(png_ptr, info_ptr->text[i].key,
Ritor1
parents:
diff changeset
402 info_ptr->text[i].text, 0,
Ritor1
parents:
diff changeset
403 info_ptr->text[i].compression);
Ritor1
parents:
diff changeset
404 #else
Ritor1
parents:
diff changeset
405 png_warning(png_ptr, "Unable to write compressed text");
Ritor1
parents:
diff changeset
406 #endif
Ritor1
parents:
diff changeset
407 /* Mark this chunk as written */
Ritor1
parents:
diff changeset
408 info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR;
Ritor1
parents:
diff changeset
409 }
Ritor1
parents:
diff changeset
410
Ritor1
parents:
diff changeset
411 else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE)
Ritor1
parents:
diff changeset
412 {
Ritor1
parents:
diff changeset
413 #ifdef PNG_WRITE_tEXt_SUPPORTED
Ritor1
parents:
diff changeset
414 /* Write uncompressed chunk */
Ritor1
parents:
diff changeset
415 png_write_tEXt(png_ptr, info_ptr->text[i].key,
Ritor1
parents:
diff changeset
416 info_ptr->text[i].text, 0);
Ritor1
parents:
diff changeset
417 #else
Ritor1
parents:
diff changeset
418 png_warning(png_ptr, "Unable to write uncompressed text");
Ritor1
parents:
diff changeset
419 #endif
Ritor1
parents:
diff changeset
420
Ritor1
parents:
diff changeset
421 /* Mark this chunk as written */
Ritor1
parents:
diff changeset
422 info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;
Ritor1
parents:
diff changeset
423 }
Ritor1
parents:
diff changeset
424 }
Ritor1
parents:
diff changeset
425 #endif
Ritor1
parents:
diff changeset
426 #ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
Ritor1
parents:
diff changeset
427 write_unknown_chunks(png_ptr, info_ptr, PNG_AFTER_IDAT);
Ritor1
parents:
diff changeset
428 #endif
Ritor1
parents:
diff changeset
429 }
Ritor1
parents:
diff changeset
430
Ritor1
parents:
diff changeset
431 png_ptr->mode |= PNG_AFTER_IDAT;
Ritor1
parents:
diff changeset
432
Ritor1
parents:
diff changeset
433 /* Write end of PNG file */
Ritor1
parents:
diff changeset
434 png_write_IEND(png_ptr);
Ritor1
parents:
diff changeset
435 /* This flush, added in libpng-1.0.8, removed from libpng-1.0.9beta03,
Ritor1
parents:
diff changeset
436 * and restored again in libpng-1.2.30, may cause some applications that
Ritor1
parents:
diff changeset
437 * do not set png_ptr->output_flush_fn to crash. If your application
Ritor1
parents:
diff changeset
438 * experiences a problem, please try building libpng with
Ritor1
parents:
diff changeset
439 * PNG_WRITE_FLUSH_AFTER_IEND_SUPPORTED defined, and report the event to
Ritor1
parents:
diff changeset
440 * png-mng-implement at lists.sf.net .
Ritor1
parents:
diff changeset
441 */
Ritor1
parents:
diff changeset
442 #ifdef PNG_WRITE_FLUSH_SUPPORTED
Ritor1
parents:
diff changeset
443 # ifdef PNG_WRITE_FLUSH_AFTER_IEND_SUPPORTED
Ritor1
parents:
diff changeset
444 png_flush(png_ptr);
Ritor1
parents:
diff changeset
445 # endif
Ritor1
parents:
diff changeset
446 #endif
Ritor1
parents:
diff changeset
447 }
Ritor1
parents:
diff changeset
448
Ritor1
parents:
diff changeset
449 #ifdef PNG_CONVERT_tIME_SUPPORTED
Ritor1
parents:
diff changeset
450 void PNGAPI
Ritor1
parents:
diff changeset
451 png_convert_from_struct_tm(png_timep ptime, PNG_CONST struct tm * ttime)
Ritor1
parents:
diff changeset
452 {
Ritor1
parents:
diff changeset
453 png_debug(1, "in png_convert_from_struct_tm");
Ritor1
parents:
diff changeset
454
Ritor1
parents:
diff changeset
455 ptime->year = (png_uint_16)(1900 + ttime->tm_year);
Ritor1
parents:
diff changeset
456 ptime->month = (png_byte)(ttime->tm_mon + 1);
Ritor1
parents:
diff changeset
457 ptime->day = (png_byte)ttime->tm_mday;
Ritor1
parents:
diff changeset
458 ptime->hour = (png_byte)ttime->tm_hour;
Ritor1
parents:
diff changeset
459 ptime->minute = (png_byte)ttime->tm_min;
Ritor1
parents:
diff changeset
460 ptime->second = (png_byte)ttime->tm_sec;
Ritor1
parents:
diff changeset
461 }
Ritor1
parents:
diff changeset
462
Ritor1
parents:
diff changeset
463 void PNGAPI
Ritor1
parents:
diff changeset
464 png_convert_from_time_t(png_timep ptime, time_t ttime)
Ritor1
parents:
diff changeset
465 {
Ritor1
parents:
diff changeset
466 struct tm *tbuf;
Ritor1
parents:
diff changeset
467
Ritor1
parents:
diff changeset
468 png_debug(1, "in png_convert_from_time_t");
Ritor1
parents:
diff changeset
469
Ritor1
parents:
diff changeset
470 tbuf = gmtime(&ttime);
Ritor1
parents:
diff changeset
471 png_convert_from_struct_tm(ptime, tbuf);
Ritor1
parents:
diff changeset
472 }
Ritor1
parents:
diff changeset
473 #endif
Ritor1
parents:
diff changeset
474
Ritor1
parents:
diff changeset
475 /* Initialize png_ptr structure, and allocate any memory needed */
Ritor1
parents:
diff changeset
476 PNG_FUNCTION(png_structp,PNGAPI
Ritor1
parents:
diff changeset
477 png_create_write_struct,(png_const_charp user_png_ver, png_voidp error_ptr,
Ritor1
parents:
diff changeset
478 png_error_ptr error_fn, png_error_ptr warn_fn),PNG_ALLOCATED)
Ritor1
parents:
diff changeset
479 {
Ritor1
parents:
diff changeset
480 #ifndef PNG_USER_MEM_SUPPORTED
Ritor1
parents:
diff changeset
481 png_structrp png_ptr = png_create_png_struct(user_png_ver, error_ptr,
Ritor1
parents:
diff changeset
482 error_fn, warn_fn, NULL, NULL, NULL);
Ritor1
parents:
diff changeset
483 #else
Ritor1
parents:
diff changeset
484 return png_create_write_struct_2(user_png_ver, error_ptr, error_fn,
Ritor1
parents:
diff changeset
485 warn_fn, NULL, NULL, NULL);
Ritor1
parents:
diff changeset
486 }
Ritor1
parents:
diff changeset
487
Ritor1
parents:
diff changeset
488 /* Alternate initialize png_ptr structure, and allocate any memory needed */
Ritor1
parents:
diff changeset
489 PNG_FUNCTION(png_structp,PNGAPI
Ritor1
parents:
diff changeset
490 png_create_write_struct_2,(png_const_charp user_png_ver, png_voidp error_ptr,
Ritor1
parents:
diff changeset
491 png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr,
Ritor1
parents:
diff changeset
492 png_malloc_ptr malloc_fn, png_free_ptr free_fn),PNG_ALLOCATED)
Ritor1
parents:
diff changeset
493 {
Ritor1
parents:
diff changeset
494 png_structrp png_ptr = png_create_png_struct(user_png_ver, error_ptr,
Ritor1
parents:
diff changeset
495 error_fn, warn_fn, mem_ptr, malloc_fn, free_fn);
Ritor1
parents:
diff changeset
496 #endif /* PNG_USER_MEM_SUPPORTED */
Ritor1
parents:
diff changeset
497 if (png_ptr != NULL)
Ritor1
parents:
diff changeset
498 {
Ritor1
parents:
diff changeset
499 /* Set the zlib control values to defaults; they can be overridden by the
Ritor1
parents:
diff changeset
500 * application after the struct has been created.
Ritor1
parents:
diff changeset
501 */
Ritor1
parents:
diff changeset
502 png_ptr->zbuffer_size = PNG_ZBUF_SIZE;
Ritor1
parents:
diff changeset
503
Ritor1
parents:
diff changeset
504 /* The 'zlib_strategy' setting is irrelevant because png_default_claim in
Ritor1
parents:
diff changeset
505 * pngwutil.c defaults it according to whether or not filters will be
Ritor1
parents:
diff changeset
506 * used, and ignores this setting.
Ritor1
parents:
diff changeset
507 */
Ritor1
parents:
diff changeset
508 png_ptr->zlib_strategy = PNG_Z_DEFAULT_STRATEGY;
Ritor1
parents:
diff changeset
509 png_ptr->zlib_level = PNG_Z_DEFAULT_COMPRESSION;
Ritor1
parents:
diff changeset
510 png_ptr->zlib_mem_level = 8;
Ritor1
parents:
diff changeset
511 png_ptr->zlib_window_bits = 15;
Ritor1
parents:
diff changeset
512 png_ptr->zlib_method = 8;
Ritor1
parents:
diff changeset
513
Ritor1
parents:
diff changeset
514 #ifdef PNG_WRITE_COMPRESSED_TEXT_SUPPORTED
Ritor1
parents:
diff changeset
515 png_ptr->zlib_text_strategy = PNG_TEXT_Z_DEFAULT_STRATEGY;
Ritor1
parents:
diff changeset
516 png_ptr->zlib_text_level = PNG_TEXT_Z_DEFAULT_COMPRESSION;
Ritor1
parents:
diff changeset
517 png_ptr->zlib_text_mem_level = 8;
Ritor1
parents:
diff changeset
518 png_ptr->zlib_text_window_bits = 15;
Ritor1
parents:
diff changeset
519 png_ptr->zlib_text_method = 8;
Ritor1
parents:
diff changeset
520 #endif /* PNG_WRITE_COMPRESSED_TEXT_SUPPORTED */
Ritor1
parents:
diff changeset
521
Ritor1
parents:
diff changeset
522 /* This is a highly dubious configuration option; by default it is off,
Ritor1
parents:
diff changeset
523 * but it may be appropriate for private builds that are testing
Ritor1
parents:
diff changeset
524 * extensions not conformant to the current specification, or of
Ritor1
parents:
diff changeset
525 * applications that must not fail to write at all costs!
Ritor1
parents:
diff changeset
526 */
Ritor1
parents:
diff changeset
527 #ifdef PNG_BENIGN_WRITE_ERRORS_SUPPORTED
Ritor1
parents:
diff changeset
528 png_ptr->flags |= PNG_FLAG_BENIGN_ERRORS_WARN;
Ritor1
parents:
diff changeset
529 /* In stable builds only warn if an application error can be completely
Ritor1
parents:
diff changeset
530 * handled.
Ritor1
parents:
diff changeset
531 */
Ritor1
parents:
diff changeset
532 #endif
Ritor1
parents:
diff changeset
533
Ritor1
parents:
diff changeset
534 /* App warnings are warnings in release (or release candidate) builds but
Ritor1
parents:
diff changeset
535 * are errors during development.
Ritor1
parents:
diff changeset
536 */
Ritor1
parents:
diff changeset
537 #if PNG_LIBPNG_BUILD_BASE_TYPE >= PNG_LIBPNG_BUILD_RC
Ritor1
parents:
diff changeset
538 png_ptr->flags |= PNG_FLAG_APP_WARNINGS_WARN;
Ritor1
parents:
diff changeset
539 #endif
Ritor1
parents:
diff changeset
540
Ritor1
parents:
diff changeset
541 /* TODO: delay this, it can be done in png_init_io() (if the app doesn't
Ritor1
parents:
diff changeset
542 * do it itself) avoiding setting the default function if it is not
Ritor1
parents:
diff changeset
543 * required.
Ritor1
parents:
diff changeset
544 */
Ritor1
parents:
diff changeset
545 png_set_write_fn(png_ptr, NULL, NULL, NULL);
Ritor1
parents:
diff changeset
546 }
Ritor1
parents:
diff changeset
547
Ritor1
parents:
diff changeset
548 return png_ptr;
Ritor1
parents:
diff changeset
549 }
Ritor1
parents:
diff changeset
550
Ritor1
parents:
diff changeset
551
Ritor1
parents:
diff changeset
552 /* Write a few rows of image data. If the image is interlaced,
Ritor1
parents:
diff changeset
553 * either you will have to write the 7 sub images, or, if you
Ritor1
parents:
diff changeset
554 * have called png_set_interlace_handling(), you will have to
Ritor1
parents:
diff changeset
555 * "write" the image seven times.
Ritor1
parents:
diff changeset
556 */
Ritor1
parents:
diff changeset
557 void PNGAPI
Ritor1
parents:
diff changeset
558 png_write_rows(png_structrp png_ptr, png_bytepp row,
Ritor1
parents:
diff changeset
559 png_uint_32 num_rows)
Ritor1
parents:
diff changeset
560 {
Ritor1
parents:
diff changeset
561 png_uint_32 i; /* row counter */
Ritor1
parents:
diff changeset
562 png_bytepp rp; /* row pointer */
Ritor1
parents:
diff changeset
563
Ritor1
parents:
diff changeset
564 png_debug(1, "in png_write_rows");
Ritor1
parents:
diff changeset
565
Ritor1
parents:
diff changeset
566 if (png_ptr == NULL)
Ritor1
parents:
diff changeset
567 return;
Ritor1
parents:
diff changeset
568
Ritor1
parents:
diff changeset
569 /* Loop through the rows */
Ritor1
parents:
diff changeset
570 for (i = 0, rp = row; i < num_rows; i++, rp++)
Ritor1
parents:
diff changeset
571 {
Ritor1
parents:
diff changeset
572 png_write_row(png_ptr, *rp);
Ritor1
parents:
diff changeset
573 }
Ritor1
parents:
diff changeset
574 }
Ritor1
parents:
diff changeset
575
Ritor1
parents:
diff changeset
576 /* Write the image. You only need to call this function once, even
Ritor1
parents:
diff changeset
577 * if you are writing an interlaced image.
Ritor1
parents:
diff changeset
578 */
Ritor1
parents:
diff changeset
579 void PNGAPI
Ritor1
parents:
diff changeset
580 png_write_image(png_structrp png_ptr, png_bytepp image)
Ritor1
parents:
diff changeset
581 {
Ritor1
parents:
diff changeset
582 png_uint_32 i; /* row index */
Ritor1
parents:
diff changeset
583 int pass, num_pass; /* pass variables */
Ritor1
parents:
diff changeset
584 png_bytepp rp; /* points to current row */
Ritor1
parents:
diff changeset
585
Ritor1
parents:
diff changeset
586 if (png_ptr == NULL)
Ritor1
parents:
diff changeset
587 return;
Ritor1
parents:
diff changeset
588
Ritor1
parents:
diff changeset
589 png_debug(1, "in png_write_image");
Ritor1
parents:
diff changeset
590
Ritor1
parents:
diff changeset
591 #ifdef PNG_WRITE_INTERLACING_SUPPORTED
Ritor1
parents:
diff changeset
592 /* Initialize interlace handling. If image is not interlaced,
Ritor1
parents:
diff changeset
593 * this will set pass to 1
Ritor1
parents:
diff changeset
594 */
Ritor1
parents:
diff changeset
595 num_pass = png_set_interlace_handling(png_ptr);
Ritor1
parents:
diff changeset
596 #else
Ritor1
parents:
diff changeset
597 num_pass = 1;
Ritor1
parents:
diff changeset
598 #endif
Ritor1
parents:
diff changeset
599 /* Loop through passes */
Ritor1
parents:
diff changeset
600 for (pass = 0; pass < num_pass; pass++)
Ritor1
parents:
diff changeset
601 {
Ritor1
parents:
diff changeset
602 /* Loop through image */
Ritor1
parents:
diff changeset
603 for (i = 0, rp = image; i < png_ptr->height; i++, rp++)
Ritor1
parents:
diff changeset
604 {
Ritor1
parents:
diff changeset
605 png_write_row(png_ptr, *rp);
Ritor1
parents:
diff changeset
606 }
Ritor1
parents:
diff changeset
607 }
Ritor1
parents:
diff changeset
608 }
Ritor1
parents:
diff changeset
609
Ritor1
parents:
diff changeset
610 #ifdef PNG_MNG_FEATURES_SUPPORTED
Ritor1
parents:
diff changeset
611 /* Performs intrapixel differencing */
Ritor1
parents:
diff changeset
612 static void
Ritor1
parents:
diff changeset
613 png_do_write_intrapixel(png_row_infop row_info, png_bytep row)
Ritor1
parents:
diff changeset
614 {
Ritor1
parents:
diff changeset
615 png_debug(1, "in png_do_write_intrapixel");
Ritor1
parents:
diff changeset
616
Ritor1
parents:
diff changeset
617 if ((row_info->color_type & PNG_COLOR_MASK_COLOR))
Ritor1
parents:
diff changeset
618 {
Ritor1
parents:
diff changeset
619 int bytes_per_pixel;
Ritor1
parents:
diff changeset
620 png_uint_32 row_width = row_info->width;
Ritor1
parents:
diff changeset
621 if (row_info->bit_depth == 8)
Ritor1
parents:
diff changeset
622 {
Ritor1
parents:
diff changeset
623 png_bytep rp;
Ritor1
parents:
diff changeset
624 png_uint_32 i;
Ritor1
parents:
diff changeset
625
Ritor1
parents:
diff changeset
626 if (row_info->color_type == PNG_COLOR_TYPE_RGB)
Ritor1
parents:
diff changeset
627 bytes_per_pixel = 3;
Ritor1
parents:
diff changeset
628
Ritor1
parents:
diff changeset
629 else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
Ritor1
parents:
diff changeset
630 bytes_per_pixel = 4;
Ritor1
parents:
diff changeset
631
Ritor1
parents:
diff changeset
632 else
Ritor1
parents:
diff changeset
633 return;
Ritor1
parents:
diff changeset
634
Ritor1
parents:
diff changeset
635 for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel)
Ritor1
parents:
diff changeset
636 {
Ritor1
parents:
diff changeset
637 *(rp) = (png_byte)((*rp - *(rp + 1)) & 0xff);
Ritor1
parents:
diff changeset
638 *(rp + 2) = (png_byte)((*(rp + 2) - *(rp + 1)) & 0xff);
Ritor1
parents:
diff changeset
639 }
Ritor1
parents:
diff changeset
640 }
Ritor1
parents:
diff changeset
641
Ritor1
parents:
diff changeset
642 #ifdef PNG_WRITE_16BIT_SUPPORTED
Ritor1
parents:
diff changeset
643 else if (row_info->bit_depth == 16)
Ritor1
parents:
diff changeset
644 {
Ritor1
parents:
diff changeset
645 png_bytep rp;
Ritor1
parents:
diff changeset
646 png_uint_32 i;
Ritor1
parents:
diff changeset
647
Ritor1
parents:
diff changeset
648 if (row_info->color_type == PNG_COLOR_TYPE_RGB)
Ritor1
parents:
diff changeset
649 bytes_per_pixel = 6;
Ritor1
parents:
diff changeset
650
Ritor1
parents:
diff changeset
651 else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
Ritor1
parents:
diff changeset
652 bytes_per_pixel = 8;
Ritor1
parents:
diff changeset
653
Ritor1
parents:
diff changeset
654 else
Ritor1
parents:
diff changeset
655 return;
Ritor1
parents:
diff changeset
656
Ritor1
parents:
diff changeset
657 for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel)
Ritor1
parents:
diff changeset
658 {
Ritor1
parents:
diff changeset
659 png_uint_32 s0 = (*(rp ) << 8) | *(rp + 1);
Ritor1
parents:
diff changeset
660 png_uint_32 s1 = (*(rp + 2) << 8) | *(rp + 3);
Ritor1
parents:
diff changeset
661 png_uint_32 s2 = (*(rp + 4) << 8) | *(rp + 5);
Ritor1
parents:
diff changeset
662 png_uint_32 red = (png_uint_32)((s0 - s1) & 0xffffL);
Ritor1
parents:
diff changeset
663 png_uint_32 blue = (png_uint_32)((s2 - s1) & 0xffffL);
Ritor1
parents:
diff changeset
664 *(rp ) = (png_byte)((red >> 8) & 0xff);
Ritor1
parents:
diff changeset
665 *(rp + 1) = (png_byte)(red & 0xff);
Ritor1
parents:
diff changeset
666 *(rp + 4) = (png_byte)((blue >> 8) & 0xff);
Ritor1
parents:
diff changeset
667 *(rp + 5) = (png_byte)(blue & 0xff);
Ritor1
parents:
diff changeset
668 }
Ritor1
parents:
diff changeset
669 }
Ritor1
parents:
diff changeset
670 #endif /* PNG_WRITE_16BIT_SUPPORTED */
Ritor1
parents:
diff changeset
671 }
Ritor1
parents:
diff changeset
672 }
Ritor1
parents:
diff changeset
673 #endif /* PNG_MNG_FEATURES_SUPPORTED */
Ritor1
parents:
diff changeset
674
Ritor1
parents:
diff changeset
675 /* Called by user to write a row of image data */
Ritor1
parents:
diff changeset
676 void PNGAPI
Ritor1
parents:
diff changeset
677 png_write_row(png_structrp png_ptr, png_const_bytep row)
Ritor1
parents:
diff changeset
678 {
Ritor1
parents:
diff changeset
679 /* 1.5.6: moved from png_struct to be a local structure: */
Ritor1
parents:
diff changeset
680 png_row_info row_info;
Ritor1
parents:
diff changeset
681
Ritor1
parents:
diff changeset
682 if (png_ptr == NULL)
Ritor1
parents:
diff changeset
683 return;
Ritor1
parents:
diff changeset
684
Ritor1
parents:
diff changeset
685 png_debug2(1, "in png_write_row (row %u, pass %d)",
Ritor1
parents:
diff changeset
686 png_ptr->row_number, png_ptr->pass);
Ritor1
parents:
diff changeset
687
Ritor1
parents:
diff changeset
688 /* Initialize transformations and other stuff if first time */
Ritor1
parents:
diff changeset
689 if (png_ptr->row_number == 0 && png_ptr->pass == 0)
Ritor1
parents:
diff changeset
690 {
Ritor1
parents:
diff changeset
691 /* Make sure we wrote the header info */
Ritor1
parents:
diff changeset
692 if (!(png_ptr->mode & PNG_WROTE_INFO_BEFORE_PLTE))
Ritor1
parents:
diff changeset
693 png_error(png_ptr,
Ritor1
parents:
diff changeset
694 "png_write_info was never called before png_write_row");
Ritor1
parents:
diff changeset
695
Ritor1
parents:
diff changeset
696 /* Check for transforms that have been set but were defined out */
Ritor1
parents:
diff changeset
697 #if !defined(PNG_WRITE_INVERT_SUPPORTED) && defined(PNG_READ_INVERT_SUPPORTED)
Ritor1
parents:
diff changeset
698 if (png_ptr->transformations & PNG_INVERT_MONO)
Ritor1
parents:
diff changeset
699 png_warning(png_ptr, "PNG_WRITE_INVERT_SUPPORTED is not defined");
Ritor1
parents:
diff changeset
700 #endif
Ritor1
parents:
diff changeset
701
Ritor1
parents:
diff changeset
702 #if !defined(PNG_WRITE_FILLER_SUPPORTED) && defined(PNG_READ_FILLER_SUPPORTED)
Ritor1
parents:
diff changeset
703 if (png_ptr->transformations & PNG_FILLER)
Ritor1
parents:
diff changeset
704 png_warning(png_ptr, "PNG_WRITE_FILLER_SUPPORTED is not defined");
Ritor1
parents:
diff changeset
705 #endif
Ritor1
parents:
diff changeset
706 #if !defined(PNG_WRITE_PACKSWAP_SUPPORTED) && \
Ritor1
parents:
diff changeset
707 defined(PNG_READ_PACKSWAP_SUPPORTED)
Ritor1
parents:
diff changeset
708 if (png_ptr->transformations & PNG_PACKSWAP)
Ritor1
parents:
diff changeset
709 png_warning(png_ptr,
Ritor1
parents:
diff changeset
710 "PNG_WRITE_PACKSWAP_SUPPORTED is not defined");
Ritor1
parents:
diff changeset
711 #endif
Ritor1
parents:
diff changeset
712
Ritor1
parents:
diff changeset
713 #if !defined(PNG_WRITE_PACK_SUPPORTED) && defined(PNG_READ_PACK_SUPPORTED)
Ritor1
parents:
diff changeset
714 if (png_ptr->transformations & PNG_PACK)
Ritor1
parents:
diff changeset
715 png_warning(png_ptr, "PNG_WRITE_PACK_SUPPORTED is not defined");
Ritor1
parents:
diff changeset
716 #endif
Ritor1
parents:
diff changeset
717
Ritor1
parents:
diff changeset
718 #if !defined(PNG_WRITE_SHIFT_SUPPORTED) && defined(PNG_READ_SHIFT_SUPPORTED)
Ritor1
parents:
diff changeset
719 if (png_ptr->transformations & PNG_SHIFT)
Ritor1
parents:
diff changeset
720 png_warning(png_ptr, "PNG_WRITE_SHIFT_SUPPORTED is not defined");
Ritor1
parents:
diff changeset
721 #endif
Ritor1
parents:
diff changeset
722
Ritor1
parents:
diff changeset
723 #if !defined(PNG_WRITE_BGR_SUPPORTED) && defined(PNG_READ_BGR_SUPPORTED)
Ritor1
parents:
diff changeset
724 if (png_ptr->transformations & PNG_BGR)
Ritor1
parents:
diff changeset
725 png_warning(png_ptr, "PNG_WRITE_BGR_SUPPORTED is not defined");
Ritor1
parents:
diff changeset
726 #endif
Ritor1
parents:
diff changeset
727
Ritor1
parents:
diff changeset
728 #if !defined(PNG_WRITE_SWAP_SUPPORTED) && defined(PNG_READ_SWAP_SUPPORTED)
Ritor1
parents:
diff changeset
729 if (png_ptr->transformations & PNG_SWAP_BYTES)
Ritor1
parents:
diff changeset
730 png_warning(png_ptr, "PNG_WRITE_SWAP_SUPPORTED is not defined");
Ritor1
parents:
diff changeset
731 #endif
Ritor1
parents:
diff changeset
732
Ritor1
parents:
diff changeset
733 png_write_start_row(png_ptr);
Ritor1
parents:
diff changeset
734 }
Ritor1
parents:
diff changeset
735
Ritor1
parents:
diff changeset
736 #ifdef PNG_WRITE_INTERLACING_SUPPORTED
Ritor1
parents:
diff changeset
737 /* If interlaced and not interested in row, return */
Ritor1
parents:
diff changeset
738 if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE))
Ritor1
parents:
diff changeset
739 {
Ritor1
parents:
diff changeset
740 switch (png_ptr->pass)
Ritor1
parents:
diff changeset
741 {
Ritor1
parents:
diff changeset
742 case 0:
Ritor1
parents:
diff changeset
743 if (png_ptr->row_number & 0x07)
Ritor1
parents:
diff changeset
744 {
Ritor1
parents:
diff changeset
745 png_write_finish_row(png_ptr);
Ritor1
parents:
diff changeset
746 return;
Ritor1
parents:
diff changeset
747 }
Ritor1
parents:
diff changeset
748 break;
Ritor1
parents:
diff changeset
749
Ritor1
parents:
diff changeset
750 case 1:
Ritor1
parents:
diff changeset
751 if ((png_ptr->row_number & 0x07) || png_ptr->width < 5)
Ritor1
parents:
diff changeset
752 {
Ritor1
parents:
diff changeset
753 png_write_finish_row(png_ptr);
Ritor1
parents:
diff changeset
754 return;
Ritor1
parents:
diff changeset
755 }
Ritor1
parents:
diff changeset
756 break;
Ritor1
parents:
diff changeset
757
Ritor1
parents:
diff changeset
758 case 2:
Ritor1
parents:
diff changeset
759 if ((png_ptr->row_number & 0x07) != 4)
Ritor1
parents:
diff changeset
760 {
Ritor1
parents:
diff changeset
761 png_write_finish_row(png_ptr);
Ritor1
parents:
diff changeset
762 return;
Ritor1
parents:
diff changeset
763 }
Ritor1
parents:
diff changeset
764 break;
Ritor1
parents:
diff changeset
765
Ritor1
parents:
diff changeset
766 case 3:
Ritor1
parents:
diff changeset
767 if ((png_ptr->row_number & 0x03) || png_ptr->width < 3)
Ritor1
parents:
diff changeset
768 {
Ritor1
parents:
diff changeset
769 png_write_finish_row(png_ptr);
Ritor1
parents:
diff changeset
770 return;
Ritor1
parents:
diff changeset
771 }
Ritor1
parents:
diff changeset
772 break;
Ritor1
parents:
diff changeset
773
Ritor1
parents:
diff changeset
774 case 4:
Ritor1
parents:
diff changeset
775 if ((png_ptr->row_number & 0x03) != 2)
Ritor1
parents:
diff changeset
776 {
Ritor1
parents:
diff changeset
777 png_write_finish_row(png_ptr);
Ritor1
parents:
diff changeset
778 return;
Ritor1
parents:
diff changeset
779 }
Ritor1
parents:
diff changeset
780 break;
Ritor1
parents:
diff changeset
781
Ritor1
parents:
diff changeset
782 case 5:
Ritor1
parents:
diff changeset
783 if ((png_ptr->row_number & 0x01) || png_ptr->width < 2)
Ritor1
parents:
diff changeset
784 {
Ritor1
parents:
diff changeset
785 png_write_finish_row(png_ptr);
Ritor1
parents:
diff changeset
786 return;
Ritor1
parents:
diff changeset
787 }
Ritor1
parents:
diff changeset
788 break;
Ritor1
parents:
diff changeset
789
Ritor1
parents:
diff changeset
790 case 6:
Ritor1
parents:
diff changeset
791 if (!(png_ptr->row_number & 0x01))
Ritor1
parents:
diff changeset
792 {
Ritor1
parents:
diff changeset
793 png_write_finish_row(png_ptr);
Ritor1
parents:
diff changeset
794 return;
Ritor1
parents:
diff changeset
795 }
Ritor1
parents:
diff changeset
796 break;
Ritor1
parents:
diff changeset
797
Ritor1
parents:
diff changeset
798 default: /* error: ignore it */
Ritor1
parents:
diff changeset
799 break;
Ritor1
parents:
diff changeset
800 }
Ritor1
parents:
diff changeset
801 }
Ritor1
parents:
diff changeset
802 #endif
Ritor1
parents:
diff changeset
803
Ritor1
parents:
diff changeset
804 /* Set up row info for transformations */
Ritor1
parents:
diff changeset
805 row_info.color_type = png_ptr->color_type;
Ritor1
parents:
diff changeset
806 row_info.width = png_ptr->usr_width;
Ritor1
parents:
diff changeset
807 row_info.channels = png_ptr->usr_channels;
Ritor1
parents:
diff changeset
808 row_info.bit_depth = png_ptr->usr_bit_depth;
Ritor1
parents:
diff changeset
809 row_info.pixel_depth = (png_byte)(row_info.bit_depth * row_info.channels);
Ritor1
parents:
diff changeset
810 row_info.rowbytes = PNG_ROWBYTES(row_info.pixel_depth, row_info.width);
Ritor1
parents:
diff changeset
811
Ritor1
parents:
diff changeset
812 png_debug1(3, "row_info->color_type = %d", row_info.color_type);
Ritor1
parents:
diff changeset
813 png_debug1(3, "row_info->width = %u", row_info.width);
Ritor1
parents:
diff changeset
814 png_debug1(3, "row_info->channels = %d", row_info.channels);
Ritor1
parents:
diff changeset
815 png_debug1(3, "row_info->bit_depth = %d", row_info.bit_depth);
Ritor1
parents:
diff changeset
816 png_debug1(3, "row_info->pixel_depth = %d", row_info.pixel_depth);
Ritor1
parents:
diff changeset
817 png_debug1(3, "row_info->rowbytes = %lu", (unsigned long)row_info.rowbytes);
Ritor1
parents:
diff changeset
818
Ritor1
parents:
diff changeset
819 /* Copy user's row into buffer, leaving room for filter byte. */
Ritor1
parents:
diff changeset
820 memcpy(png_ptr->row_buf + 1, row, row_info.rowbytes);
Ritor1
parents:
diff changeset
821
Ritor1
parents:
diff changeset
822 #ifdef PNG_WRITE_INTERLACING_SUPPORTED
Ritor1
parents:
diff changeset
823 /* Handle interlacing */
Ritor1
parents:
diff changeset
824 if (png_ptr->interlaced && png_ptr->pass < 6 &&
Ritor1
parents:
diff changeset
825 (png_ptr->transformations & PNG_INTERLACE))
Ritor1
parents:
diff changeset
826 {
Ritor1
parents:
diff changeset
827 png_do_write_interlace(&row_info, png_ptr->row_buf + 1, png_ptr->pass);
Ritor1
parents:
diff changeset
828 /* This should always get caught above, but still ... */
Ritor1
parents:
diff changeset
829 if (!(row_info.width))
Ritor1
parents:
diff changeset
830 {
Ritor1
parents:
diff changeset
831 png_write_finish_row(png_ptr);
Ritor1
parents:
diff changeset
832 return;
Ritor1
parents:
diff changeset
833 }
Ritor1
parents:
diff changeset
834 }
Ritor1
parents:
diff changeset
835 #endif
Ritor1
parents:
diff changeset
836
Ritor1
parents:
diff changeset
837 #ifdef PNG_WRITE_TRANSFORMS_SUPPORTED
Ritor1
parents:
diff changeset
838 /* Handle other transformations */
Ritor1
parents:
diff changeset
839 if (png_ptr->transformations)
Ritor1
parents:
diff changeset
840 png_do_write_transformations(png_ptr, &row_info);
Ritor1
parents:
diff changeset
841 #endif
Ritor1
parents:
diff changeset
842
Ritor1
parents:
diff changeset
843 /* At this point the row_info pixel depth must match the 'transformed' depth,
Ritor1
parents:
diff changeset
844 * which is also the output depth.
Ritor1
parents:
diff changeset
845 */
Ritor1
parents:
diff changeset
846 if (row_info.pixel_depth != png_ptr->pixel_depth ||
Ritor1
parents:
diff changeset
847 row_info.pixel_depth != png_ptr->transformed_pixel_depth)
Ritor1
parents:
diff changeset
848 png_error(png_ptr, "internal write transform logic error");
Ritor1
parents:
diff changeset
849
Ritor1
parents:
diff changeset
850 #ifdef PNG_MNG_FEATURES_SUPPORTED
Ritor1
parents:
diff changeset
851 /* Write filter_method 64 (intrapixel differencing) only if
Ritor1
parents:
diff changeset
852 * 1. Libpng was compiled with PNG_MNG_FEATURES_SUPPORTED and
Ritor1
parents:
diff changeset
853 * 2. Libpng did not write a PNG signature (this filter_method is only
Ritor1
parents:
diff changeset
854 * used in PNG datastreams that are embedded in MNG datastreams) and
Ritor1
parents:
diff changeset
855 * 3. The application called png_permit_mng_features with a mask that
Ritor1
parents:
diff changeset
856 * included PNG_FLAG_MNG_FILTER_64 and
Ritor1
parents:
diff changeset
857 * 4. The filter_method is 64 and
Ritor1
parents:
diff changeset
858 * 5. The color_type is RGB or RGBA
Ritor1
parents:
diff changeset
859 */
Ritor1
parents:
diff changeset
860 if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) &&
Ritor1
parents:
diff changeset
861 (png_ptr->filter_type == PNG_INTRAPIXEL_DIFFERENCING))
Ritor1
parents:
diff changeset
862 {
Ritor1
parents:
diff changeset
863 /* Intrapixel differencing */
Ritor1
parents:
diff changeset
864 png_do_write_intrapixel(&row_info, png_ptr->row_buf + 1);
Ritor1
parents:
diff changeset
865 }
Ritor1
parents:
diff changeset
866 #endif
Ritor1
parents:
diff changeset
867
Ritor1
parents:
diff changeset
868 /* Added at libpng-1.5.10 */
Ritor1
parents:
diff changeset
869 #ifdef PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED
Ritor1
parents:
diff changeset
870 /* Check for out-of-range palette index */
Ritor1
parents:
diff changeset
871 if (row_info.color_type == PNG_COLOR_TYPE_PALETTE &&
Ritor1
parents:
diff changeset
872 png_ptr->num_palette_max >= 0)
Ritor1
parents:
diff changeset
873 png_do_check_palette_indexes(png_ptr, &row_info);
Ritor1
parents:
diff changeset
874 #endif
Ritor1
parents:
diff changeset
875
Ritor1
parents:
diff changeset
876 /* Find a filter if necessary, filter the row and write it out. */
Ritor1
parents:
diff changeset
877 png_write_find_filter(png_ptr, &row_info);
Ritor1
parents:
diff changeset
878
Ritor1
parents:
diff changeset
879 if (png_ptr->write_row_fn != NULL)
Ritor1
parents:
diff changeset
880 (*(png_ptr->write_row_fn))(png_ptr, png_ptr->row_number, png_ptr->pass);
Ritor1
parents:
diff changeset
881 }
Ritor1
parents:
diff changeset
882
Ritor1
parents:
diff changeset
883 #ifdef PNG_WRITE_FLUSH_SUPPORTED
Ritor1
parents:
diff changeset
884 /* Set the automatic flush interval or 0 to turn flushing off */
Ritor1
parents:
diff changeset
885 void PNGAPI
Ritor1
parents:
diff changeset
886 png_set_flush(png_structrp png_ptr, int nrows)
Ritor1
parents:
diff changeset
887 {
Ritor1
parents:
diff changeset
888 png_debug(1, "in png_set_flush");
Ritor1
parents:
diff changeset
889
Ritor1
parents:
diff changeset
890 if (png_ptr == NULL)
Ritor1
parents:
diff changeset
891 return;
Ritor1
parents:
diff changeset
892
Ritor1
parents:
diff changeset
893 png_ptr->flush_dist = (nrows < 0 ? 0 : nrows);
Ritor1
parents:
diff changeset
894 }
Ritor1
parents:
diff changeset
895
Ritor1
parents:
diff changeset
896 /* Flush the current output buffers now */
Ritor1
parents:
diff changeset
897 void PNGAPI
Ritor1
parents:
diff changeset
898 png_write_flush(png_structrp png_ptr)
Ritor1
parents:
diff changeset
899 {
Ritor1
parents:
diff changeset
900 png_debug(1, "in png_write_flush");
Ritor1
parents:
diff changeset
901
Ritor1
parents:
diff changeset
902 if (png_ptr == NULL)
Ritor1
parents:
diff changeset
903 return;
Ritor1
parents:
diff changeset
904
Ritor1
parents:
diff changeset
905 /* We have already written out all of the data */
Ritor1
parents:
diff changeset
906 if (png_ptr->row_number >= png_ptr->num_rows)
Ritor1
parents:
diff changeset
907 return;
Ritor1
parents:
diff changeset
908
Ritor1
parents:
diff changeset
909 png_compress_IDAT(png_ptr, NULL, 0, Z_SYNC_FLUSH);
Ritor1
parents:
diff changeset
910 png_ptr->flush_rows = 0;
Ritor1
parents:
diff changeset
911 png_flush(png_ptr);
Ritor1
parents:
diff changeset
912 }
Ritor1
parents:
diff changeset
913 #endif /* PNG_WRITE_FLUSH_SUPPORTED */
Ritor1
parents:
diff changeset
914
Ritor1
parents:
diff changeset
915 #ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
Ritor1
parents:
diff changeset
916 static void png_reset_filter_heuristics(png_structrp png_ptr);/* forward decl */
Ritor1
parents:
diff changeset
917 #endif
Ritor1
parents:
diff changeset
918
Ritor1
parents:
diff changeset
919 /* Free any memory used in png_ptr struct without freeing the struct itself. */
Ritor1
parents:
diff changeset
920 static void
Ritor1
parents:
diff changeset
921 png_write_destroy(png_structrp png_ptr)
Ritor1
parents:
diff changeset
922 {
Ritor1
parents:
diff changeset
923 png_debug(1, "in png_write_destroy");
Ritor1
parents:
diff changeset
924
Ritor1
parents:
diff changeset
925 /* Free any memory zlib uses */
Ritor1
parents:
diff changeset
926 if (png_ptr->flags & PNG_FLAG_ZSTREAM_INITIALIZED)
Ritor1
parents:
diff changeset
927 deflateEnd(&png_ptr->zstream);
Ritor1
parents:
diff changeset
928
Ritor1
parents:
diff changeset
929 /* Free our memory. png_free checks NULL for us. */
Ritor1
parents:
diff changeset
930 png_free_buffer_list(png_ptr, &png_ptr->zbuffer_list);
Ritor1
parents:
diff changeset
931 png_free(png_ptr, png_ptr->row_buf);
Ritor1
parents:
diff changeset
932 #ifdef PNG_WRITE_FILTER_SUPPORTED
Ritor1
parents:
diff changeset
933 png_free(png_ptr, png_ptr->prev_row);
Ritor1
parents:
diff changeset
934 png_free(png_ptr, png_ptr->sub_row);
Ritor1
parents:
diff changeset
935 png_free(png_ptr, png_ptr->up_row);
Ritor1
parents:
diff changeset
936 png_free(png_ptr, png_ptr->avg_row);
Ritor1
parents:
diff changeset
937 png_free(png_ptr, png_ptr->paeth_row);
Ritor1
parents:
diff changeset
938 #endif
Ritor1
parents:
diff changeset
939
Ritor1
parents:
diff changeset
940 #ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
Ritor1
parents:
diff changeset
941 /* Use this to save a little code space, it doesn't free the filter_costs */
Ritor1
parents:
diff changeset
942 png_reset_filter_heuristics(png_ptr);
Ritor1
parents:
diff changeset
943 png_free(png_ptr, png_ptr->filter_costs);
Ritor1
parents:
diff changeset
944 png_free(png_ptr, png_ptr->inv_filter_costs);
Ritor1
parents:
diff changeset
945 #endif
Ritor1
parents:
diff changeset
946
Ritor1
parents:
diff changeset
947 #ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED
Ritor1
parents:
diff changeset
948 png_free(png_ptr, png_ptr->chunk_list);
Ritor1
parents:
diff changeset
949 #endif
Ritor1
parents:
diff changeset
950
Ritor1
parents:
diff changeset
951 /* The error handling and memory handling information is left intact at this
Ritor1
parents:
diff changeset
952 * point: the jmp_buf may still have to be freed. See png_destroy_png_struct
Ritor1
parents:
diff changeset
953 * for how this happens.
Ritor1
parents:
diff changeset
954 */
Ritor1
parents:
diff changeset
955 }
Ritor1
parents:
diff changeset
956
Ritor1
parents:
diff changeset
957 /* Free all memory used by the write.
Ritor1
parents:
diff changeset
958 * In libpng 1.6.0 this API changed quietly to no longer accept a NULL value for
Ritor1
parents:
diff changeset
959 * *png_ptr_ptr. Prior to 1.6.0 it would accept such a value and it would free
Ritor1
parents:
diff changeset
960 * the passed in info_structs but it would quietly fail to free any of the data
Ritor1
parents:
diff changeset
961 * inside them. In 1.6.0 it quietly does nothing (it has to be quiet because it
Ritor1
parents:
diff changeset
962 * has no png_ptr.)
Ritor1
parents:
diff changeset
963 */
Ritor1
parents:
diff changeset
964 void PNGAPI
Ritor1
parents:
diff changeset
965 png_destroy_write_struct(png_structpp png_ptr_ptr, png_infopp info_ptr_ptr)
Ritor1
parents:
diff changeset
966 {
Ritor1
parents:
diff changeset
967 png_debug(1, "in png_destroy_write_struct");
Ritor1
parents:
diff changeset
968
Ritor1
parents:
diff changeset
969 if (png_ptr_ptr != NULL)
Ritor1
parents:
diff changeset
970 {
Ritor1
parents:
diff changeset
971 png_structrp png_ptr = *png_ptr_ptr;
Ritor1
parents:
diff changeset
972
Ritor1
parents:
diff changeset
973 if (png_ptr != NULL) /* added in libpng 1.6.0 */
Ritor1
parents:
diff changeset
974 {
Ritor1
parents:
diff changeset
975 png_destroy_info_struct(png_ptr, info_ptr_ptr);
Ritor1
parents:
diff changeset
976
Ritor1
parents:
diff changeset
977 *png_ptr_ptr = NULL;
Ritor1
parents:
diff changeset
978 png_write_destroy(png_ptr);
Ritor1
parents:
diff changeset
979 png_destroy_png_struct(png_ptr);
Ritor1
parents:
diff changeset
980 }
Ritor1
parents:
diff changeset
981 }
Ritor1
parents:
diff changeset
982 }
Ritor1
parents:
diff changeset
983
Ritor1
parents:
diff changeset
984 /* Allow the application to select one or more row filters to use. */
Ritor1
parents:
diff changeset
985 void PNGAPI
Ritor1
parents:
diff changeset
986 png_set_filter(png_structrp png_ptr, int method, int filters)
Ritor1
parents:
diff changeset
987 {
Ritor1
parents:
diff changeset
988 png_debug(1, "in png_set_filter");
Ritor1
parents:
diff changeset
989
Ritor1
parents:
diff changeset
990 if (png_ptr == NULL)
Ritor1
parents:
diff changeset
991 return;
Ritor1
parents:
diff changeset
992
Ritor1
parents:
diff changeset
993 #ifdef PNG_MNG_FEATURES_SUPPORTED
Ritor1
parents:
diff changeset
994 if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) &&
Ritor1
parents:
diff changeset
995 (method == PNG_INTRAPIXEL_DIFFERENCING))
Ritor1
parents:
diff changeset
996 method = PNG_FILTER_TYPE_BASE;
Ritor1
parents:
diff changeset
997
Ritor1
parents:
diff changeset
998 #endif
Ritor1
parents:
diff changeset
999 if (method == PNG_FILTER_TYPE_BASE)
Ritor1
parents:
diff changeset
1000 {
Ritor1
parents:
diff changeset
1001 switch (filters & (PNG_ALL_FILTERS | 0x07))
Ritor1
parents:
diff changeset
1002 {
Ritor1
parents:
diff changeset
1003 #ifdef PNG_WRITE_FILTER_SUPPORTED
Ritor1
parents:
diff changeset
1004 case 5:
Ritor1
parents:
diff changeset
1005 case 6:
Ritor1
parents:
diff changeset
1006 case 7: png_app_error(png_ptr, "Unknown row filter for method 0");
Ritor1
parents:
diff changeset
1007 /* FALL THROUGH */
Ritor1
parents:
diff changeset
1008 #endif /* PNG_WRITE_FILTER_SUPPORTED */
Ritor1
parents:
diff changeset
1009 case PNG_FILTER_VALUE_NONE:
Ritor1
parents:
diff changeset
1010 png_ptr->do_filter = PNG_FILTER_NONE; break;
Ritor1
parents:
diff changeset
1011
Ritor1
parents:
diff changeset
1012 #ifdef PNG_WRITE_FILTER_SUPPORTED
Ritor1
parents:
diff changeset
1013 case PNG_FILTER_VALUE_SUB:
Ritor1
parents:
diff changeset
1014 png_ptr->do_filter = PNG_FILTER_SUB; break;
Ritor1
parents:
diff changeset
1015
Ritor1
parents:
diff changeset
1016 case PNG_FILTER_VALUE_UP:
Ritor1
parents:
diff changeset
1017 png_ptr->do_filter = PNG_FILTER_UP; break;
Ritor1
parents:
diff changeset
1018
Ritor1
parents:
diff changeset
1019 case PNG_FILTER_VALUE_AVG:
Ritor1
parents:
diff changeset
1020 png_ptr->do_filter = PNG_FILTER_AVG; break;
Ritor1
parents:
diff changeset
1021
Ritor1
parents:
diff changeset
1022 case PNG_FILTER_VALUE_PAETH:
Ritor1
parents:
diff changeset
1023 png_ptr->do_filter = PNG_FILTER_PAETH; break;
Ritor1
parents:
diff changeset
1024
Ritor1
parents:
diff changeset
1025 default:
Ritor1
parents:
diff changeset
1026 png_ptr->do_filter = (png_byte)filters; break;
Ritor1
parents:
diff changeset
1027 #else
Ritor1
parents:
diff changeset
1028 default:
Ritor1
parents:
diff changeset
1029 png_app_error(png_ptr, "Unknown row filter for method 0");
Ritor1
parents:
diff changeset
1030 #endif /* PNG_WRITE_FILTER_SUPPORTED */
Ritor1
parents:
diff changeset
1031 }
Ritor1
parents:
diff changeset
1032
Ritor1
parents:
diff changeset
1033 /* If we have allocated the row_buf, this means we have already started
Ritor1
parents:
diff changeset
1034 * with the image and we should have allocated all of the filter buffers
Ritor1
parents:
diff changeset
1035 * that have been selected. If prev_row isn't already allocated, then
Ritor1
parents:
diff changeset
1036 * it is too late to start using the filters that need it, since we
Ritor1
parents:
diff changeset
1037 * will be missing the data in the previous row. If an application
Ritor1
parents:
diff changeset
1038 * wants to start and stop using particular filters during compression,
Ritor1
parents:
diff changeset
1039 * it should start out with all of the filters, and then add and
Ritor1
parents:
diff changeset
1040 * remove them after the start of compression.
Ritor1
parents:
diff changeset
1041 */
Ritor1
parents:
diff changeset
1042 if (png_ptr->row_buf != NULL)
Ritor1
parents:
diff changeset
1043 {
Ritor1
parents:
diff changeset
1044 #ifdef PNG_WRITE_FILTER_SUPPORTED
Ritor1
parents:
diff changeset
1045 if ((png_ptr->do_filter & PNG_FILTER_SUB) && png_ptr->sub_row == NULL)
Ritor1
parents:
diff changeset
1046 {
Ritor1
parents:
diff changeset
1047 png_ptr->sub_row = (png_bytep)png_malloc(png_ptr,
Ritor1
parents:
diff changeset
1048 (png_ptr->rowbytes + 1));
Ritor1
parents:
diff changeset
1049 png_ptr->sub_row[0] = PNG_FILTER_VALUE_SUB;
Ritor1
parents:
diff changeset
1050 }
Ritor1
parents:
diff changeset
1051
Ritor1
parents:
diff changeset
1052 if ((png_ptr->do_filter & PNG_FILTER_UP) && png_ptr->up_row == NULL)
Ritor1
parents:
diff changeset
1053 {
Ritor1
parents:
diff changeset
1054 if (png_ptr->prev_row == NULL)
Ritor1
parents:
diff changeset
1055 {
Ritor1
parents:
diff changeset
1056 png_warning(png_ptr, "Can't add Up filter after starting");
Ritor1
parents:
diff changeset
1057 png_ptr->do_filter = (png_byte)(png_ptr->do_filter &
Ritor1
parents:
diff changeset
1058 ~PNG_FILTER_UP);
Ritor1
parents:
diff changeset
1059 }
Ritor1
parents:
diff changeset
1060
Ritor1
parents:
diff changeset
1061 else
Ritor1
parents:
diff changeset
1062 {
Ritor1
parents:
diff changeset
1063 png_ptr->up_row = (png_bytep)png_malloc(png_ptr,
Ritor1
parents:
diff changeset
1064 (png_ptr->rowbytes + 1));
Ritor1
parents:
diff changeset
1065 png_ptr->up_row[0] = PNG_FILTER_VALUE_UP;
Ritor1
parents:
diff changeset
1066 }
Ritor1
parents:
diff changeset
1067 }
Ritor1
parents:
diff changeset
1068
Ritor1
parents:
diff changeset
1069 if ((png_ptr->do_filter & PNG_FILTER_AVG) && png_ptr->avg_row == NULL)
Ritor1
parents:
diff changeset
1070 {
Ritor1
parents:
diff changeset
1071 if (png_ptr->prev_row == NULL)
Ritor1
parents:
diff changeset
1072 {
Ritor1
parents:
diff changeset
1073 png_warning(png_ptr, "Can't add Average filter after starting");
Ritor1
parents:
diff changeset
1074 png_ptr->do_filter = (png_byte)(png_ptr->do_filter &
Ritor1
parents:
diff changeset
1075 ~PNG_FILTER_AVG);
Ritor1
parents:
diff changeset
1076 }
Ritor1
parents:
diff changeset
1077
Ritor1
parents:
diff changeset
1078 else
Ritor1
parents:
diff changeset
1079 {
Ritor1
parents:
diff changeset
1080 png_ptr->avg_row = (png_bytep)png_malloc(png_ptr,
Ritor1
parents:
diff changeset
1081 (png_ptr->rowbytes + 1));
Ritor1
parents:
diff changeset
1082 png_ptr->avg_row[0] = PNG_FILTER_VALUE_AVG;
Ritor1
parents:
diff changeset
1083 }
Ritor1
parents:
diff changeset
1084 }
Ritor1
parents:
diff changeset
1085
Ritor1
parents:
diff changeset
1086 if ((png_ptr->do_filter & PNG_FILTER_PAETH) &&
Ritor1
parents:
diff changeset
1087 png_ptr->paeth_row == NULL)
Ritor1
parents:
diff changeset
1088 {
Ritor1
parents:
diff changeset
1089 if (png_ptr->prev_row == NULL)
Ritor1
parents:
diff changeset
1090 {
Ritor1
parents:
diff changeset
1091 png_warning(png_ptr, "Can't add Paeth filter after starting");
Ritor1
parents:
diff changeset
1092 png_ptr->do_filter &= (png_byte)(~PNG_FILTER_PAETH);
Ritor1
parents:
diff changeset
1093 }
Ritor1
parents:
diff changeset
1094
Ritor1
parents:
diff changeset
1095 else
Ritor1
parents:
diff changeset
1096 {
Ritor1
parents:
diff changeset
1097 png_ptr->paeth_row = (png_bytep)png_malloc(png_ptr,
Ritor1
parents:
diff changeset
1098 (png_ptr->rowbytes + 1));
Ritor1
parents:
diff changeset
1099 png_ptr->paeth_row[0] = PNG_FILTER_VALUE_PAETH;
Ritor1
parents:
diff changeset
1100 }
Ritor1
parents:
diff changeset
1101 }
Ritor1
parents:
diff changeset
1102
Ritor1
parents:
diff changeset
1103 if (png_ptr->do_filter == PNG_NO_FILTERS)
Ritor1
parents:
diff changeset
1104 #endif /* PNG_WRITE_FILTER_SUPPORTED */
Ritor1
parents:
diff changeset
1105 png_ptr->do_filter = PNG_FILTER_NONE;
Ritor1
parents:
diff changeset
1106 }
Ritor1
parents:
diff changeset
1107 }
Ritor1
parents:
diff changeset
1108 else
Ritor1
parents:
diff changeset
1109 png_error(png_ptr, "Unknown custom filter method");
Ritor1
parents:
diff changeset
1110 }
Ritor1
parents:
diff changeset
1111
Ritor1
parents:
diff changeset
1112 /* This allows us to influence the way in which libpng chooses the "best"
Ritor1
parents:
diff changeset
1113 * filter for the current scanline. While the "minimum-sum-of-absolute-
Ritor1
parents:
diff changeset
1114 * differences metric is relatively fast and effective, there is some
Ritor1
parents:
diff changeset
1115 * question as to whether it can be improved upon by trying to keep the
Ritor1
parents:
diff changeset
1116 * filtered data going to zlib more consistent, hopefully resulting in
Ritor1
parents:
diff changeset
1117 * better compression.
Ritor1
parents:
diff changeset
1118 */
Ritor1
parents:
diff changeset
1119 #ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED /* GRR 970116 */
Ritor1
parents:
diff changeset
1120 /* Convenience reset API. */
Ritor1
parents:
diff changeset
1121 static void
Ritor1
parents:
diff changeset
1122 png_reset_filter_heuristics(png_structrp png_ptr)
Ritor1
parents:
diff changeset
1123 {
Ritor1
parents:
diff changeset
1124 /* Clear out any old values in the 'weights' - this must be done because if
Ritor1
parents:
diff changeset
1125 * the app calls set_filter_heuristics multiple times with different
Ritor1
parents:
diff changeset
1126 * 'num_weights' values we would otherwise potentially have wrong sized
Ritor1
parents:
diff changeset
1127 * arrays.
Ritor1
parents:
diff changeset
1128 */
Ritor1
parents:
diff changeset
1129 png_ptr->num_prev_filters = 0;
Ritor1
parents:
diff changeset
1130 png_ptr->heuristic_method = PNG_FILTER_HEURISTIC_UNWEIGHTED;
Ritor1
parents:
diff changeset
1131 if (png_ptr->prev_filters != NULL)
Ritor1
parents:
diff changeset
1132 {
Ritor1
parents:
diff changeset
1133 png_bytep old = png_ptr->prev_filters;
Ritor1
parents:
diff changeset
1134 png_ptr->prev_filters = NULL;
Ritor1
parents:
diff changeset
1135 png_free(png_ptr, old);
Ritor1
parents:
diff changeset
1136 }
Ritor1
parents:
diff changeset
1137 if (png_ptr->filter_weights != NULL)
Ritor1
parents:
diff changeset
1138 {
Ritor1
parents:
diff changeset
1139 png_uint_16p old = png_ptr->filter_weights;
Ritor1
parents:
diff changeset
1140 png_ptr->filter_weights = NULL;
Ritor1
parents:
diff changeset
1141 png_free(png_ptr, old);
Ritor1
parents:
diff changeset
1142 }
Ritor1
parents:
diff changeset
1143
Ritor1
parents:
diff changeset
1144 if (png_ptr->inv_filter_weights != NULL)
Ritor1
parents:
diff changeset
1145 {
Ritor1
parents:
diff changeset
1146 png_uint_16p old = png_ptr->inv_filter_weights;
Ritor1
parents:
diff changeset
1147 png_ptr->inv_filter_weights = NULL;
Ritor1
parents:
diff changeset
1148 png_free(png_ptr, old);
Ritor1
parents:
diff changeset
1149 }
Ritor1
parents:
diff changeset
1150
Ritor1
parents:
diff changeset
1151 /* Leave the filter_costs - this array is fixed size. */
Ritor1
parents:
diff changeset
1152 }
Ritor1
parents:
diff changeset
1153
Ritor1
parents:
diff changeset
1154 static int
Ritor1
parents:
diff changeset
1155 png_init_filter_heuristics(png_structrp png_ptr, int heuristic_method,
Ritor1
parents:
diff changeset
1156 int num_weights)
Ritor1
parents:
diff changeset
1157 {
Ritor1
parents:
diff changeset
1158 if (png_ptr == NULL)
Ritor1
parents:
diff changeset
1159 return 0;
Ritor1
parents:
diff changeset
1160
Ritor1
parents:
diff changeset
1161 /* Clear out the arrays */
Ritor1
parents:
diff changeset
1162 png_reset_filter_heuristics(png_ptr);
Ritor1
parents:
diff changeset
1163
Ritor1
parents:
diff changeset
1164 /* Check arguments; the 'reset' function makes the correct settings for the
Ritor1
parents:
diff changeset
1165 * unweighted case, but we must handle the weight case by initializing the
Ritor1
parents:
diff changeset
1166 * arrays for the caller.
Ritor1
parents:
diff changeset
1167 */
Ritor1
parents:
diff changeset
1168 if (heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
Ritor1
parents:
diff changeset
1169 {
Ritor1
parents:
diff changeset
1170 int i;
Ritor1
parents:
diff changeset
1171
Ritor1
parents:
diff changeset
1172 if (num_weights > 0)
Ritor1
parents:
diff changeset
1173 {
Ritor1
parents:
diff changeset
1174 png_ptr->prev_filters = (png_bytep)png_malloc(png_ptr,
Ritor1
parents:
diff changeset
1175 (png_uint_32)((sizeof (png_byte)) * num_weights));
Ritor1
parents:
diff changeset
1176
Ritor1
parents:
diff changeset
1177 /* To make sure that the weighting starts out fairly */
Ritor1
parents:
diff changeset
1178 for (i = 0; i < num_weights; i++)
Ritor1
parents:
diff changeset
1179 {
Ritor1
parents:
diff changeset
1180 png_ptr->prev_filters[i] = 255;
Ritor1
parents:
diff changeset
1181 }
Ritor1
parents:
diff changeset
1182
Ritor1
parents:
diff changeset
1183 png_ptr->filter_weights = (png_uint_16p)png_malloc(png_ptr,
Ritor1
parents:
diff changeset
1184 (png_uint_32)((sizeof (png_uint_16)) * num_weights));
Ritor1
parents:
diff changeset
1185
Ritor1
parents:
diff changeset
1186 png_ptr->inv_filter_weights = (png_uint_16p)png_malloc(png_ptr,
Ritor1
parents:
diff changeset
1187 (png_uint_32)((sizeof (png_uint_16)) * num_weights));
Ritor1
parents:
diff changeset
1188
Ritor1
parents:
diff changeset
1189 for (i = 0; i < num_weights; i++)
Ritor1
parents:
diff changeset
1190 {
Ritor1
parents:
diff changeset
1191 png_ptr->inv_filter_weights[i] =
Ritor1
parents:
diff changeset
1192 png_ptr->filter_weights[i] = PNG_WEIGHT_FACTOR;
Ritor1
parents:
diff changeset
1193 }
Ritor1
parents:
diff changeset
1194
Ritor1
parents:
diff changeset
1195 /* Safe to set this now */
Ritor1
parents:
diff changeset
1196 png_ptr->num_prev_filters = (png_byte)num_weights;
Ritor1
parents:
diff changeset
1197 }
Ritor1
parents:
diff changeset
1198
Ritor1
parents:
diff changeset
1199 /* If, in the future, there are other filter methods, this would
Ritor1
parents:
diff changeset
1200 * need to be based on png_ptr->filter.
Ritor1
parents:
diff changeset
1201 */
Ritor1
parents:
diff changeset
1202 if (png_ptr->filter_costs == NULL)
Ritor1
parents:
diff changeset
1203 {
Ritor1
parents:
diff changeset
1204 png_ptr->filter_costs = (png_uint_16p)png_malloc(png_ptr,
Ritor1
parents:
diff changeset
1205 (png_uint_32)((sizeof (png_uint_16)) * PNG_FILTER_VALUE_LAST));
Ritor1
parents:
diff changeset
1206
Ritor1
parents:
diff changeset
1207 png_ptr->inv_filter_costs = (png_uint_16p)png_malloc(png_ptr,
Ritor1
parents:
diff changeset
1208 (png_uint_32)((sizeof (png_uint_16)) * PNG_FILTER_VALUE_LAST));
Ritor1
parents:
diff changeset
1209 }
Ritor1
parents:
diff changeset
1210
Ritor1
parents:
diff changeset
1211 for (i = 0; i < PNG_FILTER_VALUE_LAST; i++)
Ritor1
parents:
diff changeset
1212 {
Ritor1
parents:
diff changeset
1213 png_ptr->inv_filter_costs[i] =
Ritor1
parents:
diff changeset
1214 png_ptr->filter_costs[i] = PNG_COST_FACTOR;
Ritor1
parents:
diff changeset
1215 }
Ritor1
parents:
diff changeset
1216
Ritor1
parents:
diff changeset
1217 /* All the arrays are inited, safe to set this: */
Ritor1
parents:
diff changeset
1218 png_ptr->heuristic_method = PNG_FILTER_HEURISTIC_WEIGHTED;
Ritor1
parents:
diff changeset
1219
Ritor1
parents:
diff changeset
1220 /* Return the 'ok' code. */
Ritor1
parents:
diff changeset
1221 return 1;
Ritor1
parents:
diff changeset
1222 }
Ritor1
parents:
diff changeset
1223 else if (heuristic_method == PNG_FILTER_HEURISTIC_DEFAULT ||
Ritor1
parents:
diff changeset
1224 heuristic_method == PNG_FILTER_HEURISTIC_UNWEIGHTED)
Ritor1
parents:
diff changeset
1225 {
Ritor1
parents:
diff changeset
1226 return 1;
Ritor1
parents:
diff changeset
1227 }
Ritor1
parents:
diff changeset
1228 else
Ritor1
parents:
diff changeset
1229 {
Ritor1
parents:
diff changeset
1230 png_warning(png_ptr, "Unknown filter heuristic method");
Ritor1
parents:
diff changeset
1231 return 0;
Ritor1
parents:
diff changeset
1232 }
Ritor1
parents:
diff changeset
1233 }
Ritor1
parents:
diff changeset
1234
Ritor1
parents:
diff changeset
1235 /* Provide floating and fixed point APIs */
Ritor1
parents:
diff changeset
1236 #ifdef PNG_FLOATING_POINT_SUPPORTED
Ritor1
parents:
diff changeset
1237 void PNGAPI
Ritor1
parents:
diff changeset
1238 png_set_filter_heuristics(png_structrp png_ptr, int heuristic_method,
Ritor1
parents:
diff changeset
1239 int num_weights, png_const_doublep filter_weights,
Ritor1
parents:
diff changeset
1240 png_const_doublep filter_costs)
Ritor1
parents:
diff changeset
1241 {
Ritor1
parents:
diff changeset
1242 png_debug(1, "in png_set_filter_heuristics");
Ritor1
parents:
diff changeset
1243
Ritor1
parents:
diff changeset
1244 /* The internal API allocates all the arrays and ensures that the elements of
Ritor1
parents:
diff changeset
1245 * those arrays are set to the default value.
Ritor1
parents:
diff changeset
1246 */
Ritor1
parents:
diff changeset
1247 if (!png_init_filter_heuristics(png_ptr, heuristic_method, num_weights))
Ritor1
parents:
diff changeset
1248 return;
Ritor1
parents:
diff changeset
1249
Ritor1
parents:
diff changeset
1250 /* If using the weighted method copy in the weights. */
Ritor1
parents:
diff changeset
1251 if (heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
Ritor1
parents:
diff changeset
1252 {
Ritor1
parents:
diff changeset
1253 int i;
Ritor1
parents:
diff changeset
1254 for (i = 0; i < num_weights; i++)
Ritor1
parents:
diff changeset
1255 {
Ritor1
parents:
diff changeset
1256 if (filter_weights[i] <= 0.0)
Ritor1
parents:
diff changeset
1257 {
Ritor1
parents:
diff changeset
1258 png_ptr->inv_filter_weights[i] =
Ritor1
parents:
diff changeset
1259 png_ptr->filter_weights[i] = PNG_WEIGHT_FACTOR;
Ritor1
parents:
diff changeset
1260 }
Ritor1
parents:
diff changeset
1261
Ritor1
parents:
diff changeset
1262 else
Ritor1
parents:
diff changeset
1263 {
Ritor1
parents:
diff changeset
1264 png_ptr->inv_filter_weights[i] =
Ritor1
parents:
diff changeset
1265 (png_uint_16)(PNG_WEIGHT_FACTOR*filter_weights[i]+.5);
Ritor1
parents:
diff changeset
1266
Ritor1
parents:
diff changeset
1267 png_ptr->filter_weights[i] =
Ritor1
parents:
diff changeset
1268 (png_uint_16)(PNG_WEIGHT_FACTOR/filter_weights[i]+.5);
Ritor1
parents:
diff changeset
1269 }
Ritor1
parents:
diff changeset
1270 }
Ritor1
parents:
diff changeset
1271
Ritor1
parents:
diff changeset
1272 /* Here is where we set the relative costs of the different filters. We
Ritor1
parents:
diff changeset
1273 * should take the desired compression level into account when setting
Ritor1
parents:
diff changeset
1274 * the costs, so that Paeth, for instance, has a high relative cost at low
Ritor1
parents:
diff changeset
1275 * compression levels, while it has a lower relative cost at higher
Ritor1
parents:
diff changeset
1276 * compression settings. The filter types are in order of increasing
Ritor1
parents:
diff changeset
1277 * relative cost, so it would be possible to do this with an algorithm.
Ritor1
parents:
diff changeset
1278 */
Ritor1
parents:
diff changeset
1279 for (i = 0; i < PNG_FILTER_VALUE_LAST; i++) if (filter_costs[i] >= 1.0)
Ritor1
parents:
diff changeset
1280 {
Ritor1
parents:
diff changeset
1281 png_ptr->inv_filter_costs[i] =
Ritor1
parents:
diff changeset
1282 (png_uint_16)(PNG_COST_FACTOR / filter_costs[i] + .5);
Ritor1
parents:
diff changeset
1283
Ritor1
parents:
diff changeset
1284 png_ptr->filter_costs[i] =
Ritor1
parents:
diff changeset
1285 (png_uint_16)(PNG_COST_FACTOR * filter_costs[i] + .5);
Ritor1
parents:
diff changeset
1286 }
Ritor1
parents:
diff changeset
1287 }
Ritor1
parents:
diff changeset
1288 }
Ritor1
parents:
diff changeset
1289 #endif /* FLOATING_POINT */
Ritor1
parents:
diff changeset
1290
Ritor1
parents:
diff changeset
1291 #ifdef PNG_FIXED_POINT_SUPPORTED
Ritor1
parents:
diff changeset
1292 void PNGAPI
Ritor1
parents:
diff changeset
1293 png_set_filter_heuristics_fixed(png_structrp png_ptr, int heuristic_method,
Ritor1
parents:
diff changeset
1294 int num_weights, png_const_fixed_point_p filter_weights,
Ritor1
parents:
diff changeset
1295 png_const_fixed_point_p filter_costs)
Ritor1
parents:
diff changeset
1296 {
Ritor1
parents:
diff changeset
1297 png_debug(1, "in png_set_filter_heuristics_fixed");
Ritor1
parents:
diff changeset
1298
Ritor1
parents:
diff changeset
1299 /* The internal API allocates all the arrays and ensures that the elements of
Ritor1
parents:
diff changeset
1300 * those arrays are set to the default value.
Ritor1
parents:
diff changeset
1301 */
Ritor1
parents:
diff changeset
1302 if (!png_init_filter_heuristics(png_ptr, heuristic_method, num_weights))
Ritor1
parents:
diff changeset
1303 return;
Ritor1
parents:
diff changeset
1304
Ritor1
parents:
diff changeset
1305 /* If using the weighted method copy in the weights. */
Ritor1
parents:
diff changeset
1306 if (heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
Ritor1
parents:
diff changeset
1307 {
Ritor1
parents:
diff changeset
1308 int i;
Ritor1
parents:
diff changeset
1309 for (i = 0; i < num_weights; i++)
Ritor1
parents:
diff changeset
1310 {
Ritor1
parents:
diff changeset
1311 if (filter_weights[i] <= 0)
Ritor1
parents:
diff changeset
1312 {
Ritor1
parents:
diff changeset
1313 png_ptr->inv_filter_weights[i] =
Ritor1
parents:
diff changeset
1314 png_ptr->filter_weights[i] = PNG_WEIGHT_FACTOR;
Ritor1
parents:
diff changeset
1315 }
Ritor1
parents:
diff changeset
1316
Ritor1
parents:
diff changeset
1317 else
Ritor1
parents:
diff changeset
1318 {
Ritor1
parents:
diff changeset
1319 png_ptr->inv_filter_weights[i] = (png_uint_16)
Ritor1
parents:
diff changeset
1320 ((PNG_WEIGHT_FACTOR*filter_weights[i]+PNG_FP_HALF)/PNG_FP_1);
Ritor1
parents:
diff changeset
1321
Ritor1
parents:
diff changeset
1322 png_ptr->filter_weights[i] = (png_uint_16)((PNG_WEIGHT_FACTOR*
Ritor1
parents:
diff changeset
1323 PNG_FP_1+(filter_weights[i]/2))/filter_weights[i]);
Ritor1
parents:
diff changeset
1324 }
Ritor1
parents:
diff changeset
1325 }
Ritor1
parents:
diff changeset
1326
Ritor1
parents:
diff changeset
1327 /* Here is where we set the relative costs of the different filters. We
Ritor1
parents:
diff changeset
1328 * should take the desired compression level into account when setting
Ritor1
parents:
diff changeset
1329 * the costs, so that Paeth, for instance, has a high relative cost at low
Ritor1
parents:
diff changeset
1330 * compression levels, while it has a lower relative cost at higher
Ritor1
parents:
diff changeset
1331 * compression settings. The filter types are in order of increasing
Ritor1
parents:
diff changeset
1332 * relative cost, so it would be possible to do this with an algorithm.
Ritor1
parents:
diff changeset
1333 */
Ritor1
parents:
diff changeset
1334 for (i = 0; i < PNG_FILTER_VALUE_LAST; i++)
Ritor1
parents:
diff changeset
1335 if (filter_costs[i] >= PNG_FP_1)
Ritor1
parents:
diff changeset
1336 {
Ritor1
parents:
diff changeset
1337 png_uint_32 tmp;
Ritor1
parents:
diff changeset
1338
Ritor1
parents:
diff changeset
1339 /* Use a 32 bit unsigned temporary here because otherwise the
Ritor1
parents:
diff changeset
1340 * intermediate value will be a 32 bit *signed* integer (ANSI rules)
Ritor1
parents:
diff changeset
1341 * and this will get the wrong answer on division.
Ritor1
parents:
diff changeset
1342 */
Ritor1
parents:
diff changeset
1343 tmp = PNG_COST_FACTOR*PNG_FP_1 + (filter_costs[i]/2);
Ritor1
parents:
diff changeset
1344 tmp /= filter_costs[i];
Ritor1
parents:
diff changeset
1345
Ritor1
parents:
diff changeset
1346 png_ptr->inv_filter_costs[i] = (png_uint_16)tmp;
Ritor1
parents:
diff changeset
1347
Ritor1
parents:
diff changeset
1348 tmp = PNG_COST_FACTOR * filter_costs[i] + PNG_FP_HALF;
Ritor1
parents:
diff changeset
1349 tmp /= PNG_FP_1;
Ritor1
parents:
diff changeset
1350
Ritor1
parents:
diff changeset
1351 png_ptr->filter_costs[i] = (png_uint_16)tmp;
Ritor1
parents:
diff changeset
1352 }
Ritor1
parents:
diff changeset
1353 }
Ritor1
parents:
diff changeset
1354 }
Ritor1
parents:
diff changeset
1355 #endif /* FIXED_POINT */
Ritor1
parents:
diff changeset
1356 #endif /* PNG_WRITE_WEIGHTED_FILTER_SUPPORTED */
Ritor1
parents:
diff changeset
1357
Ritor1
parents:
diff changeset
1358 void PNGAPI
Ritor1
parents:
diff changeset
1359 png_set_compression_level(png_structrp png_ptr, int level)
Ritor1
parents:
diff changeset
1360 {
Ritor1
parents:
diff changeset
1361 png_debug(1, "in png_set_compression_level");
Ritor1
parents:
diff changeset
1362
Ritor1
parents:
diff changeset
1363 if (png_ptr == NULL)
Ritor1
parents:
diff changeset
1364 return;
Ritor1
parents:
diff changeset
1365
Ritor1
parents:
diff changeset
1366 png_ptr->zlib_level = level;
Ritor1
parents:
diff changeset
1367 }
Ritor1
parents:
diff changeset
1368
Ritor1
parents:
diff changeset
1369 void PNGAPI
Ritor1
parents:
diff changeset
1370 png_set_compression_mem_level(png_structrp png_ptr, int mem_level)
Ritor1
parents:
diff changeset
1371 {
Ritor1
parents:
diff changeset
1372 png_debug(1, "in png_set_compression_mem_level");
Ritor1
parents:
diff changeset
1373
Ritor1
parents:
diff changeset
1374 if (png_ptr == NULL)
Ritor1
parents:
diff changeset
1375 return;
Ritor1
parents:
diff changeset
1376
Ritor1
parents:
diff changeset
1377 png_ptr->zlib_mem_level = mem_level;
Ritor1
parents:
diff changeset
1378 }
Ritor1
parents:
diff changeset
1379
Ritor1
parents:
diff changeset
1380 void PNGAPI
Ritor1
parents:
diff changeset
1381 png_set_compression_strategy(png_structrp png_ptr, int strategy)
Ritor1
parents:
diff changeset
1382 {
Ritor1
parents:
diff changeset
1383 png_debug(1, "in png_set_compression_strategy");
Ritor1
parents:
diff changeset
1384
Ritor1
parents:
diff changeset
1385 if (png_ptr == NULL)
Ritor1
parents:
diff changeset
1386 return;
Ritor1
parents:
diff changeset
1387
Ritor1
parents:
diff changeset
1388 /* The flag setting here prevents the libpng dynamic selection of strategy.
Ritor1
parents:
diff changeset
1389 */
Ritor1
parents:
diff changeset
1390 png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_STRATEGY;
Ritor1
parents:
diff changeset
1391 png_ptr->zlib_strategy = strategy;
Ritor1
parents:
diff changeset
1392 }
Ritor1
parents:
diff changeset
1393
Ritor1
parents:
diff changeset
1394 /* If PNG_WRITE_OPTIMIZE_CMF_SUPPORTED is defined, libpng will use a
Ritor1
parents:
diff changeset
1395 * smaller value of window_bits if it can do so safely.
Ritor1
parents:
diff changeset
1396 */
Ritor1
parents:
diff changeset
1397 void PNGAPI
Ritor1
parents:
diff changeset
1398 png_set_compression_window_bits(png_structrp png_ptr, int window_bits)
Ritor1
parents:
diff changeset
1399 {
Ritor1
parents:
diff changeset
1400 if (png_ptr == NULL)
Ritor1
parents:
diff changeset
1401 return;
Ritor1
parents:
diff changeset
1402
Ritor1
parents:
diff changeset
1403 /* Prior to 1.6.0 this would warn but then set the window_bits value, this
Ritor1
parents:
diff changeset
1404 * meant that negative window bits values could be selected which would cause
Ritor1
parents:
diff changeset
1405 * libpng to write a non-standard PNG file with raw deflate or gzip
Ritor1
parents:
diff changeset
1406 * compressed IDAT or ancillary chunks. Such files can be read and there is
Ritor1
parents:
diff changeset
1407 * no warning on read, so this seems like a very bad idea.
Ritor1
parents:
diff changeset
1408 */
Ritor1
parents:
diff changeset
1409 if (window_bits > 15)
Ritor1
parents:
diff changeset
1410 {
Ritor1
parents:
diff changeset
1411 png_warning(png_ptr, "Only compression windows <= 32k supported by PNG");
Ritor1
parents:
diff changeset
1412 window_bits = 15;
Ritor1
parents:
diff changeset
1413 }
Ritor1
parents:
diff changeset
1414
Ritor1
parents:
diff changeset
1415 else if (window_bits < 8)
Ritor1
parents:
diff changeset
1416 {
Ritor1
parents:
diff changeset
1417 png_warning(png_ptr, "Only compression windows >= 256 supported by PNG");
Ritor1
parents:
diff changeset
1418 window_bits = 8;
Ritor1
parents:
diff changeset
1419 }
Ritor1
parents:
diff changeset
1420
Ritor1
parents:
diff changeset
1421 png_ptr->zlib_window_bits = window_bits;
Ritor1
parents:
diff changeset
1422 }
Ritor1
parents:
diff changeset
1423
Ritor1
parents:
diff changeset
1424 void PNGAPI
Ritor1
parents:
diff changeset
1425 png_set_compression_method(png_structrp png_ptr, int method)
Ritor1
parents:
diff changeset
1426 {
Ritor1
parents:
diff changeset
1427 png_debug(1, "in png_set_compression_method");
Ritor1
parents:
diff changeset
1428
Ritor1
parents:
diff changeset
1429 if (png_ptr == NULL)
Ritor1
parents:
diff changeset
1430 return;
Ritor1
parents:
diff changeset
1431
Ritor1
parents:
diff changeset
1432 /* This would produce an invalid PNG file if it worked, but it doesn't and
Ritor1
parents:
diff changeset
1433 * deflate will fault it, so it is harmless to just warn here.
Ritor1
parents:
diff changeset
1434 */
Ritor1
parents:
diff changeset
1435 if (method != 8)
Ritor1
parents:
diff changeset
1436 png_warning(png_ptr, "Only compression method 8 is supported by PNG");
Ritor1
parents:
diff changeset
1437
Ritor1
parents:
diff changeset
1438 png_ptr->zlib_method = method;
Ritor1
parents:
diff changeset
1439 }
Ritor1
parents:
diff changeset
1440
Ritor1
parents:
diff changeset
1441 /* The following were added to libpng-1.5.4 */
Ritor1
parents:
diff changeset
1442 #ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED
Ritor1
parents:
diff changeset
1443 void PNGAPI
Ritor1
parents:
diff changeset
1444 png_set_text_compression_level(png_structrp png_ptr, int level)
Ritor1
parents:
diff changeset
1445 {
Ritor1
parents:
diff changeset
1446 png_debug(1, "in png_set_text_compression_level");
Ritor1
parents:
diff changeset
1447
Ritor1
parents:
diff changeset
1448 if (png_ptr == NULL)
Ritor1
parents:
diff changeset
1449 return;
Ritor1
parents:
diff changeset
1450
Ritor1
parents:
diff changeset
1451 png_ptr->zlib_text_level = level;
Ritor1
parents:
diff changeset
1452 }
Ritor1
parents:
diff changeset
1453
Ritor1
parents:
diff changeset
1454 void PNGAPI
Ritor1
parents:
diff changeset
1455 png_set_text_compression_mem_level(png_structrp png_ptr, int mem_level)
Ritor1
parents:
diff changeset
1456 {
Ritor1
parents:
diff changeset
1457 png_debug(1, "in png_set_text_compression_mem_level");
Ritor1
parents:
diff changeset
1458
Ritor1
parents:
diff changeset
1459 if (png_ptr == NULL)
Ritor1
parents:
diff changeset
1460 return;
Ritor1
parents:
diff changeset
1461
Ritor1
parents:
diff changeset
1462 png_ptr->zlib_text_mem_level = mem_level;
Ritor1
parents:
diff changeset
1463 }
Ritor1
parents:
diff changeset
1464
Ritor1
parents:
diff changeset
1465 void PNGAPI
Ritor1
parents:
diff changeset
1466 png_set_text_compression_strategy(png_structrp png_ptr, int strategy)
Ritor1
parents:
diff changeset
1467 {
Ritor1
parents:
diff changeset
1468 png_debug(1, "in png_set_text_compression_strategy");
Ritor1
parents:
diff changeset
1469
Ritor1
parents:
diff changeset
1470 if (png_ptr == NULL)
Ritor1
parents:
diff changeset
1471 return;
Ritor1
parents:
diff changeset
1472
Ritor1
parents:
diff changeset
1473 png_ptr->zlib_text_strategy = strategy;
Ritor1
parents:
diff changeset
1474 }
Ritor1
parents:
diff changeset
1475
Ritor1
parents:
diff changeset
1476 /* If PNG_WRITE_OPTIMIZE_CMF_SUPPORTED is defined, libpng will use a
Ritor1
parents:
diff changeset
1477 * smaller value of window_bits if it can do so safely.
Ritor1
parents:
diff changeset
1478 */
Ritor1
parents:
diff changeset
1479 void PNGAPI
Ritor1
parents:
diff changeset
1480 png_set_text_compression_window_bits(png_structrp png_ptr, int window_bits)
Ritor1
parents:
diff changeset
1481 {
Ritor1
parents:
diff changeset
1482 if (png_ptr == NULL)
Ritor1
parents:
diff changeset
1483 return;
Ritor1
parents:
diff changeset
1484
Ritor1
parents:
diff changeset
1485 if (window_bits > 15)
Ritor1
parents:
diff changeset
1486 {
Ritor1
parents:
diff changeset
1487 png_warning(png_ptr, "Only compression windows <= 32k supported by PNG");
Ritor1
parents:
diff changeset
1488 window_bits = 15;
Ritor1
parents:
diff changeset
1489 }
Ritor1
parents:
diff changeset
1490
Ritor1
parents:
diff changeset
1491 else if (window_bits < 8)
Ritor1
parents:
diff changeset
1492 {
Ritor1
parents:
diff changeset
1493 png_warning(png_ptr, "Only compression windows >= 256 supported by PNG");
Ritor1
parents:
diff changeset
1494 window_bits = 8;
Ritor1
parents:
diff changeset
1495 }
Ritor1
parents:
diff changeset
1496
Ritor1
parents:
diff changeset
1497 png_ptr->zlib_text_window_bits = window_bits;
Ritor1
parents:
diff changeset
1498 }
Ritor1
parents:
diff changeset
1499
Ritor1
parents:
diff changeset
1500 void PNGAPI
Ritor1
parents:
diff changeset
1501 png_set_text_compression_method(png_structrp png_ptr, int method)
Ritor1
parents:
diff changeset
1502 {
Ritor1
parents:
diff changeset
1503 png_debug(1, "in png_set_text_compression_method");
Ritor1
parents:
diff changeset
1504
Ritor1
parents:
diff changeset
1505 if (png_ptr == NULL)
Ritor1
parents:
diff changeset
1506 return;
Ritor1
parents:
diff changeset
1507
Ritor1
parents:
diff changeset
1508 if (method != 8)
Ritor1
parents:
diff changeset
1509 png_warning(png_ptr, "Only compression method 8 is supported by PNG");
Ritor1
parents:
diff changeset
1510
Ritor1
parents:
diff changeset
1511 png_ptr->zlib_text_method = method;
Ritor1
parents:
diff changeset
1512 }
Ritor1
parents:
diff changeset
1513 #endif /* PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED */
Ritor1
parents:
diff changeset
1514 /* end of API added to libpng-1.5.4 */
Ritor1
parents:
diff changeset
1515
Ritor1
parents:
diff changeset
1516 void PNGAPI
Ritor1
parents:
diff changeset
1517 png_set_write_status_fn(png_structrp png_ptr, png_write_status_ptr write_row_fn)
Ritor1
parents:
diff changeset
1518 {
Ritor1
parents:
diff changeset
1519 if (png_ptr == NULL)
Ritor1
parents:
diff changeset
1520 return;
Ritor1
parents:
diff changeset
1521
Ritor1
parents:
diff changeset
1522 png_ptr->write_row_fn = write_row_fn;
Ritor1
parents:
diff changeset
1523 }
Ritor1
parents:
diff changeset
1524
Ritor1
parents:
diff changeset
1525 #ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED
Ritor1
parents:
diff changeset
1526 void PNGAPI
Ritor1
parents:
diff changeset
1527 png_set_write_user_transform_fn(png_structrp png_ptr, png_user_transform_ptr
Ritor1
parents:
diff changeset
1528 write_user_transform_fn)
Ritor1
parents:
diff changeset
1529 {
Ritor1
parents:
diff changeset
1530 png_debug(1, "in png_set_write_user_transform_fn");
Ritor1
parents:
diff changeset
1531
Ritor1
parents:
diff changeset
1532 if (png_ptr == NULL)
Ritor1
parents:
diff changeset
1533 return;
Ritor1
parents:
diff changeset
1534
Ritor1
parents:
diff changeset
1535 png_ptr->transformations |= PNG_USER_TRANSFORM;
Ritor1
parents:
diff changeset
1536 png_ptr->write_user_transform_fn = write_user_transform_fn;
Ritor1
parents:
diff changeset
1537 }
Ritor1
parents:
diff changeset
1538 #endif
Ritor1
parents:
diff changeset
1539
Ritor1
parents:
diff changeset
1540
Ritor1
parents:
diff changeset
1541 #ifdef PNG_INFO_IMAGE_SUPPORTED
Ritor1
parents:
diff changeset
1542 void PNGAPI
Ritor1
parents:
diff changeset
1543 png_write_png(png_structrp png_ptr, png_inforp info_ptr,
Ritor1
parents:
diff changeset
1544 int transforms, voidp params)
Ritor1
parents:
diff changeset
1545 {
Ritor1
parents:
diff changeset
1546 if (png_ptr == NULL || info_ptr == NULL)
Ritor1
parents:
diff changeset
1547 return;
Ritor1
parents:
diff changeset
1548
Ritor1
parents:
diff changeset
1549 if ((info_ptr->valid & PNG_INFO_IDAT) == 0)
Ritor1
parents:
diff changeset
1550 {
Ritor1
parents:
diff changeset
1551 png_app_error(png_ptr, "no rows for png_write_image to write");
Ritor1
parents:
diff changeset
1552 return;
Ritor1
parents:
diff changeset
1553 }
Ritor1
parents:
diff changeset
1554
Ritor1
parents:
diff changeset
1555 /* Write the file header information. */
Ritor1
parents:
diff changeset
1556 png_write_info(png_ptr, info_ptr);
Ritor1
parents:
diff changeset
1557
Ritor1
parents:
diff changeset
1558 /* ------ these transformations don't touch the info structure ------- */
Ritor1
parents:
diff changeset
1559
Ritor1
parents:
diff changeset
1560 /* Invert monochrome pixels */
Ritor1
parents:
diff changeset
1561 if (transforms & PNG_TRANSFORM_INVERT_MONO)
Ritor1
parents:
diff changeset
1562 #ifdef PNG_WRITE_INVERT_SUPPORTED
Ritor1
parents:
diff changeset
1563 png_set_invert_mono(png_ptr);
Ritor1
parents:
diff changeset
1564 #else
Ritor1
parents:
diff changeset
1565 png_app_error(png_ptr, "PNG_TRANSFORM_INVERT_MONO not supported");
Ritor1
parents:
diff changeset
1566 #endif
Ritor1
parents:
diff changeset
1567
Ritor1
parents:
diff changeset
1568 /* Shift the pixels up to a legal bit depth and fill in
Ritor1
parents:
diff changeset
1569 * as appropriate to correctly scale the image.
Ritor1
parents:
diff changeset
1570 */
Ritor1
parents:
diff changeset
1571 if (transforms & PNG_TRANSFORM_SHIFT)
Ritor1
parents:
diff changeset
1572 #ifdef PNG_WRITE_SHIFT_SUPPORTED
Ritor1
parents:
diff changeset
1573 if (info_ptr->valid & PNG_INFO_sBIT)
Ritor1
parents:
diff changeset
1574 png_set_shift(png_ptr, &info_ptr->sig_bit);
Ritor1
parents:
diff changeset
1575 #else
Ritor1
parents:
diff changeset
1576 png_app_error(png_ptr, "PNG_TRANSFORM_SHIFT not supported");
Ritor1
parents:
diff changeset
1577 #endif
Ritor1
parents:
diff changeset
1578
Ritor1
parents:
diff changeset
1579 /* Pack pixels into bytes */
Ritor1
parents:
diff changeset
1580 if (transforms & PNG_TRANSFORM_PACKING)
Ritor1
parents:
diff changeset
1581 #ifdef PNG_WRITE_PACK_SUPPORTED
Ritor1
parents:
diff changeset
1582 png_set_packing(png_ptr);
Ritor1
parents:
diff changeset
1583 #else
Ritor1
parents:
diff changeset
1584 png_app_error(png_ptr, "PNG_TRANSFORM_PACKING not supported");
Ritor1
parents:
diff changeset
1585 #endif
Ritor1
parents:
diff changeset
1586
Ritor1
parents:
diff changeset
1587 /* Swap location of alpha bytes from ARGB to RGBA */
Ritor1
parents:
diff changeset
1588 if (transforms & PNG_TRANSFORM_SWAP_ALPHA)
Ritor1
parents:
diff changeset
1589 #ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED
Ritor1
parents:
diff changeset
1590 png_set_swap_alpha(png_ptr);
Ritor1
parents:
diff changeset
1591 #else
Ritor1
parents:
diff changeset
1592 png_app_error(png_ptr, "PNG_TRANSFORM_SWAP_ALPHA not supported");
Ritor1
parents:
diff changeset
1593 #endif
Ritor1
parents:
diff changeset
1594
Ritor1
parents:
diff changeset
1595 /* Remove a filler (X) from XRGB/RGBX/AG/GA into to convert it into
Ritor1
parents:
diff changeset
1596 * RGB, note that the code expects the input color type to be G or RGB; no
Ritor1
parents:
diff changeset
1597 * alpha channel.
Ritor1
parents:
diff changeset
1598 */
Ritor1
parents:
diff changeset
1599 if (transforms &
Ritor1
parents:
diff changeset
1600 (PNG_TRANSFORM_STRIP_FILLER_AFTER|PNG_TRANSFORM_STRIP_FILLER_BEFORE))
Ritor1
parents:
diff changeset
1601 {
Ritor1
parents:
diff changeset
1602 #ifdef PNG_WRITE_FILLER_SUPPORTED
Ritor1
parents:
diff changeset
1603 if (transforms & PNG_TRANSFORM_STRIP_FILLER_AFTER)
Ritor1
parents:
diff changeset
1604 {
Ritor1
parents:
diff changeset
1605 if (transforms & PNG_TRANSFORM_STRIP_FILLER_BEFORE)
Ritor1
parents:
diff changeset
1606 png_app_error(png_ptr,
Ritor1
parents:
diff changeset
1607 "PNG_TRANSFORM_STRIP_FILLER: BEFORE+AFTER not supported");
Ritor1
parents:
diff changeset
1608
Ritor1
parents:
diff changeset
1609 /* Continue if ignored - this is the pre-1.6.10 behavior */
Ritor1
parents:
diff changeset
1610 png_set_filler(png_ptr, 0, PNG_FILLER_AFTER);
Ritor1
parents:
diff changeset
1611 }
Ritor1
parents:
diff changeset
1612
Ritor1
parents:
diff changeset
1613 else if (transforms & PNG_TRANSFORM_STRIP_FILLER_BEFORE)
Ritor1
parents:
diff changeset
1614 png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE);
Ritor1
parents:
diff changeset
1615 #else
Ritor1
parents:
diff changeset
1616 png_app_error(png_ptr, "PNG_TRANSFORM_STRIP_FILLER not supported");
Ritor1
parents:
diff changeset
1617 #endif
Ritor1
parents:
diff changeset
1618 }
Ritor1
parents:
diff changeset
1619
Ritor1
parents:
diff changeset
1620 /* Flip BGR pixels to RGB */
Ritor1
parents:
diff changeset
1621 if (transforms & PNG_TRANSFORM_BGR)
Ritor1
parents:
diff changeset
1622 #ifdef PNG_WRITE_BGR_SUPPORTED
Ritor1
parents:
diff changeset
1623 png_set_bgr(png_ptr);
Ritor1
parents:
diff changeset
1624 #else
Ritor1
parents:
diff changeset
1625 png_app_error(png_ptr, "PNG_TRANSFORM_BGR not supported");
Ritor1
parents:
diff changeset
1626 #endif
Ritor1
parents:
diff changeset
1627
Ritor1
parents:
diff changeset
1628 /* Swap bytes of 16-bit files to most significant byte first */
Ritor1
parents:
diff changeset
1629 if (transforms & PNG_TRANSFORM_SWAP_ENDIAN)
Ritor1
parents:
diff changeset
1630 #ifdef PNG_WRITE_SWAP_SUPPORTED
Ritor1
parents:
diff changeset
1631 png_set_swap(png_ptr);
Ritor1
parents:
diff changeset
1632 #else
Ritor1
parents:
diff changeset
1633 png_app_error(png_ptr, "PNG_TRANSFORM_SWAP_ENDIAN not supported");
Ritor1
parents:
diff changeset
1634 #endif
Ritor1
parents:
diff changeset
1635
Ritor1
parents:
diff changeset
1636 /* Swap bits of 1, 2, 4 bit packed pixel formats */
Ritor1
parents:
diff changeset
1637 if (transforms & PNG_TRANSFORM_PACKSWAP)
Ritor1
parents:
diff changeset
1638 #ifdef PNG_WRITE_PACKSWAP_SUPPORTED
Ritor1
parents:
diff changeset
1639 png_set_packswap(png_ptr);
Ritor1
parents:
diff changeset
1640 #else
Ritor1
parents:
diff changeset
1641 png_app_error(png_ptr, "PNG_TRANSFORM_PACKSWAP not supported");
Ritor1
parents:
diff changeset
1642 #endif
Ritor1
parents:
diff changeset
1643
Ritor1
parents:
diff changeset
1644 /* Invert the alpha channel from opacity to transparency */
Ritor1
parents:
diff changeset
1645 if (transforms & PNG_TRANSFORM_INVERT_ALPHA)
Ritor1
parents:
diff changeset
1646 #ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED
Ritor1
parents:
diff changeset
1647 png_set_invert_alpha(png_ptr);
Ritor1
parents:
diff changeset
1648 #else
Ritor1
parents:
diff changeset
1649 png_app_error(png_ptr, "PNG_TRANSFORM_INVERT_ALPHA not supported");
Ritor1
parents:
diff changeset
1650 #endif
Ritor1
parents:
diff changeset
1651
Ritor1
parents:
diff changeset
1652 /* ----------------------- end of transformations ------------------- */
Ritor1
parents:
diff changeset
1653
Ritor1
parents:
diff changeset
1654 /* Write the bits */
Ritor1
parents:
diff changeset
1655 png_write_image(png_ptr, info_ptr->row_pointers);
Ritor1
parents:
diff changeset
1656
Ritor1
parents:
diff changeset
1657 /* It is REQUIRED to call this to finish writing the rest of the file */
Ritor1
parents:
diff changeset
1658 png_write_end(png_ptr, info_ptr);
Ritor1
parents:
diff changeset
1659
Ritor1
parents:
diff changeset
1660 PNG_UNUSED(params)
Ritor1
parents:
diff changeset
1661 }
Ritor1
parents:
diff changeset
1662 #endif
Ritor1
parents:
diff changeset
1663
Ritor1
parents:
diff changeset
1664
Ritor1
parents:
diff changeset
1665 #ifdef PNG_SIMPLIFIED_WRITE_SUPPORTED
Ritor1
parents:
diff changeset
1666 #ifdef PNG_STDIO_SUPPORTED /* currently required for png_image_write_* */
Ritor1
parents:
diff changeset
1667 /* Initialize the write structure - general purpose utility. */
Ritor1
parents:
diff changeset
1668 static int
Ritor1
parents:
diff changeset
1669 png_image_write_init(png_imagep image)
Ritor1
parents:
diff changeset
1670 {
Ritor1
parents:
diff changeset
1671 png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, image,
Ritor1
parents:
diff changeset
1672 png_safe_error, png_safe_warning);
Ritor1
parents:
diff changeset
1673
Ritor1
parents:
diff changeset
1674 if (png_ptr != NULL)
Ritor1
parents:
diff changeset
1675 {
Ritor1
parents:
diff changeset
1676 png_infop info_ptr = png_create_info_struct(png_ptr);
Ritor1
parents:
diff changeset
1677
Ritor1
parents:
diff changeset
1678 if (info_ptr != NULL)
Ritor1
parents:
diff changeset
1679 {
Ritor1
parents:
diff changeset
1680 png_controlp control = png_voidcast(png_controlp,
Ritor1
parents:
diff changeset
1681 png_malloc_warn(png_ptr, (sizeof *control)));
Ritor1
parents:
diff changeset
1682
Ritor1
parents:
diff changeset
1683 if (control != NULL)
Ritor1
parents:
diff changeset
1684 {
Ritor1
parents:
diff changeset
1685 memset(control, 0, (sizeof *control));
Ritor1
parents:
diff changeset
1686
Ritor1
parents:
diff changeset
1687 control->png_ptr = png_ptr;
Ritor1
parents:
diff changeset
1688 control->info_ptr = info_ptr;
Ritor1
parents:
diff changeset
1689 control->for_write = 1;
Ritor1
parents:
diff changeset
1690
Ritor1
parents:
diff changeset
1691 image->opaque = control;
Ritor1
parents:
diff changeset
1692 return 1;
Ritor1
parents:
diff changeset
1693 }
Ritor1
parents:
diff changeset
1694
Ritor1
parents:
diff changeset
1695 /* Error clean up */
Ritor1
parents:
diff changeset
1696 png_destroy_info_struct(png_ptr, &info_ptr);
Ritor1
parents:
diff changeset
1697 }
Ritor1
parents:
diff changeset
1698
Ritor1
parents:
diff changeset
1699 png_destroy_write_struct(&png_ptr, NULL);
Ritor1
parents:
diff changeset
1700 }
Ritor1
parents:
diff changeset
1701
Ritor1
parents:
diff changeset
1702 return png_image_error(image, "png_image_write_: out of memory");
Ritor1
parents:
diff changeset
1703 }
Ritor1
parents:
diff changeset
1704
Ritor1
parents:
diff changeset
1705 /* Arguments to png_image_write_main: */
Ritor1
parents:
diff changeset
1706 typedef struct
Ritor1
parents:
diff changeset
1707 {
Ritor1
parents:
diff changeset
1708 /* Arguments: */
Ritor1
parents:
diff changeset
1709 png_imagep image;
Ritor1
parents:
diff changeset
1710 png_const_voidp buffer;
Ritor1
parents:
diff changeset
1711 png_int_32 row_stride;
Ritor1
parents:
diff changeset
1712 png_const_voidp colormap;
Ritor1
parents:
diff changeset
1713 int convert_to_8bit;
Ritor1
parents:
diff changeset
1714 /* Local variables: */
Ritor1
parents:
diff changeset
1715 png_const_voidp first_row;
Ritor1
parents:
diff changeset
1716 ptrdiff_t row_bytes;
Ritor1
parents:
diff changeset
1717 png_voidp local_row;
Ritor1
parents:
diff changeset
1718 } png_image_write_control;
Ritor1
parents:
diff changeset
1719
Ritor1
parents:
diff changeset
1720 /* Write png_uint_16 input to a 16-bit PNG; the png_ptr has already been set to
Ritor1
parents:
diff changeset
1721 * do any necessary byte swapping. The component order is defined by the
Ritor1
parents:
diff changeset
1722 * png_image format value.
Ritor1
parents:
diff changeset
1723 */
Ritor1
parents:
diff changeset
1724 static int
Ritor1
parents:
diff changeset
1725 png_write_image_16bit(png_voidp argument)
Ritor1
parents:
diff changeset
1726 {
Ritor1
parents:
diff changeset
1727 png_image_write_control *display = png_voidcast(png_image_write_control*,
Ritor1
parents:
diff changeset
1728 argument);
Ritor1
parents:
diff changeset
1729 png_imagep image = display->image;
Ritor1
parents:
diff changeset
1730 png_structrp png_ptr = image->opaque->png_ptr;
Ritor1
parents:
diff changeset
1731
Ritor1
parents:
diff changeset
1732 png_const_uint_16p input_row = png_voidcast(png_const_uint_16p,
Ritor1
parents:
diff changeset
1733 display->first_row);
Ritor1
parents:
diff changeset
1734 png_uint_16p output_row = png_voidcast(png_uint_16p, display->local_row);
Ritor1
parents:
diff changeset
1735 png_uint_16p row_end;
Ritor1
parents:
diff changeset
1736 const int channels = (image->format & PNG_FORMAT_FLAG_COLOR) ? 3 : 1;
Ritor1
parents:
diff changeset
1737 int aindex = 0;
Ritor1
parents:
diff changeset
1738 png_uint_32 y = image->height;
Ritor1
parents:
diff changeset
1739
Ritor1
parents:
diff changeset
1740 if (image->format & PNG_FORMAT_FLAG_ALPHA)
Ritor1
parents:
diff changeset
1741 {
Ritor1
parents:
diff changeset
1742 # ifdef PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED
Ritor1
parents:
diff changeset
1743 if (image->format & PNG_FORMAT_FLAG_AFIRST)
Ritor1
parents:
diff changeset
1744 {
Ritor1
parents:
diff changeset
1745 aindex = -1;
Ritor1
parents:
diff changeset
1746 ++input_row; /* To point to the first component */
Ritor1
parents:
diff changeset
1747 ++output_row;
Ritor1
parents:
diff changeset
1748 }
Ritor1
parents:
diff changeset
1749
Ritor1
parents:
diff changeset
1750 else
Ritor1
parents:
diff changeset
1751 # endif
Ritor1
parents:
diff changeset
1752 aindex = channels;
Ritor1
parents:
diff changeset
1753 }
Ritor1
parents:
diff changeset
1754
Ritor1
parents:
diff changeset
1755 else
Ritor1
parents:
diff changeset
1756 png_error(png_ptr, "png_write_image: internal call error");
Ritor1
parents:
diff changeset
1757
Ritor1
parents:
diff changeset
1758 /* Work out the output row end and count over this, note that the increment
Ritor1
parents:
diff changeset
1759 * above to 'row' means that row_end can actually be beyond the end of the
Ritor1
parents:
diff changeset
1760 * row; this is correct.
Ritor1
parents:
diff changeset
1761 */
Ritor1
parents:
diff changeset
1762 row_end = output_row + image->width * (channels+1);
Ritor1
parents:
diff changeset
1763
Ritor1
parents:
diff changeset
1764 while (y-- > 0)
Ritor1
parents:
diff changeset
1765 {
Ritor1
parents:
diff changeset
1766 png_const_uint_16p in_ptr = input_row;
Ritor1
parents:
diff changeset
1767 png_uint_16p out_ptr = output_row;
Ritor1
parents:
diff changeset
1768
Ritor1
parents:
diff changeset
1769 while (out_ptr < row_end)
Ritor1
parents:
diff changeset
1770 {
Ritor1
parents:
diff changeset
1771 const png_uint_16 alpha = in_ptr[aindex];
Ritor1
parents:
diff changeset
1772 png_uint_32 reciprocal = 0;
Ritor1
parents:
diff changeset
1773 int c;
Ritor1
parents:
diff changeset
1774
Ritor1
parents:
diff changeset
1775 out_ptr[aindex] = alpha;
Ritor1
parents:
diff changeset
1776
Ritor1
parents:
diff changeset
1777 /* Calculate a reciprocal. The correct calculation is simply
Ritor1
parents:
diff changeset
1778 * component/alpha*65535 << 15. (I.e. 15 bits of precision); this
Ritor1
parents:
diff changeset
1779 * allows correct rounding by adding .5 before the shift. 'reciprocal'
Ritor1
parents:
diff changeset
1780 * is only initialized when required.
Ritor1
parents:
diff changeset
1781 */
Ritor1
parents:
diff changeset
1782 if (alpha > 0 && alpha < 65535)
Ritor1
parents:
diff changeset
1783 reciprocal = ((0xffff<<15)+(alpha>>1))/alpha;
Ritor1
parents:
diff changeset
1784
Ritor1
parents:
diff changeset
1785 c = channels;
Ritor1
parents:
diff changeset
1786 do /* always at least one channel */
Ritor1
parents:
diff changeset
1787 {
Ritor1
parents:
diff changeset
1788 png_uint_16 component = *in_ptr++;
Ritor1
parents:
diff changeset
1789
Ritor1
parents:
diff changeset
1790 /* The following gives 65535 for an alpha of 0, which is fine,
Ritor1
parents:
diff changeset
1791 * otherwise if 0/0 is represented as some other value there is more
Ritor1
parents:
diff changeset
1792 * likely to be a discontinuity which will probably damage
Ritor1
parents:
diff changeset
1793 * compression when moving from a fully transparent area to a
Ritor1
parents:
diff changeset
1794 * nearly transparent one. (The assumption here is that opaque
Ritor1
parents:
diff changeset
1795 * areas tend not to be 0 intensity.)
Ritor1
parents:
diff changeset
1796 */
Ritor1
parents:
diff changeset
1797 if (component >= alpha)
Ritor1
parents:
diff changeset
1798 component = 65535;
Ritor1
parents:
diff changeset
1799
Ritor1
parents:
diff changeset
1800 /* component<alpha, so component/alpha is less than one and
Ritor1
parents:
diff changeset
1801 * component*reciprocal is less than 2^31.
Ritor1
parents:
diff changeset
1802 */
Ritor1
parents:
diff changeset
1803 else if (component > 0 && alpha < 65535)
Ritor1
parents:
diff changeset
1804 {
Ritor1
parents:
diff changeset
1805 png_uint_32 calc = component * reciprocal;
Ritor1
parents:
diff changeset
1806 calc += 16384; /* round to nearest */
Ritor1
parents:
diff changeset
1807 component = (png_uint_16)(calc >> 15);
Ritor1
parents:
diff changeset
1808 }
Ritor1
parents:
diff changeset
1809
Ritor1
parents:
diff changeset
1810 *out_ptr++ = component;
Ritor1
parents:
diff changeset
1811 }
Ritor1
parents:
diff changeset
1812 while (--c > 0);
Ritor1
parents:
diff changeset
1813
Ritor1
parents:
diff changeset
1814 /* Skip to next component (skip the intervening alpha channel) */
Ritor1
parents:
diff changeset
1815 ++in_ptr;
Ritor1
parents:
diff changeset
1816 ++out_ptr;
Ritor1
parents:
diff changeset
1817 }
Ritor1
parents:
diff changeset
1818
Ritor1
parents:
diff changeset
1819 png_write_row(png_ptr, png_voidcast(png_const_bytep, display->local_row));
Ritor1
parents:
diff changeset
1820 input_row += display->row_bytes/(sizeof (png_uint_16));
Ritor1
parents:
diff changeset
1821 }
Ritor1
parents:
diff changeset
1822
Ritor1
parents:
diff changeset
1823 return 1;
Ritor1
parents:
diff changeset
1824 }
Ritor1
parents:
diff changeset
1825
Ritor1
parents:
diff changeset
1826 /* Given 16-bit input (1 to 4 channels) write 8-bit output. If an alpha channel
Ritor1
parents:
diff changeset
1827 * is present it must be removed from the components, the components are then
Ritor1
parents:
diff changeset
1828 * written in sRGB encoding. No components are added or removed.
Ritor1
parents:
diff changeset
1829 *
Ritor1
parents:
diff changeset
1830 * Calculate an alpha reciprocal to reverse pre-multiplication. As above the
Ritor1
parents:
diff changeset
1831 * calculation can be done to 15 bits of accuracy; however, the output needs to
Ritor1
parents:
diff changeset
1832 * be scaled in the range 0..255*65535, so include that scaling here.
Ritor1
parents:
diff changeset
1833 */
Ritor1
parents:
diff changeset
1834 #define UNP_RECIPROCAL(alpha) ((((0xffff*0xff)<<7)+(alpha>>1))/alpha)
Ritor1
parents:
diff changeset
1835
Ritor1
parents:
diff changeset
1836 static png_byte
Ritor1
parents:
diff changeset
1837 png_unpremultiply(png_uint_32 component, png_uint_32 alpha,
Ritor1
parents:
diff changeset
1838 png_uint_32 reciprocal/*from the above macro*/)
Ritor1
parents:
diff changeset
1839 {
Ritor1
parents:
diff changeset
1840 /* The following gives 1.0 for an alpha of 0, which is fine, otherwise if 0/0
Ritor1
parents:
diff changeset
1841 * is represented as some other value there is more likely to be a
Ritor1
parents:
diff changeset
1842 * discontinuity which will probably damage compression when moving from a
Ritor1
parents:
diff changeset
1843 * fully transparent area to a nearly transparent one. (The assumption here
Ritor1
parents:
diff changeset
1844 * is that opaque areas tend not to be 0 intensity.)
Ritor1
parents:
diff changeset
1845 *
Ritor1
parents:
diff changeset
1846 * There is a rounding problem here; if alpha is less than 128 it will end up
Ritor1
parents:
diff changeset
1847 * as 0 when scaled to 8 bits. To avoid introducing spurious colors into the
Ritor1
parents:
diff changeset
1848 * output change for this too.
Ritor1
parents:
diff changeset
1849 */
Ritor1
parents:
diff changeset
1850 if (component >= alpha || alpha < 128)
Ritor1
parents:
diff changeset
1851 return 255;
Ritor1
parents:
diff changeset
1852
Ritor1
parents:
diff changeset
1853 /* component<alpha, so component/alpha is less than one and
Ritor1
parents:
diff changeset
1854 * component*reciprocal is less than 2^31.
Ritor1
parents:
diff changeset
1855 */
Ritor1
parents:
diff changeset
1856 else if (component > 0)
Ritor1
parents:
diff changeset
1857 {
Ritor1
parents:
diff changeset
1858 /* The test is that alpha/257 (rounded) is less than 255, the first value
Ritor1
parents:
diff changeset
1859 * that becomes 255 is 65407.
Ritor1
parents:
diff changeset
1860 * NOTE: this must agree with the PNG_DIV257 macro (which must, therefore,
Ritor1
parents:
diff changeset
1861 * be exact!) [Could also test reciprocal != 0]
Ritor1
parents:
diff changeset
1862 */
Ritor1
parents:
diff changeset
1863 if (alpha < 65407)
Ritor1
parents:
diff changeset
1864 {
Ritor1
parents:
diff changeset
1865 component *= reciprocal;
Ritor1
parents:
diff changeset
1866 component += 64; /* round to nearest */
Ritor1
parents:
diff changeset
1867 component >>= 7;
Ritor1
parents:
diff changeset
1868 }
Ritor1
parents:
diff changeset
1869
Ritor1
parents:
diff changeset
1870 else
Ritor1
parents:
diff changeset
1871 component *= 255;
Ritor1
parents:
diff changeset
1872
Ritor1
parents:
diff changeset
1873 /* Convert the component to sRGB. */
Ritor1
parents:
diff changeset
1874 return (png_byte)PNG_sRGB_FROM_LINEAR(component);
Ritor1
parents:
diff changeset
1875 }
Ritor1
parents:
diff changeset
1876
Ritor1
parents:
diff changeset
1877 else
Ritor1
parents:
diff changeset
1878 return 0;
Ritor1
parents:
diff changeset
1879 }
Ritor1
parents:
diff changeset
1880
Ritor1
parents:
diff changeset
1881 static int
Ritor1
parents:
diff changeset
1882 png_write_image_8bit(png_voidp argument)
Ritor1
parents:
diff changeset
1883 {
Ritor1
parents:
diff changeset
1884 png_image_write_control *display = png_voidcast(png_image_write_control*,
Ritor1
parents:
diff changeset
1885 argument);
Ritor1
parents:
diff changeset
1886 png_imagep image = display->image;
Ritor1
parents:
diff changeset
1887 png_structrp png_ptr = image->opaque->png_ptr;
Ritor1
parents:
diff changeset
1888
Ritor1
parents:
diff changeset
1889 png_const_uint_16p input_row = png_voidcast(png_const_uint_16p,
Ritor1
parents:
diff changeset
1890 display->first_row);
Ritor1
parents:
diff changeset
1891 png_bytep output_row = png_voidcast(png_bytep, display->local_row);
Ritor1
parents:
diff changeset
1892 png_uint_32 y = image->height;
Ritor1
parents:
diff changeset
1893 const int channels = (image->format & PNG_FORMAT_FLAG_COLOR) ? 3 : 1;
Ritor1
parents:
diff changeset
1894
Ritor1
parents:
diff changeset
1895 if (image->format & PNG_FORMAT_FLAG_ALPHA)
Ritor1
parents:
diff changeset
1896 {
Ritor1
parents:
diff changeset
1897 png_bytep row_end;
Ritor1
parents:
diff changeset
1898 int aindex;
Ritor1
parents:
diff changeset
1899
Ritor1
parents:
diff changeset
1900 # ifdef PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED
Ritor1
parents:
diff changeset
1901 if (image->format & PNG_FORMAT_FLAG_AFIRST)
Ritor1
parents:
diff changeset
1902 {
Ritor1
parents:
diff changeset
1903 aindex = -1;
Ritor1
parents:
diff changeset
1904 ++input_row; /* To point to the first component */
Ritor1
parents:
diff changeset
1905 ++output_row;
Ritor1
parents:
diff changeset
1906 }
Ritor1
parents:
diff changeset
1907
Ritor1
parents:
diff changeset
1908 else
Ritor1
parents:
diff changeset
1909 # endif
Ritor1
parents:
diff changeset
1910 aindex = channels;
Ritor1
parents:
diff changeset
1911
Ritor1
parents:
diff changeset
1912 /* Use row_end in place of a loop counter: */
Ritor1
parents:
diff changeset
1913 row_end = output_row + image->width * (channels+1);
Ritor1
parents:
diff changeset
1914
Ritor1
parents:
diff changeset
1915 while (y-- > 0)
Ritor1
parents:
diff changeset
1916 {
Ritor1
parents:
diff changeset
1917 png_const_uint_16p in_ptr = input_row;
Ritor1
parents:
diff changeset
1918 png_bytep out_ptr = output_row;
Ritor1
parents:
diff changeset
1919
Ritor1
parents:
diff changeset
1920 while (out_ptr < row_end)
Ritor1
parents:
diff changeset
1921 {
Ritor1
parents:
diff changeset
1922 png_uint_16 alpha = in_ptr[aindex];
Ritor1
parents:
diff changeset
1923 png_byte alphabyte = (png_byte)PNG_DIV257(alpha);
Ritor1
parents:
diff changeset
1924 png_uint_32 reciprocal = 0;
Ritor1
parents:
diff changeset
1925 int c;
Ritor1
parents:
diff changeset
1926
Ritor1
parents:
diff changeset
1927 /* Scale and write the alpha channel. */
Ritor1
parents:
diff changeset
1928 out_ptr[aindex] = alphabyte;
Ritor1
parents:
diff changeset
1929
Ritor1
parents:
diff changeset
1930 if (alphabyte > 0 && alphabyte < 255)
Ritor1
parents:
diff changeset
1931 reciprocal = UNP_RECIPROCAL(alpha);
Ritor1
parents:
diff changeset
1932
Ritor1
parents:
diff changeset
1933 c = channels;
Ritor1
parents:
diff changeset
1934 do /* always at least one channel */
Ritor1
parents:
diff changeset
1935 *out_ptr++ = png_unpremultiply(*in_ptr++, alpha, reciprocal);
Ritor1
parents:
diff changeset
1936 while (--c > 0);
Ritor1
parents:
diff changeset
1937
Ritor1
parents:
diff changeset
1938 /* Skip to next component (skip the intervening alpha channel) */
Ritor1
parents:
diff changeset
1939 ++in_ptr;
Ritor1
parents:
diff changeset
1940 ++out_ptr;
Ritor1
parents:
diff changeset
1941 } /* while out_ptr < row_end */
Ritor1
parents:
diff changeset
1942
Ritor1
parents:
diff changeset
1943 png_write_row(png_ptr, png_voidcast(png_const_bytep,
Ritor1
parents:
diff changeset
1944 display->local_row));
Ritor1
parents:
diff changeset
1945 input_row += display->row_bytes/(sizeof (png_uint_16));
Ritor1
parents:
diff changeset
1946 } /* while y */
Ritor1
parents:
diff changeset
1947 }
Ritor1
parents:
diff changeset
1948
Ritor1
parents:
diff changeset
1949 else
Ritor1
parents:
diff changeset
1950 {
Ritor1
parents:
diff changeset
1951 /* No alpha channel, so the row_end really is the end of the row and it
Ritor1
parents:
diff changeset
1952 * is sufficient to loop over the components one by one.
Ritor1
parents:
diff changeset
1953 */
Ritor1
parents:
diff changeset
1954 png_bytep row_end = output_row + image->width * channels;
Ritor1
parents:
diff changeset
1955
Ritor1
parents:
diff changeset
1956 while (y-- > 0)
Ritor1
parents:
diff changeset
1957 {
Ritor1
parents:
diff changeset
1958 png_const_uint_16p in_ptr = input_row;
Ritor1
parents:
diff changeset
1959 png_bytep out_ptr = output_row;
Ritor1
parents:
diff changeset
1960
Ritor1
parents:
diff changeset
1961 while (out_ptr < row_end)
Ritor1
parents:
diff changeset
1962 {
Ritor1
parents:
diff changeset
1963 png_uint_32 component = *in_ptr++;
Ritor1
parents:
diff changeset
1964
Ritor1
parents:
diff changeset
1965 component *= 255;
Ritor1
parents:
diff changeset
1966 *out_ptr++ = (png_byte)PNG_sRGB_FROM_LINEAR(component);
Ritor1
parents:
diff changeset
1967 }
Ritor1
parents:
diff changeset
1968
Ritor1
parents:
diff changeset
1969 png_write_row(png_ptr, output_row);
Ritor1
parents:
diff changeset
1970 input_row += display->row_bytes/(sizeof (png_uint_16));
Ritor1
parents:
diff changeset
1971 }
Ritor1
parents:
diff changeset
1972 }
Ritor1
parents:
diff changeset
1973
Ritor1
parents:
diff changeset
1974 return 1;
Ritor1
parents:
diff changeset
1975 }
Ritor1
parents:
diff changeset
1976
Ritor1
parents:
diff changeset
1977 static void
Ritor1
parents:
diff changeset
1978 png_image_set_PLTE(png_image_write_control *display)
Ritor1
parents:
diff changeset
1979 {
Ritor1
parents:
diff changeset
1980 const png_imagep image = display->image;
Ritor1
parents:
diff changeset
1981 const void *cmap = display->colormap;
Ritor1
parents:
diff changeset
1982 const int entries = image->colormap_entries > 256 ? 256 :
Ritor1
parents:
diff changeset
1983 (int)image->colormap_entries;
Ritor1
parents:
diff changeset
1984
Ritor1
parents:
diff changeset
1985 /* NOTE: the caller must check for cmap != NULL and entries != 0 */
Ritor1
parents:
diff changeset
1986 const png_uint_32 format = image->format;
Ritor1
parents:
diff changeset
1987 const int channels = PNG_IMAGE_SAMPLE_CHANNELS(format);
Ritor1
parents:
diff changeset
1988
Ritor1
parents:
diff changeset
1989 # if defined(PNG_FORMAT_BGR_SUPPORTED) &&\
Ritor1
parents:
diff changeset
1990 defined(PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED)
Ritor1
parents:
diff changeset
1991 const int afirst = (format & PNG_FORMAT_FLAG_AFIRST) != 0 &&
Ritor1
parents:
diff changeset
1992 (format & PNG_FORMAT_FLAG_ALPHA) != 0;
Ritor1
parents:
diff changeset
1993 # else
Ritor1
parents:
diff changeset
1994 # define afirst 0
Ritor1
parents:
diff changeset
1995 # endif
Ritor1
parents:
diff changeset
1996
Ritor1
parents:
diff changeset
1997 # ifdef PNG_FORMAT_BGR_SUPPORTED
Ritor1
parents:
diff changeset
1998 const int bgr = (format & PNG_FORMAT_FLAG_BGR) ? 2 : 0;
Ritor1
parents:
diff changeset
1999 # else
Ritor1
parents:
diff changeset
2000 # define bgr 0
Ritor1
parents:
diff changeset
2001 # endif
Ritor1
parents:
diff changeset
2002
Ritor1
parents:
diff changeset
2003 int i, num_trans;
Ritor1
parents:
diff changeset
2004 png_color palette[256];
Ritor1
parents:
diff changeset
2005 png_byte tRNS[256];
Ritor1
parents:
diff changeset
2006
Ritor1
parents:
diff changeset
2007 memset(tRNS, 255, (sizeof tRNS));
Ritor1
parents:
diff changeset
2008 memset(palette, 0, (sizeof palette));
Ritor1
parents:
diff changeset
2009
Ritor1
parents:
diff changeset
2010 for (i=num_trans=0; i<entries; ++i)
Ritor1
parents:
diff changeset
2011 {
Ritor1
parents:
diff changeset
2012 /* This gets automatically converted to sRGB with reversal of the
Ritor1
parents:
diff changeset
2013 * pre-multiplication if the color-map has an alpha channel.
Ritor1
parents:
diff changeset
2014 */
Ritor1
parents:
diff changeset
2015 if (format & PNG_FORMAT_FLAG_LINEAR)
Ritor1
parents:
diff changeset
2016 {
Ritor1
parents:
diff changeset
2017 png_const_uint_16p entry = png_voidcast(png_const_uint_16p, cmap);
Ritor1
parents:
diff changeset
2018
Ritor1
parents:
diff changeset
2019 entry += i * channels;
Ritor1
parents:
diff changeset
2020
Ritor1
parents:
diff changeset
2021 if (channels & 1) /* no alpha */
Ritor1
parents:
diff changeset
2022 {
Ritor1
parents:
diff changeset
2023 if (channels >= 3) /* RGB */
Ritor1
parents:
diff changeset
2024 {
Ritor1
parents:
diff changeset
2025 palette[i].blue = (png_byte)PNG_sRGB_FROM_LINEAR(255 *
Ritor1
parents:
diff changeset
2026 entry[(2 ^ bgr)]);
Ritor1
parents:
diff changeset
2027 palette[i].green = (png_byte)PNG_sRGB_FROM_LINEAR(255 *
Ritor1
parents:
diff changeset
2028 entry[1]);
Ritor1
parents:
diff changeset
2029 palette[i].red = (png_byte)PNG_sRGB_FROM_LINEAR(255 *
Ritor1
parents:
diff changeset
2030 entry[bgr]);
Ritor1
parents:
diff changeset
2031 }
Ritor1
parents:
diff changeset
2032
Ritor1
parents:
diff changeset
2033 else /* Gray */
Ritor1
parents:
diff changeset
2034 palette[i].blue = palette[i].red = palette[i].green =
Ritor1
parents:
diff changeset
2035 (png_byte)PNG_sRGB_FROM_LINEAR(255 * *entry);
Ritor1
parents:
diff changeset
2036 }
Ritor1
parents:
diff changeset
2037
Ritor1
parents:
diff changeset
2038 else /* alpha */
Ritor1
parents:
diff changeset
2039 {
Ritor1
parents:
diff changeset
2040 png_uint_16 alpha = entry[afirst ? 0 : channels-1];
Ritor1
parents:
diff changeset
2041 png_byte alphabyte = (png_byte)PNG_DIV257(alpha);
Ritor1
parents:
diff changeset
2042 png_uint_32 reciprocal = 0;
Ritor1
parents:
diff changeset
2043
Ritor1
parents:
diff changeset
2044 /* Calculate a reciprocal, as in the png_write_image_8bit code above
Ritor1
parents:
diff changeset
2045 * this is designed to produce a value scaled to 255*65535 when
Ritor1
parents:
diff changeset
2046 * divided by 128 (i.e. asr 7).
Ritor1
parents:
diff changeset
2047 */
Ritor1
parents:
diff changeset
2048 if (alphabyte > 0 && alphabyte < 255)
Ritor1
parents:
diff changeset
2049 reciprocal = (((0xffff*0xff)<<7)+(alpha>>1))/alpha;
Ritor1
parents:
diff changeset
2050
Ritor1
parents:
diff changeset
2051 tRNS[i] = alphabyte;
Ritor1
parents:
diff changeset
2052 if (alphabyte < 255)
Ritor1
parents:
diff changeset
2053 num_trans = i+1;
Ritor1
parents:
diff changeset
2054
Ritor1
parents:
diff changeset
2055 if (channels >= 3) /* RGB */
Ritor1
parents:
diff changeset
2056 {
Ritor1
parents:
diff changeset
2057 palette[i].blue = png_unpremultiply(entry[afirst + (2 ^ bgr)],
Ritor1
parents:
diff changeset
2058 alpha, reciprocal);
Ritor1
parents:
diff changeset
2059 palette[i].green = png_unpremultiply(entry[afirst + 1], alpha,
Ritor1
parents:
diff changeset
2060 reciprocal);
Ritor1
parents:
diff changeset
2061 palette[i].red = png_unpremultiply(entry[afirst + bgr], alpha,
Ritor1
parents:
diff changeset
2062 reciprocal);
Ritor1
parents:
diff changeset
2063 }
Ritor1
parents:
diff changeset
2064
Ritor1
parents:
diff changeset
2065 else /* gray */
Ritor1
parents:
diff changeset
2066 palette[i].blue = palette[i].red = palette[i].green =
Ritor1
parents:
diff changeset
2067 png_unpremultiply(entry[afirst], alpha, reciprocal);
Ritor1
parents:
diff changeset
2068 }
Ritor1
parents:
diff changeset
2069 }
Ritor1
parents:
diff changeset
2070
Ritor1
parents:
diff changeset
2071 else /* Color-map has sRGB values */
Ritor1
parents:
diff changeset
2072 {
Ritor1
parents:
diff changeset
2073 png_const_bytep entry = png_voidcast(png_const_bytep, cmap);
Ritor1
parents:
diff changeset
2074
Ritor1
parents:
diff changeset
2075 entry += i * channels;
Ritor1
parents:
diff changeset
2076
Ritor1
parents:
diff changeset
2077 switch (channels)
Ritor1
parents:
diff changeset
2078 {
Ritor1
parents:
diff changeset
2079 case 4:
Ritor1
parents:
diff changeset
2080 tRNS[i] = entry[afirst ? 0 : 3];
Ritor1
parents:
diff changeset
2081 if (tRNS[i] < 255)
Ritor1
parents:
diff changeset
2082 num_trans = i+1;
Ritor1
parents:
diff changeset
2083 /* FALL THROUGH */
Ritor1
parents:
diff changeset
2084 case 3:
Ritor1
parents:
diff changeset
2085 palette[i].blue = entry[afirst + (2 ^ bgr)];
Ritor1
parents:
diff changeset
2086 palette[i].green = entry[afirst + 1];
Ritor1
parents:
diff changeset
2087 palette[i].red = entry[afirst + bgr];
Ritor1
parents:
diff changeset
2088 break;
Ritor1
parents:
diff changeset
2089
Ritor1
parents:
diff changeset
2090 case 2:
Ritor1
parents:
diff changeset
2091 tRNS[i] = entry[1 ^ afirst];
Ritor1
parents:
diff changeset
2092 if (tRNS[i] < 255)
Ritor1
parents:
diff changeset
2093 num_trans = i+1;
Ritor1
parents:
diff changeset
2094 /* FALL THROUGH */
Ritor1
parents:
diff changeset
2095 case 1:
Ritor1
parents:
diff changeset
2096 palette[i].blue = palette[i].red = palette[i].green =
Ritor1
parents:
diff changeset
2097 entry[afirst];
Ritor1
parents:
diff changeset
2098 break;
Ritor1
parents:
diff changeset
2099
Ritor1
parents:
diff changeset
2100 default:
Ritor1
parents:
diff changeset
2101 break;
Ritor1
parents:
diff changeset
2102 }
Ritor1
parents:
diff changeset
2103 }
Ritor1
parents:
diff changeset
2104 }
Ritor1
parents:
diff changeset
2105
Ritor1
parents:
diff changeset
2106 # ifdef afirst
Ritor1
parents:
diff changeset
2107 # undef afirst
Ritor1
parents:
diff changeset
2108 # endif
Ritor1
parents:
diff changeset
2109 # ifdef bgr
Ritor1
parents:
diff changeset
2110 # undef bgr
Ritor1
parents:
diff changeset
2111 # endif
Ritor1
parents:
diff changeset
2112
Ritor1
parents:
diff changeset
2113 png_set_PLTE(image->opaque->png_ptr, image->opaque->info_ptr, palette,
Ritor1
parents:
diff changeset
2114 entries);
Ritor1
parents:
diff changeset
2115
Ritor1
parents:
diff changeset
2116 if (num_trans > 0)
Ritor1
parents:
diff changeset
2117 png_set_tRNS(image->opaque->png_ptr, image->opaque->info_ptr, tRNS,
Ritor1
parents:
diff changeset
2118 num_trans, NULL);
Ritor1
parents:
diff changeset
2119
Ritor1
parents:
diff changeset
2120 image->colormap_entries = entries;
Ritor1
parents:
diff changeset
2121 }
Ritor1
parents:
diff changeset
2122
Ritor1
parents:
diff changeset
2123 static int
Ritor1
parents:
diff changeset
2124 png_image_write_main(png_voidp argument)
Ritor1
parents:
diff changeset
2125 {
Ritor1
parents:
diff changeset
2126 png_image_write_control *display = png_voidcast(png_image_write_control*,
Ritor1
parents:
diff changeset
2127 argument);
Ritor1
parents:
diff changeset
2128 png_imagep image = display->image;
Ritor1
parents:
diff changeset
2129 png_structrp png_ptr = image->opaque->png_ptr;
Ritor1
parents:
diff changeset
2130 png_inforp info_ptr = image->opaque->info_ptr;
Ritor1
parents:
diff changeset
2131 png_uint_32 format = image->format;
Ritor1
parents:
diff changeset
2132
Ritor1
parents:
diff changeset
2133 int colormap = (format & PNG_FORMAT_FLAG_COLORMAP) != 0;
Ritor1
parents:
diff changeset
2134 int linear = !colormap && (format & PNG_FORMAT_FLAG_LINEAR) != 0; /* input */
Ritor1
parents:
diff changeset
2135 int alpha = !colormap && (format & PNG_FORMAT_FLAG_ALPHA) != 0;
Ritor1
parents:
diff changeset
2136 int write_16bit = linear && !colormap && !display->convert_to_8bit;
Ritor1
parents:
diff changeset
2137
Ritor1
parents:
diff changeset
2138 # ifdef PNG_BENIGN_ERRORS_SUPPORTED
Ritor1
parents:
diff changeset
2139 /* Make sure we error out on any bad situation */
Ritor1
parents:
diff changeset
2140 png_set_benign_errors(png_ptr, 0/*error*/);
Ritor1
parents:
diff changeset
2141 # endif
Ritor1
parents:
diff changeset
2142
Ritor1
parents:
diff changeset
2143 /* Default the 'row_stride' parameter if required. */
Ritor1
parents:
diff changeset
2144 if (display->row_stride == 0)
Ritor1
parents:
diff changeset
2145 display->row_stride = PNG_IMAGE_ROW_STRIDE(*image);
Ritor1
parents:
diff changeset
2146
Ritor1
parents:
diff changeset
2147 /* Set the required transforms then write the rows in the correct order. */
Ritor1
parents:
diff changeset
2148 if (format & PNG_FORMAT_FLAG_COLORMAP)
Ritor1
parents:
diff changeset
2149 {
Ritor1
parents:
diff changeset
2150 if (display->colormap != NULL && image->colormap_entries > 0)
Ritor1
parents:
diff changeset
2151 {
Ritor1
parents:
diff changeset
2152 png_uint_32 entries = image->colormap_entries;
Ritor1
parents:
diff changeset
2153
Ritor1
parents:
diff changeset
2154 png_set_IHDR(png_ptr, info_ptr, image->width, image->height,
Ritor1
parents:
diff changeset
2155 entries > 16 ? 8 : (entries > 4 ? 4 : (entries > 2 ? 2 : 1)),
Ritor1
parents:
diff changeset
2156 PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE,
Ritor1
parents:
diff changeset
2157 PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
Ritor1
parents:
diff changeset
2158
Ritor1
parents:
diff changeset
2159 png_image_set_PLTE(display);
Ritor1
parents:
diff changeset
2160 }
Ritor1
parents:
diff changeset
2161
Ritor1
parents:
diff changeset
2162 else
Ritor1
parents:
diff changeset
2163 png_error(image->opaque->png_ptr,
Ritor1
parents:
diff changeset
2164 "no color-map for color-mapped image");
Ritor1
parents:
diff changeset
2165 }
Ritor1
parents:
diff changeset
2166
Ritor1
parents:
diff changeset
2167 else
Ritor1
parents:
diff changeset
2168 png_set_IHDR(png_ptr, info_ptr, image->width, image->height,
Ritor1
parents:
diff changeset
2169 write_16bit ? 16 : 8,
Ritor1
parents:
diff changeset
2170 ((format & PNG_FORMAT_FLAG_COLOR) ? PNG_COLOR_MASK_COLOR : 0) +
Ritor1
parents:
diff changeset
2171 ((format & PNG_FORMAT_FLAG_ALPHA) ? PNG_COLOR_MASK_ALPHA : 0),
Ritor1
parents:
diff changeset
2172 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
Ritor1
parents:
diff changeset
2173
Ritor1
parents:
diff changeset
2174 /* Counter-intuitively the data transformations must be called *after*
Ritor1
parents:
diff changeset
2175 * png_write_info, not before as in the read code, but the 'set' functions
Ritor1
parents:
diff changeset
2176 * must still be called before. Just set the color space information, never
Ritor1
parents:
diff changeset
2177 * write an interlaced image.
Ritor1
parents:
diff changeset
2178 */
Ritor1
parents:
diff changeset
2179
Ritor1
parents:
diff changeset
2180 if (write_16bit)
Ritor1
parents:
diff changeset
2181 {
Ritor1
parents:
diff changeset
2182 /* The gamma here is 1.0 (linear) and the cHRM chunk matches sRGB. */
Ritor1
parents:
diff changeset
2183 png_set_gAMA_fixed(png_ptr, info_ptr, PNG_GAMMA_LINEAR);
Ritor1
parents:
diff changeset
2184
Ritor1
parents:
diff changeset
2185 if (!(image->flags & PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB))
Ritor1
parents:
diff changeset
2186 png_set_cHRM_fixed(png_ptr, info_ptr,
Ritor1
parents:
diff changeset
2187 /* color x y */
Ritor1
parents:
diff changeset
2188 /* white */ 31270, 32900,
Ritor1
parents:
diff changeset
2189 /* red */ 64000, 33000,
Ritor1
parents:
diff changeset
2190 /* green */ 30000, 60000,
Ritor1
parents:
diff changeset
2191 /* blue */ 15000, 6000
Ritor1
parents:
diff changeset
2192 );
Ritor1
parents:
diff changeset
2193 }
Ritor1
parents:
diff changeset
2194
Ritor1
parents:
diff changeset
2195 else if (!(image->flags & PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB))
Ritor1
parents:
diff changeset
2196 png_set_sRGB(png_ptr, info_ptr, PNG_sRGB_INTENT_PERCEPTUAL);
Ritor1
parents:
diff changeset
2197
Ritor1
parents:
diff changeset
2198 /* Else writing an 8-bit file and the *colors* aren't sRGB, but the 8-bit
Ritor1
parents:
diff changeset
2199 * space must still be gamma encoded.
Ritor1
parents:
diff changeset
2200 */
Ritor1
parents:
diff changeset
2201 else
Ritor1
parents:
diff changeset
2202 png_set_gAMA_fixed(png_ptr, info_ptr, PNG_GAMMA_sRGB_INVERSE);
Ritor1
parents:
diff changeset
2203
Ritor1
parents:
diff changeset
2204 /* Write the file header. */
Ritor1
parents:
diff changeset
2205 png_write_info(png_ptr, info_ptr);
Ritor1
parents:
diff changeset
2206
Ritor1
parents:
diff changeset
2207 /* Now set up the data transformations (*after* the header is written),
Ritor1
parents:
diff changeset
2208 * remove the handled transformations from the 'format' flags for checking.
Ritor1
parents:
diff changeset
2209 *
Ritor1
parents:
diff changeset
2210 * First check for a little endian system if writing 16 bit files.
Ritor1
parents:
diff changeset
2211 */
Ritor1
parents:
diff changeset
2212 if (write_16bit)
Ritor1
parents:
diff changeset
2213 {
Ritor1
parents:
diff changeset
2214 PNG_CONST png_uint_16 le = 0x0001;
Ritor1
parents:
diff changeset
2215
Ritor1
parents:
diff changeset
2216 if (*(png_const_bytep)&le)
Ritor1
parents:
diff changeset
2217 png_set_swap(png_ptr);
Ritor1
parents:
diff changeset
2218 }
Ritor1
parents:
diff changeset
2219
Ritor1
parents:
diff changeset
2220 # ifdef PNG_SIMPLIFIED_WRITE_BGR_SUPPORTED
Ritor1
parents:
diff changeset
2221 if (format & PNG_FORMAT_FLAG_BGR)
Ritor1
parents:
diff changeset
2222 {
Ritor1
parents:
diff changeset
2223 if (!colormap && (format & PNG_FORMAT_FLAG_COLOR) != 0)
Ritor1
parents:
diff changeset
2224 png_set_bgr(png_ptr);
Ritor1
parents:
diff changeset
2225 format &= ~PNG_FORMAT_FLAG_BGR;
Ritor1
parents:
diff changeset
2226 }
Ritor1
parents:
diff changeset
2227 # endif
Ritor1
parents:
diff changeset
2228
Ritor1
parents:
diff changeset
2229 # ifdef PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED
Ritor1
parents:
diff changeset
2230 if (format & PNG_FORMAT_FLAG_AFIRST)
Ritor1
parents:
diff changeset
2231 {
Ritor1
parents:
diff changeset
2232 if (!colormap && (format & PNG_FORMAT_FLAG_ALPHA) != 0)
Ritor1
parents:
diff changeset
2233 png_set_swap_alpha(png_ptr);
Ritor1
parents:
diff changeset
2234 format &= ~PNG_FORMAT_FLAG_AFIRST;
Ritor1
parents:
diff changeset
2235 }
Ritor1
parents:
diff changeset
2236 # endif
Ritor1
parents:
diff changeset
2237
Ritor1
parents:
diff changeset
2238 /* If there are 16 or fewer color-map entries we wrote a lower bit depth
Ritor1
parents:
diff changeset
2239 * above, but the application data is still byte packed.
Ritor1
parents:
diff changeset
2240 */
Ritor1
parents:
diff changeset
2241 if (colormap && image->colormap_entries <= 16)
Ritor1
parents:
diff changeset
2242 png_set_packing(png_ptr);
Ritor1
parents:
diff changeset
2243
Ritor1
parents:
diff changeset
2244 /* That should have handled all (both) the transforms. */
Ritor1
parents:
diff changeset
2245 if ((format & ~(png_uint_32)(PNG_FORMAT_FLAG_COLOR | PNG_FORMAT_FLAG_LINEAR |
Ritor1
parents:
diff changeset
2246 PNG_FORMAT_FLAG_ALPHA | PNG_FORMAT_FLAG_COLORMAP)) != 0)
Ritor1
parents:
diff changeset
2247 png_error(png_ptr, "png_write_image: unsupported transformation");
Ritor1
parents:
diff changeset
2248
Ritor1
parents:
diff changeset
2249 {
Ritor1
parents:
diff changeset
2250 png_const_bytep row = png_voidcast(png_const_bytep, display->buffer);
Ritor1
parents:
diff changeset
2251 ptrdiff_t row_bytes = display->row_stride;
Ritor1
parents:
diff changeset
2252
Ritor1
parents:
diff changeset
2253 if (linear)
Ritor1
parents:
diff changeset
2254 row_bytes *= (sizeof (png_uint_16));
Ritor1
parents:
diff changeset
2255
Ritor1
parents:
diff changeset
2256 if (row_bytes < 0)
Ritor1
parents:
diff changeset
2257 row += (image->height-1) * (-row_bytes);
Ritor1
parents:
diff changeset
2258
Ritor1
parents:
diff changeset
2259 display->first_row = row;
Ritor1
parents:
diff changeset
2260 display->row_bytes = row_bytes;
Ritor1
parents:
diff changeset
2261 }
Ritor1
parents:
diff changeset
2262
Ritor1
parents:
diff changeset
2263 /* Apply 'fast' options if the flag is set. */
Ritor1
parents:
diff changeset
2264 if ((image->flags & PNG_IMAGE_FLAG_FAST) != 0)
Ritor1
parents:
diff changeset
2265 {
Ritor1
parents:
diff changeset
2266 png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE, PNG_NO_FILTERS);
Ritor1
parents:
diff changeset
2267 /* NOTE: determined by experiment using pngstest, this reflects some
Ritor1
parents:
diff changeset
2268 * balance between the time to write the image once and the time to read
Ritor1
parents:
diff changeset
2269 * it about 50 times. The speed-up in pngstest was about 10-20% of the
Ritor1
parents:
diff changeset
2270 * total (user) time on a heavily loaded system.
Ritor1
parents:
diff changeset
2271 */
Ritor1
parents:
diff changeset
2272 png_set_compression_level(png_ptr, 3);
Ritor1
parents:
diff changeset
2273 }
Ritor1
parents:
diff changeset
2274
Ritor1
parents:
diff changeset
2275 /* Check for the cases that currently require a pre-transform on the row
Ritor1
parents:
diff changeset
2276 * before it is written. This only applies when the input is 16-bit and
Ritor1
parents:
diff changeset
2277 * either there is an alpha channel or it is converted to 8-bit.
Ritor1
parents:
diff changeset
2278 */
Ritor1
parents:
diff changeset
2279 if ((linear && alpha) || (!colormap && display->convert_to_8bit))
Ritor1
parents:
diff changeset
2280 {
Ritor1
parents:
diff changeset
2281 png_bytep row = png_voidcast(png_bytep, png_malloc(png_ptr,
Ritor1
parents:
diff changeset
2282 png_get_rowbytes(png_ptr, info_ptr)));
Ritor1
parents:
diff changeset
2283 int result;
Ritor1
parents:
diff changeset
2284
Ritor1
parents:
diff changeset
2285 display->local_row = row;
Ritor1
parents:
diff changeset
2286 if (write_16bit)
Ritor1
parents:
diff changeset
2287 result = png_safe_execute(image, png_write_image_16bit, display);
Ritor1
parents:
diff changeset
2288 else
Ritor1
parents:
diff changeset
2289 result = png_safe_execute(image, png_write_image_8bit, display);
Ritor1
parents:
diff changeset
2290 display->local_row = NULL;
Ritor1
parents:
diff changeset
2291
Ritor1
parents:
diff changeset
2292 png_free(png_ptr, row);
Ritor1
parents:
diff changeset
2293
Ritor1
parents:
diff changeset
2294 /* Skip the 'write_end' on error: */
Ritor1
parents:
diff changeset
2295 if (!result)
Ritor1
parents:
diff changeset
2296 return 0;
Ritor1
parents:
diff changeset
2297 }
Ritor1
parents:
diff changeset
2298
Ritor1
parents:
diff changeset
2299 /* Otherwise this is the case where the input is in a format currently
Ritor1
parents:
diff changeset
2300 * supported by the rest of the libpng write code; call it directly.
Ritor1
parents:
diff changeset
2301 */
Ritor1
parents:
diff changeset
2302 else
Ritor1
parents:
diff changeset
2303 {
Ritor1
parents:
diff changeset
2304 png_const_bytep row = png_voidcast(png_const_bytep, display->first_row);
Ritor1
parents:
diff changeset
2305 ptrdiff_t row_bytes = display->row_bytes;
Ritor1
parents:
diff changeset
2306 png_uint_32 y = image->height;
Ritor1
parents:
diff changeset
2307
Ritor1
parents:
diff changeset
2308 while (y-- > 0)
Ritor1
parents:
diff changeset
2309 {
Ritor1
parents:
diff changeset
2310 png_write_row(png_ptr, row);
Ritor1
parents:
diff changeset
2311 row += row_bytes;
Ritor1
parents:
diff changeset
2312 }
Ritor1
parents:
diff changeset
2313 }
Ritor1
parents:
diff changeset
2314
Ritor1
parents:
diff changeset
2315 png_write_end(png_ptr, info_ptr);
Ritor1
parents:
diff changeset
2316 return 1;
Ritor1
parents:
diff changeset
2317 }
Ritor1
parents:
diff changeset
2318
Ritor1
parents:
diff changeset
2319 int PNGAPI
Ritor1
parents:
diff changeset
2320 png_image_write_to_stdio(png_imagep image, FILE *file, int convert_to_8bit,
Ritor1
parents:
diff changeset
2321 const void *buffer, png_int_32 row_stride, const void *colormap)
Ritor1
parents:
diff changeset
2322 {
Ritor1
parents:
diff changeset
2323 /* Write the image to the given (FILE*). */
Ritor1
parents:
diff changeset
2324 if (image != NULL && image->version == PNG_IMAGE_VERSION)
Ritor1
parents:
diff changeset
2325 {
Ritor1
parents:
diff changeset
2326 if (file != NULL)
Ritor1
parents:
diff changeset
2327 {
Ritor1
parents:
diff changeset
2328 if (png_image_write_init(image))
Ritor1
parents:
diff changeset
2329 {
Ritor1
parents:
diff changeset
2330 png_image_write_control display;
Ritor1
parents:
diff changeset
2331 int result;
Ritor1
parents:
diff changeset
2332
Ritor1
parents:
diff changeset
2333 /* This is slightly evil, but png_init_io doesn't do anything other
Ritor1
parents:
diff changeset
2334 * than this and we haven't changed the standard IO functions so
Ritor1
parents:
diff changeset
2335 * this saves a 'safe' function.
Ritor1
parents:
diff changeset
2336 */
Ritor1
parents:
diff changeset
2337 image->opaque->png_ptr->io_ptr = file;
Ritor1
parents:
diff changeset
2338
Ritor1
parents:
diff changeset
2339 memset(&display, 0, (sizeof display));
Ritor1
parents:
diff changeset
2340 display.image = image;
Ritor1
parents:
diff changeset
2341 display.buffer = buffer;
Ritor1
parents:
diff changeset
2342 display.row_stride = row_stride;
Ritor1
parents:
diff changeset
2343 display.colormap = colormap;
Ritor1
parents:
diff changeset
2344 display.convert_to_8bit = convert_to_8bit;
Ritor1
parents:
diff changeset
2345
Ritor1
parents:
diff changeset
2346 result = png_safe_execute(image, png_image_write_main, &display);
Ritor1
parents:
diff changeset
2347 png_image_free(image);
Ritor1
parents:
diff changeset
2348 return result;
Ritor1
parents:
diff changeset
2349 }
Ritor1
parents:
diff changeset
2350
Ritor1
parents:
diff changeset
2351 else
Ritor1
parents:
diff changeset
2352 return 0;
Ritor1
parents:
diff changeset
2353 }
Ritor1
parents:
diff changeset
2354
Ritor1
parents:
diff changeset
2355 else
Ritor1
parents:
diff changeset
2356 return png_image_error(image,
Ritor1
parents:
diff changeset
2357 "png_image_write_to_stdio: invalid argument");
Ritor1
parents:
diff changeset
2358 }
Ritor1
parents:
diff changeset
2359
Ritor1
parents:
diff changeset
2360 else if (image != NULL)
Ritor1
parents:
diff changeset
2361 return png_image_error(image,
Ritor1
parents:
diff changeset
2362 "png_image_write_to_stdio: incorrect PNG_IMAGE_VERSION");
Ritor1
parents:
diff changeset
2363
Ritor1
parents:
diff changeset
2364 else
Ritor1
parents:
diff changeset
2365 return 0;
Ritor1
parents:
diff changeset
2366 }
Ritor1
parents:
diff changeset
2367
Ritor1
parents:
diff changeset
2368 int PNGAPI
Ritor1
parents:
diff changeset
2369 png_image_write_to_file(png_imagep image, const char *file_name,
Ritor1
parents:
diff changeset
2370 int convert_to_8bit, const void *buffer, png_int_32 row_stride,
Ritor1
parents:
diff changeset
2371 const void *colormap)
Ritor1
parents:
diff changeset
2372 {
Ritor1
parents:
diff changeset
2373 /* Write the image to the named file. */
Ritor1
parents:
diff changeset
2374 if (image != NULL && image->version == PNG_IMAGE_VERSION)
Ritor1
parents:
diff changeset
2375 {
Ritor1
parents:
diff changeset
2376 if (file_name != NULL)
Ritor1
parents:
diff changeset
2377 {
Ritor1
parents:
diff changeset
2378 FILE *fp = fopen(file_name, "wb");
Ritor1
parents:
diff changeset
2379
Ritor1
parents:
diff changeset
2380 if (fp != NULL)
Ritor1
parents:
diff changeset
2381 {
Ritor1
parents:
diff changeset
2382 if (png_image_write_to_stdio(image, fp, convert_to_8bit, buffer,
Ritor1
parents:
diff changeset
2383 row_stride, colormap))
Ritor1
parents:
diff changeset
2384 {
Ritor1
parents:
diff changeset
2385 int error; /* from fflush/fclose */
Ritor1
parents:
diff changeset
2386
Ritor1
parents:
diff changeset
2387 /* Make sure the file is flushed correctly. */
Ritor1
parents:
diff changeset
2388 if (fflush(fp) == 0 && ferror(fp) == 0)
Ritor1
parents:
diff changeset
2389 {
Ritor1
parents:
diff changeset
2390 if (fclose(fp) == 0)
Ritor1
parents:
diff changeset
2391 return 1;
Ritor1
parents:
diff changeset
2392
Ritor1
parents:
diff changeset
2393 error = errno; /* from fclose */
Ritor1
parents:
diff changeset
2394 }
Ritor1
parents:
diff changeset
2395
Ritor1
parents:
diff changeset
2396 else
Ritor1
parents:
diff changeset
2397 {
Ritor1
parents:
diff changeset
2398 error = errno; /* from fflush or ferror */
Ritor1
parents:
diff changeset
2399 (void)fclose(fp);
Ritor1
parents:
diff changeset
2400 }
Ritor1
parents:
diff changeset
2401
Ritor1
parents:
diff changeset
2402 (void)remove(file_name);
Ritor1
parents:
diff changeset
2403 /* The image has already been cleaned up; this is just used to
Ritor1
parents:
diff changeset
2404 * set the error (because the original write succeeded).
Ritor1
parents:
diff changeset
2405 */
Ritor1
parents:
diff changeset
2406 return png_image_error(image, strerror(error));
Ritor1
parents:
diff changeset
2407 }
Ritor1
parents:
diff changeset
2408
Ritor1
parents:
diff changeset
2409 else
Ritor1
parents:
diff changeset
2410 {
Ritor1
parents:
diff changeset
2411 /* Clean up: just the opened file. */
Ritor1
parents:
diff changeset
2412 (void)fclose(fp);
Ritor1
parents:
diff changeset
2413 (void)remove(file_name);
Ritor1
parents:
diff changeset
2414 return 0;
Ritor1
parents:
diff changeset
2415 }
Ritor1
parents:
diff changeset
2416 }
Ritor1
parents:
diff changeset
2417
Ritor1
parents:
diff changeset
2418 else
Ritor1
parents:
diff changeset
2419 return png_image_error(image, strerror(errno));
Ritor1
parents:
diff changeset
2420 }
Ritor1
parents:
diff changeset
2421
Ritor1
parents:
diff changeset
2422 else
Ritor1
parents:
diff changeset
2423 return png_image_error(image,
Ritor1
parents:
diff changeset
2424 "png_image_write_to_file: invalid argument");
Ritor1
parents:
diff changeset
2425 }
Ritor1
parents:
diff changeset
2426
Ritor1
parents:
diff changeset
2427 else if (image != NULL)
Ritor1
parents:
diff changeset
2428 return png_image_error(image,
Ritor1
parents:
diff changeset
2429 "png_image_write_to_file: incorrect PNG_IMAGE_VERSION");
Ritor1
parents:
diff changeset
2430
Ritor1
parents:
diff changeset
2431 else
Ritor1
parents:
diff changeset
2432 return 0;
Ritor1
parents:
diff changeset
2433 }
Ritor1
parents:
diff changeset
2434 #endif /* PNG_STDIO_SUPPORTED */
Ritor1
parents:
diff changeset
2435 #endif /* SIMPLIFIED_WRITE */
Ritor1
parents:
diff changeset
2436 #endif /* PNG_WRITE_SUPPORTED */