pngwrite.c revision 433b85aa347016d3110aa6e478bc35be0cc3ef88
1 2/* pngwrite.c - general routines to write a PNG file 3 * 4 * Last changed in libpng 1.2.45 [July 7, 2011] 5 * Copyright (c) 1998-2011 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/* Get internal access to png.h */ 15#define PNG_INTERNAL 16#define PNG_NO_PEDANTIC_WARNINGS 17#include "png.h" 18#ifdef PNG_WRITE_SUPPORTED 19 20/* Writes all the PNG information. This is the suggested way to use the 21 * library. If you have a new chunk to add, make a function to write it, 22 * and put it in the correct location here. If you want the chunk written 23 * after the image data, put it in png_write_end(). I strongly encourage 24 * you to supply a PNG_INFO_ flag, and check info_ptr->valid before writing 25 * the chunk, as that will keep the code from breaking if you want to just 26 * write a plain PNG file. If you have long comments, I suggest writing 27 * them in png_write_end(), and compressing them. 28 */ 29void PNGAPI 30png_write_info_before_PLTE(png_structp png_ptr, png_infop info_ptr) 31{ 32 png_debug(1, "in png_write_info_before_PLTE"); 33 34 if (png_ptr == NULL || info_ptr == NULL) 35 return; 36 if (!(png_ptr->mode & PNG_WROTE_INFO_BEFORE_PLTE)) 37 { 38 /* Write PNG signature */ 39 png_write_sig(png_ptr); 40#ifdef PNG_MNG_FEATURES_SUPPORTED 41 if ((png_ptr->mode&PNG_HAVE_PNG_SIGNATURE) && \ 42 (png_ptr->mng_features_permitted)) 43 { 44 png_warning(png_ptr, "MNG features are not allowed in a PNG datastream"); 45 png_ptr->mng_features_permitted = 0; 46 } 47#endif 48 /* Write IHDR information. */ 49 png_write_IHDR(png_ptr, info_ptr->width, info_ptr->height, 50 info_ptr->bit_depth, info_ptr->color_type, info_ptr->compression_type, 51 info_ptr->filter_type, 52#ifdef PNG_WRITE_INTERLACING_SUPPORTED 53 info_ptr->interlace_type); 54#else 55 0); 56#endif 57 /* The rest of these check to see if the valid field has the appropriate 58 * flag set, and if it does, writes the chunk. 59 */ 60#ifdef PNG_WRITE_gAMA_SUPPORTED 61 if (info_ptr->valid & PNG_INFO_gAMA) 62 { 63# ifdef PNG_FLOATING_POINT_SUPPORTED 64 png_write_gAMA(png_ptr, info_ptr->gamma); 65#else 66#ifdef PNG_FIXED_POINT_SUPPORTED 67 png_write_gAMA_fixed(png_ptr, info_ptr->int_gamma); 68# endif 69#endif 70 } 71#endif 72#ifdef PNG_WRITE_sRGB_SUPPORTED 73 if (info_ptr->valid & PNG_INFO_sRGB) 74 png_write_sRGB(png_ptr, (int)info_ptr->srgb_intent); 75#endif 76#ifdef PNG_WRITE_iCCP_SUPPORTED 77 if (info_ptr->valid & PNG_INFO_iCCP) 78 png_write_iCCP(png_ptr, info_ptr->iccp_name, PNG_COMPRESSION_TYPE_BASE, 79 info_ptr->iccp_profile, (int)info_ptr->iccp_proflen); 80#endif 81#ifdef PNG_WRITE_sBIT_SUPPORTED 82 if (info_ptr->valid & PNG_INFO_sBIT) 83 png_write_sBIT(png_ptr, &(info_ptr->sig_bit), info_ptr->color_type); 84#endif 85#ifdef PNG_WRITE_cHRM_SUPPORTED 86 if (info_ptr->valid & PNG_INFO_cHRM) 87 { 88#ifdef PNG_FLOATING_POINT_SUPPORTED 89 png_write_cHRM(png_ptr, 90 info_ptr->x_white, info_ptr->y_white, 91 info_ptr->x_red, info_ptr->y_red, 92 info_ptr->x_green, info_ptr->y_green, 93 info_ptr->x_blue, info_ptr->y_blue); 94#else 95# ifdef PNG_FIXED_POINT_SUPPORTED 96 png_write_cHRM_fixed(png_ptr, 97 info_ptr->int_x_white, info_ptr->int_y_white, 98 info_ptr->int_x_red, info_ptr->int_y_red, 99 info_ptr->int_x_green, info_ptr->int_y_green, 100 info_ptr->int_x_blue, info_ptr->int_y_blue); 101# endif 102#endif 103 } 104#endif 105#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED 106 if (info_ptr->unknown_chunks_num) 107 { 108 png_unknown_chunk *up; 109 110 png_debug(5, "writing extra chunks"); 111 112 for (up = info_ptr->unknown_chunks; 113 up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num; 114 up++) 115 { 116 int keep = png_handle_as_unknown(png_ptr, up->name); 117 if (keep != PNG_HANDLE_CHUNK_NEVER && 118 up->location && !(up->location & PNG_HAVE_PLTE) && 119 !(up->location & PNG_HAVE_IDAT) && 120 ((up->name[3] & 0x20) || keep == PNG_HANDLE_CHUNK_ALWAYS || 121 (png_ptr->flags & PNG_FLAG_KEEP_UNSAFE_CHUNKS))) 122 { 123 if (up->size == 0) 124 png_warning(png_ptr, "Writing zero-length unknown chunk"); 125 png_write_chunk(png_ptr, up->name, up->data, up->size); 126 } 127 } 128 } 129#endif 130 png_ptr->mode |= PNG_WROTE_INFO_BEFORE_PLTE; 131 } 132} 133 134void PNGAPI 135png_write_info(png_structp png_ptr, png_infop info_ptr) 136{ 137#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED) 138 int i; 139#endif 140 141 png_debug(1, "in png_write_info"); 142 143 if (png_ptr == NULL || info_ptr == NULL) 144 return; 145 146 png_write_info_before_PLTE(png_ptr, info_ptr); 147 148 if (info_ptr->valid & PNG_INFO_PLTE) 149 png_write_PLTE(png_ptr, info_ptr->palette, 150 (png_uint_32)info_ptr->num_palette); 151 else if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) 152 png_error(png_ptr, "Valid palette required for paletted images"); 153 154#ifdef PNG_WRITE_tRNS_SUPPORTED 155 if (info_ptr->valid & PNG_INFO_tRNS) 156 { 157#ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED 158 /* Invert the alpha channel (in tRNS) */ 159 if ((png_ptr->transformations & PNG_INVERT_ALPHA) && 160 info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) 161 { 162 int j; 163 for (j = 0; j<(int)info_ptr->num_trans; j++) 164 info_ptr->trans[j] = (png_byte)(255 - info_ptr->trans[j]); 165 } 166#endif 167 png_write_tRNS(png_ptr, info_ptr->trans, &(info_ptr->trans_values), 168 info_ptr->num_trans, info_ptr->color_type); 169 } 170#endif 171#ifdef PNG_WRITE_bKGD_SUPPORTED 172 if (info_ptr->valid & PNG_INFO_bKGD) 173 png_write_bKGD(png_ptr, &(info_ptr->background), info_ptr->color_type); 174#endif 175#ifdef PNG_WRITE_hIST_SUPPORTED 176 if (info_ptr->valid & PNG_INFO_hIST) 177 png_write_hIST(png_ptr, info_ptr->hist, info_ptr->num_palette); 178#endif 179#ifdef PNG_WRITE_oFFs_SUPPORTED 180 if (info_ptr->valid & PNG_INFO_oFFs) 181 png_write_oFFs(png_ptr, info_ptr->x_offset, info_ptr->y_offset, 182 info_ptr->offset_unit_type); 183#endif 184#ifdef PNG_WRITE_pCAL_SUPPORTED 185 if (info_ptr->valid & PNG_INFO_pCAL) 186 png_write_pCAL(png_ptr, info_ptr->pcal_purpose, info_ptr->pcal_X0, 187 info_ptr->pcal_X1, info_ptr->pcal_type, info_ptr->pcal_nparams, 188 info_ptr->pcal_units, info_ptr->pcal_params); 189#endif 190 191#ifdef PNG_sCAL_SUPPORTED 192 if (info_ptr->valid & PNG_INFO_sCAL) 193#ifdef PNG_WRITE_sCAL_SUPPORTED 194#if defined(PNG_FLOATING_POINT_SUPPORTED) && defined(PNG_STDIO_SUPPORTED) 195 png_write_sCAL(png_ptr, (int)info_ptr->scal_unit, 196 info_ptr->scal_pixel_width, info_ptr->scal_pixel_height); 197#else /* !FLOATING_POINT */ 198#ifdef PNG_FIXED_POINT_SUPPORTED 199 png_write_sCAL_s(png_ptr, (int)info_ptr->scal_unit, 200 info_ptr->scal_s_width, info_ptr->scal_s_height); 201#endif /* FIXED_POINT */ 202#endif /* FLOATING_POINT */ 203#else /* !WRITE_sCAL */ 204 png_warning(png_ptr, 205 "png_write_sCAL not supported; sCAL chunk not written."); 206#endif /* WRITE_sCAL */ 207#endif /* sCAL */ 208 209#ifdef PNG_WRITE_pHYs_SUPPORTED 210 if (info_ptr->valid & PNG_INFO_pHYs) 211 png_write_pHYs(png_ptr, info_ptr->x_pixels_per_unit, 212 info_ptr->y_pixels_per_unit, info_ptr->phys_unit_type); 213#endif /* pHYs */ 214 215#ifdef PNG_WRITE_tIME_SUPPORTED 216 if (info_ptr->valid & PNG_INFO_tIME) 217 { 218 png_write_tIME(png_ptr, &(info_ptr->mod_time)); 219 png_ptr->mode |= PNG_WROTE_tIME; 220 } 221#endif /* tIME */ 222 223#ifdef PNG_WRITE_sPLT_SUPPORTED 224 if (info_ptr->valid & PNG_INFO_sPLT) 225 for (i = 0; i < (int)info_ptr->splt_palettes_num; i++) 226 png_write_sPLT(png_ptr, info_ptr->splt_palettes + i); 227#endif /* sPLT */ 228 229#ifdef PNG_WRITE_TEXT_SUPPORTED 230 /* Check to see if we need to write text chunks */ 231 for (i = 0; i < info_ptr->num_text; i++) 232 { 233 png_debug2(2, "Writing header text chunk %d, type %d", i, 234 info_ptr->text[i].compression); 235 /* An internationalized chunk? */ 236 if (info_ptr->text[i].compression > 0) 237 { 238#ifdef PNG_WRITE_iTXt_SUPPORTED 239 /* Write international chunk */ 240 png_write_iTXt(png_ptr, 241 info_ptr->text[i].compression, 242 info_ptr->text[i].key, 243 info_ptr->text[i].lang, 244 info_ptr->text[i].lang_key, 245 info_ptr->text[i].text); 246#else 247 png_warning(png_ptr, "Unable to write international text"); 248#endif 249 /* Mark this chunk as written */ 250 info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; 251 } 252 /* If we want a compressed text chunk */ 253 else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_zTXt) 254 { 255#ifdef PNG_WRITE_zTXt_SUPPORTED 256 /* Write compressed chunk */ 257 png_write_zTXt(png_ptr, info_ptr->text[i].key, 258 info_ptr->text[i].text, 0, 259 info_ptr->text[i].compression); 260#else 261 png_warning(png_ptr, "Unable to write compressed text"); 262#endif 263 /* Mark this chunk as written */ 264 info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR; 265 } 266 else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE) 267 { 268#ifdef PNG_WRITE_tEXt_SUPPORTED 269 /* Write uncompressed chunk */ 270 png_write_tEXt(png_ptr, info_ptr->text[i].key, 271 info_ptr->text[i].text, 272 0); 273 /* Mark this chunk as written */ 274 info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; 275#else 276 /* Can't get here */ 277 png_warning(png_ptr, "Unable to write uncompressed text"); 278#endif 279 } 280 } 281#endif /* tEXt */ 282 283#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED 284 if (info_ptr->unknown_chunks_num) 285 { 286 png_unknown_chunk *up; 287 288 png_debug(5, "writing extra chunks"); 289 290 for (up = info_ptr->unknown_chunks; 291 up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num; 292 up++) 293 { 294 int keep = png_handle_as_unknown(png_ptr, up->name); 295 if (keep != PNG_HANDLE_CHUNK_NEVER && 296 up->location && (up->location & PNG_HAVE_PLTE) && 297 !(up->location & PNG_HAVE_IDAT) && 298 !(up->location & PNG_AFTER_IDAT) && 299 ((up->name[3] & 0x20) || keep == PNG_HANDLE_CHUNK_ALWAYS || 300 (png_ptr->flags & PNG_FLAG_KEEP_UNSAFE_CHUNKS))) 301 { 302 png_write_chunk(png_ptr, up->name, up->data, up->size); 303 } 304 } 305 } 306#endif 307} 308 309/* Writes the end of the PNG file. If you don't want to write comments or 310 * time information, you can pass NULL for info. If you already wrote these 311 * in png_write_info(), do not write them again here. If you have long 312 * comments, I suggest writing them here, and compressing them. 313 */ 314void PNGAPI 315png_write_end(png_structp png_ptr, png_infop info_ptr) 316{ 317 png_debug(1, "in png_write_end"); 318 319 if (png_ptr == NULL) 320 return; 321 if (!(png_ptr->mode & PNG_HAVE_IDAT)) 322 png_error(png_ptr, "No IDATs written into file"); 323 324 /* See if user wants us to write information chunks */ 325 if (info_ptr != NULL) 326 { 327#ifdef PNG_WRITE_TEXT_SUPPORTED 328 int i; /* local index variable */ 329#endif 330#ifdef PNG_WRITE_tIME_SUPPORTED 331 /* Check to see if user has supplied a time chunk */ 332 if ((info_ptr->valid & PNG_INFO_tIME) && 333 !(png_ptr->mode & PNG_WROTE_tIME)) 334 png_write_tIME(png_ptr, &(info_ptr->mod_time)); 335#endif 336#ifdef PNG_WRITE_TEXT_SUPPORTED 337 /* Loop through comment chunks */ 338 for (i = 0; i < info_ptr->num_text; i++) 339 { 340 png_debug2(2, "Writing trailer text chunk %d, type %d", i, 341 info_ptr->text[i].compression); 342 /* An internationalized chunk? */ 343 if (info_ptr->text[i].compression > 0) 344 { 345#ifdef PNG_WRITE_iTXt_SUPPORTED 346 /* Write international chunk */ 347 png_write_iTXt(png_ptr, 348 info_ptr->text[i].compression, 349 info_ptr->text[i].key, 350 info_ptr->text[i].lang, 351 info_ptr->text[i].lang_key, 352 info_ptr->text[i].text); 353#else 354 png_warning(png_ptr, "Unable to write international text"); 355#endif 356 /* Mark this chunk as written */ 357 info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; 358 } 359 else if (info_ptr->text[i].compression >= PNG_TEXT_COMPRESSION_zTXt) 360 { 361#ifdef PNG_WRITE_zTXt_SUPPORTED 362 /* Write compressed chunk */ 363 png_write_zTXt(png_ptr, info_ptr->text[i].key, 364 info_ptr->text[i].text, 0, 365 info_ptr->text[i].compression); 366#else 367 png_warning(png_ptr, "Unable to write compressed text"); 368#endif 369 /* Mark this chunk as written */ 370 info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR; 371 } 372 else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE) 373 { 374#ifdef PNG_WRITE_tEXt_SUPPORTED 375 /* Write uncompressed chunk */ 376 png_write_tEXt(png_ptr, info_ptr->text[i].key, 377 info_ptr->text[i].text, 0); 378#else 379 png_warning(png_ptr, "Unable to write uncompressed text"); 380#endif 381 382 /* Mark this chunk as written */ 383 info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; 384 } 385 } 386#endif 387#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED 388 if (info_ptr->unknown_chunks_num) 389 { 390 png_unknown_chunk *up; 391 392 png_debug(5, "writing extra chunks"); 393 394 for (up = info_ptr->unknown_chunks; 395 up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num; 396 up++) 397 { 398 int keep = png_handle_as_unknown(png_ptr, up->name); 399 if (keep != PNG_HANDLE_CHUNK_NEVER && 400 up->location && (up->location & PNG_AFTER_IDAT) && 401 ((up->name[3] & 0x20) || keep == PNG_HANDLE_CHUNK_ALWAYS || 402 (png_ptr->flags & PNG_FLAG_KEEP_UNSAFE_CHUNKS))) 403 { 404 png_write_chunk(png_ptr, up->name, up->data, up->size); 405 } 406 } 407 } 408#endif 409 } 410 411 png_ptr->mode |= PNG_AFTER_IDAT; 412 413 /* Write end of PNG file */ 414 png_write_IEND(png_ptr); 415 /* This flush, added in libpng-1.0.8, removed from libpng-1.0.9beta03, 416 * and restored again in libpng-1.2.30, may cause some applications that 417 * do not set png_ptr->output_flush_fn to crash. If your application 418 * experiences a problem, please try building libpng with 419 * PNG_WRITE_FLUSH_AFTER_IEND_SUPPORTED defined, and report the event to 420 * png-mng-implement at lists.sf.net . 421 */ 422#ifdef PNG_WRITE_FLUSH_SUPPORTED 423# ifdef PNG_WRITE_FLUSH_AFTER_IEND_SUPPORTED 424 png_flush(png_ptr); 425# endif 426#endif 427} 428 429#ifdef PNG_CONVERT_tIME_SUPPORTED 430/* "tm" structure is not supported on WindowsCE */ 431void PNGAPI 432png_convert_from_struct_tm(png_timep ptime, struct tm FAR * ttime) 433{ 434 png_debug(1, "in png_convert_from_struct_tm"); 435 436 ptime->year = (png_uint_16)(1900 + ttime->tm_year); 437 ptime->month = (png_byte)(ttime->tm_mon + 1); 438 ptime->day = (png_byte)ttime->tm_mday; 439 ptime->hour = (png_byte)ttime->tm_hour; 440 ptime->minute = (png_byte)ttime->tm_min; 441 ptime->second = (png_byte)ttime->tm_sec; 442} 443 444void PNGAPI 445png_convert_from_time_t(png_timep ptime, time_t ttime) 446{ 447 struct tm *tbuf; 448 449 png_debug(1, "in png_convert_from_time_t"); 450 451 tbuf = gmtime(&ttime); 452 png_convert_from_struct_tm(ptime, tbuf); 453} 454#endif 455 456/* Initialize png_ptr structure, and allocate any memory needed */ 457png_structp PNGAPI 458png_create_write_struct(png_const_charp user_png_ver, png_voidp error_ptr, 459 png_error_ptr error_fn, png_error_ptr warn_fn) 460{ 461#ifdef PNG_USER_MEM_SUPPORTED 462 return (png_create_write_struct_2(user_png_ver, error_ptr, error_fn, 463 warn_fn, png_voidp_NULL, png_malloc_ptr_NULL, png_free_ptr_NULL)); 464} 465 466/* Alternate initialize png_ptr structure, and allocate any memory needed */ 467png_structp PNGAPI 468png_create_write_struct_2(png_const_charp user_png_ver, png_voidp error_ptr, 469 png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr, 470 png_malloc_ptr malloc_fn, png_free_ptr free_fn) 471{ 472#endif /* PNG_USER_MEM_SUPPORTED */ 473#ifdef PNG_SETJMP_SUPPORTED 474 volatile 475#endif 476 png_structp png_ptr; 477#ifdef PNG_SETJMP_SUPPORTED 478#ifdef USE_FAR_KEYWORD 479 jmp_buf jmpbuf; 480#endif 481#endif 482 int i; 483 484 png_debug(1, "in png_create_write_struct"); 485 486#ifdef PNG_USER_MEM_SUPPORTED 487 png_ptr = (png_structp)png_create_struct_2(PNG_STRUCT_PNG, 488 (png_malloc_ptr)malloc_fn, (png_voidp)mem_ptr); 489#else 490 png_ptr = (png_structp)png_create_struct(PNG_STRUCT_PNG); 491#endif /* PNG_USER_MEM_SUPPORTED */ 492 if (png_ptr == NULL) 493 return (NULL); 494 495 /* Added at libpng-1.2.6 */ 496#ifdef PNG_SET_USER_LIMITS_SUPPORTED 497 png_ptr->user_width_max = PNG_USER_WIDTH_MAX; 498 png_ptr->user_height_max = PNG_USER_HEIGHT_MAX; 499#endif 500 501#ifdef PNG_SETJMP_SUPPORTED 502#ifdef USE_FAR_KEYWORD 503 if (setjmp(jmpbuf)) 504#else 505 if (setjmp(png_ptr->jmpbuf)) 506#endif 507 { 508 png_free(png_ptr, png_ptr->zbuf); 509 png_ptr->zbuf = NULL; 510#ifdef PNG_USER_MEM_SUPPORTED 511 png_destroy_struct_2((png_voidp)png_ptr, 512 (png_free_ptr)free_fn, (png_voidp)mem_ptr); 513#else 514 png_destroy_struct((png_voidp)png_ptr); 515#endif 516 return (NULL); 517 } 518#ifdef USE_FAR_KEYWORD 519 png_memcpy(png_ptr->jmpbuf, jmpbuf, png_sizeof(jmp_buf)); 520#endif 521#endif 522 523#ifdef PNG_USER_MEM_SUPPORTED 524 png_set_mem_fn(png_ptr, mem_ptr, malloc_fn, free_fn); 525#endif /* PNG_USER_MEM_SUPPORTED */ 526 png_set_error_fn(png_ptr, error_ptr, error_fn, warn_fn); 527 528 if (user_png_ver) 529 { 530 i = 0; 531 do 532 { 533 if (user_png_ver[i] != png_libpng_ver[i]) 534 png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH; 535 } while (png_libpng_ver[i++]); 536 } 537 538 if (png_ptr->flags & PNG_FLAG_LIBRARY_MISMATCH) 539 { 540 /* Libpng 0.90 and later are binary incompatible with libpng 0.89, so 541 * we must recompile any applications that use any older library version. 542 * For versions after libpng 1.0, we will be compatible, so we need 543 * only check the first digit. 544 */ 545 if (user_png_ver == NULL || user_png_ver[0] != png_libpng_ver[0] || 546 (user_png_ver[0] == '1' && user_png_ver[2] != png_libpng_ver[2]) || 547 (user_png_ver[0] == '0' && user_png_ver[2] < '9')) 548 { 549#if defined(PNG_STDIO_SUPPORTED) && !defined(_WIN32_WCE) 550 char msg[80]; 551 if (user_png_ver) 552 { 553 png_snprintf(msg, 80, 554 "Application was compiled with png.h from libpng-%.20s", 555 user_png_ver); 556 png_warning(png_ptr, msg); 557 } 558 png_snprintf(msg, 80, 559 "Application is running with png.c from libpng-%.20s", 560 png_libpng_ver); 561 png_warning(png_ptr, msg); 562#endif 563#ifdef PNG_ERROR_NUMBERS_SUPPORTED 564 png_ptr->flags = 0; 565#endif 566 png_error(png_ptr, 567 "Incompatible libpng version in application and library"); 568 } 569 } 570 571 /* Initialize zbuf - compression buffer */ 572 png_ptr->zbuf_size = PNG_ZBUF_SIZE; 573 png_ptr->zbuf = (png_bytep)png_malloc(png_ptr, 574 (png_uint_32)png_ptr->zbuf_size); 575 576 png_set_write_fn(png_ptr, png_voidp_NULL, png_rw_ptr_NULL, 577 png_flush_ptr_NULL); 578 579#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED 580 png_set_filter_heuristics(png_ptr, PNG_FILTER_HEURISTIC_DEFAULT, 581 1, png_doublep_NULL, png_doublep_NULL); 582#endif 583 584#ifdef PNG_SETJMP_SUPPORTED 585 /* Applications that neglect to set up their own setjmp() and then 586 * encounter a png_error() will longjmp here. Since the jmpbuf is 587 * then meaningless we abort instead of returning. 588 */ 589#ifdef USE_FAR_KEYWORD 590 if (setjmp(jmpbuf)) 591 PNG_ABORT(); 592 png_memcpy(png_ptr->jmpbuf, jmpbuf, png_sizeof(jmp_buf)); 593#else 594 if (setjmp(png_ptr->jmpbuf)) 595 PNG_ABORT(); 596#endif 597#endif 598 return (png_ptr); 599} 600 601/* Initialize png_ptr structure, and allocate any memory needed */ 602#if defined(PNG_1_0_X) || defined(PNG_1_2_X) 603/* Deprecated. */ 604#undef png_write_init 605void PNGAPI 606png_write_init(png_structp png_ptr) 607{ 608 /* We only come here via pre-1.0.7-compiled applications */ 609 png_write_init_2(png_ptr, "1.0.6 or earlier", 0, 0); 610} 611 612void PNGAPI 613png_write_init_2(png_structp png_ptr, png_const_charp user_png_ver, 614 png_size_t png_struct_size, png_size_t png_info_size) 615{ 616 /* We only come here via pre-1.0.12-compiled applications */ 617 if (png_ptr == NULL) return; 618#if defined(PNG_STDIO_SUPPORTED) && !defined(_WIN32_WCE) 619 if (png_sizeof(png_struct) > png_struct_size || 620 png_sizeof(png_info) > png_info_size) 621 { 622 char msg[80]; 623 png_ptr->warning_fn = NULL; 624 if (user_png_ver) 625 { 626 png_snprintf(msg, 80, 627 "Application was compiled with png.h from libpng-%.20s", 628 user_png_ver); 629 png_warning(png_ptr, msg); 630 } 631 png_snprintf(msg, 80, 632 "Application is running with png.c from libpng-%.20s", 633 png_libpng_ver); 634 png_warning(png_ptr, msg); 635 } 636#endif 637 if (png_sizeof(png_struct) > png_struct_size) 638 { 639 png_ptr->error_fn = NULL; 640#ifdef PNG_ERROR_NUMBERS_SUPPORTED 641 png_ptr->flags = 0; 642#endif 643 png_error(png_ptr, 644 "The png struct allocated by the application for writing is" 645 " too small."); 646 } 647 if (png_sizeof(png_info) > png_info_size) 648 { 649 png_ptr->error_fn = NULL; 650#ifdef PNG_ERROR_NUMBERS_SUPPORTED 651 png_ptr->flags = 0; 652#endif 653 png_error(png_ptr, 654 "The info struct allocated by the application for writing is" 655 " too small."); 656 } 657 png_write_init_3(&png_ptr, user_png_ver, png_struct_size); 658} 659#endif /* PNG_1_0_X || PNG_1_2_X */ 660 661 662void PNGAPI 663png_write_init_3(png_structpp ptr_ptr, png_const_charp user_png_ver, 664 png_size_t png_struct_size) 665{ 666 png_structp png_ptr = *ptr_ptr; 667#ifdef PNG_SETJMP_SUPPORTED 668 jmp_buf tmp_jmp; /* to save current jump buffer */ 669#endif 670 671 int i = 0; 672 673 if (png_ptr == NULL) 674 return; 675 676 do 677 { 678 if (user_png_ver[i] != png_libpng_ver[i]) 679 { 680#ifdef PNG_LEGACY_SUPPORTED 681 png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH; 682#else 683 png_ptr->warning_fn = NULL; 684 png_warning(png_ptr, 685 "Application uses deprecated png_write_init() and should be recompiled."); 686#endif 687 } 688 } while (png_libpng_ver[i++]); 689 690 png_debug(1, "in png_write_init_3"); 691 692#ifdef PNG_SETJMP_SUPPORTED 693 /* Save jump buffer and error functions */ 694 png_memcpy(tmp_jmp, png_ptr->jmpbuf, png_sizeof(jmp_buf)); 695#endif 696 697 if (png_sizeof(png_struct) > png_struct_size) 698 { 699 png_destroy_struct(png_ptr); 700 png_ptr = (png_structp)png_create_struct(PNG_STRUCT_PNG); 701 *ptr_ptr = png_ptr; 702 } 703 704 /* Reset all variables to 0 */ 705 png_memset(png_ptr, 0, png_sizeof(png_struct)); 706 707 /* Added at libpng-1.2.6 */ 708#ifdef PNG_SET_USER_LIMITS_SUPPORTED 709 png_ptr->user_width_max = PNG_USER_WIDTH_MAX; 710 png_ptr->user_height_max = PNG_USER_HEIGHT_MAX; 711#endif 712 713#ifdef PNG_SETJMP_SUPPORTED 714 /* Restore jump buffer */ 715 png_memcpy(png_ptr->jmpbuf, tmp_jmp, png_sizeof(jmp_buf)); 716#endif 717 718 png_set_write_fn(png_ptr, png_voidp_NULL, png_rw_ptr_NULL, 719 png_flush_ptr_NULL); 720 721 /* Initialize zbuf - compression buffer */ 722 png_ptr->zbuf_size = PNG_ZBUF_SIZE; 723 png_ptr->zbuf = (png_bytep)png_malloc(png_ptr, 724 (png_uint_32)png_ptr->zbuf_size); 725#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED 726 png_set_filter_heuristics(png_ptr, PNG_FILTER_HEURISTIC_DEFAULT, 727 1, png_doublep_NULL, png_doublep_NULL); 728#endif 729} 730 731/* Write a few rows of image data. If the image is interlaced, 732 * either you will have to write the 7 sub images, or, if you 733 * have called png_set_interlace_handling(), you will have to 734 * "write" the image seven times. 735 */ 736void PNGAPI 737png_write_rows(png_structp png_ptr, png_bytepp row, 738 png_uint_32 num_rows) 739{ 740 png_uint_32 i; /* row counter */ 741 png_bytepp rp; /* row pointer */ 742 743 png_debug(1, "in png_write_rows"); 744 745 if (png_ptr == NULL) 746 return; 747 748 /* Loop through the rows */ 749 for (i = 0, rp = row; i < num_rows; i++, rp++) 750 { 751 png_write_row(png_ptr, *rp); 752 } 753} 754 755/* Write the image. You only need to call this function once, even 756 * if you are writing an interlaced image. 757 */ 758void PNGAPI 759png_write_image(png_structp png_ptr, png_bytepp image) 760{ 761 png_uint_32 i; /* row index */ 762 int pass, num_pass; /* pass variables */ 763 png_bytepp rp; /* points to current row */ 764 765 if (png_ptr == NULL) 766 return; 767 768 png_debug(1, "in png_write_image"); 769 770#ifdef PNG_WRITE_INTERLACING_SUPPORTED 771 /* Initialize interlace handling. If image is not interlaced, 772 * this will set pass to 1 773 */ 774 num_pass = png_set_interlace_handling(png_ptr); 775#else 776 num_pass = 1; 777#endif 778 /* Loop through passes */ 779 for (pass = 0; pass < num_pass; pass++) 780 { 781 /* Loop through image */ 782 for (i = 0, rp = image; i < png_ptr->height; i++, rp++) 783 { 784 png_write_row(png_ptr, *rp); 785 } 786 } 787} 788 789/* Called by user to write a row of image data */ 790void PNGAPI 791png_write_row(png_structp png_ptr, png_bytep row) 792{ 793 if (png_ptr == NULL) 794 return; 795 796 png_debug2(1, "in png_write_row (row %ld, pass %d)", 797 png_ptr->row_number, png_ptr->pass); 798 799 /* Initialize transformations and other stuff if first time */ 800 if (png_ptr->row_number == 0 && png_ptr->pass == 0) 801 { 802 /* Make sure we wrote the header info */ 803 if (!(png_ptr->mode & PNG_WROTE_INFO_BEFORE_PLTE)) 804 png_error(png_ptr, 805 "png_write_info was never called before png_write_row."); 806 807 /* Check for transforms that have been set but were defined out */ 808#if !defined(PNG_WRITE_INVERT_SUPPORTED) && defined(PNG_READ_INVERT_SUPPORTED) 809 if (png_ptr->transformations & PNG_INVERT_MONO) 810 png_warning(png_ptr, 811 "PNG_WRITE_INVERT_SUPPORTED is not defined."); 812#endif 813#if !defined(PNG_WRITE_FILLER_SUPPORTED) && defined(PNG_READ_FILLER_SUPPORTED) 814 if (png_ptr->transformations & PNG_FILLER) 815 png_warning(png_ptr, 816 "PNG_WRITE_FILLER_SUPPORTED is not defined."); 817#endif 818#if !defined(PNG_WRITE_PACKSWAP_SUPPORTED) && \ 819 defined(PNG_READ_PACKSWAP_SUPPORTED) 820 if (png_ptr->transformations & PNG_PACKSWAP) 821 png_warning(png_ptr, 822 "PNG_WRITE_PACKSWAP_SUPPORTED is not defined."); 823#endif 824#if !defined(PNG_WRITE_PACK_SUPPORTED) && defined(PNG_READ_PACK_SUPPORTED) 825 if (png_ptr->transformations & PNG_PACK) 826 png_warning(png_ptr, "PNG_WRITE_PACK_SUPPORTED is not defined."); 827#endif 828#if !defined(PNG_WRITE_SHIFT_SUPPORTED) && defined(PNG_READ_SHIFT_SUPPORTED) 829 if (png_ptr->transformations & PNG_SHIFT) 830 png_warning(png_ptr, "PNG_WRITE_SHIFT_SUPPORTED is not defined."); 831#endif 832#if !defined(PNG_WRITE_BGR_SUPPORTED) && defined(PNG_READ_BGR_SUPPORTED) 833 if (png_ptr->transformations & PNG_BGR) 834 png_warning(png_ptr, "PNG_WRITE_BGR_SUPPORTED is not defined."); 835#endif 836#if !defined(PNG_WRITE_SWAP_SUPPORTED) && defined(PNG_READ_SWAP_SUPPORTED) 837 if (png_ptr->transformations & PNG_SWAP_BYTES) 838 png_warning(png_ptr, "PNG_WRITE_SWAP_SUPPORTED is not defined."); 839#endif 840 841 png_write_start_row(png_ptr); 842 } 843 844#ifdef PNG_WRITE_INTERLACING_SUPPORTED 845 /* If interlaced and not interested in row, return */ 846 if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE)) 847 { 848 switch (png_ptr->pass) 849 { 850 case 0: 851 if (png_ptr->row_number & 0x07) 852 { 853 png_write_finish_row(png_ptr); 854 return; 855 } 856 break; 857 case 1: 858 if ((png_ptr->row_number & 0x07) || png_ptr->width < 5) 859 { 860 png_write_finish_row(png_ptr); 861 return; 862 } 863 break; 864 case 2: 865 if ((png_ptr->row_number & 0x07) != 4) 866 { 867 png_write_finish_row(png_ptr); 868 return; 869 } 870 break; 871 case 3: 872 if ((png_ptr->row_number & 0x03) || png_ptr->width < 3) 873 { 874 png_write_finish_row(png_ptr); 875 return; 876 } 877 break; 878 case 4: 879 if ((png_ptr->row_number & 0x03) != 2) 880 { 881 png_write_finish_row(png_ptr); 882 return; 883 } 884 break; 885 case 5: 886 if ((png_ptr->row_number & 0x01) || png_ptr->width < 2) 887 { 888 png_write_finish_row(png_ptr); 889 return; 890 } 891 break; 892 case 6: 893 if (!(png_ptr->row_number & 0x01)) 894 { 895 png_write_finish_row(png_ptr); 896 return; 897 } 898 break; 899 } 900 } 901#endif 902 903 /* Set up row info for transformations */ 904 png_ptr->row_info.color_type = png_ptr->color_type; 905 png_ptr->row_info.width = png_ptr->usr_width; 906 png_ptr->row_info.channels = png_ptr->usr_channels; 907 png_ptr->row_info.bit_depth = png_ptr->usr_bit_depth; 908 png_ptr->row_info.pixel_depth = (png_byte)(png_ptr->row_info.bit_depth * 909 png_ptr->row_info.channels); 910 911 png_ptr->row_info.rowbytes = PNG_ROWBYTES(png_ptr->row_info.pixel_depth, 912 png_ptr->row_info.width); 913 914 png_debug1(3, "row_info->color_type = %d", png_ptr->row_info.color_type); 915 png_debug1(3, "row_info->width = %lu", png_ptr->row_info.width); 916 png_debug1(3, "row_info->channels = %d", png_ptr->row_info.channels); 917 png_debug1(3, "row_info->bit_depth = %d", png_ptr->row_info.bit_depth); 918 png_debug1(3, "row_info->pixel_depth = %d", png_ptr->row_info.pixel_depth); 919 png_debug1(3, "row_info->rowbytes = %lu", png_ptr->row_info.rowbytes); 920 921 /* Copy user's row into buffer, leaving room for filter byte. */ 922 png_memcpy_check(png_ptr, png_ptr->row_buf + 1, row, 923 png_ptr->row_info.rowbytes); 924 925#ifdef PNG_WRITE_INTERLACING_SUPPORTED 926 /* Handle interlacing */ 927 if (png_ptr->interlaced && png_ptr->pass < 6 && 928 (png_ptr->transformations & PNG_INTERLACE)) 929 { 930 png_do_write_interlace(&(png_ptr->row_info), 931 png_ptr->row_buf + 1, png_ptr->pass); 932 /* This should always get caught above, but still ... */ 933 if (!(png_ptr->row_info.width)) 934 { 935 png_write_finish_row(png_ptr); 936 return; 937 } 938 } 939#endif 940 941 /* Handle other transformations */ 942 if (png_ptr->transformations) 943 png_do_write_transformations(png_ptr); 944 945#ifdef PNG_MNG_FEATURES_SUPPORTED 946 /* Write filter_method 64 (intrapixel differencing) only if 947 * 1. Libpng was compiled with PNG_MNG_FEATURES_SUPPORTED and 948 * 2. Libpng did not write a PNG signature (this filter_method is only 949 * used in PNG datastreams that are embedded in MNG datastreams) and 950 * 3. The application called png_permit_mng_features with a mask that 951 * included PNG_FLAG_MNG_FILTER_64 and 952 * 4. The filter_method is 64 and 953 * 5. The color_type is RGB or RGBA 954 */ 955 if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) && 956 (png_ptr->filter_type == PNG_INTRAPIXEL_DIFFERENCING)) 957 { 958 /* Intrapixel differencing */ 959 png_do_write_intrapixel(&(png_ptr->row_info), png_ptr->row_buf + 1); 960 } 961#endif 962 963 /* Find a filter if necessary, filter the row and write it out. */ 964 png_write_find_filter(png_ptr, &(png_ptr->row_info)); 965 966 if (png_ptr->write_row_fn != NULL) 967 (*(png_ptr->write_row_fn))(png_ptr, png_ptr->row_number, png_ptr->pass); 968} 969 970#ifdef PNG_WRITE_FLUSH_SUPPORTED 971/* Set the automatic flush interval or 0 to turn flushing off */ 972void PNGAPI 973png_set_flush(png_structp png_ptr, int nrows) 974{ 975 png_debug(1, "in png_set_flush"); 976 977 if (png_ptr == NULL) 978 return; 979 png_ptr->flush_dist = (nrows < 0 ? 0 : nrows); 980} 981 982/* Flush the current output buffers now */ 983void PNGAPI 984png_write_flush(png_structp png_ptr) 985{ 986 int wrote_IDAT; 987 988 png_debug(1, "in png_write_flush"); 989 990 if (png_ptr == NULL) 991 return; 992 /* We have already written out all of the data */ 993 if (png_ptr->row_number >= png_ptr->num_rows) 994 return; 995 996 do 997 { 998 int ret; 999 1000 /* Compress the data */ 1001 ret = deflate(&png_ptr->zstream, Z_SYNC_FLUSH); 1002 wrote_IDAT = 0; 1003 1004 /* Check for compression errors */ 1005 if (ret != Z_OK) 1006 { 1007 if (png_ptr->zstream.msg != NULL) 1008 png_error(png_ptr, png_ptr->zstream.msg); 1009 else 1010 png_error(png_ptr, "zlib error"); 1011 } 1012 1013 if (!(png_ptr->zstream.avail_out)) 1014 { 1015 /* Write the IDAT and reset the zlib output buffer */ 1016 png_write_IDAT(png_ptr, png_ptr->zbuf, 1017 png_ptr->zbuf_size); 1018 png_ptr->zstream.next_out = png_ptr->zbuf; 1019 png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; 1020 wrote_IDAT = 1; 1021 } 1022 } while(wrote_IDAT == 1); 1023 1024 /* If there is any data left to be output, write it into a new IDAT */ 1025 if (png_ptr->zbuf_size != png_ptr->zstream.avail_out) 1026 { 1027 /* Write the IDAT and reset the zlib output buffer */ 1028 png_write_IDAT(png_ptr, png_ptr->zbuf, 1029 png_ptr->zbuf_size - png_ptr->zstream.avail_out); 1030 png_ptr->zstream.next_out = png_ptr->zbuf; 1031 png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; 1032 } 1033 png_ptr->flush_rows = 0; 1034 png_flush(png_ptr); 1035} 1036#endif /* PNG_WRITE_FLUSH_SUPPORTED */ 1037 1038/* Free all memory used by the write */ 1039void PNGAPI 1040png_destroy_write_struct(png_structpp png_ptr_ptr, png_infopp info_ptr_ptr) 1041{ 1042 png_structp png_ptr = NULL; 1043 png_infop info_ptr = NULL; 1044#ifdef PNG_USER_MEM_SUPPORTED 1045 png_free_ptr free_fn = NULL; 1046 png_voidp mem_ptr = NULL; 1047#endif 1048 1049 png_debug(1, "in png_destroy_write_struct"); 1050 1051 if (png_ptr_ptr != NULL) 1052 { 1053 png_ptr = *png_ptr_ptr; 1054#ifdef PNG_USER_MEM_SUPPORTED 1055 free_fn = png_ptr->free_fn; 1056 mem_ptr = png_ptr->mem_ptr; 1057#endif 1058 } 1059 1060#ifdef PNG_USER_MEM_SUPPORTED 1061 if (png_ptr != NULL) 1062 { 1063 free_fn = png_ptr->free_fn; 1064 mem_ptr = png_ptr->mem_ptr; 1065 } 1066#endif 1067 1068 if (info_ptr_ptr != NULL) 1069 info_ptr = *info_ptr_ptr; 1070 1071 if (info_ptr != NULL) 1072 { 1073 if (png_ptr != NULL) 1074 { 1075 png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1); 1076 1077#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED 1078 if (png_ptr->num_chunk_list) 1079 { 1080 png_free(png_ptr, png_ptr->chunk_list); 1081 png_ptr->chunk_list = NULL; 1082 png_ptr->num_chunk_list = 0; 1083 } 1084#endif 1085 } 1086 1087#ifdef PNG_USER_MEM_SUPPORTED 1088 png_destroy_struct_2((png_voidp)info_ptr, (png_free_ptr)free_fn, 1089 (png_voidp)mem_ptr); 1090#else 1091 png_destroy_struct((png_voidp)info_ptr); 1092#endif 1093 *info_ptr_ptr = NULL; 1094 } 1095 1096 if (png_ptr != NULL) 1097 { 1098 png_write_destroy(png_ptr); 1099#ifdef PNG_USER_MEM_SUPPORTED 1100 png_destroy_struct_2((png_voidp)png_ptr, (png_free_ptr)free_fn, 1101 (png_voidp)mem_ptr); 1102#else 1103 png_destroy_struct((png_voidp)png_ptr); 1104#endif 1105 *png_ptr_ptr = NULL; 1106 } 1107} 1108 1109 1110/* Free any memory used in png_ptr struct (old method) */ 1111void /* PRIVATE */ 1112png_write_destroy(png_structp png_ptr) 1113{ 1114#ifdef PNG_SETJMP_SUPPORTED 1115 jmp_buf tmp_jmp; /* Save jump buffer */ 1116#endif 1117 png_error_ptr error_fn; 1118 png_error_ptr warning_fn; 1119 png_voidp error_ptr; 1120#ifdef PNG_USER_MEM_SUPPORTED 1121 png_free_ptr free_fn; 1122#endif 1123 1124 png_debug(1, "in png_write_destroy"); 1125 1126 /* Free any memory zlib uses */ 1127 deflateEnd(&png_ptr->zstream); 1128 1129 /* Free our memory. png_free checks NULL for us. */ 1130 png_free(png_ptr, png_ptr->zbuf); 1131 png_free(png_ptr, png_ptr->row_buf); 1132#ifdef PNG_WRITE_FILTER_SUPPORTED 1133 png_free(png_ptr, png_ptr->prev_row); 1134 png_free(png_ptr, png_ptr->sub_row); 1135 png_free(png_ptr, png_ptr->up_row); 1136 png_free(png_ptr, png_ptr->avg_row); 1137 png_free(png_ptr, png_ptr->paeth_row); 1138#endif 1139 1140#ifdef PNG_TIME_RFC1123_SUPPORTED 1141 png_free(png_ptr, png_ptr->time_buffer); 1142#endif 1143 1144#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED 1145 png_free(png_ptr, png_ptr->prev_filters); 1146 png_free(png_ptr, png_ptr->filter_weights); 1147 png_free(png_ptr, png_ptr->inv_filter_weights); 1148 png_free(png_ptr, png_ptr->filter_costs); 1149 png_free(png_ptr, png_ptr->inv_filter_costs); 1150#endif 1151 1152#ifdef PNG_SETJMP_SUPPORTED 1153 /* Reset structure */ 1154 png_memcpy(tmp_jmp, png_ptr->jmpbuf, png_sizeof(jmp_buf)); 1155#endif 1156 1157 error_fn = png_ptr->error_fn; 1158 warning_fn = png_ptr->warning_fn; 1159 error_ptr = png_ptr->error_ptr; 1160#ifdef PNG_USER_MEM_SUPPORTED 1161 free_fn = png_ptr->free_fn; 1162#endif 1163 1164 png_memset(png_ptr, 0, png_sizeof(png_struct)); 1165 1166 png_ptr->error_fn = error_fn; 1167 png_ptr->warning_fn = warning_fn; 1168 png_ptr->error_ptr = error_ptr; 1169#ifdef PNG_USER_MEM_SUPPORTED 1170 png_ptr->free_fn = free_fn; 1171#endif 1172 1173#ifdef PNG_SETJMP_SUPPORTED 1174 png_memcpy(png_ptr->jmpbuf, tmp_jmp, png_sizeof(jmp_buf)); 1175#endif 1176} 1177 1178/* Allow the application to select one or more row filters to use. */ 1179void PNGAPI 1180png_set_filter(png_structp png_ptr, int method, int filters) 1181{ 1182 png_debug(1, "in png_set_filter"); 1183 1184 if (png_ptr == NULL) 1185 return; 1186#ifdef PNG_MNG_FEATURES_SUPPORTED 1187 if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) && 1188 (method == PNG_INTRAPIXEL_DIFFERENCING)) 1189 method = PNG_FILTER_TYPE_BASE; 1190#endif 1191 if (method == PNG_FILTER_TYPE_BASE) 1192 { 1193 switch (filters & (PNG_ALL_FILTERS | 0x07)) 1194 { 1195#ifdef PNG_WRITE_FILTER_SUPPORTED 1196 case 5: 1197 case 6: 1198 case 7: png_warning(png_ptr, "Unknown row filter for method 0"); 1199#endif /* PNG_WRITE_FILTER_SUPPORTED */ 1200 case PNG_FILTER_VALUE_NONE: 1201 png_ptr->do_filter = PNG_FILTER_NONE; break; 1202#ifdef PNG_WRITE_FILTER_SUPPORTED 1203 case PNG_FILTER_VALUE_SUB: 1204 png_ptr->do_filter = PNG_FILTER_SUB; break; 1205 case PNG_FILTER_VALUE_UP: 1206 png_ptr->do_filter = PNG_FILTER_UP; break; 1207 case PNG_FILTER_VALUE_AVG: 1208 png_ptr->do_filter = PNG_FILTER_AVG; break; 1209 case PNG_FILTER_VALUE_PAETH: 1210 png_ptr->do_filter = PNG_FILTER_PAETH; break; 1211 default: png_ptr->do_filter = (png_byte)filters; break; 1212#else 1213 default: png_warning(png_ptr, "Unknown row filter for method 0"); 1214#endif /* PNG_WRITE_FILTER_SUPPORTED */ 1215 } 1216 1217 /* If we have allocated the row_buf, this means we have already started 1218 * with the image and we should have allocated all of the filter buffers 1219 * that have been selected. If prev_row isn't already allocated, then 1220 * it is too late to start using the filters that need it, since we 1221 * will be missing the data in the previous row. If an application 1222 * wants to start and stop using particular filters during compression, 1223 * it should start out with all of the filters, and then add and 1224 * remove them after the start of compression. 1225 */ 1226 if (png_ptr->row_buf != NULL) 1227 { 1228#ifdef PNG_WRITE_FILTER_SUPPORTED 1229 if ((png_ptr->do_filter & PNG_FILTER_SUB) && png_ptr->sub_row == NULL) 1230 { 1231 png_ptr->sub_row = (png_bytep)png_malloc(png_ptr, 1232 (png_ptr->rowbytes + 1)); 1233 png_ptr->sub_row[0] = PNG_FILTER_VALUE_SUB; 1234 } 1235 1236 if ((png_ptr->do_filter & PNG_FILTER_UP) && png_ptr->up_row == NULL) 1237 { 1238 if (png_ptr->prev_row == NULL) 1239 { 1240 png_warning(png_ptr, "Can't add Up filter after starting"); 1241 png_ptr->do_filter &= ~PNG_FILTER_UP; 1242 } 1243 else 1244 { 1245 png_ptr->up_row = (png_bytep)png_malloc(png_ptr, 1246 (png_ptr->rowbytes + 1)); 1247 png_ptr->up_row[0] = PNG_FILTER_VALUE_UP; 1248 } 1249 } 1250 1251 if ((png_ptr->do_filter & PNG_FILTER_AVG) && png_ptr->avg_row == NULL) 1252 { 1253 if (png_ptr->prev_row == NULL) 1254 { 1255 png_warning(png_ptr, "Can't add Average filter after starting"); 1256 png_ptr->do_filter &= ~PNG_FILTER_AVG; 1257 } 1258 else 1259 { 1260 png_ptr->avg_row = (png_bytep)png_malloc(png_ptr, 1261 (png_ptr->rowbytes + 1)); 1262 png_ptr->avg_row[0] = PNG_FILTER_VALUE_AVG; 1263 } 1264 } 1265 1266 if ((png_ptr->do_filter & PNG_FILTER_PAETH) && 1267 png_ptr->paeth_row == NULL) 1268 { 1269 if (png_ptr->prev_row == NULL) 1270 { 1271 png_warning(png_ptr, "Can't add Paeth filter after starting"); 1272 png_ptr->do_filter &= (png_byte)(~PNG_FILTER_PAETH); 1273 } 1274 else 1275 { 1276 png_ptr->paeth_row = (png_bytep)png_malloc(png_ptr, 1277 (png_ptr->rowbytes + 1)); 1278 png_ptr->paeth_row[0] = PNG_FILTER_VALUE_PAETH; 1279 } 1280 } 1281 1282 if (png_ptr->do_filter == PNG_NO_FILTERS) 1283#endif /* PNG_WRITE_FILTER_SUPPORTED */ 1284 png_ptr->do_filter = PNG_FILTER_NONE; 1285 } 1286 } 1287 else 1288 png_error(png_ptr, "Unknown custom filter method"); 1289} 1290 1291/* This allows us to influence the way in which libpng chooses the "best" 1292 * filter for the current scanline. While the "minimum-sum-of-absolute- 1293 * differences metric is relatively fast and effective, there is some 1294 * question as to whether it can be improved upon by trying to keep the 1295 * filtered data going to zlib more consistent, hopefully resulting in 1296 * better compression. 1297 */ 1298#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED /* GRR 970116 */ 1299void PNGAPI 1300png_set_filter_heuristics(png_structp png_ptr, int heuristic_method, 1301 int num_weights, png_doublep filter_weights, 1302 png_doublep filter_costs) 1303{ 1304 int i; 1305 1306 png_debug(1, "in png_set_filter_heuristics"); 1307 1308 if (png_ptr == NULL) 1309 return; 1310 if (heuristic_method >= PNG_FILTER_HEURISTIC_LAST) 1311 { 1312 png_warning(png_ptr, "Unknown filter heuristic method"); 1313 return; 1314 } 1315 1316 if (heuristic_method == PNG_FILTER_HEURISTIC_DEFAULT) 1317 { 1318 heuristic_method = PNG_FILTER_HEURISTIC_UNWEIGHTED; 1319 } 1320 1321 if (num_weights < 0 || filter_weights == NULL || 1322 heuristic_method == PNG_FILTER_HEURISTIC_UNWEIGHTED) 1323 { 1324 num_weights = 0; 1325 } 1326 1327 png_ptr->num_prev_filters = (png_byte)num_weights; 1328 png_ptr->heuristic_method = (png_byte)heuristic_method; 1329 1330 if (num_weights > 0) 1331 { 1332 if (png_ptr->prev_filters == NULL) 1333 { 1334 png_ptr->prev_filters = (png_bytep)png_malloc(png_ptr, 1335 (png_uint_32)(png_sizeof(png_byte) * num_weights)); 1336 1337 /* To make sure that the weighting starts out fairly */ 1338 for (i = 0; i < num_weights; i++) 1339 { 1340 png_ptr->prev_filters[i] = 255; 1341 } 1342 } 1343 1344 if (png_ptr->filter_weights == NULL) 1345 { 1346 png_ptr->filter_weights = (png_uint_16p)png_malloc(png_ptr, 1347 (png_uint_32)(png_sizeof(png_uint_16) * num_weights)); 1348 1349 png_ptr->inv_filter_weights = (png_uint_16p)png_malloc(png_ptr, 1350 (png_uint_32)(png_sizeof(png_uint_16) * num_weights)); 1351 for (i = 0; i < num_weights; i++) 1352 { 1353 png_ptr->inv_filter_weights[i] = 1354 png_ptr->filter_weights[i] = PNG_WEIGHT_FACTOR; 1355 } 1356 } 1357 1358 for (i = 0; i < num_weights; i++) 1359 { 1360 if (filter_weights[i] < 0.0) 1361 { 1362 png_ptr->inv_filter_weights[i] = 1363 png_ptr->filter_weights[i] = PNG_WEIGHT_FACTOR; 1364 } 1365 else 1366 { 1367 png_ptr->inv_filter_weights[i] = 1368 (png_uint_16)((double)PNG_WEIGHT_FACTOR*filter_weights[i]+0.5); 1369 png_ptr->filter_weights[i] = 1370 (png_uint_16)((double)PNG_WEIGHT_FACTOR/filter_weights[i]+0.5); 1371 } 1372 } 1373 } 1374 1375 /* If, in the future, there are other filter methods, this would 1376 * need to be based on png_ptr->filter. 1377 */ 1378 if (png_ptr->filter_costs == NULL) 1379 { 1380 png_ptr->filter_costs = (png_uint_16p)png_malloc(png_ptr, 1381 (png_uint_32)(png_sizeof(png_uint_16) * PNG_FILTER_VALUE_LAST)); 1382 1383 png_ptr->inv_filter_costs = (png_uint_16p)png_malloc(png_ptr, 1384 (png_uint_32)(png_sizeof(png_uint_16) * PNG_FILTER_VALUE_LAST)); 1385 1386 for (i = 0; i < PNG_FILTER_VALUE_LAST; i++) 1387 { 1388 png_ptr->inv_filter_costs[i] = 1389 png_ptr->filter_costs[i] = PNG_COST_FACTOR; 1390 } 1391 } 1392 1393 /* Here is where we set the relative costs of the different filters. We 1394 * should take the desired compression level into account when setting 1395 * the costs, so that Paeth, for instance, has a high relative cost at low 1396 * compression levels, while it has a lower relative cost at higher 1397 * compression settings. The filter types are in order of increasing 1398 * relative cost, so it would be possible to do this with an algorithm. 1399 */ 1400 for (i = 0; i < PNG_FILTER_VALUE_LAST; i++) 1401 { 1402 if (filter_costs == NULL || filter_costs[i] < 0.0) 1403 { 1404 png_ptr->inv_filter_costs[i] = 1405 png_ptr->filter_costs[i] = PNG_COST_FACTOR; 1406 } 1407 else if (filter_costs[i] >= 1.0) 1408 { 1409 png_ptr->inv_filter_costs[i] = 1410 (png_uint_16)((double)PNG_COST_FACTOR / filter_costs[i] + 0.5); 1411 png_ptr->filter_costs[i] = 1412 (png_uint_16)((double)PNG_COST_FACTOR * filter_costs[i] + 0.5); 1413 } 1414 } 1415} 1416#endif /* PNG_WRITE_WEIGHTED_FILTER_SUPPORTED */ 1417 1418void PNGAPI 1419png_set_compression_level(png_structp png_ptr, int level) 1420{ 1421 png_debug(1, "in png_set_compression_level"); 1422 1423 if (png_ptr == NULL) 1424 return; 1425 png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_LEVEL; 1426 png_ptr->zlib_level = level; 1427} 1428 1429void PNGAPI 1430png_set_compression_mem_level(png_structp png_ptr, int mem_level) 1431{ 1432 png_debug(1, "in png_set_compression_mem_level"); 1433 1434 if (png_ptr == NULL) 1435 return; 1436 png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_MEM_LEVEL; 1437 png_ptr->zlib_mem_level = mem_level; 1438} 1439 1440void PNGAPI 1441png_set_compression_strategy(png_structp png_ptr, int strategy) 1442{ 1443 png_debug(1, "in png_set_compression_strategy"); 1444 1445 if (png_ptr == NULL) 1446 return; 1447 png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_STRATEGY; 1448 png_ptr->zlib_strategy = strategy; 1449} 1450 1451void PNGAPI 1452png_set_compression_window_bits(png_structp png_ptr, int window_bits) 1453{ 1454 if (png_ptr == NULL) 1455 return; 1456 if (window_bits > 15) 1457 png_warning(png_ptr, "Only compression windows <= 32k supported by PNG"); 1458 else if (window_bits < 8) 1459 png_warning(png_ptr, "Only compression windows >= 256 supported by PNG"); 1460#ifndef WBITS_8_OK 1461 /* Avoid libpng bug with 256-byte windows */ 1462 if (window_bits == 8) 1463 { 1464 png_warning(png_ptr, "Compression window is being reset to 512"); 1465 window_bits = 9; 1466 } 1467#endif 1468 png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_WINDOW_BITS; 1469 png_ptr->zlib_window_bits = window_bits; 1470} 1471 1472void PNGAPI 1473png_set_compression_method(png_structp png_ptr, int method) 1474{ 1475 png_debug(1, "in png_set_compression_method"); 1476 1477 if (png_ptr == NULL) 1478 return; 1479 if (method != 8) 1480 png_warning(png_ptr, "Only compression method 8 is supported by PNG"); 1481 png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_METHOD; 1482 png_ptr->zlib_method = method; 1483} 1484 1485void PNGAPI 1486png_set_write_status_fn(png_structp png_ptr, png_write_status_ptr write_row_fn) 1487{ 1488 if (png_ptr == NULL) 1489 return; 1490 png_ptr->write_row_fn = write_row_fn; 1491} 1492 1493#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED 1494void PNGAPI 1495png_set_write_user_transform_fn(png_structp png_ptr, png_user_transform_ptr 1496 write_user_transform_fn) 1497{ 1498 png_debug(1, "in png_set_write_user_transform_fn"); 1499 1500 if (png_ptr == NULL) 1501 return; 1502 png_ptr->transformations |= PNG_USER_TRANSFORM; 1503 png_ptr->write_user_transform_fn = write_user_transform_fn; 1504} 1505#endif 1506 1507 1508#ifdef PNG_INFO_IMAGE_SUPPORTED 1509void PNGAPI 1510png_write_png(png_structp png_ptr, png_infop info_ptr, 1511 int transforms, voidp params) 1512{ 1513 if (png_ptr == NULL || info_ptr == NULL) 1514 return; 1515 1516 /* Write the file header information. */ 1517 png_write_info(png_ptr, info_ptr); 1518 1519 /* ------ these transformations don't touch the info structure ------- */ 1520 1521#ifdef PNG_WRITE_INVERT_SUPPORTED 1522 /* Invert monochrome pixels */ 1523 if (transforms & PNG_TRANSFORM_INVERT_MONO) 1524 png_set_invert_mono(png_ptr); 1525#endif 1526 1527#ifdef PNG_WRITE_SHIFT_SUPPORTED 1528 /* Shift the pixels up to a legal bit depth and fill in 1529 * as appropriate to correctly scale the image. 1530 */ 1531 if ((transforms & PNG_TRANSFORM_SHIFT) 1532 && (info_ptr->valid & PNG_INFO_sBIT)) 1533 png_set_shift(png_ptr, &info_ptr->sig_bit); 1534#endif 1535 1536#ifdef PNG_WRITE_PACK_SUPPORTED 1537 /* Pack pixels into bytes */ 1538 if (transforms & PNG_TRANSFORM_PACKING) 1539 png_set_packing(png_ptr); 1540#endif 1541 1542#ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED 1543 /* Swap location of alpha bytes from ARGB to RGBA */ 1544 if (transforms & PNG_TRANSFORM_SWAP_ALPHA) 1545 png_set_swap_alpha(png_ptr); 1546#endif 1547 1548#ifdef PNG_WRITE_FILLER_SUPPORTED 1549 /* Pack XRGB/RGBX/ARGB/RGBA into * RGB (4 channels -> 3 channels) */ 1550 if (transforms & PNG_TRANSFORM_STRIP_FILLER_AFTER) 1551 png_set_filler(png_ptr, 0, PNG_FILLER_AFTER); 1552 else if (transforms & PNG_TRANSFORM_STRIP_FILLER_BEFORE) 1553 png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE); 1554#endif 1555 1556#ifdef PNG_WRITE_BGR_SUPPORTED 1557 /* Flip BGR pixels to RGB */ 1558 if (transforms & PNG_TRANSFORM_BGR) 1559 png_set_bgr(png_ptr); 1560#endif 1561 1562#ifdef PNG_WRITE_SWAP_SUPPORTED 1563 /* Swap bytes of 16-bit files to most significant byte first */ 1564 if (transforms & PNG_TRANSFORM_SWAP_ENDIAN) 1565 png_set_swap(png_ptr); 1566#endif 1567 1568#ifdef PNG_WRITE_PACKSWAP_SUPPORTED 1569 /* Swap bits of 1, 2, 4 bit packed pixel formats */ 1570 if (transforms & PNG_TRANSFORM_PACKSWAP) 1571 png_set_packswap(png_ptr); 1572#endif 1573 1574#ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED 1575 /* Invert the alpha channel from opacity to transparency */ 1576 if (transforms & PNG_TRANSFORM_INVERT_ALPHA) 1577 png_set_invert_alpha(png_ptr); 1578#endif 1579 1580 /* ----------------------- end of transformations ------------------- */ 1581 1582 /* Write the bits */ 1583 if (info_ptr->valid & PNG_INFO_IDAT) 1584 png_write_image(png_ptr, info_ptr->row_pointers); 1585 1586 /* It is REQUIRED to call this to finish writing the rest of the file */ 1587 png_write_end(png_ptr, info_ptr); 1588 1589 transforms = transforms; /* Quiet compiler warnings */ 1590 params = params; 1591} 1592#endif 1593#endif /* PNG_WRITE_SUPPORTED */ 1594