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