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