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