pngwrite.c (80181B)
1 /* pngwrite.c - general routines to write a PNG file 2 * 3 * Copyright (c) 2018-2025 Cosmin Truta 4 * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson 5 * Copyright (c) 1996-1997 Andreas Dilger 6 * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. 7 * 8 * This code is released under the libpng license. 9 * For conditions of distribution and use, see the disclaimer 10 * and license in png.h 11 */ 12 13 #include "pngpriv.h" 14 #ifdef PNG_SIMPLIFIED_WRITE_STDIO_SUPPORTED 15 # include <errno.h> 16 #endif /* SIMPLIFIED_WRITE_STDIO */ 17 18 #ifdef PNG_WRITE_SUPPORTED 19 20 #ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED 21 /* Write out all the unknown chunks for the current given location */ 22 static void 23 write_unknown_chunks(png_structrp png_ptr, png_const_inforp info_ptr, 24 unsigned int where) 25 { 26 if (info_ptr->unknown_chunks_num != 0) 27 { 28 png_const_unknown_chunkp up; 29 30 png_debug(5, "writing extra chunks"); 31 32 for (up = info_ptr->unknown_chunks; 33 up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num; 34 ++up) 35 if ((up->location & where) != 0) 36 { 37 /* If per-chunk unknown chunk handling is enabled use it, otherwise 38 * just write the chunks the application has set. 39 */ 40 #ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED 41 int keep = png_handle_as_unknown(png_ptr, up->name); 42 43 /* NOTE: this code is radically different from the read side in the 44 * matter of handling an ancillary unknown chunk. In the read side 45 * the default behavior is to discard it, in the code below the default 46 * behavior is to write it. Critical chunks are, however, only 47 * written if explicitly listed or if the default is set to write all 48 * unknown chunks. 49 * 50 * The default handling is also slightly weird - it is not possible to 51 * stop the writing of all unsafe-to-copy chunks! 52 * 53 * TODO: REVIEW: this would seem to be a bug. 54 */ 55 if (keep != PNG_HANDLE_CHUNK_NEVER && 56 ((up->name[3] & 0x20) /* safe-to-copy overrides everything */ || 57 keep == PNG_HANDLE_CHUNK_ALWAYS || 58 (keep == PNG_HANDLE_CHUNK_AS_DEFAULT && 59 png_ptr->unknown_default == PNG_HANDLE_CHUNK_ALWAYS))) 60 #endif 61 { 62 /* TODO: review, what is wrong with a zero length unknown chunk? */ 63 if (up->size == 0) 64 png_warning(png_ptr, "Writing zero-length unknown chunk"); 65 66 png_write_chunk(png_ptr, up->name, up->data, up->size); 67 } 68 } 69 } 70 } 71 #endif /* WRITE_UNKNOWN_CHUNKS */ 72 73 /* Writes all the PNG information. This is the suggested way to use the 74 * library. If you have a new chunk to add, make a function to write it, 75 * and put it in the correct location here. If you want the chunk written 76 * after the image data, put it in png_write_end(). I strongly encourage 77 * you to supply a PNG_INFO_<chunk> flag, and check info_ptr->valid before 78 * writing the chunk, as that will keep the code from breaking if you want 79 * to just write a plain PNG file. If you have long comments, I suggest 80 * writing them in png_write_end(), and compressing them. 81 */ 82 void PNGAPI 83 png_write_info_before_PLTE(png_structrp png_ptr, png_const_inforp info_ptr) 84 { 85 png_debug(1, "in png_write_info_before_PLTE"); 86 87 if (png_ptr == NULL || info_ptr == NULL) 88 return; 89 90 if ((png_ptr->mode & PNG_WROTE_INFO_BEFORE_PLTE) == 0) 91 { 92 /* Write PNG signature */ 93 png_write_sig(png_ptr); 94 95 #ifdef PNG_MNG_FEATURES_SUPPORTED 96 if ((png_ptr->mode & PNG_HAVE_PNG_SIGNATURE) != 0 && \ 97 png_ptr->mng_features_permitted != 0) 98 { 99 png_warning(png_ptr, 100 "MNG features are not allowed in a PNG datastream"); 101 png_ptr->mng_features_permitted = 0; 102 } 103 #endif 104 105 /* Write IHDR information. */ 106 png_write_IHDR(png_ptr, info_ptr->width, info_ptr->height, 107 info_ptr->bit_depth, info_ptr->color_type, info_ptr->compression_type, 108 info_ptr->filter_type, 109 #ifdef PNG_WRITE_INTERLACING_SUPPORTED 110 info_ptr->interlace_type 111 #else 112 0 113 #endif 114 ); 115 116 /* The rest of these check to see if the valid field has the appropriate 117 * flag set, and if it does, writes the chunk. 118 * 119 * 1.6.0: COLORSPACE support controls the writing of these chunks too, and 120 * the chunks will be written if the WRITE routine is there and 121 * information * is available in the COLORSPACE. (See 122 * png_colorspace_sync_info in png.c for where the valid flags get set.) 123 * 124 * Under certain circumstances the colorspace can be invalidated without 125 * syncing the info_struct 'valid' flags; this happens if libpng detects 126 * an error and calls png_error while the color space is being set, yet 127 * the application continues writing the PNG. So check the 'invalid' 128 * flag here too. 129 */ 130 #ifdef PNG_WRITE_APNG_SUPPORTED 131 if ((info_ptr->valid & PNG_INFO_acTL) != 0) 132 png_write_acTL(png_ptr, info_ptr->num_frames, info_ptr->num_plays); 133 #endif 134 #ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED 135 /* Write unknown chunks first; PNG v3 establishes a precedence order 136 * for colourspace chunks. It is certain therefore that new 137 * colourspace chunks will have a precedence and very likely it will be 138 * higher than all known so far. Writing the unknown chunks here is 139 * most likely to present the chunks in the most convenient order. 140 * 141 * FUTURE: maybe write chunks in the order the app calls png_set_chnk 142 * to give the app control. 143 */ 144 write_unknown_chunks(png_ptr, info_ptr, PNG_HAVE_IHDR); 145 #endif 146 147 #ifdef PNG_WRITE_sBIT_SUPPORTED 148 /* PNG v3: a streaming app will need to see this before cICP because 149 * the information is helpful in handling HLG encoding (which is 150 * natively 10 bits but gets expanded to 16 in PNG.) 151 * 152 * The app shouldn't care about the order ideally, but it might have 153 * no choice. In PNG v3, apps are allowed to reject PNGs where the 154 * APNG chunks are out of order so it behooves libpng to be nice here. 155 */ 156 if ((info_ptr->valid & PNG_INFO_sBIT) != 0) 157 png_write_sBIT(png_ptr, &(info_ptr->sig_bit), info_ptr->color_type); 158 #endif 159 160 /* PNG v3: the July 2004 version of the TR introduced the concept of colour 161 * space priority. As above it therefore behooves libpng to write the colour 162 * space chunks in the priority order so that a streaming app need not buffer 163 * them. 164 * 165 * PNG v3: Chunks mDCV and cLLI provide ancillary information for the 166 * interpretation of the colourspace chunkgs but do not require support for 167 * those chunks so are outside the "COLORSPACE" check but before the write of 168 * the colourspace chunks themselves. 169 */ 170 #ifdef PNG_WRITE_cLLI_SUPPORTED 171 if ((info_ptr->valid & PNG_INFO_cLLI) != 0) 172 { 173 png_write_cLLI_fixed(png_ptr, info_ptr->maxCLL, info_ptr->maxFALL); 174 } 175 #endif 176 #ifdef PNG_WRITE_mDCV_SUPPORTED 177 if ((info_ptr->valid & PNG_INFO_mDCV) != 0) 178 { 179 png_write_mDCV_fixed(png_ptr, 180 info_ptr->mastering_red_x, info_ptr->mastering_red_y, 181 info_ptr->mastering_green_x, info_ptr->mastering_green_y, 182 info_ptr->mastering_blue_x, info_ptr->mastering_blue_y, 183 info_ptr->mastering_white_x, info_ptr->mastering_white_y, 184 info_ptr->mastering_maxDL, info_ptr->mastering_minDL); 185 } 186 #endif 187 188 # ifdef PNG_WRITE_cICP_SUPPORTED /* Priority 4 */ 189 if ((info_ptr->valid & PNG_INFO_cICP) != 0) 190 { 191 png_write_cICP(png_ptr, 192 info_ptr->cicp_colour_primaries, 193 info_ptr->cicp_transfer_function, 194 info_ptr->cicp_matrix_coefficients, 195 info_ptr->cicp_video_full_range_flag); 196 } 197 # endif 198 199 # ifdef PNG_WRITE_iCCP_SUPPORTED /* Priority 3 */ 200 if ((info_ptr->valid & PNG_INFO_iCCP) != 0) 201 { 202 png_write_iCCP(png_ptr, info_ptr->iccp_name, 203 info_ptr->iccp_profile, info_ptr->iccp_proflen); 204 } 205 # endif 206 207 # ifdef PNG_WRITE_sRGB_SUPPORTED /* Priority 2 */ 208 if ((info_ptr->valid & PNG_INFO_sRGB) != 0) 209 png_write_sRGB(png_ptr, info_ptr->rendering_intent); 210 # endif /* WRITE_sRGB */ 211 212 # ifdef PNG_WRITE_gAMA_SUPPORTED /* Priority 1 */ 213 if ((info_ptr->valid & PNG_INFO_gAMA) != 0) 214 png_write_gAMA_fixed(png_ptr, info_ptr->gamma); 215 # endif 216 217 # ifdef PNG_WRITE_cHRM_SUPPORTED /* Also priority 1 */ 218 if ((info_ptr->valid & PNG_INFO_cHRM) != 0) 219 png_write_cHRM_fixed(png_ptr, &info_ptr->cHRM); 220 # endif 221 222 png_ptr->mode |= PNG_WROTE_INFO_BEFORE_PLTE; 223 } 224 } 225 226 void PNGAPI 227 png_write_info(png_structrp png_ptr, png_const_inforp info_ptr) 228 { 229 #if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED) 230 int i; 231 #endif 232 233 png_debug(1, "in png_write_info"); 234 235 if (png_ptr == NULL || info_ptr == NULL) 236 return; 237 238 png_write_info_before_PLTE(png_ptr, info_ptr); 239 240 if ((info_ptr->valid & PNG_INFO_PLTE) != 0) 241 png_write_PLTE(png_ptr, info_ptr->palette, 242 (png_uint_32)info_ptr->num_palette); 243 244 else if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) 245 png_error(png_ptr, "Valid palette required for paletted images"); 246 247 #ifdef PNG_WRITE_tRNS_SUPPORTED 248 if ((info_ptr->valid & PNG_INFO_tRNS) !=0) 249 { 250 #ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED 251 /* Invert the alpha channel (in tRNS) */ 252 if ((png_ptr->transformations & PNG_INVERT_ALPHA) != 0 && 253 info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) 254 { 255 int j, jend; 256 257 jend = info_ptr->num_trans; 258 if (jend > PNG_MAX_PALETTE_LENGTH) 259 jend = PNG_MAX_PALETTE_LENGTH; 260 261 for (j = 0; j<jend; ++j) 262 info_ptr->trans_alpha[j] = 263 (png_byte)(255 - info_ptr->trans_alpha[j]); 264 } 265 #endif 266 png_write_tRNS(png_ptr, info_ptr->trans_alpha, &(info_ptr->trans_color), 267 info_ptr->num_trans, info_ptr->color_type); 268 } 269 #endif 270 #ifdef PNG_WRITE_bKGD_SUPPORTED 271 if ((info_ptr->valid & PNG_INFO_bKGD) != 0) 272 png_write_bKGD(png_ptr, &(info_ptr->background), info_ptr->color_type); 273 #endif 274 275 #ifdef PNG_WRITE_eXIf_SUPPORTED 276 if ((info_ptr->valid & PNG_INFO_eXIf) != 0) 277 { 278 png_write_eXIf(png_ptr, info_ptr->exif, info_ptr->num_exif); 279 png_ptr->mode |= PNG_WROTE_eXIf; 280 } 281 #endif 282 283 #ifdef PNG_WRITE_hIST_SUPPORTED 284 if ((info_ptr->valid & PNG_INFO_hIST) != 0) 285 png_write_hIST(png_ptr, info_ptr->hist, info_ptr->num_palette); 286 #endif 287 288 #ifdef PNG_WRITE_oFFs_SUPPORTED 289 if ((info_ptr->valid & PNG_INFO_oFFs) != 0) 290 png_write_oFFs(png_ptr, info_ptr->x_offset, info_ptr->y_offset, 291 info_ptr->offset_unit_type); 292 #endif 293 294 #ifdef PNG_WRITE_pCAL_SUPPORTED 295 if ((info_ptr->valid & PNG_INFO_pCAL) != 0) 296 png_write_pCAL(png_ptr, info_ptr->pcal_purpose, info_ptr->pcal_X0, 297 info_ptr->pcal_X1, info_ptr->pcal_type, info_ptr->pcal_nparams, 298 info_ptr->pcal_units, info_ptr->pcal_params); 299 #endif 300 301 #ifdef PNG_WRITE_sCAL_SUPPORTED 302 if ((info_ptr->valid & PNG_INFO_sCAL) != 0) 303 png_write_sCAL_s(png_ptr, (int)info_ptr->scal_unit, 304 info_ptr->scal_s_width, info_ptr->scal_s_height); 305 #endif /* sCAL */ 306 307 #ifdef PNG_WRITE_pHYs_SUPPORTED 308 if ((info_ptr->valid & PNG_INFO_pHYs) != 0) 309 png_write_pHYs(png_ptr, info_ptr->x_pixels_per_unit, 310 info_ptr->y_pixels_per_unit, info_ptr->phys_unit_type); 311 #endif /* pHYs */ 312 313 #ifdef PNG_WRITE_tIME_SUPPORTED 314 if ((info_ptr->valid & PNG_INFO_tIME) != 0) 315 { 316 png_write_tIME(png_ptr, &(info_ptr->mod_time)); 317 png_ptr->mode |= PNG_WROTE_tIME; 318 } 319 #endif /* tIME */ 320 321 #ifdef PNG_WRITE_sPLT_SUPPORTED 322 if ((info_ptr->valid & PNG_INFO_sPLT) != 0) 323 for (i = 0; i < (int)info_ptr->splt_palettes_num; i++) 324 png_write_sPLT(png_ptr, info_ptr->splt_palettes + i); 325 #endif /* sPLT */ 326 327 #ifdef PNG_WRITE_TEXT_SUPPORTED 328 /* Check to see if we need to write text chunks */ 329 for (i = 0; i < info_ptr->num_text; i++) 330 { 331 png_debug2(2, "Writing header text chunk %d, type %d", i, 332 info_ptr->text[i].compression); 333 /* An internationalized chunk? */ 334 if (info_ptr->text[i].compression > 0) 335 { 336 #ifdef PNG_WRITE_iTXt_SUPPORTED 337 /* Write international chunk */ 338 png_write_iTXt(png_ptr, 339 info_ptr->text[i].compression, 340 info_ptr->text[i].key, 341 info_ptr->text[i].lang, 342 info_ptr->text[i].lang_key, 343 info_ptr->text[i].text); 344 /* Mark this chunk as written */ 345 if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE) 346 info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; 347 else 348 info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR; 349 #else 350 png_warning(png_ptr, "Unable to write international text"); 351 #endif 352 } 353 354 /* If we want a compressed text chunk */ 355 else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_zTXt) 356 { 357 #ifdef PNG_WRITE_zTXt_SUPPORTED 358 /* Write compressed chunk */ 359 png_write_zTXt(png_ptr, info_ptr->text[i].key, 360 info_ptr->text[i].text, info_ptr->text[i].compression); 361 /* Mark this chunk as written */ 362 info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR; 363 #else 364 png_warning(png_ptr, "Unable to write compressed text"); 365 #endif 366 } 367 368 else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE) 369 { 370 #ifdef PNG_WRITE_tEXt_SUPPORTED 371 /* Write uncompressed chunk */ 372 png_write_tEXt(png_ptr, info_ptr->text[i].key, 373 info_ptr->text[i].text, 374 0); 375 /* Mark this chunk as written */ 376 info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; 377 #else 378 /* Can't get here */ 379 png_warning(png_ptr, "Unable to write uncompressed text"); 380 #endif 381 } 382 } 383 #endif /* tEXt */ 384 385 #ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED 386 write_unknown_chunks(png_ptr, info_ptr, PNG_HAVE_PLTE); 387 #endif 388 } 389 390 /* Writes the end of the PNG file. If you don't want to write comments or 391 * time information, you can pass NULL for info. If you already wrote these 392 * in png_write_info(), do not write them again here. If you have long 393 * comments, I suggest writing them here, and compressing them. 394 */ 395 void PNGAPI 396 png_write_end(png_structrp png_ptr, png_inforp info_ptr) 397 { 398 png_debug(1, "in png_write_end"); 399 400 if (png_ptr == NULL) 401 return; 402 403 if ((png_ptr->mode & PNG_HAVE_IDAT) == 0) 404 png_error(png_ptr, "No IDATs written into file"); 405 406 #ifdef PNG_WRITE_APNG_SUPPORTED 407 if (png_ptr->num_frames_written != png_ptr->num_frames_to_write) 408 png_error(png_ptr, "Not enough frames written"); 409 #endif 410 411 #ifdef PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED 412 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE && 413 png_ptr->num_palette_max >= png_ptr->num_palette) 414 png_benign_error(png_ptr, "Wrote palette index exceeding num_palette"); 415 #endif 416 417 /* See if user wants us to write information chunks */ 418 if (info_ptr != NULL) 419 { 420 #ifdef PNG_WRITE_TEXT_SUPPORTED 421 int i; /* local index variable */ 422 #endif 423 #ifdef PNG_WRITE_tIME_SUPPORTED 424 /* Check to see if user has supplied a time chunk */ 425 if ((info_ptr->valid & PNG_INFO_tIME) != 0 && 426 (png_ptr->mode & PNG_WROTE_tIME) == 0) 427 png_write_tIME(png_ptr, &(info_ptr->mod_time)); 428 429 #endif 430 #ifdef PNG_WRITE_TEXT_SUPPORTED 431 /* Loop through comment chunks */ 432 for (i = 0; i < info_ptr->num_text; i++) 433 { 434 png_debug2(2, "Writing trailer text chunk %d, type %d", i, 435 info_ptr->text[i].compression); 436 /* An internationalized chunk? */ 437 if (info_ptr->text[i].compression > 0) 438 { 439 #ifdef PNG_WRITE_iTXt_SUPPORTED 440 /* Write international chunk */ 441 png_write_iTXt(png_ptr, 442 info_ptr->text[i].compression, 443 info_ptr->text[i].key, 444 info_ptr->text[i].lang, 445 info_ptr->text[i].lang_key, 446 info_ptr->text[i].text); 447 /* Mark this chunk as written */ 448 if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE) 449 info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; 450 else 451 info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR; 452 #else 453 png_warning(png_ptr, "Unable to write international text"); 454 #endif 455 } 456 457 else if (info_ptr->text[i].compression >= PNG_TEXT_COMPRESSION_zTXt) 458 { 459 #ifdef PNG_WRITE_zTXt_SUPPORTED 460 /* Write compressed chunk */ 461 png_write_zTXt(png_ptr, info_ptr->text[i].key, 462 info_ptr->text[i].text, info_ptr->text[i].compression); 463 /* Mark this chunk as written */ 464 info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR; 465 #else 466 png_warning(png_ptr, "Unable to write compressed text"); 467 #endif 468 } 469 470 else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE) 471 { 472 #ifdef PNG_WRITE_tEXt_SUPPORTED 473 /* Write uncompressed chunk */ 474 png_write_tEXt(png_ptr, info_ptr->text[i].key, 475 info_ptr->text[i].text, 0); 476 /* Mark this chunk as written */ 477 info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; 478 #else 479 png_warning(png_ptr, "Unable to write uncompressed text"); 480 #endif 481 } 482 } 483 #endif 484 485 #ifdef PNG_WRITE_eXIf_SUPPORTED 486 if ((info_ptr->valid & PNG_INFO_eXIf) != 0 && 487 (png_ptr->mode & PNG_WROTE_eXIf) == 0) 488 png_write_eXIf(png_ptr, info_ptr->exif, info_ptr->num_exif); 489 #endif 490 491 #ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED 492 write_unknown_chunks(png_ptr, info_ptr, PNG_AFTER_IDAT); 493 #endif 494 } 495 496 png_ptr->mode |= PNG_AFTER_IDAT; 497 498 /* Write end of PNG file */ 499 png_write_IEND(png_ptr); 500 501 /* This flush, added in libpng-1.0.8, removed from libpng-1.0.9beta03, 502 * and restored again in libpng-1.2.30, may cause some applications that 503 * do not set png_ptr->output_flush_fn to crash. If your application 504 * experiences a problem, please try building libpng with 505 * PNG_WRITE_FLUSH_AFTER_IEND_SUPPORTED defined, and report the event to 506 * png-mng-implement at lists.sf.net . 507 */ 508 #ifdef PNG_WRITE_FLUSH_SUPPORTED 509 # ifdef PNG_WRITE_FLUSH_AFTER_IEND_SUPPORTED 510 png_flush(png_ptr); 511 # endif 512 #endif 513 } 514 515 #ifdef PNG_CONVERT_tIME_SUPPORTED 516 void PNGAPI 517 png_convert_from_struct_tm(png_timep ptime, const struct tm * ttime) 518 { 519 png_debug(1, "in png_convert_from_struct_tm"); 520 521 ptime->year = (png_uint_16)(1900 + ttime->tm_year); 522 ptime->month = (png_byte)(ttime->tm_mon + 1); 523 ptime->day = (png_byte)ttime->tm_mday; 524 ptime->hour = (png_byte)ttime->tm_hour; 525 ptime->minute = (png_byte)ttime->tm_min; 526 ptime->second = (png_byte)ttime->tm_sec; 527 } 528 529 void PNGAPI 530 png_convert_from_time_t(png_timep ptime, time_t ttime) 531 { 532 struct tm *tbuf; 533 534 png_debug(1, "in png_convert_from_time_t"); 535 536 tbuf = gmtime(&ttime); 537 if (tbuf == NULL) 538 { 539 /* TODO: add a safe function which takes a png_ptr argument and raises 540 * a png_error if the ttime argument is invalid and the call to gmtime 541 * fails as a consequence. 542 */ 543 memset(ptime, 0, sizeof(*ptime)); 544 return; 545 } 546 547 png_convert_from_struct_tm(ptime, tbuf); 548 } 549 #endif 550 551 /* Initialize png_ptr structure, and allocate any memory needed */ 552 PNG_FUNCTION(png_structp,PNGAPI 553 png_create_write_struct,(png_const_charp user_png_ver, png_voidp error_ptr, 554 png_error_ptr error_fn, png_error_ptr warn_fn),PNG_ALLOCATED) 555 { 556 #ifndef PNG_USER_MEM_SUPPORTED 557 png_structrp png_ptr = png_create_png_struct(user_png_ver, error_ptr, 558 error_fn, warn_fn, NULL, NULL, NULL); 559 #else 560 return png_create_write_struct_2(user_png_ver, error_ptr, error_fn, 561 warn_fn, NULL, NULL, NULL); 562 } 563 564 /* Alternate initialize png_ptr structure, and allocate any memory needed */ 565 PNG_FUNCTION(png_structp,PNGAPI 566 png_create_write_struct_2,(png_const_charp user_png_ver, png_voidp error_ptr, 567 png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr, 568 png_malloc_ptr malloc_fn, png_free_ptr free_fn),PNG_ALLOCATED) 569 { 570 png_structrp png_ptr = png_create_png_struct(user_png_ver, error_ptr, 571 error_fn, warn_fn, mem_ptr, malloc_fn, free_fn); 572 #endif /* USER_MEM */ 573 if (png_ptr != NULL) 574 { 575 /* Set the zlib control values to defaults; they can be overridden by the 576 * application after the struct has been created. 577 */ 578 png_ptr->zbuffer_size = PNG_ZBUF_SIZE; 579 580 /* The 'zlib_strategy' setting is irrelevant because png_default_claim in 581 * pngwutil.c defaults it according to whether or not filters will be 582 * used, and ignores this setting. 583 */ 584 png_ptr->zlib_strategy = PNG_Z_DEFAULT_STRATEGY; 585 png_ptr->zlib_level = PNG_Z_DEFAULT_COMPRESSION; 586 png_ptr->zlib_mem_level = 8; 587 png_ptr->zlib_window_bits = 15; 588 png_ptr->zlib_method = 8; 589 590 #ifdef PNG_WRITE_COMPRESSED_TEXT_SUPPORTED 591 png_ptr->zlib_text_strategy = PNG_TEXT_Z_DEFAULT_STRATEGY; 592 png_ptr->zlib_text_level = PNG_TEXT_Z_DEFAULT_COMPRESSION; 593 png_ptr->zlib_text_mem_level = 8; 594 png_ptr->zlib_text_window_bits = 15; 595 png_ptr->zlib_text_method = 8; 596 #endif /* WRITE_COMPRESSED_TEXT */ 597 598 /* This is a highly dubious configuration option; by default it is off, 599 * but it may be appropriate for private builds that are testing 600 * extensions not conformant to the current specification, or of 601 * applications that must not fail to write at all costs! 602 */ 603 #ifdef PNG_BENIGN_WRITE_ERRORS_SUPPORTED 604 /* In stable builds only warn if an application error can be completely 605 * handled. 606 */ 607 png_ptr->flags |= PNG_FLAG_BENIGN_ERRORS_WARN; 608 #endif 609 610 /* App warnings are warnings in release (or release candidate) builds but 611 * are errors during development. 612 */ 613 #if PNG_RELEASE_BUILD 614 png_ptr->flags |= PNG_FLAG_APP_WARNINGS_WARN; 615 #endif 616 617 /* TODO: delay this, it can be done in png_init_io() (if the app doesn't 618 * do it itself) avoiding setting the default function if it is not 619 * required. 620 */ 621 png_set_write_fn(png_ptr, NULL, NULL, NULL); 622 } 623 624 return png_ptr; 625 } 626 627 628 /* Write a few rows of image data. If the image is interlaced, 629 * either you will have to write the 7 sub images, or, if you 630 * have called png_set_interlace_handling(), you will have to 631 * "write" the image seven times. 632 */ 633 void PNGAPI 634 png_write_rows(png_structrp png_ptr, png_bytepp row, 635 png_uint_32 num_rows) 636 { 637 png_uint_32 i; /* row counter */ 638 png_bytepp rp; /* row pointer */ 639 640 png_debug(1, "in png_write_rows"); 641 642 if (png_ptr == NULL) 643 return; 644 645 /* Loop through the rows */ 646 for (i = 0, rp = row; i < num_rows; i++, rp++) 647 { 648 png_write_row(png_ptr, *rp); 649 } 650 } 651 652 /* Write the image. You only need to call this function once, even 653 * if you are writing an interlaced image. 654 */ 655 void PNGAPI 656 png_write_image(png_structrp png_ptr, png_bytepp image) 657 { 658 png_uint_32 i; /* row index */ 659 int pass, num_pass; /* pass variables */ 660 png_bytepp rp; /* points to current row */ 661 662 if (png_ptr == NULL) 663 return; 664 665 png_debug(1, "in png_write_image"); 666 667 #ifdef PNG_WRITE_INTERLACING_SUPPORTED 668 /* Initialize interlace handling. If image is not interlaced, 669 * this will set pass to 1 670 */ 671 num_pass = png_set_interlace_handling(png_ptr); 672 #else 673 num_pass = 1; 674 #endif 675 /* Loop through passes */ 676 for (pass = 0; pass < num_pass; pass++) 677 { 678 /* Loop through image */ 679 for (i = 0, rp = image; i < png_ptr->height; i++, rp++) 680 { 681 png_write_row(png_ptr, *rp); 682 } 683 } 684 } 685 686 #ifdef PNG_MNG_FEATURES_SUPPORTED 687 /* Performs intrapixel differencing */ 688 static void 689 png_do_write_intrapixel(png_row_infop row_info, png_bytep row) 690 { 691 png_debug(1, "in png_do_write_intrapixel"); 692 693 if ((row_info->color_type & PNG_COLOR_MASK_COLOR) != 0) 694 { 695 int bytes_per_pixel; 696 png_uint_32 row_width = row_info->width; 697 if (row_info->bit_depth == 8) 698 { 699 png_bytep rp; 700 png_uint_32 i; 701 702 if (row_info->color_type == PNG_COLOR_TYPE_RGB) 703 bytes_per_pixel = 3; 704 705 else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) 706 bytes_per_pixel = 4; 707 708 else 709 return; 710 711 for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel) 712 { 713 *(rp) = (png_byte)(*rp - *(rp + 1)); 714 *(rp + 2) = (png_byte)(*(rp + 2) - *(rp + 1)); 715 } 716 } 717 718 #ifdef PNG_WRITE_16BIT_SUPPORTED 719 else if (row_info->bit_depth == 16) 720 { 721 png_bytep rp; 722 png_uint_32 i; 723 724 if (row_info->color_type == PNG_COLOR_TYPE_RGB) 725 bytes_per_pixel = 6; 726 727 else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) 728 bytes_per_pixel = 8; 729 730 else 731 return; 732 733 for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel) 734 { 735 png_uint_32 s0 = (png_uint_32)(*(rp ) << 8) | *(rp + 1); 736 png_uint_32 s1 = (png_uint_32)(*(rp + 2) << 8) | *(rp + 3); 737 png_uint_32 s2 = (png_uint_32)(*(rp + 4) << 8) | *(rp + 5); 738 png_uint_32 red = (png_uint_32)((s0 - s1) & 0xffffL); 739 png_uint_32 blue = (png_uint_32)((s2 - s1) & 0xffffL); 740 *(rp ) = (png_byte)(red >> 8); 741 *(rp + 1) = (png_byte)red; 742 *(rp + 4) = (png_byte)(blue >> 8); 743 *(rp + 5) = (png_byte)blue; 744 } 745 } 746 #endif /* WRITE_16BIT */ 747 } 748 } 749 #endif /* MNG_FEATURES */ 750 751 /* Called by user to write a row of image data */ 752 void PNGAPI 753 png_write_row(png_structrp png_ptr, png_const_bytep row) 754 { 755 /* 1.5.6: moved from png_struct to be a local structure: */ 756 png_row_info row_info; 757 758 png_debug2(1, "in png_write_row (row %u, pass %d)", 759 png_ptr->row_number, png_ptr->pass); 760 761 if (png_ptr == NULL) 762 return; 763 764 /* Initialize transformations and other stuff if first time */ 765 if (png_ptr->row_number == 0 && png_ptr->pass == 0) 766 { 767 /* Make sure we wrote the header info */ 768 if ((png_ptr->mode & PNG_WROTE_INFO_BEFORE_PLTE) == 0) 769 png_error(png_ptr, 770 "png_write_info was never called before png_write_row"); 771 772 /* Check for transforms that have been set but were defined out */ 773 #if !defined(PNG_WRITE_INVERT_SUPPORTED) && defined(PNG_READ_INVERT_SUPPORTED) 774 if ((png_ptr->transformations & PNG_INVERT_MONO) != 0) 775 png_warning(png_ptr, "PNG_WRITE_INVERT_SUPPORTED is not defined"); 776 #endif 777 778 #if !defined(PNG_WRITE_FILLER_SUPPORTED) && defined(PNG_READ_FILLER_SUPPORTED) 779 if ((png_ptr->transformations & PNG_FILLER) != 0) 780 png_warning(png_ptr, "PNG_WRITE_FILLER_SUPPORTED is not defined"); 781 #endif 782 #if !defined(PNG_WRITE_PACKSWAP_SUPPORTED) && \ 783 defined(PNG_READ_PACKSWAP_SUPPORTED) 784 if ((png_ptr->transformations & PNG_PACKSWAP) != 0) 785 png_warning(png_ptr, 786 "PNG_WRITE_PACKSWAP_SUPPORTED is not defined"); 787 #endif 788 789 #if !defined(PNG_WRITE_PACK_SUPPORTED) && defined(PNG_READ_PACK_SUPPORTED) 790 if ((png_ptr->transformations & PNG_PACK) != 0) 791 png_warning(png_ptr, "PNG_WRITE_PACK_SUPPORTED is not defined"); 792 #endif 793 794 #if !defined(PNG_WRITE_SHIFT_SUPPORTED) && defined(PNG_READ_SHIFT_SUPPORTED) 795 if ((png_ptr->transformations & PNG_SHIFT) != 0) 796 png_warning(png_ptr, "PNG_WRITE_SHIFT_SUPPORTED is not defined"); 797 #endif 798 799 #if !defined(PNG_WRITE_BGR_SUPPORTED) && defined(PNG_READ_BGR_SUPPORTED) 800 if ((png_ptr->transformations & PNG_BGR) != 0) 801 png_warning(png_ptr, "PNG_WRITE_BGR_SUPPORTED is not defined"); 802 #endif 803 804 #if !defined(PNG_WRITE_SWAP_SUPPORTED) && defined(PNG_READ_SWAP_SUPPORTED) 805 if ((png_ptr->transformations & PNG_SWAP_BYTES) != 0) 806 png_warning(png_ptr, "PNG_WRITE_SWAP_SUPPORTED is not defined"); 807 #endif 808 809 png_write_start_row(png_ptr); 810 } 811 812 #ifdef PNG_WRITE_INTERLACING_SUPPORTED 813 /* If interlaced and not interested in row, return */ 814 if (png_ptr->interlaced != 0 && 815 (png_ptr->transformations & PNG_INTERLACE) != 0) 816 { 817 switch (png_ptr->pass) 818 { 819 case 0: 820 if ((png_ptr->row_number & 0x07) != 0) 821 { 822 png_write_finish_row(png_ptr); 823 return; 824 } 825 break; 826 827 case 1: 828 if ((png_ptr->row_number & 0x07) != 0 || png_ptr->width < 5) 829 { 830 png_write_finish_row(png_ptr); 831 return; 832 } 833 break; 834 835 case 2: 836 if ((png_ptr->row_number & 0x07) != 4) 837 { 838 png_write_finish_row(png_ptr); 839 return; 840 } 841 break; 842 843 case 3: 844 if ((png_ptr->row_number & 0x03) != 0 || png_ptr->width < 3) 845 { 846 png_write_finish_row(png_ptr); 847 return; 848 } 849 break; 850 851 case 4: 852 if ((png_ptr->row_number & 0x03) != 2) 853 { 854 png_write_finish_row(png_ptr); 855 return; 856 } 857 break; 858 859 case 5: 860 if ((png_ptr->row_number & 0x01) != 0 || png_ptr->width < 2) 861 { 862 png_write_finish_row(png_ptr); 863 return; 864 } 865 break; 866 867 case 6: 868 if ((png_ptr->row_number & 0x01) == 0) 869 { 870 png_write_finish_row(png_ptr); 871 return; 872 } 873 break; 874 875 default: /* error: ignore it */ 876 break; 877 } 878 } 879 #endif 880 881 /* Set up row info for transformations */ 882 row_info.color_type = png_ptr->color_type; 883 row_info.width = png_ptr->usr_width; 884 row_info.channels = png_ptr->usr_channels; 885 row_info.bit_depth = png_ptr->usr_bit_depth; 886 row_info.pixel_depth = (png_byte)(row_info.bit_depth * row_info.channels); 887 row_info.rowbytes = PNG_ROWBYTES(row_info.pixel_depth, row_info.width); 888 889 png_debug1(3, "row_info->color_type = %d", row_info.color_type); 890 png_debug1(3, "row_info->width = %u", row_info.width); 891 png_debug1(3, "row_info->channels = %d", row_info.channels); 892 png_debug1(3, "row_info->bit_depth = %d", row_info.bit_depth); 893 png_debug1(3, "row_info->pixel_depth = %d", row_info.pixel_depth); 894 png_debug1(3, "row_info->rowbytes = %lu", (unsigned long)row_info.rowbytes); 895 896 /* Copy user's row into buffer, leaving room for filter byte. */ 897 memcpy(png_ptr->row_buf + 1, row, row_info.rowbytes); 898 899 #ifdef PNG_WRITE_INTERLACING_SUPPORTED 900 /* Handle interlacing */ 901 if (png_ptr->interlaced && png_ptr->pass < 6 && 902 (png_ptr->transformations & PNG_INTERLACE) != 0) 903 { 904 png_do_write_interlace(&row_info, png_ptr->row_buf + 1, png_ptr->pass); 905 /* This should always get caught above, but still ... */ 906 if (row_info.width == 0) 907 { 908 png_write_finish_row(png_ptr); 909 return; 910 } 911 } 912 #endif 913 914 #ifdef PNG_WRITE_TRANSFORMS_SUPPORTED 915 /* Handle other transformations */ 916 if (png_ptr->transformations != 0) 917 png_do_write_transformations(png_ptr, &row_info); 918 #endif 919 920 /* At this point the row_info pixel depth must match the 'transformed' depth, 921 * which is also the output depth. 922 */ 923 if (row_info.pixel_depth != png_ptr->pixel_depth || 924 row_info.pixel_depth != png_ptr->transformed_pixel_depth) 925 png_error(png_ptr, "internal write transform logic error"); 926 927 #ifdef PNG_MNG_FEATURES_SUPPORTED 928 /* Write filter_method 64 (intrapixel differencing) only if 929 * 1. Libpng was compiled with PNG_MNG_FEATURES_SUPPORTED and 930 * 2. Libpng did not write a PNG signature (this filter_method is only 931 * used in PNG datastreams that are embedded in MNG datastreams) and 932 * 3. The application called png_permit_mng_features with a mask that 933 * included PNG_FLAG_MNG_FILTER_64 and 934 * 4. The filter_method is 64 and 935 * 5. The color_type is RGB or RGBA 936 */ 937 if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) != 0 && 938 (png_ptr->filter_type == PNG_INTRAPIXEL_DIFFERENCING)) 939 { 940 /* Intrapixel differencing */ 941 png_do_write_intrapixel(&row_info, png_ptr->row_buf + 1); 942 } 943 #endif 944 945 /* Added at libpng-1.5.10 */ 946 #ifdef PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED 947 /* Check for out-of-range palette index */ 948 if (row_info.color_type == PNG_COLOR_TYPE_PALETTE && 949 png_ptr->num_palette_max >= 0) 950 png_do_check_palette_indexes(png_ptr, &row_info); 951 #endif 952 953 /* Find a filter if necessary, filter the row and write it out. */ 954 png_write_find_filter(png_ptr, &row_info); 955 956 if (png_ptr->write_row_fn != NULL) 957 (*(png_ptr->write_row_fn))(png_ptr, png_ptr->row_number, png_ptr->pass); 958 } 959 960 #ifdef PNG_WRITE_FLUSH_SUPPORTED 961 /* Set the automatic flush interval or 0 to turn flushing off */ 962 void PNGAPI 963 png_set_flush(png_structrp png_ptr, int nrows) 964 { 965 png_debug(1, "in png_set_flush"); 966 967 if (png_ptr == NULL) 968 return; 969 970 png_ptr->flush_dist = (nrows < 0 ? 0 : (png_uint_32)nrows); 971 } 972 973 /* Flush the current output buffers now */ 974 void PNGAPI 975 png_write_flush(png_structrp png_ptr) 976 { 977 png_debug(1, "in png_write_flush"); 978 979 if (png_ptr == NULL) 980 return; 981 982 /* We have already written out all of the data */ 983 if (png_ptr->row_number >= png_ptr->num_rows) 984 return; 985 986 png_compress_IDAT(png_ptr, NULL, 0, Z_SYNC_FLUSH); 987 png_ptr->flush_rows = 0; 988 png_flush(png_ptr); 989 } 990 #endif /* WRITE_FLUSH */ 991 992 /* Free any memory used in png_ptr struct without freeing the struct itself. */ 993 static void 994 png_write_destroy(png_structrp png_ptr) 995 { 996 png_debug(1, "in png_write_destroy"); 997 998 /* Free any memory zlib uses */ 999 if ((png_ptr->flags & PNG_FLAG_ZSTREAM_INITIALIZED) != 0) 1000 deflateEnd(&png_ptr->zstream); 1001 1002 /* Free our memory. png_free checks NULL for us. */ 1003 png_free_buffer_list(png_ptr, &png_ptr->zbuffer_list); 1004 png_free(png_ptr, png_ptr->row_buf); 1005 png_ptr->row_buf = NULL; 1006 #ifdef PNG_WRITE_FILTER_SUPPORTED 1007 png_free(png_ptr, png_ptr->prev_row); 1008 png_free(png_ptr, png_ptr->try_row); 1009 png_free(png_ptr, png_ptr->tst_row); 1010 png_ptr->prev_row = NULL; 1011 png_ptr->try_row = NULL; 1012 png_ptr->tst_row = NULL; 1013 #endif 1014 1015 #ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED 1016 png_free(png_ptr, png_ptr->chunk_list); 1017 png_ptr->chunk_list = NULL; 1018 #endif 1019 1020 /* The error handling and memory handling information is left intact at this 1021 * point: the jmp_buf may still have to be freed. See png_destroy_png_struct 1022 * for how this happens. 1023 */ 1024 } 1025 1026 /* Free all memory used by the write. 1027 * In libpng 1.6.0 this API changed quietly to no longer accept a NULL value for 1028 * *png_ptr_ptr. Prior to 1.6.0 it would accept such a value and it would free 1029 * the passed in info_structs but it would quietly fail to free any of the data 1030 * inside them. In 1.6.0 it quietly does nothing (it has to be quiet because it 1031 * has no png_ptr.) 1032 */ 1033 void PNGAPI 1034 png_destroy_write_struct(png_structpp png_ptr_ptr, png_infopp info_ptr_ptr) 1035 { 1036 png_debug(1, "in png_destroy_write_struct"); 1037 1038 if (png_ptr_ptr != NULL) 1039 { 1040 png_structrp png_ptr = *png_ptr_ptr; 1041 1042 if (png_ptr != NULL) /* added in libpng 1.6.0 */ 1043 { 1044 png_destroy_info_struct(png_ptr, info_ptr_ptr); 1045 1046 *png_ptr_ptr = NULL; 1047 png_write_destroy(png_ptr); 1048 png_destroy_png_struct(png_ptr); 1049 } 1050 } 1051 } 1052 1053 /* Allow the application to select one or more row filters to use. */ 1054 void PNGAPI 1055 png_set_filter(png_structrp png_ptr, int method, int filters) 1056 { 1057 png_debug(1, "in png_set_filter"); 1058 1059 if (png_ptr == NULL) 1060 return; 1061 1062 #ifdef PNG_MNG_FEATURES_SUPPORTED 1063 if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) != 0 && 1064 (method == PNG_INTRAPIXEL_DIFFERENCING)) 1065 method = PNG_FILTER_TYPE_BASE; 1066 1067 #endif 1068 if (method == PNG_FILTER_TYPE_BASE) 1069 { 1070 switch (filters & (PNG_ALL_FILTERS | 0x07)) 1071 { 1072 #ifdef PNG_WRITE_FILTER_SUPPORTED 1073 case 5: 1074 case 6: 1075 case 7: png_app_error(png_ptr, "Unknown row filter for method 0"); 1076 #endif /* WRITE_FILTER */ 1077 /* FALLTHROUGH */ 1078 case PNG_FILTER_VALUE_NONE: 1079 png_ptr->do_filter = PNG_FILTER_NONE; break; 1080 1081 #ifdef PNG_WRITE_FILTER_SUPPORTED 1082 case PNG_FILTER_VALUE_SUB: 1083 png_ptr->do_filter = PNG_FILTER_SUB; break; 1084 1085 case PNG_FILTER_VALUE_UP: 1086 png_ptr->do_filter = PNG_FILTER_UP; break; 1087 1088 case PNG_FILTER_VALUE_AVG: 1089 png_ptr->do_filter = PNG_FILTER_AVG; break; 1090 1091 case PNG_FILTER_VALUE_PAETH: 1092 png_ptr->do_filter = PNG_FILTER_PAETH; break; 1093 1094 default: 1095 png_ptr->do_filter = (png_byte)filters; break; 1096 #else 1097 default: 1098 png_app_error(png_ptr, "Unknown row filter for method 0"); 1099 #endif /* WRITE_FILTER */ 1100 } 1101 1102 #ifdef PNG_WRITE_FILTER_SUPPORTED 1103 /* If we have allocated the row_buf, this means we have already started 1104 * with the image and we should have allocated all of the filter buffers 1105 * that have been selected. If prev_row isn't already allocated, then 1106 * it is too late to start using the filters that need it, since we 1107 * will be missing the data in the previous row. If an application 1108 * wants to start and stop using particular filters during compression, 1109 * it should start out with all of the filters, and then remove them 1110 * or add them back after the start of compression. 1111 * 1112 * NOTE: this is a nasty constraint on the code, because it means that the 1113 * prev_row buffer must be maintained even if there are currently no 1114 * 'prev_row' requiring filters active. 1115 */ 1116 if (png_ptr->row_buf != NULL) 1117 { 1118 int num_filters; 1119 png_alloc_size_t buf_size; 1120 1121 /* Repeat the checks in png_write_start_row; 1 pixel high or wide 1122 * images cannot benefit from certain filters. If this isn't done here 1123 * the check below will fire on 1 pixel high images. 1124 */ 1125 if (png_ptr->height == 1) 1126 filters &= ~(PNG_FILTER_UP|PNG_FILTER_AVG|PNG_FILTER_PAETH); 1127 1128 if (png_ptr->width == 1) 1129 filters &= ~(PNG_FILTER_SUB|PNG_FILTER_AVG|PNG_FILTER_PAETH); 1130 1131 if ((filters & (PNG_FILTER_UP|PNG_FILTER_AVG|PNG_FILTER_PAETH)) != 0 1132 && png_ptr->prev_row == NULL) 1133 { 1134 /* This is the error case, however it is benign - the previous row 1135 * is not available so the filter can't be used. Just warn here. 1136 */ 1137 png_app_warning(png_ptr, 1138 "png_set_filter: UP/AVG/PAETH cannot be added after start"); 1139 filters &= ~(PNG_FILTER_UP|PNG_FILTER_AVG|PNG_FILTER_PAETH); 1140 } 1141 1142 num_filters = 0; 1143 1144 if (filters & PNG_FILTER_SUB) 1145 num_filters++; 1146 1147 if (filters & PNG_FILTER_UP) 1148 num_filters++; 1149 1150 if (filters & PNG_FILTER_AVG) 1151 num_filters++; 1152 1153 if (filters & PNG_FILTER_PAETH) 1154 num_filters++; 1155 1156 /* Allocate needed row buffers if they have not already been 1157 * allocated. 1158 */ 1159 buf_size = PNG_ROWBYTES(png_ptr->usr_channels * png_ptr->usr_bit_depth, 1160 png_ptr->width) + 1; 1161 1162 if (png_ptr->try_row == NULL) 1163 png_ptr->try_row = png_voidcast(png_bytep, 1164 png_malloc(png_ptr, buf_size)); 1165 1166 if (num_filters > 1) 1167 { 1168 if (png_ptr->tst_row == NULL) 1169 png_ptr->tst_row = png_voidcast(png_bytep, 1170 png_malloc(png_ptr, buf_size)); 1171 } 1172 } 1173 png_ptr->do_filter = (png_byte)filters; 1174 #endif 1175 } 1176 else 1177 png_error(png_ptr, "Unknown custom filter method"); 1178 } 1179 1180 #ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED /* DEPRECATED */ 1181 /* Provide floating and fixed point APIs */ 1182 #ifdef PNG_FLOATING_POINT_SUPPORTED 1183 void PNGAPI 1184 png_set_filter_heuristics(png_structrp png_ptr, int heuristic_method, 1185 int num_weights, png_const_doublep filter_weights, 1186 png_const_doublep filter_costs) 1187 { 1188 PNG_UNUSED(png_ptr) 1189 PNG_UNUSED(heuristic_method) 1190 PNG_UNUSED(num_weights) 1191 PNG_UNUSED(filter_weights) 1192 PNG_UNUSED(filter_costs) 1193 } 1194 #endif /* FLOATING_POINT */ 1195 1196 #ifdef PNG_FIXED_POINT_SUPPORTED 1197 void PNGAPI 1198 png_set_filter_heuristics_fixed(png_structrp png_ptr, int heuristic_method, 1199 int num_weights, png_const_fixed_point_p filter_weights, 1200 png_const_fixed_point_p filter_costs) 1201 { 1202 PNG_UNUSED(png_ptr) 1203 PNG_UNUSED(heuristic_method) 1204 PNG_UNUSED(num_weights) 1205 PNG_UNUSED(filter_weights) 1206 PNG_UNUSED(filter_costs) 1207 } 1208 #endif /* FIXED_POINT */ 1209 #endif /* WRITE_WEIGHTED_FILTER */ 1210 1211 #ifdef PNG_WRITE_CUSTOMIZE_COMPRESSION_SUPPORTED 1212 void PNGAPI 1213 png_set_compression_level(png_structrp png_ptr, int level) 1214 { 1215 png_debug(1, "in png_set_compression_level"); 1216 1217 if (png_ptr == NULL) 1218 return; 1219 1220 png_ptr->zlib_level = level; 1221 } 1222 1223 void PNGAPI 1224 png_set_compression_mem_level(png_structrp png_ptr, int mem_level) 1225 { 1226 png_debug(1, "in png_set_compression_mem_level"); 1227 1228 if (png_ptr == NULL) 1229 return; 1230 1231 png_ptr->zlib_mem_level = mem_level; 1232 } 1233 1234 void PNGAPI 1235 png_set_compression_strategy(png_structrp png_ptr, int strategy) 1236 { 1237 png_debug(1, "in png_set_compression_strategy"); 1238 1239 if (png_ptr == NULL) 1240 return; 1241 1242 /* The flag setting here prevents the libpng dynamic selection of strategy. 1243 */ 1244 png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_STRATEGY; 1245 png_ptr->zlib_strategy = strategy; 1246 } 1247 1248 /* If PNG_WRITE_OPTIMIZE_CMF_SUPPORTED is defined, libpng will use a 1249 * smaller value of window_bits if it can do so safely. 1250 */ 1251 void PNGAPI 1252 png_set_compression_window_bits(png_structrp png_ptr, int window_bits) 1253 { 1254 png_debug(1, "in png_set_compression_window_bits"); 1255 1256 if (png_ptr == NULL) 1257 return; 1258 1259 /* Prior to 1.6.0 this would warn but then set the window_bits value. This 1260 * meant that negative window bits values could be selected that would cause 1261 * libpng to write a non-standard PNG file with raw deflate or gzip 1262 * compressed IDAT or ancillary chunks. Such files can be read and there is 1263 * no warning on read, so this seems like a very bad idea. 1264 */ 1265 if (window_bits > 15) 1266 { 1267 png_warning(png_ptr, "Only compression windows <= 32k supported by PNG"); 1268 window_bits = 15; 1269 } 1270 1271 else if (window_bits < 8) 1272 { 1273 png_warning(png_ptr, "Only compression windows >= 256 supported by PNG"); 1274 window_bits = 8; 1275 } 1276 1277 png_ptr->zlib_window_bits = window_bits; 1278 } 1279 1280 void PNGAPI 1281 png_set_compression_method(png_structrp png_ptr, int method) 1282 { 1283 png_debug(1, "in png_set_compression_method"); 1284 1285 if (png_ptr == NULL) 1286 return; 1287 1288 /* This would produce an invalid PNG file if it worked, but it doesn't and 1289 * deflate will fault it, so it is harmless to just warn here. 1290 */ 1291 if (method != 8) 1292 png_warning(png_ptr, "Only compression method 8 is supported by PNG"); 1293 1294 png_ptr->zlib_method = method; 1295 } 1296 #endif /* WRITE_CUSTOMIZE_COMPRESSION */ 1297 1298 /* The following were added to libpng-1.5.4 */ 1299 #ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED 1300 void PNGAPI 1301 png_set_text_compression_level(png_structrp png_ptr, int level) 1302 { 1303 png_debug(1, "in png_set_text_compression_level"); 1304 1305 if (png_ptr == NULL) 1306 return; 1307 1308 png_ptr->zlib_text_level = level; 1309 } 1310 1311 void PNGAPI 1312 png_set_text_compression_mem_level(png_structrp png_ptr, int mem_level) 1313 { 1314 png_debug(1, "in png_set_text_compression_mem_level"); 1315 1316 if (png_ptr == NULL) 1317 return; 1318 1319 png_ptr->zlib_text_mem_level = mem_level; 1320 } 1321 1322 void PNGAPI 1323 png_set_text_compression_strategy(png_structrp png_ptr, int strategy) 1324 { 1325 png_debug(1, "in png_set_text_compression_strategy"); 1326 1327 if (png_ptr == NULL) 1328 return; 1329 1330 png_ptr->zlib_text_strategy = strategy; 1331 } 1332 1333 /* If PNG_WRITE_OPTIMIZE_CMF_SUPPORTED is defined, libpng will use a 1334 * smaller value of window_bits if it can do so safely. 1335 */ 1336 void PNGAPI 1337 png_set_text_compression_window_bits(png_structrp png_ptr, int window_bits) 1338 { 1339 png_debug(1, "in png_set_text_compression_window_bits"); 1340 1341 if (png_ptr == NULL) 1342 return; 1343 1344 if (window_bits > 15) 1345 { 1346 png_warning(png_ptr, "Only compression windows <= 32k supported by PNG"); 1347 window_bits = 15; 1348 } 1349 1350 else if (window_bits < 8) 1351 { 1352 png_warning(png_ptr, "Only compression windows >= 256 supported by PNG"); 1353 window_bits = 8; 1354 } 1355 1356 png_ptr->zlib_text_window_bits = window_bits; 1357 } 1358 1359 void PNGAPI 1360 png_set_text_compression_method(png_structrp png_ptr, int method) 1361 { 1362 png_debug(1, "in png_set_text_compression_method"); 1363 1364 if (png_ptr == NULL) 1365 return; 1366 1367 if (method != 8) 1368 png_warning(png_ptr, "Only compression method 8 is supported by PNG"); 1369 1370 png_ptr->zlib_text_method = method; 1371 } 1372 #endif /* WRITE_CUSTOMIZE_ZTXT_COMPRESSION */ 1373 /* end of API added to libpng-1.5.4 */ 1374 1375 void PNGAPI 1376 png_set_write_status_fn(png_structrp png_ptr, png_write_status_ptr write_row_fn) 1377 { 1378 png_debug(1, "in png_set_write_status_fn"); 1379 1380 if (png_ptr == NULL) 1381 return; 1382 1383 png_ptr->write_row_fn = write_row_fn; 1384 } 1385 1386 #ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED 1387 void PNGAPI 1388 png_set_write_user_transform_fn(png_structrp png_ptr, png_user_transform_ptr 1389 write_user_transform_fn) 1390 { 1391 png_debug(1, "in png_set_write_user_transform_fn"); 1392 1393 if (png_ptr == NULL) 1394 return; 1395 1396 png_ptr->transformations |= PNG_USER_TRANSFORM; 1397 png_ptr->write_user_transform_fn = write_user_transform_fn; 1398 } 1399 #endif 1400 1401 1402 #ifdef PNG_INFO_IMAGE_SUPPORTED 1403 void PNGAPI 1404 png_write_png(png_structrp png_ptr, png_inforp info_ptr, 1405 int transforms, voidp params) 1406 { 1407 png_debug(1, "in png_write_png"); 1408 1409 if (png_ptr == NULL || info_ptr == NULL) 1410 return; 1411 1412 if ((info_ptr->valid & PNG_INFO_IDAT) == 0) 1413 { 1414 png_app_error(png_ptr, "no rows for png_write_image to write"); 1415 return; 1416 } 1417 1418 /* Write the file header information. */ 1419 png_write_info(png_ptr, info_ptr); 1420 1421 /* ------ these transformations don't touch the info structure ------- */ 1422 1423 /* Invert monochrome pixels */ 1424 if ((transforms & PNG_TRANSFORM_INVERT_MONO) != 0) 1425 #ifdef PNG_WRITE_INVERT_SUPPORTED 1426 png_set_invert_mono(png_ptr); 1427 #else 1428 png_app_error(png_ptr, "PNG_TRANSFORM_INVERT_MONO not supported"); 1429 #endif 1430 1431 /* Shift the pixels up to a legal bit depth and fill in 1432 * as appropriate to correctly scale the image. 1433 */ 1434 if ((transforms & PNG_TRANSFORM_SHIFT) != 0) 1435 #ifdef PNG_WRITE_SHIFT_SUPPORTED 1436 if ((info_ptr->valid & PNG_INFO_sBIT) != 0) 1437 png_set_shift(png_ptr, &info_ptr->sig_bit); 1438 #else 1439 png_app_error(png_ptr, "PNG_TRANSFORM_SHIFT not supported"); 1440 #endif 1441 1442 /* Pack pixels into bytes */ 1443 if ((transforms & PNG_TRANSFORM_PACKING) != 0) 1444 #ifdef PNG_WRITE_PACK_SUPPORTED 1445 png_set_packing(png_ptr); 1446 #else 1447 png_app_error(png_ptr, "PNG_TRANSFORM_PACKING not supported"); 1448 #endif 1449 1450 /* Swap location of alpha bytes from ARGB to RGBA */ 1451 if ((transforms & PNG_TRANSFORM_SWAP_ALPHA) != 0) 1452 #ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED 1453 png_set_swap_alpha(png_ptr); 1454 #else 1455 png_app_error(png_ptr, "PNG_TRANSFORM_SWAP_ALPHA not supported"); 1456 #endif 1457 1458 /* Remove a filler (X) from XRGB/RGBX/AG/GA into to convert it into 1459 * RGB, note that the code expects the input color type to be G or RGB; no 1460 * alpha channel. 1461 */ 1462 if ((transforms & (PNG_TRANSFORM_STRIP_FILLER_AFTER| 1463 PNG_TRANSFORM_STRIP_FILLER_BEFORE)) != 0) 1464 { 1465 #ifdef PNG_WRITE_FILLER_SUPPORTED 1466 if ((transforms & PNG_TRANSFORM_STRIP_FILLER_AFTER) != 0) 1467 { 1468 if ((transforms & PNG_TRANSFORM_STRIP_FILLER_BEFORE) != 0) 1469 png_app_error(png_ptr, 1470 "PNG_TRANSFORM_STRIP_FILLER: BEFORE+AFTER not supported"); 1471 1472 /* Continue if ignored - this is the pre-1.6.10 behavior */ 1473 png_set_filler(png_ptr, 0, PNG_FILLER_AFTER); 1474 } 1475 1476 else if ((transforms & PNG_TRANSFORM_STRIP_FILLER_BEFORE) != 0) 1477 png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE); 1478 #else 1479 png_app_error(png_ptr, "PNG_TRANSFORM_STRIP_FILLER not supported"); 1480 #endif 1481 } 1482 1483 /* Flip BGR pixels to RGB */ 1484 if ((transforms & PNG_TRANSFORM_BGR) != 0) 1485 #ifdef PNG_WRITE_BGR_SUPPORTED 1486 png_set_bgr(png_ptr); 1487 #else 1488 png_app_error(png_ptr, "PNG_TRANSFORM_BGR not supported"); 1489 #endif 1490 1491 /* Swap bytes of 16-bit files to most significant byte first */ 1492 if ((transforms & PNG_TRANSFORM_SWAP_ENDIAN) != 0) 1493 #ifdef PNG_WRITE_SWAP_SUPPORTED 1494 png_set_swap(png_ptr); 1495 #else 1496 png_app_error(png_ptr, "PNG_TRANSFORM_SWAP_ENDIAN not supported"); 1497 #endif 1498 1499 /* Swap bits of 1-bit, 2-bit, 4-bit packed pixel formats */ 1500 if ((transforms & PNG_TRANSFORM_PACKSWAP) != 0) 1501 #ifdef PNG_WRITE_PACKSWAP_SUPPORTED 1502 png_set_packswap(png_ptr); 1503 #else 1504 png_app_error(png_ptr, "PNG_TRANSFORM_PACKSWAP not supported"); 1505 #endif 1506 1507 /* Invert the alpha channel from opacity to transparency */ 1508 if ((transforms & PNG_TRANSFORM_INVERT_ALPHA) != 0) 1509 #ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED 1510 png_set_invert_alpha(png_ptr); 1511 #else 1512 png_app_error(png_ptr, "PNG_TRANSFORM_INVERT_ALPHA not supported"); 1513 #endif 1514 1515 /* ----------------------- end of transformations ------------------- */ 1516 1517 /* Write the bits */ 1518 png_write_image(png_ptr, info_ptr->row_pointers); 1519 1520 /* It is REQUIRED to call this to finish writing the rest of the file */ 1521 png_write_end(png_ptr, info_ptr); 1522 1523 PNG_UNUSED(params) 1524 } 1525 #endif 1526 1527 1528 #ifdef PNG_SIMPLIFIED_WRITE_SUPPORTED 1529 /* Initialize the write structure - general purpose utility. */ 1530 static int 1531 png_image_write_init(png_imagep image) 1532 { 1533 png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, image, 1534 png_safe_error, png_safe_warning); 1535 1536 if (png_ptr != NULL) 1537 { 1538 png_infop info_ptr = png_create_info_struct(png_ptr); 1539 1540 if (info_ptr != NULL) 1541 { 1542 png_controlp control = png_voidcast(png_controlp, 1543 png_malloc_warn(png_ptr, (sizeof *control))); 1544 1545 if (control != NULL) 1546 { 1547 memset(control, 0, (sizeof *control)); 1548 1549 control->png_ptr = png_ptr; 1550 control->info_ptr = info_ptr; 1551 control->for_write = 1; 1552 1553 image->opaque = control; 1554 return 1; 1555 } 1556 1557 /* Error clean up */ 1558 png_destroy_info_struct(png_ptr, &info_ptr); 1559 } 1560 1561 png_destroy_write_struct(&png_ptr, NULL); 1562 } 1563 1564 return png_image_error(image, "png_image_write_: out of memory"); 1565 } 1566 1567 /* Arguments to png_image_write_main: */ 1568 typedef struct 1569 { 1570 /* Arguments: */ 1571 png_imagep image; 1572 png_const_voidp buffer; 1573 png_int_32 row_stride; 1574 png_const_voidp colormap; 1575 int convert_to_8bit; 1576 /* Local variables: */ 1577 png_const_voidp first_row; 1578 ptrdiff_t row_bytes; 1579 png_voidp local_row; 1580 /* Byte count for memory writing */ 1581 png_bytep memory; 1582 png_alloc_size_t memory_bytes; /* not used for STDIO */ 1583 png_alloc_size_t output_bytes; /* running total */ 1584 } png_image_write_control; 1585 1586 /* Write png_uint_16 input to a 16-bit PNG; the png_ptr has already been set to 1587 * do any necessary byte swapping. The component order is defined by the 1588 * png_image format value. 1589 */ 1590 static int 1591 png_write_image_16bit(png_voidp argument) 1592 { 1593 png_image_write_control *display = png_voidcast(png_image_write_control*, 1594 argument); 1595 png_imagep image = display->image; 1596 png_structrp png_ptr = image->opaque->png_ptr; 1597 1598 png_const_uint_16p input_row = png_voidcast(png_const_uint_16p, 1599 display->first_row); 1600 png_uint_16p output_row = png_voidcast(png_uint_16p, display->local_row); 1601 png_uint_16p row_end; 1602 unsigned int channels = (image->format & PNG_FORMAT_FLAG_COLOR) != 0 ? 1603 3 : 1; 1604 int aindex = 0; 1605 png_uint_32 y = image->height; 1606 1607 if ((image->format & PNG_FORMAT_FLAG_ALPHA) != 0) 1608 { 1609 # ifdef PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED 1610 if ((image->format & PNG_FORMAT_FLAG_AFIRST) != 0) 1611 { 1612 aindex = -1; 1613 ++input_row; /* To point to the first component */ 1614 ++output_row; 1615 } 1616 else 1617 aindex = (int)channels; 1618 # else 1619 aindex = (int)channels; 1620 # endif 1621 } 1622 1623 else 1624 png_error(png_ptr, "png_write_image: internal call error"); 1625 1626 /* Work out the output row end and count over this, note that the increment 1627 * above to 'row' means that row_end can actually be beyond the end of the 1628 * row; this is correct. 1629 */ 1630 row_end = output_row + image->width * (channels+1); 1631 1632 for (; y > 0; --y) 1633 { 1634 png_const_uint_16p in_ptr = input_row; 1635 png_uint_16p out_ptr = output_row; 1636 1637 while (out_ptr < row_end) 1638 { 1639 png_uint_16 alpha = in_ptr[aindex]; 1640 png_uint_32 reciprocal = 0; 1641 int c; 1642 1643 out_ptr[aindex] = alpha; 1644 1645 /* Calculate a reciprocal. The correct calculation is simply 1646 * component/alpha*65535 << 15. (I.e. 15 bits of precision); this 1647 * allows correct rounding by adding .5 before the shift. 'reciprocal' 1648 * is only initialized when required. 1649 */ 1650 if (alpha > 0 && alpha < 65535) 1651 reciprocal = ((0xffff<<15)+(alpha>>1))/alpha; 1652 1653 c = (int)channels; 1654 do /* always at least one channel */ 1655 { 1656 png_uint_16 component = *in_ptr++; 1657 1658 /* The following gives 65535 for an alpha of 0, which is fine, 1659 * otherwise if 0/0 is represented as some other value there is more 1660 * likely to be a discontinuity which will probably damage 1661 * compression when moving from a fully transparent area to a 1662 * nearly transparent one. (The assumption here is that opaque 1663 * areas tend not to be 0 intensity.) 1664 */ 1665 if (component >= alpha) 1666 component = 65535; 1667 1668 /* component<alpha, so component/alpha is less than one and 1669 * component*reciprocal is less than 2^31. 1670 */ 1671 else if (component > 0 && alpha < 65535) 1672 { 1673 png_uint_32 calc = component * reciprocal; 1674 calc += 16384; /* round to nearest */ 1675 component = (png_uint_16)(calc >> 15); 1676 } 1677 1678 *out_ptr++ = component; 1679 } 1680 while (--c > 0); 1681 1682 /* Skip to next component (skip the intervening alpha channel) */ 1683 ++in_ptr; 1684 ++out_ptr; 1685 } 1686 1687 png_write_row(png_ptr, png_voidcast(png_const_bytep, display->local_row)); 1688 input_row += (png_uint_16)display->row_bytes/(sizeof (png_uint_16)); 1689 } 1690 1691 return 1; 1692 } 1693 1694 /* Given 16-bit input (1 to 4 channels) write 8-bit output. If an alpha channel 1695 * is present it must be removed from the components, the components are then 1696 * written in sRGB encoding. No components are added or removed. 1697 * 1698 * Calculate an alpha reciprocal to reverse pre-multiplication. As above the 1699 * calculation can be done to 15 bits of accuracy; however, the output needs to 1700 * be scaled in the range 0..255*65535, so include that scaling here. 1701 */ 1702 # define UNP_RECIPROCAL(alpha) ((((0xffff*0xff)<<7)+((alpha)>>1))/(alpha)) 1703 1704 static png_byte 1705 png_unpremultiply(png_uint_32 component, png_uint_32 alpha, 1706 png_uint_32 reciprocal/*from the above macro*/) 1707 { 1708 /* The following gives 1.0 for an alpha of 0, which is fine, otherwise if 0/0 1709 * is represented as some other value there is more likely to be a 1710 * discontinuity which will probably damage compression when moving from a 1711 * fully transparent area to a nearly transparent one. (The assumption here 1712 * is that opaque areas tend not to be 0 intensity.) 1713 * 1714 * There is a rounding problem here; if alpha is less than 128 it will end up 1715 * as 0 when scaled to 8 bits. To avoid introducing spurious colors into the 1716 * output change for this too. 1717 */ 1718 if (component >= alpha || alpha < 128) 1719 return 255; 1720 1721 /* component<alpha, so component/alpha is less than one and 1722 * component*reciprocal is less than 2^31. 1723 */ 1724 else if (component > 0) 1725 { 1726 /* The test is that alpha/257 (rounded) is less than 255, the first value 1727 * that becomes 255 is 65407. 1728 * NOTE: this must agree with the PNG_DIV257 macro (which must, therefore, 1729 * be exact!) [Could also test reciprocal != 0] 1730 */ 1731 if (alpha < 65407) 1732 { 1733 component *= reciprocal; 1734 component += 64; /* round to nearest */ 1735 component >>= 7; 1736 } 1737 1738 else 1739 component *= 255; 1740 1741 /* Convert the component to sRGB. */ 1742 return (png_byte)PNG_sRGB_FROM_LINEAR(component); 1743 } 1744 1745 else 1746 return 0; 1747 } 1748 1749 static int 1750 png_write_image_8bit(png_voidp argument) 1751 { 1752 png_image_write_control *display = png_voidcast(png_image_write_control*, 1753 argument); 1754 png_imagep image = display->image; 1755 png_structrp png_ptr = image->opaque->png_ptr; 1756 1757 png_const_uint_16p input_row = png_voidcast(png_const_uint_16p, 1758 display->first_row); 1759 png_bytep output_row = png_voidcast(png_bytep, display->local_row); 1760 png_uint_32 y = image->height; 1761 unsigned int channels = (image->format & PNG_FORMAT_FLAG_COLOR) != 0 ? 1762 3 : 1; 1763 1764 if ((image->format & PNG_FORMAT_FLAG_ALPHA) != 0) 1765 { 1766 png_bytep row_end; 1767 int aindex; 1768 1769 # ifdef PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED 1770 if ((image->format & PNG_FORMAT_FLAG_AFIRST) != 0) 1771 { 1772 aindex = -1; 1773 ++input_row; /* To point to the first component */ 1774 ++output_row; 1775 } 1776 1777 else 1778 # endif 1779 aindex = (int)channels; 1780 1781 /* Use row_end in place of a loop counter: */ 1782 row_end = output_row + image->width * (channels+1); 1783 1784 for (; y > 0; --y) 1785 { 1786 png_const_uint_16p in_ptr = input_row; 1787 png_bytep out_ptr = output_row; 1788 1789 while (out_ptr < row_end) 1790 { 1791 png_uint_16 alpha = in_ptr[aindex]; 1792 png_byte alphabyte = (png_byte)PNG_DIV257(alpha); 1793 png_uint_32 reciprocal = 0; 1794 int c; 1795 1796 /* Scale and write the alpha channel. */ 1797 out_ptr[aindex] = alphabyte; 1798 1799 if (alphabyte > 0 && alphabyte < 255) 1800 reciprocal = UNP_RECIPROCAL(alpha); 1801 1802 c = (int)channels; 1803 do /* always at least one channel */ 1804 *out_ptr++ = png_unpremultiply(*in_ptr++, alpha, reciprocal); 1805 while (--c > 0); 1806 1807 /* Skip to next component (skip the intervening alpha channel) */ 1808 ++in_ptr; 1809 ++out_ptr; 1810 } /* while out_ptr < row_end */ 1811 1812 png_write_row(png_ptr, png_voidcast(png_const_bytep, 1813 display->local_row)); 1814 input_row += (png_uint_16)display->row_bytes/(sizeof (png_uint_16)); 1815 } /* while y */ 1816 } 1817 1818 else 1819 { 1820 /* No alpha channel, so the row_end really is the end of the row and it 1821 * is sufficient to loop over the components one by one. 1822 */ 1823 png_bytep row_end = output_row + image->width * channels; 1824 1825 for (; y > 0; --y) 1826 { 1827 png_const_uint_16p in_ptr = input_row; 1828 png_bytep out_ptr = output_row; 1829 1830 while (out_ptr < row_end) 1831 { 1832 png_uint_32 component = *in_ptr++; 1833 1834 component *= 255; 1835 *out_ptr++ = (png_byte)PNG_sRGB_FROM_LINEAR(component); 1836 } 1837 1838 png_write_row(png_ptr, output_row); 1839 input_row += (png_uint_16)display->row_bytes/(sizeof (png_uint_16)); 1840 } 1841 } 1842 1843 return 1; 1844 } 1845 1846 static void 1847 png_image_set_PLTE(png_image_write_control *display) 1848 { 1849 png_imagep image = display->image; 1850 const void *cmap = display->colormap; 1851 int entries = image->colormap_entries > 256 ? 256 : 1852 (int)image->colormap_entries; 1853 1854 /* NOTE: the caller must check for cmap != NULL and entries != 0 */ 1855 png_uint_32 format = image->format; 1856 unsigned int channels = PNG_IMAGE_SAMPLE_CHANNELS(format); 1857 1858 # if defined(PNG_FORMAT_BGR_SUPPORTED) &&\ 1859 defined(PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED) 1860 int afirst = (format & PNG_FORMAT_FLAG_AFIRST) != 0 && 1861 (format & PNG_FORMAT_FLAG_ALPHA) != 0; 1862 # else 1863 # define afirst 0 1864 # endif 1865 1866 # ifdef PNG_FORMAT_BGR_SUPPORTED 1867 int bgr = (format & PNG_FORMAT_FLAG_BGR) != 0 ? 2 : 0; 1868 # else 1869 # define bgr 0 1870 # endif 1871 1872 int i, num_trans; 1873 png_color palette[256]; 1874 png_byte tRNS[256]; 1875 1876 memset(tRNS, 255, (sizeof tRNS)); 1877 memset(palette, 0, (sizeof palette)); 1878 1879 for (i=num_trans=0; i<entries; ++i) 1880 { 1881 /* This gets automatically converted to sRGB with reversal of the 1882 * pre-multiplication if the color-map has an alpha channel. 1883 */ 1884 if ((format & PNG_FORMAT_FLAG_LINEAR) != 0) 1885 { 1886 png_const_uint_16p entry = png_voidcast(png_const_uint_16p, cmap); 1887 1888 entry += (unsigned int)i * channels; 1889 1890 if ((channels & 1) != 0) /* no alpha */ 1891 { 1892 if (channels >= 3) /* RGB */ 1893 { 1894 palette[i].blue = (png_byte)PNG_sRGB_FROM_LINEAR(255 * 1895 entry[(2 ^ bgr)]); 1896 palette[i].green = (png_byte)PNG_sRGB_FROM_LINEAR(255 * 1897 entry[1]); 1898 palette[i].red = (png_byte)PNG_sRGB_FROM_LINEAR(255 * 1899 entry[bgr]); 1900 } 1901 1902 else /* Gray */ 1903 palette[i].blue = palette[i].red = palette[i].green = 1904 (png_byte)PNG_sRGB_FROM_LINEAR(255 * *entry); 1905 } 1906 1907 else /* alpha */ 1908 { 1909 png_uint_16 alpha = entry[afirst ? 0 : channels-1]; 1910 png_byte alphabyte = (png_byte)PNG_DIV257(alpha); 1911 png_uint_32 reciprocal = 0; 1912 1913 /* Calculate a reciprocal, as in the png_write_image_8bit code above 1914 * this is designed to produce a value scaled to 255*65535 when 1915 * divided by 128 (i.e. asr 7). 1916 */ 1917 if (alphabyte > 0 && alphabyte < 255) 1918 reciprocal = (((0xffff*0xff)<<7)+(alpha>>1))/alpha; 1919 1920 tRNS[i] = alphabyte; 1921 if (alphabyte < 255) 1922 num_trans = i+1; 1923 1924 if (channels >= 3) /* RGB */ 1925 { 1926 palette[i].blue = png_unpremultiply(entry[afirst + (2 ^ bgr)], 1927 alpha, reciprocal); 1928 palette[i].green = png_unpremultiply(entry[afirst + 1], alpha, 1929 reciprocal); 1930 palette[i].red = png_unpremultiply(entry[afirst + bgr], alpha, 1931 reciprocal); 1932 } 1933 1934 else /* gray */ 1935 palette[i].blue = palette[i].red = palette[i].green = 1936 png_unpremultiply(entry[afirst], alpha, reciprocal); 1937 } 1938 } 1939 1940 else /* Color-map has sRGB values */ 1941 { 1942 png_const_bytep entry = png_voidcast(png_const_bytep, cmap); 1943 1944 entry += (unsigned int)i * channels; 1945 1946 switch (channels) 1947 { 1948 case 4: 1949 tRNS[i] = entry[afirst ? 0 : 3]; 1950 if (tRNS[i] < 255) 1951 num_trans = i+1; 1952 /* FALLTHROUGH */ 1953 case 3: 1954 palette[i].blue = entry[afirst + (2 ^ bgr)]; 1955 palette[i].green = entry[afirst + 1]; 1956 palette[i].red = entry[afirst + bgr]; 1957 break; 1958 1959 case 2: 1960 tRNS[i] = entry[1 ^ afirst]; 1961 if (tRNS[i] < 255) 1962 num_trans = i+1; 1963 /* FALLTHROUGH */ 1964 case 1: 1965 palette[i].blue = palette[i].red = palette[i].green = 1966 entry[afirst]; 1967 break; 1968 1969 default: 1970 break; 1971 } 1972 } 1973 } 1974 1975 # ifdef afirst 1976 # undef afirst 1977 # endif 1978 # ifdef bgr 1979 # undef bgr 1980 # endif 1981 1982 png_set_PLTE(image->opaque->png_ptr, image->opaque->info_ptr, palette, 1983 entries); 1984 1985 if (num_trans > 0) 1986 png_set_tRNS(image->opaque->png_ptr, image->opaque->info_ptr, tRNS, 1987 num_trans, NULL); 1988 1989 image->colormap_entries = (png_uint_32)entries; 1990 } 1991 1992 static int 1993 png_image_write_main(png_voidp argument) 1994 { 1995 png_image_write_control *display = png_voidcast(png_image_write_control*, 1996 argument); 1997 png_imagep image = display->image; 1998 png_structrp png_ptr = image->opaque->png_ptr; 1999 png_inforp info_ptr = image->opaque->info_ptr; 2000 png_uint_32 format = image->format; 2001 2002 /* The following four ints are actually booleans */ 2003 int colormap = (format & PNG_FORMAT_FLAG_COLORMAP); 2004 int linear = !colormap && (format & PNG_FORMAT_FLAG_LINEAR); /* input */ 2005 int alpha = !colormap && (format & PNG_FORMAT_FLAG_ALPHA); 2006 int write_16bit = linear && (display->convert_to_8bit == 0); 2007 2008 # ifdef PNG_BENIGN_ERRORS_SUPPORTED 2009 /* Make sure we error out on any bad situation */ 2010 png_set_benign_errors(png_ptr, 0/*error*/); 2011 # endif 2012 2013 /* Default the 'row_stride' parameter if required, also check the row stride 2014 * and total image size to ensure that they are within the system limits. 2015 */ 2016 { 2017 unsigned int channels = PNG_IMAGE_PIXEL_CHANNELS(image->format); 2018 2019 if (image->width <= 0x7fffffffU/channels) /* no overflow */ 2020 { 2021 png_uint_32 check; 2022 png_uint_32 png_row_stride = image->width * channels; 2023 2024 if (display->row_stride == 0) 2025 display->row_stride = (png_int_32)/*SAFE*/png_row_stride; 2026 2027 if (display->row_stride < 0) 2028 check = (png_uint_32)(-display->row_stride); 2029 2030 else 2031 check = (png_uint_32)display->row_stride; 2032 2033 if (check >= png_row_stride) 2034 { 2035 /* Now check for overflow of the image buffer calculation; this 2036 * limits the whole image size to 32 bits for API compatibility with 2037 * the current, 32-bit, PNG_IMAGE_BUFFER_SIZE macro. 2038 */ 2039 if (image->height > 0xffffffffU/png_row_stride) 2040 png_error(image->opaque->png_ptr, "memory image too large"); 2041 } 2042 2043 else 2044 png_error(image->opaque->png_ptr, "supplied row stride too small"); 2045 } 2046 2047 else 2048 png_error(image->opaque->png_ptr, "image row stride too large"); 2049 } 2050 2051 /* Set the required transforms then write the rows in the correct order. */ 2052 if ((format & PNG_FORMAT_FLAG_COLORMAP) != 0) 2053 { 2054 if (display->colormap != NULL && image->colormap_entries > 0) 2055 { 2056 png_uint_32 entries = image->colormap_entries; 2057 2058 png_set_IHDR(png_ptr, info_ptr, image->width, image->height, 2059 entries > 16 ? 8 : (entries > 4 ? 4 : (entries > 2 ? 2 : 1)), 2060 PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE, 2061 PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); 2062 2063 png_image_set_PLTE(display); 2064 } 2065 2066 else 2067 png_error(image->opaque->png_ptr, 2068 "no color-map for color-mapped image"); 2069 } 2070 2071 else 2072 png_set_IHDR(png_ptr, info_ptr, image->width, image->height, 2073 write_16bit ? 16 : 8, 2074 ((format & PNG_FORMAT_FLAG_COLOR) ? PNG_COLOR_MASK_COLOR : 0) + 2075 ((format & PNG_FORMAT_FLAG_ALPHA) ? PNG_COLOR_MASK_ALPHA : 0), 2076 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); 2077 2078 /* Counter-intuitively the data transformations must be called *after* 2079 * png_write_info, not before as in the read code, but the 'set' functions 2080 * must still be called before. Just set the color space information, never 2081 * write an interlaced image. 2082 */ 2083 2084 if (write_16bit != 0) 2085 { 2086 /* The gamma here is 1.0 (linear) and the cHRM chunk matches sRGB. */ 2087 png_set_gAMA_fixed(png_ptr, info_ptr, PNG_GAMMA_LINEAR); 2088 2089 if ((image->flags & PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB) == 0) 2090 png_set_cHRM_fixed(png_ptr, info_ptr, 2091 /* color x y */ 2092 /* white */ 31270, 32900, 2093 /* red */ 64000, 33000, 2094 /* green */ 30000, 60000, 2095 /* blue */ 15000, 6000 2096 ); 2097 } 2098 2099 else if ((image->flags & PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB) == 0) 2100 png_set_sRGB(png_ptr, info_ptr, PNG_sRGB_INTENT_PERCEPTUAL); 2101 2102 /* Else writing an 8-bit file and the *colors* aren't sRGB, but the 8-bit 2103 * space must still be gamma encoded. 2104 */ 2105 else 2106 png_set_gAMA_fixed(png_ptr, info_ptr, PNG_GAMMA_sRGB_INVERSE); 2107 2108 /* Write the file header. */ 2109 png_write_info(png_ptr, info_ptr); 2110 2111 /* Now set up the data transformations (*after* the header is written), 2112 * remove the handled transformations from the 'format' flags for checking. 2113 * 2114 * First check for a little endian system if writing 16-bit files. 2115 */ 2116 if (write_16bit != 0) 2117 { 2118 png_uint_16 le = 0x0001; 2119 2120 if ((*(png_const_bytep) & le) != 0) 2121 png_set_swap(png_ptr); 2122 } 2123 2124 # ifdef PNG_SIMPLIFIED_WRITE_BGR_SUPPORTED 2125 if ((format & PNG_FORMAT_FLAG_BGR) != 0) 2126 { 2127 if (colormap == 0 && (format & PNG_FORMAT_FLAG_COLOR) != 0) 2128 png_set_bgr(png_ptr); 2129 format &= ~PNG_FORMAT_FLAG_BGR; 2130 } 2131 # endif 2132 2133 # ifdef PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED 2134 if ((format & PNG_FORMAT_FLAG_AFIRST) != 0) 2135 { 2136 if (colormap == 0 && (format & PNG_FORMAT_FLAG_ALPHA) != 0) 2137 png_set_swap_alpha(png_ptr); 2138 format &= ~PNG_FORMAT_FLAG_AFIRST; 2139 } 2140 # endif 2141 2142 /* If there are 16 or fewer color-map entries we wrote a lower bit depth 2143 * above, but the application data is still byte packed. 2144 */ 2145 if (colormap != 0 && image->colormap_entries <= 16) 2146 png_set_packing(png_ptr); 2147 2148 /* That should have handled all (both) the transforms. */ 2149 if ((format & ~(png_uint_32)(PNG_FORMAT_FLAG_COLOR | PNG_FORMAT_FLAG_LINEAR | 2150 PNG_FORMAT_FLAG_ALPHA | PNG_FORMAT_FLAG_COLORMAP)) != 0) 2151 png_error(png_ptr, "png_write_image: unsupported transformation"); 2152 2153 { 2154 png_const_bytep row = png_voidcast(png_const_bytep, display->buffer); 2155 ptrdiff_t row_bytes = display->row_stride; 2156 2157 if (linear != 0) 2158 row_bytes *= (sizeof (png_uint_16)); 2159 2160 if (row_bytes < 0) 2161 row += (image->height-1) * (-row_bytes); 2162 2163 display->first_row = row; 2164 display->row_bytes = row_bytes; 2165 } 2166 2167 /* Apply 'fast' options if the flag is set. */ 2168 if ((image->flags & PNG_IMAGE_FLAG_FAST) != 0) 2169 { 2170 png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE, PNG_NO_FILTERS); 2171 /* NOTE: determined by experiment using pngstest, this reflects some 2172 * balance between the time to write the image once and the time to read 2173 * it about 50 times. The speed-up in pngstest was about 10-20% of the 2174 * total (user) time on a heavily loaded system. 2175 */ 2176 # ifdef PNG_WRITE_CUSTOMIZE_COMPRESSION_SUPPORTED 2177 png_set_compression_level(png_ptr, 3); 2178 # endif 2179 } 2180 2181 /* Check for the cases that currently require a pre-transform on the row 2182 * before it is written. This only applies when the input is 16-bit and 2183 * either there is an alpha channel or it is converted to 8-bit. 2184 */ 2185 if (linear != 0 && (alpha != 0 || display->convert_to_8bit != 0)) 2186 { 2187 png_bytep row = png_voidcast(png_bytep, png_malloc(png_ptr, 2188 png_get_rowbytes(png_ptr, info_ptr))); 2189 int result; 2190 2191 display->local_row = row; 2192 if (write_16bit != 0) 2193 result = png_safe_execute(image, png_write_image_16bit, display); 2194 else 2195 result = png_safe_execute(image, png_write_image_8bit, display); 2196 display->local_row = NULL; 2197 2198 png_free(png_ptr, row); 2199 2200 /* Skip the 'write_end' on error: */ 2201 if (result == 0) 2202 return 0; 2203 } 2204 2205 /* Otherwise this is the case where the input is in a format currently 2206 * supported by the rest of the libpng write code; call it directly. 2207 */ 2208 else 2209 { 2210 png_const_bytep row = png_voidcast(png_const_bytep, display->first_row); 2211 ptrdiff_t row_bytes = display->row_bytes; 2212 png_uint_32 y = image->height; 2213 2214 for (; y > 0; --y) 2215 { 2216 png_write_row(png_ptr, row); 2217 row += row_bytes; 2218 } 2219 } 2220 2221 png_write_end(png_ptr, info_ptr); 2222 return 1; 2223 } 2224 2225 2226 static void (PNGCBAPI 2227 image_memory_write)(png_structp png_ptr, png_bytep/*const*/ data, size_t size) 2228 { 2229 png_image_write_control *display = png_voidcast(png_image_write_control*, 2230 png_ptr->io_ptr/*backdoor: png_get_io_ptr(png_ptr)*/); 2231 png_alloc_size_t ob = display->output_bytes; 2232 2233 /* Check for overflow; this should never happen: */ 2234 if (size <= ((png_alloc_size_t)-1) - ob) 2235 { 2236 /* I don't think libpng ever does this, but just in case: */ 2237 if (size > 0) 2238 { 2239 if (display->memory_bytes >= ob+size) /* writing */ 2240 memcpy(display->memory+ob, data, size); 2241 2242 /* Always update the size: */ 2243 display->output_bytes = ob+size; 2244 } 2245 } 2246 2247 else 2248 png_error(png_ptr, "png_image_write_to_memory: PNG too big"); 2249 } 2250 2251 static void (PNGCBAPI 2252 image_memory_flush)(png_structp png_ptr) 2253 { 2254 PNG_UNUSED(png_ptr) 2255 } 2256 2257 static int 2258 png_image_write_memory(png_voidp argument) 2259 { 2260 png_image_write_control *display = png_voidcast(png_image_write_control*, 2261 argument); 2262 2263 /* The rest of the memory-specific init and write_main in an error protected 2264 * environment. This case needs to use callbacks for the write operations 2265 * since libpng has no built in support for writing to memory. 2266 */ 2267 png_set_write_fn(display->image->opaque->png_ptr, display/*io_ptr*/, 2268 image_memory_write, image_memory_flush); 2269 2270 return png_image_write_main(display); 2271 } 2272 2273 int PNGAPI 2274 png_image_write_to_memory(png_imagep image, void *memory, 2275 png_alloc_size_t * PNG_RESTRICT memory_bytes, int convert_to_8bit, 2276 const void *buffer, png_int_32 row_stride, const void *colormap) 2277 { 2278 /* Write the image to the given buffer, or count the bytes if it is NULL */ 2279 if (image != NULL && image->version == PNG_IMAGE_VERSION) 2280 { 2281 if (memory_bytes != NULL && buffer != NULL) 2282 { 2283 /* This is to give the caller an easier error detection in the NULL 2284 * case and guard against uninitialized variable problems: 2285 */ 2286 if (memory == NULL) 2287 *memory_bytes = 0; 2288 2289 if (png_image_write_init(image) != 0) 2290 { 2291 png_image_write_control display; 2292 int result; 2293 2294 memset(&display, 0, (sizeof display)); 2295 display.image = image; 2296 display.buffer = buffer; 2297 display.row_stride = row_stride; 2298 display.colormap = colormap; 2299 display.convert_to_8bit = convert_to_8bit; 2300 display.memory = png_voidcast(png_bytep, memory); 2301 display.memory_bytes = *memory_bytes; 2302 display.output_bytes = 0; 2303 2304 result = png_safe_execute(image, png_image_write_memory, &display); 2305 png_image_free(image); 2306 2307 /* write_memory returns true even if we ran out of buffer. */ 2308 if (result) 2309 { 2310 /* On out-of-buffer this function returns '0' but still updates 2311 * memory_bytes: 2312 */ 2313 if (memory != NULL && display.output_bytes > *memory_bytes) 2314 result = 0; 2315 2316 *memory_bytes = display.output_bytes; 2317 } 2318 2319 return result; 2320 } 2321 2322 else 2323 return 0; 2324 } 2325 2326 else 2327 return png_image_error(image, 2328 "png_image_write_to_memory: invalid argument"); 2329 } 2330 2331 else if (image != NULL) 2332 return png_image_error(image, 2333 "png_image_write_to_memory: incorrect PNG_IMAGE_VERSION"); 2334 2335 else 2336 return 0; 2337 } 2338 2339 #ifdef PNG_SIMPLIFIED_WRITE_STDIO_SUPPORTED 2340 int PNGAPI 2341 png_image_write_to_stdio(png_imagep image, FILE *file, int convert_to_8bit, 2342 const void *buffer, png_int_32 row_stride, const void *colormap) 2343 { 2344 /* Write the image to the given FILE object. */ 2345 if (image != NULL && image->version == PNG_IMAGE_VERSION) 2346 { 2347 if (file != NULL && buffer != NULL) 2348 { 2349 if (png_image_write_init(image) != 0) 2350 { 2351 png_image_write_control display; 2352 int result; 2353 2354 /* This is slightly evil, but png_init_io doesn't do anything other 2355 * than this and we haven't changed the standard IO functions so 2356 * this saves a 'safe' function. 2357 */ 2358 image->opaque->png_ptr->io_ptr = file; 2359 2360 memset(&display, 0, (sizeof display)); 2361 display.image = image; 2362 display.buffer = buffer; 2363 display.row_stride = row_stride; 2364 display.colormap = colormap; 2365 display.convert_to_8bit = convert_to_8bit; 2366 2367 result = png_safe_execute(image, png_image_write_main, &display); 2368 png_image_free(image); 2369 return result; 2370 } 2371 2372 else 2373 return 0; 2374 } 2375 2376 else 2377 return png_image_error(image, 2378 "png_image_write_to_stdio: invalid argument"); 2379 } 2380 2381 else if (image != NULL) 2382 return png_image_error(image, 2383 "png_image_write_to_stdio: incorrect PNG_IMAGE_VERSION"); 2384 2385 else 2386 return 0; 2387 } 2388 2389 int PNGAPI 2390 png_image_write_to_file(png_imagep image, const char *file_name, 2391 int convert_to_8bit, const void *buffer, png_int_32 row_stride, 2392 const void *colormap) 2393 { 2394 /* Write the image to the named file. */ 2395 if (image != NULL && image->version == PNG_IMAGE_VERSION) 2396 { 2397 if (file_name != NULL && buffer != NULL) 2398 { 2399 FILE *fp = fopen(file_name, "wb"); 2400 2401 if (fp != NULL) 2402 { 2403 if (png_image_write_to_stdio(image, fp, convert_to_8bit, buffer, 2404 row_stride, colormap) != 0) 2405 { 2406 int error; /* from fflush/fclose */ 2407 2408 /* Make sure the file is flushed correctly. */ 2409 if (fflush(fp) == 0 && ferror(fp) == 0) 2410 { 2411 if (fclose(fp) == 0) 2412 return 1; 2413 2414 error = errno; /* from fclose */ 2415 } 2416 2417 else 2418 { 2419 error = errno; /* from fflush or ferror */ 2420 (void)fclose(fp); 2421 } 2422 2423 (void)remove(file_name); 2424 /* The image has already been cleaned up; this is just used to 2425 * set the error (because the original write succeeded). 2426 */ 2427 return png_image_error(image, strerror(error)); 2428 } 2429 2430 else 2431 { 2432 /* Clean up: just the opened file. */ 2433 (void)fclose(fp); 2434 (void)remove(file_name); 2435 return 0; 2436 } 2437 } 2438 2439 else 2440 return png_image_error(image, strerror(errno)); 2441 } 2442 2443 else 2444 return png_image_error(image, 2445 "png_image_write_to_file: invalid argument"); 2446 } 2447 2448 else if (image != NULL) 2449 return png_image_error(image, 2450 "png_image_write_to_file: incorrect PNG_IMAGE_VERSION"); 2451 2452 else 2453 return 0; 2454 } 2455 #endif /* SIMPLIFIED_WRITE_STDIO */ 2456 #endif /* SIMPLIFIED_WRITE */ 2457 2458 #ifdef PNG_WRITE_APNG_SUPPORTED 2459 void PNGAPI 2460 png_write_frame_head(png_structp png_ptr, png_infop info_ptr, 2461 png_bytepp row_pointers, png_uint_32 width, png_uint_32 height, 2462 png_uint_32 x_offset, png_uint_32 y_offset, 2463 png_uint_16 delay_num, png_uint_16 delay_den, png_byte dispose_op, 2464 png_byte blend_op) 2465 { 2466 png_debug(1, "in png_write_frame_head"); 2467 2468 /* there is a chance this has been set after png_write_info was called, 2469 * so it would be set but not written. is there a way to be sure? */ 2470 if ((info_ptr->valid & PNG_INFO_acTL) == 0) 2471 png_error(png_ptr, "png_write_frame_head(): acTL not set"); 2472 2473 png_write_reset(png_ptr); 2474 2475 png_write_reinit(png_ptr, info_ptr, width, height); 2476 2477 if ((png_ptr->apng_flags & PNG_FIRST_FRAME_HIDDEN) == 0 || 2478 png_ptr->num_frames_written != 0) 2479 png_write_fcTL(png_ptr, width, height, x_offset, y_offset, 2480 delay_num, delay_den, dispose_op, blend_op); 2481 2482 PNG_UNUSED(row_pointers) 2483 } 2484 2485 void PNGAPI 2486 png_write_frame_tail(png_structp png_ptr, png_infop info_ptr) 2487 { 2488 png_debug(1, "in png_write_frame_tail"); 2489 2490 png_ptr->num_frames_written++; 2491 2492 PNG_UNUSED(info_ptr) 2493 } 2494 #endif /* WRITE_APNG */ 2495 #endif /* WRITE */