]>
Commit | Line | Data |
---|---|---|
259182b6 ER |
1 | Index: pngread.c |
2 | =================================================================== | |
6df9a45f | 3 | --- pngread.c |
4 | +++ pngread.c | |
9f147502 | 5 | @@ -413,6 +413,11 @@ |
259182b6 ER |
6 | #if defined(PNG_READ_zTXt_SUPPORTED) |
7 | PNG_CONST PNG_zTXt; | |
8 | #endif | |
9 | +#if defined(PNG_READ_APNG_SUPPORTED) | |
10 | + PNG_CONST PNG_acTL; | |
11 | + PNG_CONST PNG_fcTL; | |
12 | + PNG_CONST PNG_fdAT; | |
13 | +#endif | |
14 | #endif /* PNG_USE_LOCAL_ARRAYS */ | |
c501f448 JB |
15 | png_uint_32 length = png_read_chunk_header(png_ptr); |
16 | PNG_CONST png_bytep chunk_name = png_ptr->chunk_name; | |
9f147502 | 17 | @@ -457,6 +462,9 @@ |
259182b6 ER |
18 | !(png_ptr->mode & PNG_HAVE_PLTE)) |
19 | png_error(png_ptr, "Missing PLTE before IDAT"); | |
20 | ||
21 | +#if defined(PNG_READ_APNG_SUPPORTED) | |
22 | + png_have_info(png_ptr, info_ptr); | |
23 | +#endif | |
24 | png_ptr->idat_size = length; | |
25 | png_ptr->mode |= PNG_HAVE_IDAT; | |
26 | break; | |
9f147502 | 27 | @@ -529,12 +537,97 @@ |
c501f448 | 28 | else if (!png_memcmp(chunk_name, png_iTXt, 4)) |
259182b6 ER |
29 | png_handle_iTXt(png_ptr, info_ptr, length); |
30 | #endif | |
31 | +#if defined(PNG_READ_APNG_SUPPORTED) | |
6df9a45f | 32 | + else if (!png_memcmp(chunk_name, png_acTL, 4)) |
259182b6 | 33 | + png_handle_acTL(png_ptr, info_ptr, length); |
6df9a45f | 34 | + else if (!png_memcmp(chunk_name, png_fcTL, 4)) |
259182b6 | 35 | + png_handle_fcTL(png_ptr, info_ptr, length); |
6df9a45f | 36 | + else if (!png_memcmp(chunk_name, png_fdAT, 4)) |
259182b6 ER |
37 | + png_handle_fdAT(png_ptr, info_ptr, length); |
38 | +#endif | |
39 | else | |
40 | png_handle_unknown(png_ptr, info_ptr, length); | |
41 | } | |
42 | } | |
43 | #endif /* PNG_NO_SEQUENTIAL_READ_SUPPORTED */ | |
44 | ||
45 | +#if defined(PNG_READ_APNG_SUPPORTED) | |
46 | +void PNGAPI | |
47 | +png_read_frame_head(png_structp png_ptr, png_infop info_ptr) | |
48 | +{ | |
49 | + png_byte have_chunk_after_DAT; /* after IDAT or after fdAT */ | |
50 | + | |
6df9a45f | 51 | + png_debug(0, "Reading frame head"); |
259182b6 ER |
52 | + |
53 | + if (!(png_ptr->mode & PNG_HAVE_acTL)) | |
54 | + png_error(png_ptr, "attempt to png_read_frame_head() but " | |
55 | + "no acTL present"); | |
56 | + | |
57 | + /* do nothing for the main IDAT */ | |
58 | + if (png_ptr->num_frames_read == 0) | |
59 | + return; | |
60 | + | |
61 | + png_crc_finish(png_ptr, 0); /* CRC from last IDAT or fdAT chunk */ | |
62 | + | |
63 | + png_read_reset(png_ptr); | |
64 | + png_ptr->mode &= ~PNG_HAVE_fcTL; | |
65 | + | |
66 | + have_chunk_after_DAT = 0; | |
67 | + for (;;) | |
68 | + { | |
69 | +#ifdef PNG_USE_LOCAL_ARRAYS | |
70 | + PNG_IDAT; | |
71 | + PNG_fdAT; | |
72 | + PNG_fcTL; | |
73 | +#endif | |
74 | + png_byte chunk_length[4]; | |
75 | + png_uint_32 length; | |
76 | + | |
77 | + png_read_data(png_ptr, chunk_length, 4); | |
78 | + length = png_get_uint_31(png_ptr, chunk_length); | |
79 | + | |
80 | + png_reset_crc(png_ptr); | |
81 | + png_crc_read(png_ptr, png_ptr->chunk_name, 4); | |
82 | + | |
83 | + if (!png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) | |
84 | + { | |
85 | + /* discard trailing IDATs for the first frame */ | |
86 | + if (have_chunk_after_DAT || png_ptr->num_frames_read > 1) | |
87 | + png_error(png_ptr, "png_read_frame_head(): out of place IDAT"); | |
88 | + png_crc_finish(png_ptr, length); | |
89 | + } | |
90 | + else if (!png_memcmp(png_ptr->chunk_name, png_fcTL, 4)) | |
91 | + { | |
92 | + png_handle_fcTL(png_ptr, info_ptr, length); | |
93 | + have_chunk_after_DAT = 1; | |
94 | + } | |
95 | + else if (!png_memcmp(png_ptr->chunk_name, png_fdAT, 4)) | |
96 | + { | |
97 | + png_ensure_sequence_number(png_ptr, length); | |
98 | + | |
99 | + /* discard trailing fdATs for frames other than the first */ | |
100 | + if (!have_chunk_after_DAT && png_ptr->num_frames_read > 1) | |
101 | + png_crc_finish(png_ptr, length - 4); | |
102 | + else if(png_ptr->mode & PNG_HAVE_fcTL) | |
103 | + { | |
104 | + png_ptr->idat_size = length - 4; | |
105 | + png_ptr->mode |= PNG_HAVE_IDAT; | |
106 | + | |
107 | + break; | |
108 | + } | |
109 | + else | |
110 | + png_error(png_ptr, "png_read_frame_head(): out of place fdAT"); | |
111 | + } | |
112 | + else | |
113 | + { | |
114 | + png_warning(png_ptr, "Skipped (ignored) a chunk " | |
115 | + "between APNG chunks"); | |
116 | + png_crc_finish(png_ptr, length); | |
117 | + } | |
118 | + } | |
119 | +} | |
120 | +#endif /* PNG_READ_APNG_SUPPORTED */ | |
121 | + | |
6df9a45f | 122 | /* Optional call to update the users info_ptr structure */ |
259182b6 ER |
123 | void PNGAPI |
124 | png_read_update_info(png_structp png_ptr, png_infop info_ptr) | |
9f147502 | 125 | @@ -573,6 +666,10 @@ |
259182b6 ER |
126 | { |
127 | #ifdef PNG_USE_LOCAL_ARRAYS | |
128 | PNG_CONST PNG_IDAT; | |
129 | +#if defined(PNG_READ_APNG_SUPPORTED) | |
130 | + PNG_CONST PNG_fdAT; | |
131 | + PNG_CONST PNG_IEND; | |
132 | +#endif | |
133 | PNG_CONST int png_pass_dsp_mask[7] = {0xff, 0x0f, 0xff, 0x33, 0xff, 0x55, | |
c501f448 | 134 | 0xff}; |
259182b6 | 135 | PNG_CONST int png_pass_mask[7] = {0x80, 0x08, 0x88, 0x22, 0xaa, 0x55, 0xff}; |
9f147502 | 136 | @@ -703,13 +800,39 @@ |
259182b6 ER |
137 | { |
138 | if (!(png_ptr->zstream.avail_in)) | |
139 | { | |
140 | - while (!png_ptr->idat_size) | |
141 | + png_uint_32 bytes_to_skip = 0; | |
6df9a45f | 142 | + |
259182b6 ER |
143 | + while (!png_ptr->idat_size || bytes_to_skip != 0) |
144 | { | |
259182b6 | 145 | - png_crc_finish(png_ptr, 0); |
259182b6 | 146 | + png_crc_finish(png_ptr, bytes_to_skip); |
6df9a45f | 147 | + bytes_to_skip = 0; |
c501f448 JB |
148 | |
149 | png_ptr->idat_size = png_read_chunk_header(png_ptr); | |
259182b6 ER |
150 | +#if defined(PNG_READ_APNG_SUPPORTED) |
151 | + if (png_ptr->num_frames_read == 0) | |
152 | + { | |
153 | +#endif | |
c501f448 JB |
154 | if (png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) |
155 | png_error(png_ptr, "Not enough image data"); | |
259182b6 ER |
156 | +#if defined(PNG_READ_APNG_SUPPORTED) |
157 | + } | |
158 | + else | |
159 | + { | |
160 | + if (!png_memcmp(png_ptr->chunk_name, png_IEND, 4)) | |
161 | + png_error(png_ptr, "Not enough image data"); | |
162 | + if (png_memcmp(png_ptr->chunk_name, png_fdAT, 4)) | |
163 | + { | |
164 | + png_warning(png_ptr, "Skipped (ignored) a chunk " | |
165 | + "between APNG chunks"); | |
166 | + bytes_to_skip = png_ptr->idat_size; | |
167 | + continue; | |
168 | + } | |
169 | + | |
170 | + png_ensure_sequence_number(png_ptr, png_ptr->idat_size); | |
171 | + | |
172 | + png_ptr->idat_size -= 4; | |
173 | + } | |
174 | +#endif | |
175 | } | |
176 | png_ptr->zstream.avail_in = (uInt)png_ptr->zbuf_size; | |
177 | png_ptr->zstream.next_in = png_ptr->zbuf; | |
9f147502 | 178 | @@ -727,6 +850,9 @@ |
259182b6 ER |
179 | png_error(png_ptr, "Extra compressed data"); |
180 | png_ptr->mode |= PNG_AFTER_IDAT; | |
181 | png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED; | |
182 | +#if defined(PNG_READ_APNG_SUPPORTED) | |
183 | + png_ptr->num_frames_read++; | |
184 | +#endif | |
185 | break; | |
186 | } | |
187 | if (ret != Z_OK) | |
9f147502 | 188 | @@ -981,6 +1107,11 @@ |
259182b6 ER |
189 | #if defined(PNG_READ_zTXt_SUPPORTED) |
190 | PNG_CONST PNG_zTXt; | |
191 | #endif | |
192 | +#if defined(PNG_READ_APNG_SUPPORTED) | |
193 | + PNG_CONST PNG_acTL; | |
194 | + PNG_CONST PNG_fcTL; | |
195 | + PNG_CONST PNG_fdAT; | |
196 | +#endif | |
197 | #endif /* PNG_USE_LOCAL_ARRAYS */ | |
c501f448 JB |
198 | png_uint_32 length = png_read_chunk_header(png_ptr); |
199 | PNG_CONST png_bytep chunk_name = png_ptr->chunk_name; | |
9f147502 | 200 | @@ -1081,6 +1212,14 @@ |
c501f448 | 201 | else if (!png_memcmp(chunk_name, png_iTXt, 4)) |
259182b6 ER |
202 | png_handle_iTXt(png_ptr, info_ptr, length); |
203 | #endif | |
204 | +#if defined(PNG_READ_APNG_SUPPORTED) | |
6df9a45f | 205 | + else if (!png_memcmp(chunk_name, png_acTL, 4)) |
259182b6 | 206 | + png_handle_acTL(png_ptr, info_ptr, length); |
6df9a45f | 207 | + else if (!png_memcmp(chunk_name, png_fcTL, 4)) |
259182b6 | 208 | + png_handle_fcTL(png_ptr, info_ptr, length); |
6df9a45f | 209 | + else if (!png_memcmp(chunk_name, png_fdAT, 4)) |
259182b6 ER |
210 | + png_handle_fdAT(png_ptr, info_ptr, length); |
211 | +#endif | |
212 | else | |
213 | png_handle_unknown(png_ptr, info_ptr, length); | |
214 | } while (!(png_ptr->mode & PNG_HAVE_IEND)); | |
259182b6 ER |
215 | Index: pngget.c |
216 | =================================================================== | |
6df9a45f | 217 | --- pngget.c |
218 | +++ pngget.c | |
9f147502 | 219 | @@ -839,6 +839,167 @@ |
259182b6 ER |
220 | } |
221 | #endif | |
222 | ||
223 | +#if defined(PNG_APNG_SUPPORTED) | |
224 | +png_uint_32 PNGAPI | |
225 | +png_get_acTL(png_structp png_ptr, png_infop info_ptr, | |
226 | + png_uint_32 *num_frames, png_uint_32 *num_plays) | |
227 | +{ | |
6df9a45f | 228 | + png_debug1(1, "in %s retrieval function", "acTL"); |
259182b6 ER |
229 | + |
230 | + if (png_ptr != NULL && info_ptr != NULL && | |
231 | + (info_ptr->valid & PNG_INFO_acTL) && | |
232 | + num_frames != NULL && num_plays != NULL) | |
233 | + { | |
234 | + *num_frames = info_ptr->num_frames; | |
235 | + *num_plays = info_ptr->num_plays; | |
236 | + return (1); | |
237 | + } | |
238 | + | |
239 | + return (0); | |
240 | +} | |
241 | + | |
242 | +png_uint_32 PNGAPI | |
243 | +png_get_num_frames(png_structp png_ptr, png_infop info_ptr) | |
244 | +{ | |
6df9a45f | 245 | + png_debug(1, "in png_get_num_frames()"); |
259182b6 ER |
246 | + |
247 | + if (png_ptr != NULL && info_ptr != NULL) | |
248 | + return (info_ptr->num_frames); | |
249 | + return (0); | |
250 | +} | |
251 | + | |
252 | +png_uint_32 PNGAPI | |
253 | +png_get_num_plays(png_structp png_ptr, png_infop info_ptr) | |
254 | +{ | |
6df9a45f | 255 | + png_debug(1, "in png_get_num_plays()"); |
259182b6 ER |
256 | + |
257 | + if (png_ptr != NULL && info_ptr != NULL) | |
258 | + return (info_ptr->num_plays); | |
259 | + return (0); | |
260 | +} | |
261 | + | |
262 | +png_uint_32 PNGAPI | |
263 | +png_get_next_frame_fcTL(png_structp png_ptr, png_infop info_ptr, | |
264 | + png_uint_32 *width, png_uint_32 *height, | |
265 | + png_uint_32 *x_offset, png_uint_32 *y_offset, | |
266 | + png_uint_16 *delay_num, png_uint_16 *delay_den, | |
267 | + png_byte *dispose_op, png_byte *blend_op) | |
268 | +{ | |
6df9a45f | 269 | + png_debug1(1, "in %s retrieval function", "fcTL"); |
259182b6 ER |
270 | + |
271 | + if (png_ptr != NULL && info_ptr != NULL && | |
272 | + (info_ptr->valid & PNG_INFO_fcTL) && | |
273 | + width != NULL && height != NULL && | |
274 | + x_offset != NULL && x_offset != NULL && | |
275 | + delay_num != NULL && delay_den != NULL && | |
276 | + dispose_op != NULL && blend_op != NULL) | |
277 | + { | |
278 | + *width = info_ptr->next_frame_width; | |
279 | + *height = info_ptr->next_frame_height; | |
280 | + *x_offset = info_ptr->next_frame_x_offset; | |
281 | + *y_offset = info_ptr->next_frame_y_offset; | |
282 | + *delay_num = info_ptr->next_frame_delay_num; | |
283 | + *delay_den = info_ptr->next_frame_delay_den; | |
284 | + *dispose_op = info_ptr->next_frame_dispose_op; | |
285 | + *blend_op = info_ptr->next_frame_blend_op; | |
286 | + return (1); | |
287 | + } | |
288 | + | |
289 | + return (0); | |
290 | +} | |
291 | + | |
292 | +png_uint_32 PNGAPI | |
293 | +png_get_next_frame_width(png_structp png_ptr, png_infop info_ptr) | |
294 | +{ | |
6df9a45f | 295 | + png_debug(1, "in png_get_next_frame_width()"); |
259182b6 ER |
296 | + |
297 | + if (png_ptr != NULL && info_ptr != NULL) | |
298 | + return (info_ptr->next_frame_width); | |
299 | + return (0); | |
300 | +} | |
301 | + | |
302 | +png_uint_32 PNGAPI | |
303 | +png_get_next_frame_height(png_structp png_ptr, png_infop info_ptr) | |
304 | +{ | |
6df9a45f | 305 | + png_debug(1, "in png_get_next_frame_height()"); |
259182b6 ER |
306 | + |
307 | + if (png_ptr != NULL && info_ptr != NULL) | |
308 | + return (info_ptr->next_frame_height); | |
309 | + return (0); | |
310 | +} | |
311 | + | |
312 | +png_uint_32 PNGAPI | |
313 | +png_get_next_frame_x_offset(png_structp png_ptr, png_infop info_ptr) | |
314 | +{ | |
6df9a45f | 315 | + png_debug(1, "in png_get_next_frame_x_offset()"); |
259182b6 ER |
316 | + |
317 | + if (png_ptr != NULL && info_ptr != NULL) | |
318 | + return (info_ptr->next_frame_x_offset); | |
319 | + return (0); | |
320 | +} | |
321 | + | |
322 | +png_uint_32 PNGAPI | |
323 | +png_get_next_frame_y_offset(png_structp png_ptr, png_infop info_ptr) | |
324 | +{ | |
6df9a45f | 325 | + png_debug(1, "in png_get_next_frame_y_offset()"); |
259182b6 ER |
326 | + |
327 | + if (png_ptr != NULL && info_ptr != NULL) | |
328 | + return (info_ptr->next_frame_y_offset); | |
329 | + return (0); | |
330 | +} | |
331 | + | |
332 | +png_uint_16 PNGAPI | |
333 | +png_get_next_frame_delay_num(png_structp png_ptr, png_infop info_ptr) | |
334 | +{ | |
6df9a45f | 335 | + png_debug(1, "in png_get_next_frame_delay_num()"); |
259182b6 ER |
336 | + |
337 | + if (png_ptr != NULL && info_ptr != NULL) | |
338 | + return (info_ptr->next_frame_delay_num); | |
339 | + return (0); | |
340 | +} | |
341 | + | |
342 | +png_uint_16 PNGAPI | |
343 | +png_get_next_frame_delay_den(png_structp png_ptr, png_infop info_ptr) | |
344 | +{ | |
6df9a45f | 345 | + png_debug(1, "in png_get_next_frame_delay_den()"); |
259182b6 ER |
346 | + |
347 | + if (png_ptr != NULL && info_ptr != NULL) | |
348 | + return (info_ptr->next_frame_delay_den); | |
349 | + return (0); | |
350 | +} | |
351 | + | |
352 | +png_byte PNGAPI | |
353 | +png_get_next_frame_dispose_op(png_structp png_ptr, png_infop info_ptr) | |
354 | +{ | |
6df9a45f | 355 | + png_debug(1, "in png_get_next_frame_dispose_op()"); |
259182b6 ER |
356 | + |
357 | + if (png_ptr != NULL && info_ptr != NULL) | |
358 | + return (info_ptr->next_frame_dispose_op); | |
359 | + return (0); | |
360 | +} | |
361 | + | |
362 | +png_byte PNGAPI | |
363 | +png_get_next_frame_blend_op(png_structp png_ptr, png_infop info_ptr) | |
364 | +{ | |
6df9a45f | 365 | + png_debug(1, "in png_get_next_frame_blend_op()"); |
259182b6 ER |
366 | + |
367 | + if (png_ptr != NULL && info_ptr != NULL) | |
368 | + return (info_ptr->next_frame_blend_op); | |
369 | + return (0); | |
370 | +} | |
371 | + | |
372 | +png_byte PNGAPI | |
373 | +png_get_first_frame_is_hidden(png_structp png_ptr, png_infop info_ptr) | |
374 | +{ | |
6df9a45f | 375 | + png_debug(1, "in png_first_frame_is_hidden()"); |
259182b6 ER |
376 | + |
377 | + if (png_ptr != NULL) | |
378 | + return (png_byte)(png_ptr->apng_flags & PNG_FIRST_FRAME_HIDDEN); | |
379 | + | |
380 | + return 0; | |
381 | +} | |
382 | +#endif /* PNG_APNG_SUPPORTED */ | |
383 | + | |
384 | #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED) | |
385 | png_uint_32 PNGAPI | |
386 | png_get_unknown_chunks(png_structp png_ptr, png_infop info_ptr, | |
e4744232 ER |
387 | Index: png.c |
388 | =================================================================== | |
6df9a45f | 389 | --- png.c |
390 | +++ png.c | |
9f147502 | 391 | @@ -54,6 +54,9 @@ |
e4744232 ER |
392 | PNG_tIME; |
393 | PNG_tRNS; | |
394 | PNG_zTXt; | |
395 | +PNG_acTL; | |
396 | +PNG_fcTL; | |
397 | +PNG_fdAT; | |
398 | ||
399 | #ifdef PNG_READ_SUPPORTED | |
6df9a45f | 400 | /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ |
259182b6 ER |
401 | Index: png.h |
402 | =================================================================== | |
6df9a45f | 403 | --- png.h |
404 | +++ png.h | |
9f147502 | 405 | @@ -1016,6 +1016,19 @@ |
259182b6 ER |
406 | png_fixed_point int_y_blue; |
407 | #endif | |
408 | ||
409 | +#if defined(PNG_APNG_SUPPORTED) | |
410 | + png_uint_32 num_frames; /* including default image */ | |
411 | + png_uint_32 num_plays; | |
412 | + png_uint_32 next_frame_width; | |
413 | + png_uint_32 next_frame_height; | |
414 | + png_uint_32 next_frame_x_offset; | |
415 | + png_uint_32 next_frame_y_offset; | |
416 | + png_uint_16 next_frame_delay_num; | |
417 | + png_uint_16 next_frame_delay_den; | |
418 | + png_byte next_frame_dispose_op; | |
419 | + png_byte next_frame_blend_op; | |
420 | +#endif | |
421 | + | |
422 | } png_info; | |
423 | ||
424 | typedef png_info FAR * png_infop; | |
9f147502 | 425 | @@ -1117,6 +1130,8 @@ |
259182b6 ER |
426 | #define PNG_INFO_sPLT 0x2000 /* ESR, 1.0.6 */ |
427 | #define PNG_INFO_sCAL 0x4000 /* ESR, 1.0.6 */ | |
428 | #define PNG_INFO_IDAT 0x8000L /* ESR, 1.0.6 */ | |
429 | +#define PNG_INFO_acTL 0x10000L | |
430 | +#define PNG_INFO_fcTL 0x20000L | |
431 | ||
432 | /* This is used for the transformation routines, as some of them | |
433 | * change these values for the row. It also should enable using | |
9f147502 | 434 | @@ -1157,6 +1172,10 @@ |
259182b6 ER |
435 | typedef void (PNGAPI *png_progressive_end_ptr) PNGARG((png_structp, png_infop)); |
436 | typedef void (PNGAPI *png_progressive_row_ptr) PNGARG((png_structp, png_bytep, | |
437 | png_uint_32, int)); | |
438 | +#if defined(PNG_APNG_SUPPORTED) | |
439 | +typedef void (PNGAPI *png_progressive_frame_ptr) PNGARG((png_structp, | |
440 | + png_uint_32)); | |
259182b6 | 441 | +#endif |
6df9a45f | 442 | #endif |
259182b6 ER |
443 | |
444 | #if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ | |
9f147502 | 445 | @@ -1491,6 +1510,39 @@ |
259182b6 ER |
446 | png_uint_32 user_height_max; |
447 | #endif | |
448 | ||
449 | +#if defined(PNG_APNG_SUPPORTED) | |
450 | + png_uint_32 apng_flags; | |
451 | + png_uint_32 next_seq_num; /* next fcTL/fdAT chunk sequence number */ | |
452 | + png_uint_32 first_frame_width; | |
453 | + png_uint_32 first_frame_height; | |
454 | + | |
455 | +#if defined(PNG_READ_APNG_SUPPORTED) | |
456 | + png_uint_32 num_frames_read; /* incremented after all image data of */ | |
457 | + /* a frame is read */ | |
458 | +#ifdef PNG_PROGRESSIVE_READ_SUPPORTED | |
459 | + png_progressive_frame_ptr frame_info_fn; /* frame info read callback */ | |
460 | + png_progressive_frame_ptr frame_end_fn; /* frame data read callback */ | |
461 | +#endif | |
462 | +#endif | |
463 | + | |
464 | +#if defined(PNG_WRITE_APNG_SUPPORTED) | |
465 | + png_uint_32 num_frames_to_write; | |
466 | + png_uint_32 num_frames_written; | |
467 | +#endif | |
468 | +#endif | |
469 | + | |
470 | +/* For png_struct.apng_flags: */ | |
471 | +#define PNG_FIRST_FRAME_HIDDEN 0x0001 | |
472 | + | |
473 | +/* dispose_op flags from inside fcTL */ | |
474 | +#define PNG_DISPOSE_OP_NONE 0x00 | |
475 | +#define PNG_DISPOSE_OP_BACKGROUND 0x01 | |
476 | +#define PNG_DISPOSE_OP_PREVIOUS 0x02 | |
477 | + | |
478 | +/* blend_op flags from inside fcTL */ | |
479 | +#define PNG_BLEND_OP_SOURCE 0x00 | |
480 | +#define PNG_BLEND_OP_OVER 0x01 | |
481 | + | |
482 | /* New member added in libpng-1.0.25 and 1.2.17 */ | |
483 | #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED) | |
9f147502 KK |
484 | /* Storage for unknown chunk that the library doesn't recognize. */ |
485 | @@ -1824,6 +1876,18 @@ | |
259182b6 ER |
486 | extern PNG_EXPORT(void,png_write_image) PNGARG((png_structp png_ptr, |
487 | png_bytepp image)); | |
488 | ||
489 | +#if defined(PNG_WRITE_APNG_SUPPORTED) | |
490 | +extern PNG_EXPORT (void,png_write_frame_head) PNGARG((png_structp png_ptr, | |
491 | + png_infop png_info, png_bytepp row_pointers, | |
492 | + png_uint_32 width, png_uint_32 height, | |
493 | + png_uint_32 x_offset, png_uint_32 y_offset, | |
494 | + png_uint_16 delay_num, png_uint_16 delay_den, png_byte dispose_op, | |
495 | + png_byte blend_op)); | |
496 | + | |
497 | +extern PNG_EXPORT (void,png_write_frame_tail) PNGARG((png_structp png_ptr, | |
498 | + png_infop png_info)); | |
499 | +#endif | |
500 | + | |
9f147502 | 501 | /* Writes the end of the PNG file. */ |
259182b6 ER |
502 | extern PNG_EXPORT(void,png_write_end) PNGARG((png_structp png_ptr, |
503 | png_infop info_ptr)); | |
9f147502 | 504 | @@ -2077,6 +2141,11 @@ |
259182b6 ER |
505 | png_voidp progressive_ptr, |
506 | png_progressive_info_ptr info_fn, png_progressive_row_ptr row_fn, | |
507 | png_progressive_end_ptr end_fn)); | |
508 | +#if defined(PNG_READ_APNG_SUPPORTED) | |
509 | +extern PNG_EXPORT(void,png_set_progressive_frame_fn) PNGARG((png_structp png_ptr, | |
510 | + png_progressive_frame_ptr frame_info_fn, | |
511 | + png_progressive_frame_ptr frame_end_fn)); | |
512 | +#endif | |
513 | ||
9f147502 | 514 | /* Returns the user pointer associated with the push read functions */ |
259182b6 | 515 | extern PNG_EXPORT(png_voidp,png_get_progressive_ptr) |
9f147502 | 516 | @@ -2517,6 +2586,59 @@ |
259182b6 ER |
517 | #endif |
518 | #endif /* PNG_sCAL_SUPPORTED || PNG_WRITE_sCAL_SUPPORTED */ | |
519 | ||
520 | +#if defined(PNG_APNG_SUPPORTED) | |
521 | +extern PNG_EXPORT(png_uint_32,png_get_acTL) PNGARG((png_structp png_ptr, | |
522 | + png_infop info_ptr, png_uint_32 *num_frames, png_uint_32 *num_plays)); | |
523 | +extern PNG_EXPORT(png_uint_32,png_set_acTL) PNGARG((png_structp png_ptr, | |
524 | + png_infop info_ptr, png_uint_32 num_frames, png_uint_32 num_plays)); | |
525 | +extern PNG_EXPORT(png_uint_32,png_get_num_frames) PNGARG((png_structp png_ptr, | |
526 | + png_infop info_ptr)); | |
527 | +extern PNG_EXPORT(png_uint_32,png_get_num_plays) | |
528 | + PNGARG((png_structp png_ptr, png_infop info_ptr)); | |
529 | + | |
530 | +extern PNG_EXPORT(png_uint_32,png_get_next_frame_fcTL) | |
531 | + PNGARG((png_structp png_ptr, png_infop info_ptr, png_uint_32 *width, | |
532 | + png_uint_32 *height, png_uint_32 *x_offset, png_uint_32 *y_offset, | |
533 | + png_uint_16 *delay_num, png_uint_16 *delay_den, png_byte *dispose_op, | |
534 | + png_byte *blend_op)); | |
535 | +extern PNG_EXPORT(png_uint_32,png_set_next_frame_fcTL) | |
536 | + PNGARG((png_structp png_ptr, png_infop info_ptr, png_uint_32 width, | |
537 | + png_uint_32 height, png_uint_32 x_offset, png_uint_32 y_offset, | |
538 | + png_uint_16 delay_num, png_uint_16 delay_den, png_byte dispose_op, | |
539 | + png_byte blend_op)); | |
540 | +extern PNG_EXPORT(void,png_ensure_fcTL_is_valid) | |
541 | + PNGARG((png_structp png_ptr, | |
542 | + png_uint_32 width, png_uint_32 height, | |
543 | + png_uint_32 x_offset, png_uint_32 y_offset, | |
544 | + png_uint_16 delay_num, png_uint_16 delay_den, | |
545 | + png_byte dispose_op, png_byte blend_op)); | |
546 | +extern PNG_EXPORT(png_uint_32,png_get_next_frame_width) | |
547 | + PNGARG((png_structp png_ptr, png_infop info_ptr)); | |
548 | +extern PNG_EXPORT(png_uint_32,png_get_next_frame_height) | |
549 | + PNGARG((png_structp png_ptr, png_infop info_ptr)); | |
550 | +extern PNG_EXPORT(png_uint_32,png_get_next_frame_x_offset) | |
551 | + PNGARG((png_structp png_ptr, png_infop info_ptr)); | |
552 | +extern PNG_EXPORT(png_uint_32,png_get_next_frame_y_offset) | |
553 | + PNGARG((png_structp png_ptr, png_infop info_ptr)); | |
554 | +extern PNG_EXPORT(png_uint_16,png_get_next_frame_delay_num) | |
555 | + PNGARG((png_structp png_ptr, png_infop info_ptr)); | |
556 | +extern PNG_EXPORT(png_uint_16,png_get_next_frame_delay_den) | |
557 | + PNGARG((png_structp png_ptr, png_infop info_ptr)); | |
558 | +extern PNG_EXPORT(png_byte,png_get_next_frame_dispose_op) | |
559 | + PNGARG((png_structp png_ptr, png_infop info_ptr)); | |
560 | +extern PNG_EXPORT(png_byte,png_get_next_frame_blend_op) | |
561 | + PNGARG((png_structp png_ptr, png_infop info_ptr)); | |
562 | +extern PNG_EXPORT(png_byte,png_get_first_frame_is_hidden) | |
563 | + PNGARG((png_structp png_ptr, png_infop info_ptr)); | |
564 | +extern PNG_EXPORT(png_uint_32,png_set_first_frame_is_hidden) | |
565 | + PNGARG((png_structp png_ptr, png_infop info_ptr, png_byte is_hidden)); | |
566 | +#endif /* PNG_APNG_SUPPORTED */ | |
567 | + | |
568 | +#if defined(PNG_READ_APNG_SUPPORTED) | |
569 | +extern PNG_EXPORT(void,png_read_frame_head) PNGARG((png_structp png_ptr, | |
570 | + png_infop info_ptr)); | |
571 | +#endif | |
572 | + | |
9f147502 KK |
573 | #ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED |
574 | /* Provide a list of chunks and how they are to be handled, if the built-in | |
259182b6 | 575 | handling or default unknown chunk handling is not desired. Any chunks not |
9f147502 | 576 | @@ -2883,6 +3005,8 @@ |
259182b6 ER |
577 | #define PNG_BACKGROUND_IS_GRAY 0x800 |
578 | #define PNG_HAVE_PNG_SIGNATURE 0x1000 | |
579 | #define PNG_HAVE_CHUNK_AFTER_IDAT 0x2000 /* Have another chunk after IDAT */ | |
580 | +#define PNG_HAVE_acTL 0x4000 | |
581 | +#define PNG_HAVE_fcTL 0x8000L | |
582 | ||
9f147502 | 583 | /* Flags for the transformations the PNG library does on the image data */ |
259182b6 | 584 | #define PNG_BGR 0x0001 |
9f147502 | 585 | @@ -3024,6 +3148,9 @@ |
259182b6 ER |
586 | #define PNG_tIME png_byte png_tIME[5] = {116, 73, 77, 69, '\0'} |
587 | #define PNG_tRNS png_byte png_tRNS[5] = {116, 82, 78, 83, '\0'} | |
588 | #define PNG_zTXt png_byte png_zTXt[5] = {122, 84, 88, 116, '\0'} | |
589 | +#define PNG_acTL png_byte png_acTL[5] = { 97, 99, 84, 76, '\0'} | |
590 | +#define PNG_fcTL png_byte png_fcTL[5] = {102, 99, 84, 76, '\0'} | |
591 | +#define PNG_fdAT png_byte png_fdAT[5] = {102, 100, 65, 84, '\0'} | |
592 | ||
593 | #ifdef PNG_USE_GLOBAL_ARRAYS | |
594 | PNG_EXPORT_VAR (png_byte FARDATA) png_IHDR[5]; | |
9f147502 | 595 | @@ -3047,6 +3174,9 @@ |
259182b6 ER |
596 | PNG_EXPORT_VAR (png_byte FARDATA) png_tIME[5]; |
597 | PNG_EXPORT_VAR (png_byte FARDATA) png_tRNS[5]; | |
598 | PNG_EXPORT_VAR (png_byte FARDATA) png_zTXt[5]; | |
599 | +PNG_EXPORT_VAR (png_byte FARDATA) png_acTL[5]; | |
600 | +PNG_EXPORT_VAR (png_byte FARDATA) png_fcTL[5]; | |
601 | +PNG_EXPORT_VAR (png_byte FARDATA) png_fdAT[5]; | |
602 | #endif /* PNG_USE_GLOBAL_ARRAYS */ | |
603 | ||
604 | #if defined(PNG_1_0_X) || defined (PNG_1_2_X) | |
9f147502 | 605 | @@ -3322,6 +3452,17 @@ |
259182b6 ER |
606 | #endif |
607 | #endif | |
608 | ||
609 | +#if defined(PNG_WRITE_APNG_SUPPORTED) | |
610 | +PNG_EXTERN void png_write_acTL PNGARG((png_structp png_ptr, | |
611 | + png_uint_32 num_frames, png_uint_32 num_plays)); | |
612 | + | |
613 | +PNG_EXTERN void png_write_fcTL PNGARG((png_structp png_ptr, | |
614 | + png_uint_32 width, png_uint_32 height, | |
615 | + png_uint_32 x_offset, png_uint_32 y_offset, | |
616 | + png_uint_16 delay_num, png_uint_16 delay_den, | |
617 | + png_byte dispose_op, png_byte blend_op)); | |
618 | +#endif | |
619 | + | |
620 | /* Called when finished processing a row of data */ | |
621 | PNG_EXTERN void png_write_finish_row PNGARG((png_structp png_ptr)); | |
622 | ||
9f147502 | 623 | @@ -3373,6 +3514,20 @@ |
259182b6 ER |
624 | PNG_EXTERN void png_read_transform_info PNGARG((png_structp png_ptr, |
625 | png_infop info_ptr)); | |
626 | ||
627 | +#if defined(PNG_READ_APNG_SUPPORTED) | |
628 | +/* private, reset some things to become ready for reading next frame */ | |
629 | +PNG_EXTERN void png_read_reset PNGARG((png_structp png_ptr)); | |
630 | +PNG_EXTERN void png_read_reinit PNGARG((png_structp png_ptr, | |
631 | + png_infop info_ptr)); | |
632 | +PNG_EXTERN void png_progressive_read_reset PNGARG((png_structp png_ptr)); | |
633 | +#endif | |
634 | +#if defined(PNG_WRITE_APNG_SUPPORTED) | |
635 | +/* private, reset some things to become ready for writing next frame */ | |
636 | +PNG_EXTERN void png_write_reset PNGARG((png_structp png_ptr)); | |
637 | +PNG_EXTERN void png_write_reinit PNGARG((png_structp png_ptr, | |
638 | + png_infop info_ptr, png_uint_32 width, png_uint_32 height)); | |
639 | +#endif | |
640 | + | |
9f147502 | 641 | /* These are the functions that do the transformations */ |
259182b6 ER |
642 | #if defined(PNG_READ_FILLER_SUPPORTED) |
643 | PNG_EXTERN void png_do_read_filler PNGARG((png_row_infop row_info, | |
9f147502 | 644 | @@ -3588,6 +3743,18 @@ |
259182b6 ER |
645 | png_uint_32 length)); |
646 | #endif | |
647 | ||
648 | +#if defined(PNG_READ_APNG_SUPPORTED) | |
649 | +PNG_EXTERN void png_handle_acTL PNGARG((png_structp png_ptr, png_infop info_ptr, | |
650 | + png_uint_32 length)); | |
651 | +PNG_EXTERN void png_handle_fcTL PNGARG((png_structp png_ptr, png_infop info_ptr, | |
652 | + png_uint_32 length)); | |
653 | +PNG_EXTERN void png_have_info PNGARG((png_structp png_ptr, png_infop info_ptr)); | |
654 | +PNG_EXTERN void png_handle_fdAT PNGARG((png_structp png_ptr, png_infop info_ptr, | |
655 | + png_uint_32 length)); | |
656 | +PNG_EXTERN void png_ensure_sequence_number PNGARG((png_structp png_ptr, | |
657 | + png_uint_32 length)); | |
658 | +#endif | |
659 | + | |
660 | PNG_EXTERN void png_handle_unknown PNGARG((png_structp png_ptr, | |
661 | png_infop info_ptr, png_uint_32 length)); | |
662 | ||
259182b6 ER |
663 | Index: pngwrite.c |
664 | =================================================================== | |
6df9a45f | 665 | --- pngwrite.c |
666 | +++ pngwrite.c | |
9f147502 | 667 | @@ -53,6 +53,10 @@ |
6df9a45f | 668 | /* The rest of these check to see if the valid field has the appropriate |
669 | * flag set, and if it does, writes the chunk. | |
670 | */ | |
259182b6 ER |
671 | +#if defined(PNG_WRITE_APNG_SUPPORTED) |
672 | + if (info_ptr->valid & PNG_INFO_acTL) | |
673 | + png_write_acTL(png_ptr, info_ptr->num_frames, info_ptr->num_plays); | |
674 | +#endif | |
6df9a45f | 675 | #if defined(PNG_WRITE_gAMA_SUPPORTED) |
676 | if (info_ptr->valid & PNG_INFO_gAMA) | |
259182b6 | 677 | { |
9f147502 | 678 | @@ -314,6 +318,10 @@ |
259182b6 ER |
679 | return; |
680 | if (!(png_ptr->mode & PNG_HAVE_IDAT)) | |
681 | png_error(png_ptr, "No IDATs written into file"); | |
682 | +#if defined(PNG_WRITE_APNG_SUPPORTED) | |
683 | + if (png_ptr->num_frames_written != png_ptr->num_frames_to_write) | |
684 | + png_error(png_ptr, "Not enough frames written"); | |
685 | +#endif | |
686 | ||
6df9a45f | 687 | /* See if user wants us to write information chunks */ |
259182b6 | 688 | if (info_ptr != NULL) |
9f147502 | 689 | @@ -1558,4 +1566,39 @@ |
259182b6 ER |
690 | params = params; |
691 | } | |
692 | #endif | |
693 | + | |
694 | +#if defined(PNG_WRITE_APNG_SUPPORTED) | |
695 | +void PNGAPI | |
696 | +png_write_frame_head(png_structp png_ptr, png_infop info_ptr, | |
697 | + png_bytepp row_pointers, png_uint_32 width, png_uint_32 height, | |
698 | + png_uint_32 x_offset, png_uint_32 y_offset, | |
699 | + png_uint_16 delay_num, png_uint_16 delay_den, png_byte dispose_op, | |
700 | + png_byte blend_op) | |
701 | +{ | |
6df9a45f | 702 | + png_debug(1, "in png_write_frame_head"); |
259182b6 ER |
703 | + |
704 | + /* there is a chance this has been set after png_write_info was called, | |
705 | + * so it would be set but not written. is there a way to be sure? */ | |
706 | + if (!(info_ptr->valid & PNG_INFO_acTL)) | |
707 | + png_error(png_ptr, "png_write_frame_head(): acTL not set"); | |
708 | + | |
709 | + png_write_reset(png_ptr); | |
710 | + | |
711 | + png_write_reinit(png_ptr, info_ptr, width, height); | |
712 | + | |
713 | + if ( !(png_ptr->num_frames_written == 0 && | |
714 | + (png_ptr->apng_flags & PNG_FIRST_FRAME_HIDDEN) ) ) | |
715 | + png_write_fcTL(png_ptr, width, height, x_offset, y_offset, | |
716 | + delay_num, delay_den, dispose_op, blend_op); | |
717 | +} | |
718 | + | |
719 | +void PNGAPI | |
720 | +png_write_frame_tail(png_structp png_ptr, png_infop png_info) | |
721 | +{ | |
6df9a45f | 722 | + png_debug(1, "in png_write_frame_tail"); |
259182b6 ER |
723 | + |
724 | + png_ptr->num_frames_written++; | |
725 | +} | |
726 | +#endif /* PNG_WRITE_APNG_SUPPORTED */ | |
727 | + | |
728 | #endif /* PNG_WRITE_SUPPORTED */ | |
e4744232 | 729 | Index: pngconf.h |
259182b6 | 730 | =================================================================== |
6df9a45f | 731 | --- pngconf.h |
732 | +++ pngconf.h | |
9f147502 | 733 | @@ -944,6 +944,10 @@ |
e4744232 ER |
734 | # define PNG_READ_zTXt_SUPPORTED |
735 | # define PNG_zTXt_SUPPORTED | |
736 | #endif | |
737 | +#ifndef PNG_NO_READ_APNG | |
738 | +# define PNG_READ_APNG_SUPPORTED | |
739 | +# define PNG_APNG_SUPPORTED | |
259182b6 | 740 | +#endif |
9f147502 KK |
741 | #ifndef PNG_NO_READ_OPT_PLTE |
742 | # define PNG_READ_OPT_PLTE_SUPPORTED /* only affects support of the */ | |
743 | #endif /* optional PLTE chunk in RGB and RGBA images */ | |
744 | @@ -1091,6 +1095,12 @@ | |
e4744232 ER |
745 | # define PNG_zTXt_SUPPORTED |
746 | # endif | |
747 | #endif | |
748 | +#ifndef PNG_NO_WRITE_APNG | |
749 | +# define PNG_WRITE_APNG_SUPPORTED | |
750 | +# ifndef PNG_APNG_SUPPORTED | |
751 | +# define PNG_APNG_SUPPORTED | |
752 | +# endif | |
753 | +#endif | |
9f147502 KK |
754 | #if defined(PNG_WRITE_iTXt_SUPPORTED) || defined(PNG_WRITE_tEXt_SUPPORTED) || \ |
755 | defined(PNG_WRITE_zTXt_SUPPORTED) | |
756 | # define PNG_WRITE_TEXT_SUPPORTED | |
259182b6 ER |
757 | Index: pngpread.c |
758 | =================================================================== | |
6df9a45f | 759 | --- pngpread.c |
760 | +++ pngpread.c | |
9f147502 | 761 | @@ -205,6 +205,11 @@ |
259182b6 ER |
762 | #if defined(PNG_READ_zTXt_SUPPORTED) |
763 | PNG_CONST PNG_zTXt; | |
764 | #endif | |
765 | +#if defined(PNG_READ_APNG_SUPPORTED) | |
766 | + PNG_CONST PNG_acTL; | |
767 | + PNG_CONST PNG_fcTL; | |
768 | + PNG_CONST PNG_fdAT; | |
769 | +#endif | |
770 | #endif /* PNG_USE_LOCAL_ARRAYS */ | |
771 | /* First we make sure we have enough data for the 4 byte chunk name | |
772 | * and the 4 byte chunk length before proceeding with decoding the | |
9f147502 | 773 | @@ -230,6 +235,103 @@ |
259182b6 ER |
774 | png_ptr->mode |= PNG_HAVE_CHUNK_HEADER; |
775 | } | |
6df9a45f | 776 | |
259182b6 ER |
777 | +#if defined(PNG_READ_APNG_SUPPORTED) |
778 | + if (png_ptr->num_frames_read > 0 && | |
779 | + png_ptr->num_frames_read < info_ptr->num_frames) | |
780 | + { | |
781 | + if (!png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) | |
782 | + { | |
783 | + /* discard trailing IDATs for the first frame */ | |
784 | + if (png_ptr->mode & PNG_HAVE_fcTL || png_ptr->num_frames_read > 1) | |
785 | + png_error(png_ptr, "out of place IDAT"); | |
786 | + | |
787 | + if (png_ptr->push_length + 4 > png_ptr->buffer_size) | |
788 | + { | |
789 | + png_push_save_buffer(png_ptr); | |
790 | + return; | |
791 | + } | |
792 | + png_push_crc_skip(png_ptr, png_ptr->push_length); | |
793 | + png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER; | |
794 | + return; | |
795 | + } | |
796 | + else if (!png_memcmp(png_ptr->chunk_name, png_fdAT, 4)) | |
797 | + { | |
798 | + if (png_ptr->buffer_size < 4) | |
799 | + { | |
800 | + png_push_save_buffer(png_ptr); | |
801 | + return; | |
802 | + } | |
803 | + png_ensure_sequence_number(png_ptr, 4); | |
804 | + | |
805 | + if (!(png_ptr->mode & PNG_HAVE_fcTL)) | |
806 | + { | |
807 | + /* discard trailing fdATs for frames other than the first */ | |
808 | + if (png_ptr->num_frames_read < 2) | |
809 | + png_error(png_ptr, "out of place fdAT"); | |
810 | + | |
811 | + if (png_ptr->push_length + 4 > png_ptr->buffer_size) | |
812 | + { | |
813 | + png_push_save_buffer(png_ptr); | |
814 | + return; | |
815 | + } | |
816 | + png_push_crc_skip(png_ptr, png_ptr->push_length); | |
817 | + png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER; | |
818 | + return; | |
819 | + } | |
820 | + else | |
821 | + { | |
822 | + /* frame data follows */ | |
823 | + png_ptr->idat_size = png_ptr->push_length - 4; | |
824 | + png_ptr->mode |= PNG_HAVE_IDAT; | |
825 | + png_ptr->process_mode = PNG_READ_IDAT_MODE; | |
826 | + | |
827 | + return; | |
828 | + } | |
829 | + } | |
830 | + else if(!png_memcmp(png_ptr->chunk_name, png_fcTL, 4)) | |
831 | + { | |
832 | + if (png_ptr->push_length + 4 > png_ptr->buffer_size) | |
833 | + { | |
834 | + png_push_save_buffer(png_ptr); | |
835 | + return; | |
836 | + } | |
837 | + | |
838 | + png_read_reset(png_ptr); | |
839 | + png_ptr->mode &= ~PNG_HAVE_fcTL; | |
840 | + | |
841 | + png_handle_fcTL(png_ptr, info_ptr, png_ptr->push_length); | |
842 | + | |
843 | + if (!(png_ptr->mode & PNG_HAVE_fcTL)) | |
844 | + png_error(png_ptr, "missing required fcTL chunk"); | |
845 | + | |
846 | + png_read_reinit(png_ptr, info_ptr); | |
847 | + png_progressive_read_reset(png_ptr); | |
848 | + | |
849 | + if (png_ptr->frame_info_fn != NULL) | |
850 | + (*(png_ptr->frame_info_fn))(png_ptr, png_ptr->num_frames_read); | |
851 | + | |
852 | + png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER; | |
853 | + | |
854 | + return; | |
855 | + } | |
856 | + else | |
857 | + { | |
858 | + if (png_ptr->push_length + 4 > png_ptr->buffer_size) | |
859 | + { | |
860 | + png_push_save_buffer(png_ptr); | |
861 | + return; | |
862 | + } | |
863 | + png_warning(png_ptr, "Skipped (ignored) a chunk " | |
864 | + "between APNG chunks"); | |
865 | + png_push_crc_skip(png_ptr, png_ptr->push_length); | |
866 | + png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER; | |
867 | + return; | |
868 | + } | |
869 | + | |
870 | + return; | |
871 | + } | |
872 | +#endif /* PNG_READ_APNG_SUPPORTED */ | |
873 | + | |
874 | if (!png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) | |
6df9a45f | 875 | if (png_ptr->mode & PNG_AFTER_IDAT) |
259182b6 | 876 | png_ptr->mode |= PNG_HAVE_CHUNK_AFTER_IDAT; |
9f147502 | 877 | @@ -325,6 +427,9 @@ |
259182b6 ER |
878 | png_error(png_ptr, "Too many IDAT's found"); |
879 | } | |
880 | ||
881 | +#if defined(PNG_READ_APNG_SUPPORTED) | |
882 | + png_have_info(png_ptr, info_ptr); | |
883 | +#endif | |
884 | png_ptr->idat_size = png_ptr->push_length; | |
885 | png_ptr->mode |= PNG_HAVE_IDAT; | |
886 | png_ptr->process_mode = PNG_READ_IDAT_MODE; | |
9f147502 | 887 | @@ -555,6 +660,38 @@ |
259182b6 | 888 | } |
6df9a45f | 889 | |
259182b6 ER |
890 | #endif |
891 | +#if defined(PNG_READ_APNG_SUPPORTED) | |
892 | + else if (!png_memcmp(png_ptr->chunk_name, png_acTL, 4)) | |
893 | + { | |
894 | + if (png_ptr->push_length + 4 > png_ptr->buffer_size) | |
895 | + { | |
896 | + png_push_save_buffer(png_ptr); | |
897 | + return; | |
898 | + } | |
6df9a45f | 899 | + |
259182b6 ER |
900 | + png_handle_acTL(png_ptr, info_ptr, png_ptr->push_length); |
901 | + } | |
902 | + else if (!png_memcmp(png_ptr->chunk_name, png_fcTL, 4)) | |
903 | + { | |
904 | + if (png_ptr->push_length + 4 > png_ptr->buffer_size) | |
905 | + { | |
906 | + png_push_save_buffer(png_ptr); | |
907 | + return; | |
908 | + } | |
6df9a45f | 909 | + |
259182b6 ER |
910 | + png_handle_fcTL(png_ptr, info_ptr, png_ptr->push_length); |
911 | + } | |
912 | + else if (!png_memcmp(png_ptr->chunk_name, png_fdAT, 4)) | |
913 | + { | |
914 | + if (png_ptr->push_length + 4 > png_ptr->buffer_size) | |
915 | + { | |
916 | + png_push_save_buffer(png_ptr); | |
917 | + return; | |
918 | + } | |
6df9a45f | 919 | + |
259182b6 ER |
920 | + png_handle_fdAT(png_ptr, info_ptr, png_ptr->push_length); |
921 | + } | |
922 | +#endif /* PNG_READ_APNG_SUPPORTED */ | |
923 | else | |
924 | { | |
925 | if (png_ptr->push_length + 4 > png_ptr->buffer_size) | |
9f147502 | 926 | @@ -729,13 +866,17 @@ |
259182b6 ER |
927 | png_push_read_IDAT(png_structp png_ptr) |
928 | { | |
929 | #ifdef PNG_USE_LOCAL_ARRAYS | |
930 | - PNG_CONST PNG_IDAT; | |
931 | + PNG_IDAT; | |
932 | +#if defined(PNG_READ_APNG_SUPPORTED) | |
933 | + PNG_fdAT; | |
934 | + PNG_IEND; | |
259182b6 | 935 | +#endif |
6df9a45f | 936 | #endif |
259182b6 ER |
937 | if (!(png_ptr->mode & PNG_HAVE_CHUNK_HEADER)) |
938 | { | |
939 | png_byte chunk_length[4]; | |
940 | ||
941 | - if (png_ptr->buffer_size < 8) | |
942 | + if (png_ptr->buffer_size < 12) | |
943 | { | |
944 | png_push_save_buffer(png_ptr); | |
945 | return; | |
9f147502 | 946 | @@ -747,15 +888,62 @@ |
259182b6 ER |
947 | png_crc_read(png_ptr, png_ptr->chunk_name, 4); |
948 | png_ptr->mode |= PNG_HAVE_CHUNK_HEADER; | |
949 | ||
950 | - if (png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) | |
951 | +#if defined(PNG_READ_APNG_SUPPORTED) | |
952 | + if (png_memcmp(png_ptr->chunk_name, (png_bytep)png_fdAT, 4) | |
953 | + && png_ptr->num_frames_read > 0) | |
6df9a45f | 954 | + { |
259182b6 ER |
955 | + if (png_ptr->flags & PNG_FLAG_ZLIB_FINISHED) |
956 | + { | |
957 | + png_ptr->process_mode = PNG_READ_CHUNK_MODE; | |
958 | + if (png_ptr->frame_end_fn != NULL) | |
959 | + (*(png_ptr->frame_end_fn))(png_ptr, png_ptr->num_frames_read); | |
960 | + png_ptr->num_frames_read++; | |
961 | + return; | |
962 | + } | |
963 | + else | |
964 | + { | |
965 | + if (!png_memcmp(png_ptr->chunk_name, png_IEND, 4)) | |
966 | + png_error(png_ptr, "Not enough image data"); | |
967 | + if (png_ptr->push_length + 4 > png_ptr->buffer_size) | |
968 | + { | |
969 | + png_push_save_buffer(png_ptr); | |
970 | + return; | |
971 | + } | |
972 | + png_warning(png_ptr, "Skipping (ignoring) a chunk between " | |
973 | + "APNG chunks"); | |
974 | + png_crc_finish(png_ptr, png_ptr->push_length); | |
975 | + png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER; | |
976 | + return; | |
977 | + } | |
978 | + } | |
979 | + else | |
980 | +#endif | |
6df9a45f | 981 | + if (png_memcmp(png_ptr->chunk_name, png_IDAT, 4) |
982 | +#if defined(PNG_READ_APNG_SUPPORTED) | |
983 | + && (png_ptr->num_frames_read == 0) | |
984 | +#endif | |
985 | + ) | |
986 | { | |
259182b6 ER |
987 | png_ptr->process_mode = PNG_READ_CHUNK_MODE; |
988 | if (!(png_ptr->flags & PNG_FLAG_ZLIB_FINISHED)) | |
989 | png_error(png_ptr, "Not enough compressed data"); | |
990 | +#if defined(PNG_READ_APNG_SUPPORTED) | |
991 | + if (png_ptr->frame_end_fn != NULL) | |
992 | + (*(png_ptr->frame_end_fn))(png_ptr, png_ptr->num_frames_read); | |
993 | + png_ptr->num_frames_read++; | |
994 | +#endif | |
995 | return; | |
996 | } | |
997 | ||
998 | png_ptr->idat_size = png_ptr->push_length; | |
999 | + | |
1000 | +#if defined(PNG_READ_APNG_SUPPORTED) | |
1001 | + if(png_ptr->num_frames_read > 0) | |
1002 | + { | |
1003 | + png_ensure_sequence_number(png_ptr, 4); | |
1004 | + png_ptr->idat_size -= 4; | |
1005 | + } | |
1006 | +#endif | |
1007 | } | |
1008 | if (png_ptr->idat_size && png_ptr->save_buffer_size) | |
1009 | { | |
9f147502 | 1010 | @@ -1716,6 +1904,17 @@ |
259182b6 ER |
1011 | png_set_read_fn(png_ptr, progressive_ptr, png_push_fill_buffer); |
1012 | } | |
1013 | ||
1014 | +#if defined(PNG_READ_APNG_SUPPORTED) | |
1015 | +void PNGAPI | |
1016 | +png_set_progressive_frame_fn(png_structp png_ptr, | |
1017 | + png_progressive_frame_ptr frame_info_fn, | |
1018 | + png_progressive_frame_ptr frame_end_fn) | |
1019 | +{ | |
1020 | + png_ptr->frame_info_fn = frame_info_fn; | |
1021 | + png_ptr->frame_end_fn = frame_end_fn; | |
1022 | +} | |
1023 | +#endif | |
1024 | + | |
1025 | png_voidp PNGAPI | |
1026 | png_get_progressive_ptr(png_structp png_ptr) | |
1027 | { | |
e4744232 ER |
1028 | Index: pngset.c |
1029 | =================================================================== | |
6df9a45f | 1030 | --- pngset.c |
1031 | +++ pngset.c | |
9f147502 | 1032 | @@ -320,6 +320,11 @@ |
e4744232 ER |
1033 | info_ptr->rowbytes = (png_size_t)0; |
1034 | else | |
c501f448 | 1035 | info_ptr->rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth, width); |
e4744232 ER |
1036 | + |
1037 | +#if defined(PNG_APNG_SUPPORTED) | |
1038 | + /* for non-animated png. this may be overritten from an acTL chunk later */ | |
1039 | + info_ptr->num_frames = 1; | |
1040 | +#endif | |
1041 | } | |
1042 | ||
1043 | #if defined(PNG_oFFs_SUPPORTED) | |
9f147502 | 1044 | @@ -1007,6 +1012,142 @@ |
e4744232 ER |
1045 | } |
1046 | #endif /* PNG_sPLT_SUPPORTED */ | |
1047 | ||
1048 | +#if defined(PNG_APNG_SUPPORTED) | |
1049 | +png_uint_32 PNGAPI | |
1050 | +png_set_acTL(png_structp png_ptr, png_infop info_ptr, | |
1051 | + png_uint_32 num_frames, png_uint_32 num_plays) | |
1052 | +{ | |
6df9a45f | 1053 | + png_debug1(1, "in %s storage function", "acTL"); |
e4744232 ER |
1054 | + |
1055 | + if (png_ptr == NULL || info_ptr == NULL) | |
1056 | + { | |
1057 | + png_warning(png_ptr, | |
1058 | + "Call to png_set_acTL() with NULL png_ptr " | |
1059 | + "or info_ptr ignored"); | |
1060 | + return (0); | |
1061 | + } | |
1062 | + if (num_frames == 0) | |
1063 | + { | |
1064 | + png_warning(png_ptr, | |
1065 | + "Ignoring attempt to set acTL with num_frames zero"); | |
1066 | + return (0); | |
1067 | + } | |
1068 | + if (num_frames > PNG_UINT_31_MAX) | |
1069 | + { | |
1070 | + png_warning(png_ptr, | |
1071 | + "Ignoring attempt to set acTL with num_frames > 2^31-1"); | |
1072 | + return (0); | |
1073 | + } | |
1074 | + if (num_plays > PNG_UINT_31_MAX) | |
1075 | + { | |
1076 | + png_warning(png_ptr, | |
1077 | + "Ignoring attempt to set acTL with num_plays " | |
1078 | + "> 2^31-1"); | |
1079 | + return (0); | |
1080 | + } | |
1081 | + | |
1082 | + info_ptr->num_frames = num_frames; | |
1083 | + info_ptr->num_plays = num_plays; | |
1084 | + | |
1085 | + info_ptr->valid |= PNG_INFO_acTL; | |
1086 | + | |
1087 | + return (1); | |
1088 | +} | |
1089 | + | |
1090 | +/* delay_num and delay_den can hold any 16-bit values including zero */ | |
1091 | +png_uint_32 PNGAPI | |
1092 | +png_set_next_frame_fcTL(png_structp png_ptr, png_infop info_ptr, | |
1093 | + png_uint_32 width, png_uint_32 height, | |
1094 | + png_uint_32 x_offset, png_uint_32 y_offset, | |
1095 | + png_uint_16 delay_num, png_uint_16 delay_den, | |
1096 | + png_byte dispose_op, png_byte blend_op) | |
1097 | +{ | |
6df9a45f | 1098 | + png_debug1(1, "in %s storage function", "fcTL"); |
e4744232 ER |
1099 | + |
1100 | + if (png_ptr == NULL || info_ptr == NULL) | |
1101 | + { | |
1102 | + png_warning(png_ptr, | |
1103 | + "Call to png_set_fcTL() with NULL png_ptr or info_ptr " | |
1104 | + "ignored"); | |
1105 | + return (0); | |
1106 | + } | |
1107 | + | |
1108 | + png_ensure_fcTL_is_valid(png_ptr, width, height, x_offset, y_offset, | |
1109 | + delay_num, delay_den, dispose_op, blend_op); | |
1110 | + | |
6df9a45f | 1111 | + if (blend_op == PNG_BLEND_OP_OVER) |
1112 | + { | |
1113 | + if (!(png_ptr->color_type & PNG_COLOR_MASK_ALPHA) && | |
1114 | + !(png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))) | |
1115 | + { | |
1116 | + png_warning(png_ptr, "PNG_BLEND_OP_OVER is meaningless " | |
1117 | + "and wasteful for opaque images, ignored"); | |
1118 | + blend_op = PNG_BLEND_OP_SOURCE; | |
1119 | + } | |
1120 | + } | |
1121 | + | |
e4744232 ER |
1122 | + info_ptr->next_frame_width = width; |
1123 | + info_ptr->next_frame_height = height; | |
1124 | + info_ptr->next_frame_x_offset = x_offset; | |
1125 | + info_ptr->next_frame_y_offset = y_offset; | |
1126 | + info_ptr->next_frame_delay_num = delay_num; | |
1127 | + info_ptr->next_frame_delay_den = delay_den; | |
1128 | + info_ptr->next_frame_dispose_op = dispose_op; | |
1129 | + info_ptr->next_frame_blend_op = blend_op; | |
1130 | + | |
1131 | + info_ptr->valid |= PNG_INFO_fcTL; | |
1132 | + | |
1133 | + return (1); | |
1134 | +} | |
1135 | + | |
1136 | +void /* PRIVATE */ | |
1137 | +png_ensure_fcTL_is_valid(png_structp png_ptr, | |
1138 | + png_uint_32 width, png_uint_32 height, | |
1139 | + png_uint_32 x_offset, png_uint_32 y_offset, | |
1140 | + png_uint_16 delay_num, png_uint_16 delay_den, | |
1141 | + png_byte dispose_op, png_byte blend_op) | |
1142 | +{ | |
1143 | + if (width + x_offset > png_ptr->first_frame_width || | |
1144 | + height + y_offset > png_ptr->first_frame_height) | |
1145 | + png_error(png_ptr, "dimensions of a frame are greater than" | |
1146 | + "the ones in IHDR"); | |
1147 | + if (width > PNG_UINT_31_MAX) | |
1148 | + png_error(png_ptr, "invalid width in fcTL (> 2^31-1)"); | |
1149 | + if (height > PNG_UINT_31_MAX) | |
1150 | + png_error(png_ptr, "invalid height in fcTL (> 2^31-1)"); | |
1151 | + if (x_offset > PNG_UINT_31_MAX) | |
1152 | + png_error(png_ptr, "invalid x_offset in fcTL (> 2^31-1)"); | |
1153 | + if (y_offset > PNG_UINT_31_MAX) | |
1154 | + png_error(png_ptr, "invalid y_offset in fcTL (> 2^31-1)"); | |
1155 | + | |
1156 | + if (dispose_op != PNG_DISPOSE_OP_NONE && | |
1157 | + dispose_op != PNG_DISPOSE_OP_BACKGROUND && | |
1158 | + dispose_op != PNG_DISPOSE_OP_PREVIOUS) | |
1159 | + png_error(png_ptr, "invalid dispose_op in fcTL"); | |
1160 | + | |
1161 | + if (blend_op != PNG_BLEND_OP_SOURCE && | |
1162 | + blend_op != PNG_BLEND_OP_OVER) | |
1163 | + png_error(png_ptr, "invalid blend_op in fcTL"); | |
e4744232 ER |
1164 | +} |
1165 | + | |
1166 | +png_uint_32 PNGAPI | |
1167 | +png_set_first_frame_is_hidden(png_structp png_ptr, png_infop info_ptr, | |
1168 | + png_byte is_hidden) | |
1169 | +{ | |
6df9a45f | 1170 | + png_debug(1, "in png_first_frame_is_hidden()"); |
e4744232 ER |
1171 | + |
1172 | + if (png_ptr == NULL) | |
1173 | + return 0; | |
1174 | + | |
1175 | + if(is_hidden) | |
1176 | + png_ptr->apng_flags |= PNG_FIRST_FRAME_HIDDEN; | |
1177 | + else | |
1178 | + png_ptr->apng_flags &= ~PNG_FIRST_FRAME_HIDDEN; | |
1179 | + | |
1180 | + return 1; | |
1181 | +} | |
1182 | +#endif /* PNG_APNG_SUPPORTED */ | |
1183 | + | |
1184 | #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED) | |
1185 | void PNGAPI | |
1186 | png_set_unknown_chunks(png_structp png_ptr, | |
259182b6 ER |
1187 | Index: pngrutil.c |
1188 | =================================================================== | |
6df9a45f | 1189 | --- pngrutil.c |
1190 | +++ pngrutil.c | |
9f147502 | 1191 | @@ -424,6 +424,11 @@ |
259182b6 ER |
1192 | filter_type = buf[11]; |
1193 | interlace_type = buf[12]; | |
1194 | ||
1195 | +#if defined(PNG_READ_APNG_SUPPORTED) | |
1196 | + png_ptr->first_frame_width = width; | |
1197 | + png_ptr->first_frame_height = height; | |
1198 | +#endif | |
1199 | + | |
6df9a45f | 1200 | /* Set internal variables */ |
259182b6 ER |
1201 | png_ptr->width = width; |
1202 | png_ptr->height = height; | |
9f147502 | 1203 | @@ -2230,6 +2235,168 @@ |
259182b6 ER |
1204 | } |
1205 | #endif | |
1206 | ||
1207 | +#if defined(PNG_READ_APNG_SUPPORTED) | |
1208 | +void /* PRIVATE */ | |
1209 | +png_handle_acTL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) | |
1210 | +{ | |
1211 | + png_byte data[8]; | |
1212 | + png_uint_32 num_frames; | |
1213 | + png_uint_32 num_plays; | |
1214 | + png_uint_32 didSet; | |
1215 | + | |
6df9a45f | 1216 | + png_debug(1, "in png_handle_acTL"); |
259182b6 ER |
1217 | + |
1218 | + if (!(png_ptr->mode & PNG_HAVE_IHDR)) | |
1219 | + { | |
1220 | + png_error(png_ptr, "Missing IHDR before acTL"); | |
1221 | + } | |
1222 | + else if (png_ptr->mode & PNG_HAVE_IDAT) | |
1223 | + { | |
1224 | + png_warning(png_ptr, "Invalid acTL after IDAT skipped"); | |
1225 | + png_crc_finish(png_ptr, length); | |
1226 | + return; | |
1227 | + } | |
1228 | + else if (png_ptr->mode & PNG_HAVE_acTL) | |
1229 | + { | |
1230 | + png_warning(png_ptr, "Duplicate acTL skipped"); | |
1231 | + png_crc_finish(png_ptr, length); | |
1232 | + return; | |
1233 | + } | |
1234 | + else if (length != 8) | |
1235 | + { | |
1236 | + png_warning(png_ptr, "acTL with invalid length skipped"); | |
1237 | + png_crc_finish(png_ptr, length); | |
1238 | + return; | |
1239 | + } | |
1240 | + | |
1241 | + png_crc_read(png_ptr, data, 8); | |
1242 | + png_crc_finish(png_ptr, 0); | |
1243 | + | |
1244 | + num_frames = png_get_uint_31(png_ptr, data); | |
1245 | + num_plays = png_get_uint_31(png_ptr, data + 4); | |
1246 | + | |
1247 | + /* the set function will do error checking on num_frames */ | |
1248 | + didSet = png_set_acTL(png_ptr, info_ptr, num_frames, num_plays); | |
1249 | + if(didSet) | |
1250 | + png_ptr->mode |= PNG_HAVE_acTL; | |
1251 | +} | |
1252 | + | |
1253 | +void /* PRIVATE */ | |
1254 | +png_handle_fcTL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) | |
1255 | +{ | |
1256 | + png_byte data[22]; | |
1257 | + png_uint_32 width; | |
1258 | + png_uint_32 height; | |
1259 | + png_uint_32 x_offset; | |
1260 | + png_uint_32 y_offset; | |
1261 | + png_uint_16 delay_num; | |
1262 | + png_uint_16 delay_den; | |
1263 | + png_byte dispose_op; | |
1264 | + png_byte blend_op; | |
1265 | + | |
6df9a45f | 1266 | + png_debug(1, "in png_handle_fcTL"); |
259182b6 ER |
1267 | + |
1268 | + if (!(png_ptr->mode & PNG_HAVE_IHDR)) | |
1269 | + { | |
1270 | + png_error(png_ptr, "Missing IHDR before fcTL"); | |
1271 | + } | |
1272 | + else if (png_ptr->mode & PNG_HAVE_IDAT) | |
1273 | + { | |
1274 | + /* for any frames other then the first this message may be misleading, | |
1275 | + * but correct. PNG_HAVE_IDAT is unset before the frame head is read | |
1276 | + * i can't think of a better message */ | |
1277 | + png_warning(png_ptr, "Invalid fcTL after IDAT skipped"); | |
1278 | + png_crc_finish(png_ptr, length); | |
1279 | + return; | |
1280 | + } | |
1281 | + else if (png_ptr->mode & PNG_HAVE_fcTL) | |
1282 | + { | |
1283 | + png_warning(png_ptr, "Duplicate fcTL within one frame skipped"); | |
1284 | + png_crc_finish(png_ptr, length); | |
1285 | + return; | |
1286 | + } | |
1287 | + else if (length != 26) | |
1288 | + { | |
1289 | + png_warning(png_ptr, "fcTL with invalid length skipped"); | |
1290 | + png_crc_finish(png_ptr, length); | |
1291 | + return; | |
1292 | + } | |
1293 | + | |
1294 | + png_ensure_sequence_number(png_ptr, length); | |
1295 | + | |
1296 | + png_crc_read(png_ptr, data, 22); | |
1297 | + png_crc_finish(png_ptr, 0); | |
1298 | + | |
1299 | + width = png_get_uint_31(png_ptr, data); | |
1300 | + height = png_get_uint_31(png_ptr, data + 4); | |
1301 | + x_offset = png_get_uint_31(png_ptr, data + 8); | |
1302 | + y_offset = png_get_uint_31(png_ptr, data + 12); | |
1303 | + delay_num = png_get_uint_16(data + 16); | |
1304 | + delay_den = png_get_uint_16(data + 18); | |
1305 | + dispose_op = data[20]; | |
1306 | + blend_op = data[21]; | |
1307 | + | |
1308 | + if (png_ptr->num_frames_read == 0 && (x_offset != 0 || y_offset != 0)) | |
1309 | + png_error(png_ptr, "fcTL for the first frame must have zero offset"); | |
1310 | + if (png_ptr->num_frames_read == 0 && | |
1311 | + (width != info_ptr->width || height != info_ptr->height)) | |
1312 | + png_error(png_ptr, "size in first frame's fcTL must match " | |
1313 | + "the size in IHDR"); | |
1314 | + | |
1315 | + /* the set function will do more error checking */ | |
1316 | + png_set_next_frame_fcTL(png_ptr, info_ptr, width, height, | |
1317 | + x_offset, y_offset, delay_num, delay_den, | |
1318 | + dispose_op, blend_op); | |
1319 | + | |
1320 | + png_read_reinit(png_ptr, info_ptr); | |
1321 | + | |
1322 | + png_ptr->mode |= PNG_HAVE_fcTL; | |
1323 | +} | |
1324 | + | |
1325 | +void /* PRIVATE */ | |
1326 | +png_have_info(png_structp png_ptr, png_infop info_ptr) | |
1327 | +{ | |
1328 | + if((info_ptr->valid & PNG_INFO_acTL) && !(info_ptr->valid & PNG_INFO_fcTL)) | |
1329 | + { | |
1330 | + png_ptr->apng_flags |= PNG_FIRST_FRAME_HIDDEN; | |
1331 | + info_ptr->num_frames++; | |
1332 | + } | |
1333 | +} | |
1334 | + | |
1335 | +void /* PRIVATE */ | |
1336 | +png_handle_fdAT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) | |
1337 | +{ | |
1338 | + png_ensure_sequence_number(png_ptr, length); | |
1339 | + | |
1340 | + /* This function is only called from png_read_end(), png_read_info(), | |
1341 | + * and png_push_read_chunk() which means that: | |
1342 | + * - the user doesn't want to read this frame | |
1343 | + * - or this is an out-of-place fdAT | |
1344 | + * in either case it is safe to ignore the chunk with a warning */ | |
1345 | + png_warning(png_ptr, "ignoring fdAT chunk"); | |
1346 | + png_crc_finish(png_ptr, length - 4); | |
1347 | +} | |
1348 | + | |
1349 | +void /* PRIVATE */ | |
1350 | +png_ensure_sequence_number(png_structp png_ptr, png_uint_32 length) | |
1351 | +{ | |
1352 | + png_byte data[4]; | |
1353 | + png_uint_32 sequence_number; | |
1354 | + | |
1355 | + if (length < 4) | |
1356 | + png_error(png_ptr, "invalid fcTL or fdAT chunk found"); | |
1357 | + | |
1358 | + png_crc_read(png_ptr, data, 4); | |
1359 | + sequence_number = png_get_uint_31(png_ptr, data); | |
1360 | + | |
1361 | + if (sequence_number != png_ptr->next_seq_num) | |
1362 | + png_error(png_ptr, "fcTL or fdAT chunk with out-of-order sequence " | |
1363 | + "number found"); | |
1364 | + | |
1365 | + png_ptr->next_seq_num++; | |
1366 | +} | |
1367 | +#endif /* PNG_READ_APNG_SUPPORTED */ | |
1368 | + | |
1369 | /* This function is called when we haven't found a handler for a | |
1370 | chunk. If there isn't a problem with the chunk itself (ie bad | |
1371 | chunk name, CRC, or a critical chunk), the chunk is silently ignored | |
9f147502 | 1372 | @@ -3249,4 +3416,84 @@ |
259182b6 ER |
1373 | |
1374 | png_ptr->flags |= PNG_FLAG_ROW_INIT; | |
1375 | } | |
1376 | + | |
1377 | +#if defined(PNG_READ_APNG_SUPPORTED) | |
1378 | +/* This function is to be called after the main IDAT set has been read and | |
1379 | + * before a new IDAT is read. It resets some parts of png_ptr | |
1380 | + * to make them usable by the read functions again */ | |
1381 | +void /* PRIVATE */ | |
1382 | +png_read_reset(png_structp png_ptr) | |
1383 | +{ | |
1384 | + png_ptr->mode &= ~PNG_HAVE_IDAT; | |
1385 | + png_ptr->mode &= ~PNG_AFTER_IDAT; | |
1386 | + png_ptr->row_number = 0; | |
1387 | + png_ptr->pass = 0; | |
1388 | + png_ptr->flags &= ~PNG_FLAG_ROW_INIT; | |
1389 | +} | |
1390 | + | |
1391 | +void /* PRIVATE */ | |
1392 | +png_read_reinit(png_structp png_ptr, png_infop info_ptr) | |
1393 | +{ | |
1394 | + png_ptr->width = info_ptr->next_frame_width; | |
1395 | + png_ptr->height = info_ptr->next_frame_height; | |
1396 | + png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth,png_ptr->width); | |
6df9a45f | 1397 | + if (png_ptr->prev_row) |
1398 | + png_memset_check(png_ptr, png_ptr->prev_row, 0, png_ptr->rowbytes + 1); | |
259182b6 ER |
1399 | +} |
1400 | + | |
1401 | +/* same as png_read_reset() but for the progressive reader */ | |
1402 | +void /* PRIVATE */ | |
1403 | +png_progressive_read_reset(png_structp png_ptr) | |
1404 | +{ | |
1405 | +#ifdef PNG_USE_LOCAL_ARRAYS | |
1406 | + /* start of interlace block */ | |
1407 | + const int FARDATA png_pass_start[] = {0, 4, 0, 2, 0, 1, 0}; | |
1408 | + | |
1409 | + /* offset to next interlace block */ | |
1410 | + const int FARDATA png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1}; | |
1411 | + | |
1412 | + /* start of interlace block in the y direction */ | |
1413 | + const int FARDATA png_pass_ystart[] = {0, 0, 4, 0, 2, 0, 1}; | |
1414 | + | |
1415 | + /* offset to next interlace block in the y direction */ | |
1416 | + const int FARDATA png_pass_yinc[] = {8, 8, 8, 4, 4, 2, 2}; | |
1417 | +#endif | |
1418 | + png_uint_32 row_bytes; | |
1419 | + | |
1420 | + if (png_ptr->interlaced) | |
1421 | + { | |
1422 | + if (!(png_ptr->transformations & PNG_INTERLACE)) | |
1423 | + png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 - | |
1424 | + png_pass_ystart[0]) / png_pass_yinc[0]; | |
1425 | + else | |
1426 | + png_ptr->num_rows = png_ptr->height; | |
1427 | + | |
1428 | + png_ptr->iwidth = (png_ptr->width + | |
1429 | + png_pass_inc[png_ptr->pass] - 1 - | |
1430 | + png_pass_start[png_ptr->pass]) / | |
1431 | + png_pass_inc[png_ptr->pass]; | |
1432 | + | |
1433 | + row_bytes = PNG_ROWBYTES(png_ptr->pixel_depth,png_ptr->iwidth) + 1; | |
1434 | + | |
1435 | + png_ptr->irowbytes = (png_size_t)row_bytes; | |
1436 | + if((png_uint_32)png_ptr->irowbytes != row_bytes) | |
1437 | + png_error(png_ptr, "png_progressive_read_reset(): Rowbytes " | |
1438 | + "overflow"); | |
1439 | + } | |
1440 | + else | |
1441 | + { | |
1442 | + png_ptr->num_rows = png_ptr->height; | |
1443 | + png_ptr->iwidth = png_ptr->width; | |
1444 | + png_ptr->irowbytes = png_ptr->rowbytes + 1; | |
1445 | + } | |
1446 | + | |
1447 | + png_ptr->flags &= ~PNG_FLAG_ZLIB_FINISHED; | |
1448 | + if (inflateReset(&(png_ptr->zstream)) != Z_OK) | |
1449 | + png_error(png_ptr, "inflateReset failed"); | |
1450 | + png_ptr->zstream.avail_in = 0; | |
1451 | + png_ptr->zstream.next_in = 0; | |
1452 | + png_ptr->zstream.next_out = png_ptr->row_buf; | |
1453 | + png_ptr->zstream.avail_out = (uInt)png_ptr->irowbytes; | |
1454 | +} | |
1455 | +#endif /* PNG_READ_APNG_SUPPORTED */ | |
1456 | #endif /* PNG_READ_SUPPORTED */ | |
1457 | Index: pngwutil.c | |
1458 | =================================================================== | |
6df9a45f | 1459 | --- pngwutil.c |
1460 | +++ pngwutil.c | |
9f147502 | 1461 | @@ -511,6 +511,11 @@ |
6df9a45f | 1462 | /* Write the chunk */ |
c501f448 | 1463 | png_write_chunk(png_ptr, (png_bytep)png_IHDR, buf, (png_size_t)13); |
259182b6 ER |
1464 | |
1465 | +#if defined(PNG_WRITE_APNG_SUPPORTED) | |
1466 | + png_ptr->first_frame_width = width; | |
1467 | + png_ptr->first_frame_height = height; | |
1468 | +#endif | |
1469 | + | |
6df9a45f | 1470 | /* Initialize zlib with PNG info */ |
259182b6 ER |
1471 | png_ptr->zstream.zalloc = png_zalloc; |
1472 | png_ptr->zstream.zfree = png_zfree; | |
9f147502 | 1473 | @@ -633,6 +638,9 @@ |
259182b6 ER |
1474 | { |
1475 | #ifdef PNG_USE_LOCAL_ARRAYS | |
1476 | PNG_IDAT; | |
1477 | +#if defined(PNG_WRITE_APNG_SUPPORTED) | |
1478 | + PNG_fdAT; | |
259182b6 | 1479 | +#endif |
c501f448 | 1480 | #endif |
6df9a45f | 1481 | png_debug(1, "in png_write_IDAT"); |
259182b6 | 1482 | |
9f147502 | 1483 | @@ -677,7 +685,28 @@ |
259182b6 ER |
1484 | "Invalid zlib compression method or flags in IDAT"); |
1485 | } | |
1486 | ||
259182b6 ER |
1487 | +#if defined(PNG_WRITE_APNG_SUPPORTED) |
1488 | + if(png_ptr->num_frames_written == 0) | |
1489 | +#endif | |
6df9a45f | 1490 | png_write_chunk(png_ptr, (png_bytep)png_IDAT, data, length); |
259182b6 ER |
1491 | +#if defined(PNG_WRITE_APNG_SUPPORTED) |
1492 | + else | |
1493 | + { | |
1494 | + png_byte buf[4]; | |
1495 | + | |
1496 | + png_write_chunk_start(png_ptr, (png_bytep)png_fdAT, 4 + length); | |
1497 | + | |
1498 | + png_save_uint_32(buf, png_ptr->next_seq_num); | |
1499 | + png_write_chunk_data(png_ptr, buf, 4); | |
1500 | + | |
1501 | + png_write_chunk_data(png_ptr, data, length); | |
1502 | + | |
1503 | + png_write_chunk_end(png_ptr); | |
1504 | + | |
1505 | + png_ptr->next_seq_num++; | |
1506 | + } | |
1507 | +#endif | |
1508 | + | |
1509 | png_ptr->mode |= PNG_HAVE_IDAT; | |
1510 | } | |
1511 | ||
9f147502 | 1512 | @@ -1719,6 +1748,70 @@ |
259182b6 ER |
1513 | } |
1514 | #endif | |
1515 | ||
1516 | +#if defined(PNG_WRITE_APNG_SUPPORTED) | |
1517 | +void /* PRIVATE */ | |
1518 | +png_write_acTL(png_structp png_ptr, | |
1519 | + png_uint_32 num_frames, png_uint_32 num_plays) | |
1520 | +{ | |
1521 | +#ifdef PNG_USE_LOCAL_ARRAYS | |
1522 | + PNG_acTL; | |
1523 | +#endif | |
1524 | + png_byte data[16]; | |
1525 | + | |
6df9a45f | 1526 | + png_debug(1, "in png_write_acTL"); |
259182b6 ER |
1527 | + |
1528 | + png_ptr->num_frames_to_write = num_frames; | |
1529 | + | |
1530 | + if (png_ptr->apng_flags & PNG_FIRST_FRAME_HIDDEN) | |
1531 | + num_frames--; | |
1532 | + | |
1533 | + png_save_uint_32(data, num_frames); | |
1534 | + png_save_uint_32(data + 4, num_plays); | |
1535 | + | |
1536 | + png_write_chunk(png_ptr, (png_bytep)png_acTL, data, (png_size_t)8); | |
1537 | +} | |
1538 | + | |
1539 | +void /* PRIVATE */ | |
1540 | +png_write_fcTL(png_structp png_ptr, png_uint_32 width, png_uint_32 height, | |
1541 | + png_uint_32 x_offset, png_uint_32 y_offset, | |
1542 | + png_uint_16 delay_num, png_uint_16 delay_den, png_byte dispose_op, | |
1543 | + png_byte blend_op) | |
1544 | +{ | |
1545 | +#ifdef PNG_USE_LOCAL_ARRAYS | |
1546 | + PNG_fcTL; | |
1547 | +#endif | |
1548 | + png_byte data[26]; | |
1549 | + | |
6df9a45f | 1550 | + png_debug(1, "in png_write_fcTL"); |
259182b6 ER |
1551 | + |
1552 | + if (png_ptr->num_frames_written == 0 && (x_offset != 0 || y_offset != 0)) | |
6df9a45f | 1553 | + png_error(png_ptr, "x and/or y offset for the first frame aren't 0"); |
259182b6 ER |
1554 | + if (png_ptr->num_frames_written == 0 && |
1555 | + (width != png_ptr->first_frame_width || | |
1556 | + height != png_ptr->first_frame_height)) | |
1557 | + png_error(png_ptr, "width and/or height in the first frame's fcTL " | |
6df9a45f | 1558 | + "don't match the ones in IHDR"); |
259182b6 ER |
1559 | + |
1560 | + /* more error checking */ | |
1561 | + png_ensure_fcTL_is_valid(png_ptr, width, height, x_offset, y_offset, | |
1562 | + delay_num, delay_den, dispose_op, blend_op); | |
1563 | + | |
1564 | + png_save_uint_32(data, png_ptr->next_seq_num); | |
1565 | + png_save_uint_32(data + 4, width); | |
1566 | + png_save_uint_32(data + 8, height); | |
1567 | + png_save_uint_32(data + 12, x_offset); | |
1568 | + png_save_uint_32(data + 16, y_offset); | |
1569 | + png_save_uint_16(data + 20, delay_num); | |
1570 | + png_save_uint_16(data + 22, delay_den); | |
1571 | + data[24] = dispose_op; | |
1572 | + data[25] = blend_op; | |
1573 | + | |
1574 | + png_write_chunk(png_ptr, (png_bytep)png_fcTL, data, (png_size_t)26); | |
1575 | + | |
1576 | + png_ptr->next_seq_num++; | |
1577 | +} | |
1578 | +#endif /* PNG_WRITE_APNG_SUPPORTED */ | |
1579 | + | |
6df9a45f | 1580 | /* Initializes the row writing capability of libpng */ |
259182b6 ER |
1581 | void /* PRIVATE */ |
1582 | png_write_start_row(png_structp png_ptr) | |
9f147502 | 1583 | @@ -2122,6 +2215,8 @@ |
6df9a45f | 1584 | #if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) |
1585 | int num_p_filters = (int)png_ptr->num_prev_filters; | |
1586 | #endif | |
1587 | + if (png_ptr->row_number == 0) | |
1588 | + filter_to_do &= ~(PNG_FILTER_UP | PNG_FILTER_AVG | PNG_FILTER_PAETH); /* they use previous row */ | |
1589 | ||
1590 | png_debug(1, "in png_write_find_filter"); | |
1591 | /* Find out how many bytes offset each pixel is */ | |
9f147502 | 1592 | @@ -2788,4 +2883,39 @@ |
259182b6 ER |
1593 | } |
1594 | #endif | |
1595 | } | |
1596 | + | |
1597 | +#if defined(PNG_WRITE_APNG_SUPPORTED) | |
1598 | +void /* PRIVATE */ | |
1599 | +png_write_reset(png_structp png_ptr) | |
1600 | +{ | |
1601 | + png_ptr->row_number = 0; | |
1602 | + png_ptr->pass = 0; | |
1603 | + png_ptr->mode &= ~PNG_HAVE_IDAT; | |
1604 | +} | |
1605 | + | |
1606 | +void /* PRIVATE */ | |
1607 | +png_write_reinit(png_structp png_ptr, png_infop info_ptr, | |
1608 | + png_uint_32 width, png_uint_32 height) | |
1609 | +{ | |
1610 | + if (png_ptr->num_frames_written == 0 && | |
1611 | + (width != png_ptr->first_frame_width || | |
1612 | + height != png_ptr->first_frame_height)) | |
1613 | + png_error(png_ptr, "width and/or height in the first frame's fcTL " | |
6df9a45f | 1614 | + "don't match the ones in IHDR"); |
259182b6 ER |
1615 | + if (width > png_ptr->first_frame_width || |
1616 | + height > png_ptr->first_frame_height) | |
1617 | + png_error(png_ptr, "width and/or height for a frame greater than" | |
1618 | + "the ones in IHDR"); | |
1619 | + | |
1620 | + png_set_IHDR(png_ptr, info_ptr, width, height, | |
1621 | + info_ptr->bit_depth, info_ptr->color_type, | |
1622 | + info_ptr->interlace_type, info_ptr->compression_type, | |
1623 | + info_ptr->filter_type); | |
1624 | + | |
1625 | + png_ptr->width = width; | |
1626 | + png_ptr->height = height; | |
1627 | + png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth, width); | |
1628 | + png_ptr->usr_width = png_ptr->width; | |
1629 | +} | |
1630 | +#endif | |
1631 | #endif /* PNG_WRITE_SUPPORTED */ | |
1632 | Index: pngrtran.c | |
1633 | =================================================================== | |
6df9a45f | 1634 | --- pngrtran.c |
1635 | +++ pngrtran.c | |
9f147502 | 1636 | @@ -1321,7 +1321,7 @@ |
6df9a45f | 1637 | * pixels. This check added to libpng-1.2.19 |
1638 | */ | |
259182b6 ER |
1639 | #if (PNG_WARN_UNINITIALIZED_ROW==1) |
1640 | - png_error(png_ptr, "Uninitialized row"); | |
1641 | + png_warning(png_ptr, "Uninitialized row"); | |
1642 | #else | |
1643 | png_warning(png_ptr, "Uninitialized row"); | |
1644 | #endif |