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