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