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