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