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