pngwutil.c revision 0640679f04398a7d06319d5c47b0f71bf82854a0
1 2/* pngwutil.c - utilities to write a PNG file 3 * 4 * Last changed in libpng 1.2.27 [April 29, 2008] 5 * For conditions of distribution and use, see copyright notice in png.h 6 * Copyright (c) 1998-2008 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#define PNG_INTERNAL 12#include "png.h" 13#ifdef PNG_WRITE_SUPPORTED 14 15/* Place a 32-bit number into a buffer in PNG byte order. We work 16 * with unsigned numbers for convenience, although one supported 17 * ancillary chunk uses signed (two's complement) numbers. 18 */ 19void PNGAPI 20png_save_uint_32(png_bytep buf, png_uint_32 i) 21{ 22 buf[0] = (png_byte)((i >> 24) & 0xff); 23 buf[1] = (png_byte)((i >> 16) & 0xff); 24 buf[2] = (png_byte)((i >> 8) & 0xff); 25 buf[3] = (png_byte)(i & 0xff); 26} 27 28/* The png_save_int_32 function assumes integers are stored in two's 29 * complement format. If this isn't the case, then this routine needs to 30 * be modified to write data in two's complement format. 31 */ 32void PNGAPI 33png_save_int_32(png_bytep buf, png_int_32 i) 34{ 35 buf[0] = (png_byte)((i >> 24) & 0xff); 36 buf[1] = (png_byte)((i >> 16) & 0xff); 37 buf[2] = (png_byte)((i >> 8) & 0xff); 38 buf[3] = (png_byte)(i & 0xff); 39} 40 41/* Place a 16-bit number into a buffer in PNG byte order. 42 * The parameter is declared unsigned int, not png_uint_16, 43 * just to avoid potential problems on pre-ANSI C compilers. 44 */ 45void PNGAPI 46png_save_uint_16(png_bytep buf, unsigned int i) 47{ 48 buf[0] = (png_byte)((i >> 8) & 0xff); 49 buf[1] = (png_byte)(i & 0xff); 50} 51 52/* Write a PNG chunk all at once. The type is an array of ASCII characters 53 * representing the chunk name. The array must be at least 4 bytes in 54 * length, and does not need to be null terminated. To be safe, pass the 55 * pre-defined chunk names here, and if you need a new one, define it 56 * where the others are defined. The length is the length of the data. 57 * All the data must be present. If that is not possible, use the 58 * png_write_chunk_start(), png_write_chunk_data(), and png_write_chunk_end() 59 * functions instead. 60 */ 61void PNGAPI 62png_write_chunk(png_structp png_ptr, png_bytep chunk_name, 63 png_bytep data, png_size_t length) 64{ 65 if(png_ptr == NULL) return; 66 png_write_chunk_start(png_ptr, chunk_name, (png_uint_32)length); 67 png_write_chunk_data(png_ptr, data, length); 68 png_write_chunk_end(png_ptr); 69} 70 71/* Write the start of a PNG chunk. The type is the chunk type. 72 * The total_length is the sum of the lengths of all the data you will be 73 * passing in png_write_chunk_data(). 74 */ 75void PNGAPI 76png_write_chunk_start(png_structp png_ptr, png_bytep chunk_name, 77 png_uint_32 length) 78{ 79 png_byte buf[4]; 80 png_debug2(0, "Writing %s chunk (%lu bytes)\n", chunk_name, length); 81 if(png_ptr == NULL) return; 82 83 /* write the length */ 84 png_save_uint_32(buf, length); 85 png_write_data(png_ptr, buf, (png_size_t)4); 86 87 /* write the chunk name */ 88 png_write_data(png_ptr, chunk_name, (png_size_t)4); 89 /* reset the crc and run it over the chunk name */ 90 png_reset_crc(png_ptr); 91 png_calculate_crc(png_ptr, chunk_name, (png_size_t)4); 92} 93 94/* Write the data of a PNG chunk started with png_write_chunk_start(). 95 * Note that multiple calls to this function are allowed, and that the 96 * sum of the lengths from these calls *must* add up to the total_length 97 * given to png_write_chunk_start(). 98 */ 99void PNGAPI 100png_write_chunk_data(png_structp png_ptr, png_bytep data, png_size_t length) 101{ 102 /* write the data, and run the CRC over it */ 103 if(png_ptr == NULL) return; 104 if (data != NULL && length > 0) 105 { 106 png_calculate_crc(png_ptr, data, length); 107 png_write_data(png_ptr, data, length); 108 } 109} 110 111/* Finish a chunk started with png_write_chunk_start(). */ 112void PNGAPI 113png_write_chunk_end(png_structp png_ptr) 114{ 115 png_byte buf[4]; 116 117 if(png_ptr == NULL) return; 118 119 /* write the crc */ 120 png_save_uint_32(buf, png_ptr->crc); 121 122 png_write_data(png_ptr, buf, (png_size_t)4); 123} 124 125/* Simple function to write the signature. If we have already written 126 * the magic bytes of the signature, or more likely, the PNG stream is 127 * being embedded into another stream and doesn't need its own signature, 128 * we should call png_set_sig_bytes() to tell libpng how many of the 129 * bytes have already been written. 130 */ 131void /* PRIVATE */ 132png_write_sig(png_structp png_ptr) 133{ 134 png_byte png_signature[8] = {137, 80, 78, 71, 13, 10, 26, 10}; 135 /* write the rest of the 8 byte signature */ 136 png_write_data(png_ptr, &png_signature[png_ptr->sig_bytes], 137 (png_size_t)8 - png_ptr->sig_bytes); 138 if(png_ptr->sig_bytes < 3) 139 png_ptr->mode |= PNG_HAVE_PNG_SIGNATURE; 140} 141 142#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_iCCP_SUPPORTED) 143/* 144 * This pair of functions encapsulates the operation of (a) compressing a 145 * text string, and (b) issuing it later as a series of chunk data writes. 146 * The compression_state structure is shared context for these functions 147 * set up by the caller in order to make the whole mess thread-safe. 148 */ 149 150typedef struct 151{ 152 char *input; /* the uncompressed input data */ 153 int input_len; /* its length */ 154 int num_output_ptr; /* number of output pointers used */ 155 int max_output_ptr; /* size of output_ptr */ 156 png_charpp output_ptr; /* array of pointers to output */ 157} compression_state; 158 159/* compress given text into storage in the png_ptr structure */ 160static int /* PRIVATE */ 161png_text_compress(png_structp png_ptr, 162 png_charp text, png_size_t text_len, int compression, 163 compression_state *comp) 164{ 165 int ret; 166 167 comp->num_output_ptr = 0; 168 comp->max_output_ptr = 0; 169 comp->output_ptr = NULL; 170 comp->input = NULL; 171 comp->input_len = 0; 172 173 /* we may just want to pass the text right through */ 174 if (compression == PNG_TEXT_COMPRESSION_NONE) 175 { 176 comp->input = text; 177 comp->input_len = text_len; 178 return((int)text_len); 179 } 180 181 if (compression >= PNG_TEXT_COMPRESSION_LAST) 182 { 183#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE) 184 char msg[50]; 185 png_snprintf(msg, 50, "Unknown compression type %d", compression); 186 png_warning(png_ptr, msg); 187#else 188 png_warning(png_ptr, "Unknown compression type"); 189#endif 190 } 191 192 /* We can't write the chunk until we find out how much data we have, 193 * which means we need to run the compressor first and save the 194 * output. This shouldn't be a problem, as the vast majority of 195 * comments should be reasonable, but we will set up an array of 196 * malloc'd pointers to be sure. 197 * 198 * If we knew the application was well behaved, we could simplify this 199 * greatly by assuming we can always malloc an output buffer large 200 * enough to hold the compressed text ((1001 * text_len / 1000) + 12) 201 * and malloc this directly. The only time this would be a bad idea is 202 * if we can't malloc more than 64K and we have 64K of random input 203 * data, or if the input string is incredibly large (although this 204 * wouldn't cause a failure, just a slowdown due to swapping). 205 */ 206 207 /* set up the compression buffers */ 208 png_ptr->zstream.avail_in = (uInt)text_len; 209 png_ptr->zstream.next_in = (Bytef *)text; 210 png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; 211 png_ptr->zstream.next_out = (Bytef *)png_ptr->zbuf; 212 213 /* this is the same compression loop as in png_write_row() */ 214 do 215 { 216 /* compress the data */ 217 ret = deflate(&png_ptr->zstream, Z_NO_FLUSH); 218 if (ret != Z_OK) 219 { 220 /* error */ 221 if (png_ptr->zstream.msg != NULL) 222 png_error(png_ptr, png_ptr->zstream.msg); 223 else 224 png_error(png_ptr, "zlib error"); 225 } 226 /* check to see if we need more room */ 227 if (!(png_ptr->zstream.avail_out)) 228 { 229 /* make sure the output array has room */ 230 if (comp->num_output_ptr >= comp->max_output_ptr) 231 { 232 int old_max; 233 234 old_max = comp->max_output_ptr; 235 comp->max_output_ptr = comp->num_output_ptr + 4; 236 if (comp->output_ptr != NULL) 237 { 238 png_charpp old_ptr; 239 240 old_ptr = comp->output_ptr; 241 comp->output_ptr = (png_charpp)png_malloc(png_ptr, 242 (png_uint_32)(comp->max_output_ptr * 243 png_sizeof (png_charpp))); 244 png_memcpy(comp->output_ptr, old_ptr, old_max 245 * png_sizeof (png_charp)); 246 png_free(png_ptr, old_ptr); 247 } 248 else 249 comp->output_ptr = (png_charpp)png_malloc(png_ptr, 250 (png_uint_32)(comp->max_output_ptr * 251 png_sizeof (png_charp))); 252 } 253 254 /* save the data */ 255 comp->output_ptr[comp->num_output_ptr] = (png_charp)png_malloc(png_ptr, 256 (png_uint_32)png_ptr->zbuf_size); 257 png_memcpy(comp->output_ptr[comp->num_output_ptr], png_ptr->zbuf, 258 png_ptr->zbuf_size); 259 comp->num_output_ptr++; 260 261 /* and reset the buffer */ 262 png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; 263 png_ptr->zstream.next_out = png_ptr->zbuf; 264 } 265 /* continue until we don't have any more to compress */ 266 } while (png_ptr->zstream.avail_in); 267 268 /* finish the compression */ 269 do 270 { 271 /* tell zlib we are finished */ 272 ret = deflate(&png_ptr->zstream, Z_FINISH); 273 274 if (ret == Z_OK) 275 { 276 /* check to see if we need more room */ 277 if (!(png_ptr->zstream.avail_out)) 278 { 279 /* check to make sure our output array has room */ 280 if (comp->num_output_ptr >= comp->max_output_ptr) 281 { 282 int old_max; 283 284 old_max = comp->max_output_ptr; 285 comp->max_output_ptr = comp->num_output_ptr + 4; 286 if (comp->output_ptr != NULL) 287 { 288 png_charpp old_ptr; 289 290 old_ptr = comp->output_ptr; 291 /* This could be optimized to realloc() */ 292 comp->output_ptr = (png_charpp)png_malloc(png_ptr, 293 (png_uint_32)(comp->max_output_ptr * 294 png_sizeof (png_charpp))); 295 png_memcpy(comp->output_ptr, old_ptr, 296 old_max * png_sizeof (png_charp)); 297 png_free(png_ptr, old_ptr); 298 } 299 else 300 comp->output_ptr = (png_charpp)png_malloc(png_ptr, 301 (png_uint_32)(comp->max_output_ptr * 302 png_sizeof (png_charp))); 303 } 304 305 /* save off the data */ 306 comp->output_ptr[comp->num_output_ptr] = 307 (png_charp)png_malloc(png_ptr, (png_uint_32)png_ptr->zbuf_size); 308 png_memcpy(comp->output_ptr[comp->num_output_ptr], png_ptr->zbuf, 309 png_ptr->zbuf_size); 310 comp->num_output_ptr++; 311 312 /* and reset the buffer pointers */ 313 png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; 314 png_ptr->zstream.next_out = png_ptr->zbuf; 315 } 316 } 317 else if (ret != Z_STREAM_END) 318 { 319 /* we got an error */ 320 if (png_ptr->zstream.msg != NULL) 321 png_error(png_ptr, png_ptr->zstream.msg); 322 else 323 png_error(png_ptr, "zlib error"); 324 } 325 } while (ret != Z_STREAM_END); 326 327 /* text length is number of buffers plus last buffer */ 328 text_len = png_ptr->zbuf_size * comp->num_output_ptr; 329 if (png_ptr->zstream.avail_out < png_ptr->zbuf_size) 330 text_len += png_ptr->zbuf_size - (png_size_t)png_ptr->zstream.avail_out; 331 332 return((int)text_len); 333} 334 335/* ship the compressed text out via chunk writes */ 336static void /* PRIVATE */ 337png_write_compressed_data_out(png_structp png_ptr, compression_state *comp) 338{ 339 int i; 340 341 /* handle the no-compression case */ 342 if (comp->input) 343 { 344 png_write_chunk_data(png_ptr, (png_bytep)comp->input, 345 (png_size_t)comp->input_len); 346 return; 347 } 348 349 /* write saved output buffers, if any */ 350 for (i = 0; i < comp->num_output_ptr; i++) 351 { 352 png_write_chunk_data(png_ptr,(png_bytep)comp->output_ptr[i], 353 png_ptr->zbuf_size); 354 png_free(png_ptr, comp->output_ptr[i]); 355 comp->output_ptr[i]=NULL; 356 } 357 if (comp->max_output_ptr != 0) 358 png_free(png_ptr, comp->output_ptr); 359 comp->output_ptr=NULL; 360 /* write anything left in zbuf */ 361 if (png_ptr->zstream.avail_out < (png_uint_32)png_ptr->zbuf_size) 362 png_write_chunk_data(png_ptr, png_ptr->zbuf, 363 png_ptr->zbuf_size - png_ptr->zstream.avail_out); 364 365 /* reset zlib for another zTXt/iTXt or image data */ 366 deflateReset(&png_ptr->zstream); 367 png_ptr->zstream.data_type = Z_BINARY; 368} 369#endif 370 371/* Write the IHDR chunk, and update the png_struct with the necessary 372 * information. Note that the rest of this code depends upon this 373 * information being correct. 374 */ 375void /* PRIVATE */ 376png_write_IHDR(png_structp png_ptr, png_uint_32 width, png_uint_32 height, 377 int bit_depth, int color_type, int compression_type, int filter_type, 378 int interlace_type) 379{ 380#ifdef PNG_USE_LOCAL_ARRAYS 381 PNG_IHDR; 382#endif 383 int ret; 384 385 png_byte buf[13]; /* buffer to store the IHDR info */ 386 387 png_debug(1, "in png_write_IHDR\n"); 388 /* Check that we have valid input data from the application info */ 389 switch (color_type) 390 { 391 case PNG_COLOR_TYPE_GRAY: 392 switch (bit_depth) 393 { 394 case 1: 395 case 2: 396 case 4: 397 case 8: 398 case 16: png_ptr->channels = 1; break; 399 default: png_error(png_ptr,"Invalid bit depth for grayscale image"); 400 } 401 break; 402 case PNG_COLOR_TYPE_RGB: 403 if (bit_depth != 8 && bit_depth != 16) 404 png_error(png_ptr, "Invalid bit depth for RGB image"); 405 png_ptr->channels = 3; 406 break; 407 case PNG_COLOR_TYPE_PALETTE: 408 switch (bit_depth) 409 { 410 case 1: 411 case 2: 412 case 4: 413 case 8: png_ptr->channels = 1; break; 414 default: png_error(png_ptr, "Invalid bit depth for paletted image"); 415 } 416 break; 417 case PNG_COLOR_TYPE_GRAY_ALPHA: 418 if (bit_depth != 8 && bit_depth != 16) 419 png_error(png_ptr, "Invalid bit depth for grayscale+alpha image"); 420 png_ptr->channels = 2; 421 break; 422 case PNG_COLOR_TYPE_RGB_ALPHA: 423 if (bit_depth != 8 && bit_depth != 16) 424 png_error(png_ptr, "Invalid bit depth for RGBA image"); 425 png_ptr->channels = 4; 426 break; 427 default: 428 png_error(png_ptr, "Invalid image color type specified"); 429 } 430 431 if (compression_type != PNG_COMPRESSION_TYPE_BASE) 432 { 433 png_warning(png_ptr, "Invalid compression type specified"); 434 compression_type = PNG_COMPRESSION_TYPE_BASE; 435 } 436 437 /* Write filter_method 64 (intrapixel differencing) only if 438 * 1. Libpng was compiled with PNG_MNG_FEATURES_SUPPORTED and 439 * 2. Libpng did not write a PNG signature (this filter_method is only 440 * used in PNG datastreams that are embedded in MNG datastreams) and 441 * 3. The application called png_permit_mng_features with a mask that 442 * included PNG_FLAG_MNG_FILTER_64 and 443 * 4. The filter_method is 64 and 444 * 5. The color_type is RGB or RGBA 445 */ 446 if ( 447#if defined(PNG_MNG_FEATURES_SUPPORTED) 448 !((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) && 449 ((png_ptr->mode&PNG_HAVE_PNG_SIGNATURE) == 0) && 450 (color_type == PNG_COLOR_TYPE_RGB || 451 color_type == PNG_COLOR_TYPE_RGB_ALPHA) && 452 (filter_type == PNG_INTRAPIXEL_DIFFERENCING)) && 453#endif 454 filter_type != PNG_FILTER_TYPE_BASE) 455 { 456 png_warning(png_ptr, "Invalid filter type specified"); 457 filter_type = PNG_FILTER_TYPE_BASE; 458 } 459 460#ifdef PNG_WRITE_INTERLACING_SUPPORTED 461 if (interlace_type != PNG_INTERLACE_NONE && 462 interlace_type != PNG_INTERLACE_ADAM7) 463 { 464 png_warning(png_ptr, "Invalid interlace type specified"); 465 interlace_type = PNG_INTERLACE_ADAM7; 466 } 467#else 468 interlace_type=PNG_INTERLACE_NONE; 469#endif 470 471 /* save off the relevent information */ 472 png_ptr->bit_depth = (png_byte)bit_depth; 473 png_ptr->color_type = (png_byte)color_type; 474 png_ptr->interlaced = (png_byte)interlace_type; 475#if defined(PNG_MNG_FEATURES_SUPPORTED) 476 png_ptr->filter_type = (png_byte)filter_type; 477#endif 478 png_ptr->compression_type = (png_byte)compression_type; 479 png_ptr->width = width; 480 png_ptr->height = height; 481 482 png_ptr->pixel_depth = (png_byte)(bit_depth * png_ptr->channels); 483 png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth, width); 484 /* set the usr info, so any transformations can modify it */ 485 png_ptr->usr_width = png_ptr->width; 486 png_ptr->usr_bit_depth = png_ptr->bit_depth; 487 png_ptr->usr_channels = png_ptr->channels; 488 489 /* pack the header information into the buffer */ 490 png_save_uint_32(buf, width); 491 png_save_uint_32(buf + 4, height); 492 buf[8] = (png_byte)bit_depth; 493 buf[9] = (png_byte)color_type; 494 buf[10] = (png_byte)compression_type; 495 buf[11] = (png_byte)filter_type; 496 buf[12] = (png_byte)interlace_type; 497 498 /* write the chunk */ 499 png_write_chunk(png_ptr, png_IHDR, buf, (png_size_t)13); 500 501 /* initialize zlib with PNG info */ 502 png_ptr->zstream.zalloc = png_zalloc; 503 png_ptr->zstream.zfree = png_zfree; 504 png_ptr->zstream.opaque = (voidpf)png_ptr; 505 if (!(png_ptr->do_filter)) 506 { 507 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE || 508 png_ptr->bit_depth < 8) 509 png_ptr->do_filter = PNG_FILTER_NONE; 510 else 511 png_ptr->do_filter = PNG_ALL_FILTERS; 512 } 513 if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_STRATEGY)) 514 { 515 if (png_ptr->do_filter != PNG_FILTER_NONE) 516 png_ptr->zlib_strategy = Z_FILTERED; 517 else 518 png_ptr->zlib_strategy = Z_DEFAULT_STRATEGY; 519 } 520 if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_LEVEL)) 521 png_ptr->zlib_level = Z_DEFAULT_COMPRESSION; 522 if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_MEM_LEVEL)) 523 png_ptr->zlib_mem_level = 8; 524 if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_WINDOW_BITS)) 525 png_ptr->zlib_window_bits = 15; 526 if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_METHOD)) 527 png_ptr->zlib_method = 8; 528 ret = deflateInit2(&png_ptr->zstream, png_ptr->zlib_level, 529 png_ptr->zlib_method, png_ptr->zlib_window_bits, 530 png_ptr->zlib_mem_level, png_ptr->zlib_strategy); 531 if (ret != Z_OK) 532 { 533 if (ret == Z_VERSION_ERROR) png_error(png_ptr, 534 "zlib failed to initialize compressor -- version error"); 535 if (ret == Z_STREAM_ERROR) png_error(png_ptr, 536 "zlib failed to initialize compressor -- stream error"); 537 if (ret == Z_MEM_ERROR) png_error(png_ptr, 538 "zlib failed to initialize compressor -- mem error"); 539 png_error(png_ptr, "zlib failed to initialize compressor"); 540 } 541 png_ptr->zstream.next_out = png_ptr->zbuf; 542 png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; 543 /* libpng is not interested in zstream.data_type */ 544 /* set it to a predefined value, to avoid its evaluation inside zlib */ 545 png_ptr->zstream.data_type = Z_BINARY; 546 547 png_ptr->mode = PNG_HAVE_IHDR; 548} 549 550/* write the palette. We are careful not to trust png_color to be in the 551 * correct order for PNG, so people can redefine it to any convenient 552 * structure. 553 */ 554void /* PRIVATE */ 555png_write_PLTE(png_structp png_ptr, png_colorp palette, png_uint_32 num_pal) 556{ 557#ifdef PNG_USE_LOCAL_ARRAYS 558 PNG_PLTE; 559#endif 560 png_uint_32 i; 561 png_colorp pal_ptr; 562 png_byte buf[3]; 563 564 png_debug(1, "in png_write_PLTE\n"); 565 if (( 566#if defined(PNG_MNG_FEATURES_SUPPORTED) 567 !(png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE) && 568#endif 569 num_pal == 0) || num_pal > 256) 570 { 571 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) 572 { 573 png_error(png_ptr, "Invalid number of colors in palette"); 574 } 575 else 576 { 577 png_warning(png_ptr, "Invalid number of colors in palette"); 578 return; 579 } 580 } 581 582 if (!(png_ptr->color_type&PNG_COLOR_MASK_COLOR)) 583 { 584 png_warning(png_ptr, 585 "Ignoring request to write a PLTE chunk in grayscale PNG"); 586 return; 587 } 588 589 png_ptr->num_palette = (png_uint_16)num_pal; 590 png_debug1(3, "num_palette = %d\n", png_ptr->num_palette); 591 592 png_write_chunk_start(png_ptr, png_PLTE, num_pal * 3); 593#ifndef PNG_NO_POINTER_INDEXING 594 for (i = 0, pal_ptr = palette; i < num_pal; i++, pal_ptr++) 595 { 596 buf[0] = pal_ptr->red; 597 buf[1] = pal_ptr->green; 598 buf[2] = pal_ptr->blue; 599 png_write_chunk_data(png_ptr, buf, (png_size_t)3); 600 } 601#else 602 /* This is a little slower but some buggy compilers need to do this instead */ 603 pal_ptr=palette; 604 for (i = 0; i < num_pal; i++) 605 { 606 buf[0] = pal_ptr[i].red; 607 buf[1] = pal_ptr[i].green; 608 buf[2] = pal_ptr[i].blue; 609 png_write_chunk_data(png_ptr, buf, (png_size_t)3); 610 } 611#endif 612 png_write_chunk_end(png_ptr); 613 png_ptr->mode |= PNG_HAVE_PLTE; 614} 615 616/* write an IDAT chunk */ 617void /* PRIVATE */ 618png_write_IDAT(png_structp png_ptr, png_bytep data, png_size_t length) 619{ 620#ifdef PNG_USE_LOCAL_ARRAYS 621 PNG_IDAT; 622#endif 623 png_debug(1, "in png_write_IDAT\n"); 624 625 /* Optimize the CMF field in the zlib stream. */ 626 /* This hack of the zlib stream is compliant to the stream specification. */ 627 if (!(png_ptr->mode & PNG_HAVE_IDAT) && 628 png_ptr->compression_type == PNG_COMPRESSION_TYPE_BASE) 629 { 630 unsigned int z_cmf = data[0]; /* zlib compression method and flags */ 631 if ((z_cmf & 0x0f) == 8 && (z_cmf & 0xf0) <= 0x70) 632 { 633 /* Avoid memory underflows and multiplication overflows. */ 634 /* The conditions below are practically always satisfied; 635 however, they still must be checked. */ 636 if (length >= 2 && 637 png_ptr->height < 16384 && png_ptr->width < 16384) 638 { 639 png_uint_32 uncompressed_idat_size = png_ptr->height * 640 ((png_ptr->width * 641 png_ptr->channels * png_ptr->bit_depth + 15) >> 3); 642 unsigned int z_cinfo = z_cmf >> 4; 643 unsigned int half_z_window_size = 1 << (z_cinfo + 7); 644 while (uncompressed_idat_size <= half_z_window_size && 645 half_z_window_size >= 256) 646 { 647 z_cinfo--; 648 half_z_window_size >>= 1; 649 } 650 z_cmf = (z_cmf & 0x0f) | (z_cinfo << 4); 651 if (data[0] != (png_byte)z_cmf) 652 { 653 data[0] = (png_byte)z_cmf; 654 data[1] &= 0xe0; 655 data[1] += (png_byte)(0x1f - ((z_cmf << 8) + data[1]) % 0x1f); 656 } 657 } 658 } 659 else 660 png_error(png_ptr, 661 "Invalid zlib compression method or flags in IDAT"); 662 } 663 664 png_write_chunk(png_ptr, png_IDAT, data, length); 665 png_ptr->mode |= PNG_HAVE_IDAT; 666} 667 668/* write an IEND chunk */ 669void /* PRIVATE */ 670png_write_IEND(png_structp png_ptr) 671{ 672#ifdef PNG_USE_LOCAL_ARRAYS 673 PNG_IEND; 674#endif 675 png_debug(1, "in png_write_IEND\n"); 676 png_write_chunk(png_ptr, png_IEND, png_bytep_NULL, 677 (png_size_t)0); 678 png_ptr->mode |= PNG_HAVE_IEND; 679} 680 681#if defined(PNG_WRITE_gAMA_SUPPORTED) 682/* write a gAMA chunk */ 683#ifdef PNG_FLOATING_POINT_SUPPORTED 684void /* PRIVATE */ 685png_write_gAMA(png_structp png_ptr, double file_gamma) 686{ 687#ifdef PNG_USE_LOCAL_ARRAYS 688 PNG_gAMA; 689#endif 690 png_uint_32 igamma; 691 png_byte buf[4]; 692 693 png_debug(1, "in png_write_gAMA\n"); 694 /* file_gamma is saved in 1/100,000ths */ 695 igamma = (png_uint_32)(file_gamma * 100000.0 + 0.5); 696 png_save_uint_32(buf, igamma); 697 png_write_chunk(png_ptr, png_gAMA, buf, (png_size_t)4); 698} 699#endif 700#ifdef PNG_FIXED_POINT_SUPPORTED 701void /* PRIVATE */ 702png_write_gAMA_fixed(png_structp png_ptr, png_fixed_point file_gamma) 703{ 704#ifdef PNG_USE_LOCAL_ARRAYS 705 PNG_gAMA; 706#endif 707 png_byte buf[4]; 708 709 png_debug(1, "in png_write_gAMA\n"); 710 /* file_gamma is saved in 1/100,000ths */ 711 png_save_uint_32(buf, (png_uint_32)file_gamma); 712 png_write_chunk(png_ptr, png_gAMA, buf, (png_size_t)4); 713} 714#endif 715#endif 716 717#if defined(PNG_WRITE_sRGB_SUPPORTED) 718/* write a sRGB chunk */ 719void /* PRIVATE */ 720png_write_sRGB(png_structp png_ptr, int srgb_intent) 721{ 722#ifdef PNG_USE_LOCAL_ARRAYS 723 PNG_sRGB; 724#endif 725 png_byte buf[1]; 726 727 png_debug(1, "in png_write_sRGB\n"); 728 if(srgb_intent >= PNG_sRGB_INTENT_LAST) 729 png_warning(png_ptr, 730 "Invalid sRGB rendering intent specified"); 731 buf[0]=(png_byte)srgb_intent; 732 png_write_chunk(png_ptr, png_sRGB, buf, (png_size_t)1); 733} 734#endif 735 736#if defined(PNG_WRITE_iCCP_SUPPORTED) 737/* write an iCCP chunk */ 738void /* PRIVATE */ 739png_write_iCCP(png_structp png_ptr, png_charp name, int compression_type, 740 png_charp profile, int profile_len) 741{ 742#ifdef PNG_USE_LOCAL_ARRAYS 743 PNG_iCCP; 744#endif 745 png_size_t name_len; 746 png_charp new_name; 747 compression_state comp; 748 int embedded_profile_len = 0; 749 750 png_debug(1, "in png_write_iCCP\n"); 751 752 comp.num_output_ptr = 0; 753 comp.max_output_ptr = 0; 754 comp.output_ptr = NULL; 755 comp.input = NULL; 756 comp.input_len = 0; 757 758 if (name == NULL || (name_len = png_check_keyword(png_ptr, name, 759 &new_name)) == 0) 760 { 761 png_warning(png_ptr, "Empty keyword in iCCP chunk"); 762 return; 763 } 764 765 if (compression_type != PNG_COMPRESSION_TYPE_BASE) 766 png_warning(png_ptr, "Unknown compression type in iCCP chunk"); 767 768 if (profile == NULL) 769 profile_len = 0; 770 771 if (profile_len > 3) 772 embedded_profile_len = 773 ((*( (png_bytep)profile ))<<24) | 774 ((*( (png_bytep)profile+1))<<16) | 775 ((*( (png_bytep)profile+2))<< 8) | 776 ((*( (png_bytep)profile+3)) ); 777 778 if (profile_len < embedded_profile_len) 779 { 780 png_warning(png_ptr, 781 "Embedded profile length too large in iCCP chunk"); 782 return; 783 } 784 785 if (profile_len > embedded_profile_len) 786 { 787 png_warning(png_ptr, 788 "Truncating profile to actual length in iCCP chunk"); 789 profile_len = embedded_profile_len; 790 } 791 792 if (profile_len) 793 profile_len = png_text_compress(png_ptr, profile, (png_size_t)profile_len, 794 PNG_COMPRESSION_TYPE_BASE, &comp); 795 796 /* make sure we include the NULL after the name and the compression type */ 797 png_write_chunk_start(png_ptr, png_iCCP, 798 (png_uint_32)name_len+profile_len+2); 799 new_name[name_len+1]=0x00; 800 png_write_chunk_data(png_ptr, (png_bytep)new_name, name_len + 2); 801 802 if (profile_len) 803 png_write_compressed_data_out(png_ptr, &comp); 804 805 png_write_chunk_end(png_ptr); 806 png_free(png_ptr, new_name); 807} 808#endif 809 810#if defined(PNG_WRITE_sPLT_SUPPORTED) 811/* write a sPLT chunk */ 812void /* PRIVATE */ 813png_write_sPLT(png_structp png_ptr, png_sPLT_tp spalette) 814{ 815#ifdef PNG_USE_LOCAL_ARRAYS 816 PNG_sPLT; 817#endif 818 png_size_t name_len; 819 png_charp new_name; 820 png_byte entrybuf[10]; 821 int entry_size = (spalette->depth == 8 ? 6 : 10); 822 int palette_size = entry_size * spalette->nentries; 823 png_sPLT_entryp ep; 824#ifdef PNG_NO_POINTER_INDEXING 825 int i; 826#endif 827 828 png_debug(1, "in png_write_sPLT\n"); 829 if (spalette->name == NULL || (name_len = png_check_keyword(png_ptr, 830 spalette->name, &new_name))==0) 831 { 832 png_warning(png_ptr, "Empty keyword in sPLT chunk"); 833 return; 834 } 835 836 /* make sure we include the NULL after the name */ 837 png_write_chunk_start(png_ptr, png_sPLT, 838 (png_uint_32)(name_len + 2 + palette_size)); 839 png_write_chunk_data(png_ptr, (png_bytep)new_name, name_len + 1); 840 png_write_chunk_data(png_ptr, (png_bytep)&spalette->depth, 1); 841 842 /* loop through each palette entry, writing appropriately */ 843#ifndef PNG_NO_POINTER_INDEXING 844 for (ep = spalette->entries; ep<spalette->entries+spalette->nentries; ep++) 845 { 846 if (spalette->depth == 8) 847 { 848 entrybuf[0] = (png_byte)ep->red; 849 entrybuf[1] = (png_byte)ep->green; 850 entrybuf[2] = (png_byte)ep->blue; 851 entrybuf[3] = (png_byte)ep->alpha; 852 png_save_uint_16(entrybuf + 4, ep->frequency); 853 } 854 else 855 { 856 png_save_uint_16(entrybuf + 0, ep->red); 857 png_save_uint_16(entrybuf + 2, ep->green); 858 png_save_uint_16(entrybuf + 4, ep->blue); 859 png_save_uint_16(entrybuf + 6, ep->alpha); 860 png_save_uint_16(entrybuf + 8, ep->frequency); 861 } 862 png_write_chunk_data(png_ptr, entrybuf, (png_size_t)entry_size); 863 } 864#else 865 ep=spalette->entries; 866 for (i=0; i>spalette->nentries; i++) 867 { 868 if (spalette->depth == 8) 869 { 870 entrybuf[0] = (png_byte)ep[i].red; 871 entrybuf[1] = (png_byte)ep[i].green; 872 entrybuf[2] = (png_byte)ep[i].blue; 873 entrybuf[3] = (png_byte)ep[i].alpha; 874 png_save_uint_16(entrybuf + 4, ep[i].frequency); 875 } 876 else 877 { 878 png_save_uint_16(entrybuf + 0, ep[i].red); 879 png_save_uint_16(entrybuf + 2, ep[i].green); 880 png_save_uint_16(entrybuf + 4, ep[i].blue); 881 png_save_uint_16(entrybuf + 6, ep[i].alpha); 882 png_save_uint_16(entrybuf + 8, ep[i].frequency); 883 } 884 png_write_chunk_data(png_ptr, entrybuf, entry_size); 885 } 886#endif 887 888 png_write_chunk_end(png_ptr); 889 png_free(png_ptr, new_name); 890} 891#endif 892 893#if defined(PNG_WRITE_sBIT_SUPPORTED) 894/* write the sBIT chunk */ 895void /* PRIVATE */ 896png_write_sBIT(png_structp png_ptr, png_color_8p sbit, int color_type) 897{ 898#ifdef PNG_USE_LOCAL_ARRAYS 899 PNG_sBIT; 900#endif 901 png_byte buf[4]; 902 png_size_t size; 903 904 png_debug(1, "in png_write_sBIT\n"); 905 /* make sure we don't depend upon the order of PNG_COLOR_8 */ 906 if (color_type & PNG_COLOR_MASK_COLOR) 907 { 908 png_byte maxbits; 909 910 maxbits = (png_byte)(color_type==PNG_COLOR_TYPE_PALETTE ? 8 : 911 png_ptr->usr_bit_depth); 912 if (sbit->red == 0 || sbit->red > maxbits || 913 sbit->green == 0 || sbit->green > maxbits || 914 sbit->blue == 0 || sbit->blue > maxbits) 915 { 916 png_warning(png_ptr, "Invalid sBIT depth specified"); 917 return; 918 } 919 buf[0] = sbit->red; 920 buf[1] = sbit->green; 921 buf[2] = sbit->blue; 922 size = 3; 923 } 924 else 925 { 926 if (sbit->gray == 0 || sbit->gray > png_ptr->usr_bit_depth) 927 { 928 png_warning(png_ptr, "Invalid sBIT depth specified"); 929 return; 930 } 931 buf[0] = sbit->gray; 932 size = 1; 933 } 934 935 if (color_type & PNG_COLOR_MASK_ALPHA) 936 { 937 if (sbit->alpha == 0 || sbit->alpha > png_ptr->usr_bit_depth) 938 { 939 png_warning(png_ptr, "Invalid sBIT depth specified"); 940 return; 941 } 942 buf[size++] = sbit->alpha; 943 } 944 945 png_write_chunk(png_ptr, png_sBIT, buf, size); 946} 947#endif 948 949#if defined(PNG_WRITE_cHRM_SUPPORTED) 950/* write the cHRM chunk */ 951#ifdef PNG_FLOATING_POINT_SUPPORTED 952void /* PRIVATE */ 953png_write_cHRM(png_structp png_ptr, double white_x, double white_y, 954 double red_x, double red_y, double green_x, double green_y, 955 double blue_x, double blue_y) 956{ 957#ifdef PNG_USE_LOCAL_ARRAYS 958 PNG_cHRM; 959#endif 960 png_byte buf[32]; 961 png_uint_32 itemp; 962 963 png_debug(1, "in png_write_cHRM\n"); 964 /* each value is saved in 1/100,000ths */ 965 if (white_x < 0 || white_x > 0.8 || white_y < 0 || white_y > 0.8 || 966 white_x + white_y > 1.0) 967 { 968 png_warning(png_ptr, "Invalid cHRM white point specified"); 969#if !defined(PNG_NO_CONSOLE_IO) 970 fprintf(stderr,"white_x=%f, white_y=%f\n",white_x, white_y); 971#endif 972 return; 973 } 974 itemp = (png_uint_32)(white_x * 100000.0 + 0.5); 975 png_save_uint_32(buf, itemp); 976 itemp = (png_uint_32)(white_y * 100000.0 + 0.5); 977 png_save_uint_32(buf + 4, itemp); 978 979 if (red_x < 0 || red_y < 0 || red_x + red_y > 1.0) 980 { 981 png_warning(png_ptr, "Invalid cHRM red point specified"); 982 return; 983 } 984 itemp = (png_uint_32)(red_x * 100000.0 + 0.5); 985 png_save_uint_32(buf + 8, itemp); 986 itemp = (png_uint_32)(red_y * 100000.0 + 0.5); 987 png_save_uint_32(buf + 12, itemp); 988 989 if (green_x < 0 || green_y < 0 || green_x + green_y > 1.0) 990 { 991 png_warning(png_ptr, "Invalid cHRM green point specified"); 992 return; 993 } 994 itemp = (png_uint_32)(green_x * 100000.0 + 0.5); 995 png_save_uint_32(buf + 16, itemp); 996 itemp = (png_uint_32)(green_y * 100000.0 + 0.5); 997 png_save_uint_32(buf + 20, itemp); 998 999 if (blue_x < 0 || blue_y < 0 || blue_x + blue_y > 1.0) 1000 { 1001 png_warning(png_ptr, "Invalid cHRM blue point specified"); 1002 return; 1003 } 1004 itemp = (png_uint_32)(blue_x * 100000.0 + 0.5); 1005 png_save_uint_32(buf + 24, itemp); 1006 itemp = (png_uint_32)(blue_y * 100000.0 + 0.5); 1007 png_save_uint_32(buf + 28, itemp); 1008 1009 png_write_chunk(png_ptr, png_cHRM, buf, (png_size_t)32); 1010} 1011#endif 1012#ifdef PNG_FIXED_POINT_SUPPORTED 1013void /* PRIVATE */ 1014png_write_cHRM_fixed(png_structp png_ptr, png_fixed_point white_x, 1015 png_fixed_point white_y, png_fixed_point red_x, png_fixed_point red_y, 1016 png_fixed_point green_x, png_fixed_point green_y, png_fixed_point blue_x, 1017 png_fixed_point blue_y) 1018{ 1019#ifdef PNG_USE_LOCAL_ARRAYS 1020 PNG_cHRM; 1021#endif 1022 png_byte buf[32]; 1023 1024 png_debug(1, "in png_write_cHRM\n"); 1025 /* each value is saved in 1/100,000ths */ 1026 if (white_x > 80000L || white_y > 80000L || white_x + white_y > 100000L) 1027 { 1028 png_warning(png_ptr, "Invalid fixed cHRM white point specified"); 1029#if !defined(PNG_NO_CONSOLE_IO) 1030 fprintf(stderr,"white_x=%ld, white_y=%ld\n",white_x, white_y); 1031#endif 1032 return; 1033 } 1034 png_save_uint_32(buf, (png_uint_32)white_x); 1035 png_save_uint_32(buf + 4, (png_uint_32)white_y); 1036 1037 if (red_x + red_y > 100000L) 1038 { 1039 png_warning(png_ptr, "Invalid cHRM fixed red point specified"); 1040 return; 1041 } 1042 png_save_uint_32(buf + 8, (png_uint_32)red_x); 1043 png_save_uint_32(buf + 12, (png_uint_32)red_y); 1044 1045 if (green_x + green_y > 100000L) 1046 { 1047 png_warning(png_ptr, "Invalid fixed cHRM green point specified"); 1048 return; 1049 } 1050 png_save_uint_32(buf + 16, (png_uint_32)green_x); 1051 png_save_uint_32(buf + 20, (png_uint_32)green_y); 1052 1053 if (blue_x + blue_y > 100000L) 1054 { 1055 png_warning(png_ptr, "Invalid fixed cHRM blue point specified"); 1056 return; 1057 } 1058 png_save_uint_32(buf + 24, (png_uint_32)blue_x); 1059 png_save_uint_32(buf + 28, (png_uint_32)blue_y); 1060 1061 png_write_chunk(png_ptr, png_cHRM, buf, (png_size_t)32); 1062} 1063#endif 1064#endif 1065 1066#if defined(PNG_WRITE_tRNS_SUPPORTED) 1067/* write the tRNS chunk */ 1068void /* PRIVATE */ 1069png_write_tRNS(png_structp png_ptr, png_bytep trans, png_color_16p tran, 1070 int num_trans, int color_type) 1071{ 1072#ifdef PNG_USE_LOCAL_ARRAYS 1073 PNG_tRNS; 1074#endif 1075 png_byte buf[6]; 1076 1077 png_debug(1, "in png_write_tRNS\n"); 1078 if (color_type == PNG_COLOR_TYPE_PALETTE) 1079 { 1080 if (num_trans <= 0 || num_trans > (int)png_ptr->num_palette) 1081 { 1082 png_warning(png_ptr,"Invalid number of transparent colors specified"); 1083 return; 1084 } 1085 /* write the chunk out as it is */ 1086 png_write_chunk(png_ptr, png_tRNS, trans, (png_size_t)num_trans); 1087 } 1088 else if (color_type == PNG_COLOR_TYPE_GRAY) 1089 { 1090 /* one 16 bit value */ 1091 if(tran->gray >= (1 << png_ptr->bit_depth)) 1092 { 1093 png_warning(png_ptr, 1094 "Ignoring attempt to write tRNS chunk out-of-range for bit_depth"); 1095 return; 1096 } 1097 png_save_uint_16(buf, tran->gray); 1098 png_write_chunk(png_ptr, png_tRNS, buf, (png_size_t)2); 1099 } 1100 else if (color_type == PNG_COLOR_TYPE_RGB) 1101 { 1102 /* three 16 bit values */ 1103 png_save_uint_16(buf, tran->red); 1104 png_save_uint_16(buf + 2, tran->green); 1105 png_save_uint_16(buf + 4, tran->blue); 1106 if(png_ptr->bit_depth == 8 && (buf[0] | buf[2] | buf[4])) 1107 { 1108 png_warning(png_ptr, 1109 "Ignoring attempt to write 16-bit tRNS chunk when bit_depth is 8"); 1110 return; 1111 } 1112 png_write_chunk(png_ptr, png_tRNS, buf, (png_size_t)6); 1113 } 1114 else 1115 { 1116 png_warning(png_ptr, "Can't write tRNS with an alpha channel"); 1117 } 1118} 1119#endif 1120 1121#if defined(PNG_WRITE_bKGD_SUPPORTED) 1122/* write the background chunk */ 1123void /* PRIVATE */ 1124png_write_bKGD(png_structp png_ptr, png_color_16p back, int color_type) 1125{ 1126#ifdef PNG_USE_LOCAL_ARRAYS 1127 PNG_bKGD; 1128#endif 1129 png_byte buf[6]; 1130 1131 png_debug(1, "in png_write_bKGD\n"); 1132 if (color_type == PNG_COLOR_TYPE_PALETTE) 1133 { 1134 if ( 1135#if defined(PNG_MNG_FEATURES_SUPPORTED) 1136 (png_ptr->num_palette || 1137 (!(png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE))) && 1138#endif 1139 back->index > png_ptr->num_palette) 1140 { 1141 png_warning(png_ptr, "Invalid background palette index"); 1142 return; 1143 } 1144 buf[0] = back->index; 1145 png_write_chunk(png_ptr, png_bKGD, buf, (png_size_t)1); 1146 } 1147 else if (color_type & PNG_COLOR_MASK_COLOR) 1148 { 1149 png_save_uint_16(buf, back->red); 1150 png_save_uint_16(buf + 2, back->green); 1151 png_save_uint_16(buf + 4, back->blue); 1152 if(png_ptr->bit_depth == 8 && (buf[0] | buf[2] | buf[4])) 1153 { 1154 png_warning(png_ptr, 1155 "Ignoring attempt to write 16-bit bKGD chunk when bit_depth is 8"); 1156 return; 1157 } 1158 png_write_chunk(png_ptr, png_bKGD, buf, (png_size_t)6); 1159 } 1160 else 1161 { 1162 if(back->gray >= (1 << png_ptr->bit_depth)) 1163 { 1164 png_warning(png_ptr, 1165 "Ignoring attempt to write bKGD chunk out-of-range for bit_depth"); 1166 return; 1167 } 1168 png_save_uint_16(buf, back->gray); 1169 png_write_chunk(png_ptr, png_bKGD, buf, (png_size_t)2); 1170 } 1171} 1172#endif 1173 1174#if defined(PNG_WRITE_hIST_SUPPORTED) 1175/* write the histogram */ 1176void /* PRIVATE */ 1177png_write_hIST(png_structp png_ptr, png_uint_16p hist, int num_hist) 1178{ 1179#ifdef PNG_USE_LOCAL_ARRAYS 1180 PNG_hIST; 1181#endif 1182 int i; 1183 png_byte buf[3]; 1184 1185 png_debug(1, "in png_write_hIST\n"); 1186 if (num_hist > (int)png_ptr->num_palette) 1187 { 1188 png_debug2(3, "num_hist = %d, num_palette = %d\n", num_hist, 1189 png_ptr->num_palette); 1190 png_warning(png_ptr, "Invalid number of histogram entries specified"); 1191 return; 1192 } 1193 1194 png_write_chunk_start(png_ptr, png_hIST, (png_uint_32)(num_hist * 2)); 1195 for (i = 0; i < num_hist; i++) 1196 { 1197 png_save_uint_16(buf, hist[i]); 1198 png_write_chunk_data(png_ptr, buf, (png_size_t)2); 1199 } 1200 png_write_chunk_end(png_ptr); 1201} 1202#endif 1203 1204#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_pCAL_SUPPORTED) || \ 1205 defined(PNG_WRITE_iCCP_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED) 1206/* Check that the tEXt or zTXt keyword is valid per PNG 1.0 specification, 1207 * and if invalid, correct the keyword rather than discarding the entire 1208 * chunk. The PNG 1.0 specification requires keywords 1-79 characters in 1209 * length, forbids leading or trailing whitespace, multiple internal spaces, 1210 * and the non-break space (0x80) from ISO 8859-1. Returns keyword length. 1211 * 1212 * The new_key is allocated to hold the corrected keyword and must be freed 1213 * by the calling routine. This avoids problems with trying to write to 1214 * static keywords without having to have duplicate copies of the strings. 1215 */ 1216png_size_t /* PRIVATE */ 1217png_check_keyword(png_structp png_ptr, png_charp key, png_charpp new_key) 1218{ 1219 png_size_t key_len; 1220 png_charp kp, dp; 1221 int kflag; 1222 int kwarn=0; 1223 1224 png_debug(1, "in png_check_keyword\n"); 1225 *new_key = NULL; 1226 1227 if (key == NULL || (key_len = png_strlen(key)) == 0) 1228 { 1229 png_warning(png_ptr, "zero length keyword"); 1230 return ((png_size_t)0); 1231 } 1232 1233 png_debug1(2, "Keyword to be checked is '%s'\n", key); 1234 1235 *new_key = (png_charp)png_malloc_warn(png_ptr, (png_uint_32)(key_len + 2)); 1236 if (*new_key == NULL) 1237 { 1238 png_warning(png_ptr, "Out of memory while procesing keyword"); 1239 return ((png_size_t)0); 1240 } 1241 1242 /* Replace non-printing characters with a blank and print a warning */ 1243 for (kp = key, dp = *new_key; *kp != '\0'; kp++, dp++) 1244 { 1245 if ((png_byte)*kp < 0x20 || 1246 ((png_byte)*kp > 0x7E && (png_byte)*kp < 0xA1)) 1247 { 1248#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE) 1249 char msg[40]; 1250 1251 png_snprintf(msg, 40, 1252 "invalid keyword character 0x%02X", (png_byte)*kp); 1253 png_warning(png_ptr, msg); 1254#else 1255 png_warning(png_ptr, "invalid character in keyword"); 1256#endif 1257 *dp = ' '; 1258 } 1259 else 1260 { 1261 *dp = *kp; 1262 } 1263 } 1264 *dp = '\0'; 1265 1266 /* Remove any trailing white space. */ 1267 kp = *new_key + key_len - 1; 1268 if (*kp == ' ') 1269 { 1270 png_warning(png_ptr, "trailing spaces removed from keyword"); 1271 1272 while (*kp == ' ') 1273 { 1274 *(kp--) = '\0'; 1275 key_len--; 1276 } 1277 } 1278 1279 /* Remove any leading white space. */ 1280 kp = *new_key; 1281 if (*kp == ' ') 1282 { 1283 png_warning(png_ptr, "leading spaces removed from keyword"); 1284 1285 while (*kp == ' ') 1286 { 1287 kp++; 1288 key_len--; 1289 } 1290 } 1291 1292 png_debug1(2, "Checking for multiple internal spaces in '%s'\n", kp); 1293 1294 /* Remove multiple internal spaces. */ 1295 for (kflag = 0, dp = *new_key; *kp != '\0'; kp++) 1296 { 1297 if (*kp == ' ' && kflag == 0) 1298 { 1299 *(dp++) = *kp; 1300 kflag = 1; 1301 } 1302 else if (*kp == ' ') 1303 { 1304 key_len--; 1305 kwarn=1; 1306 } 1307 else 1308 { 1309 *(dp++) = *kp; 1310 kflag = 0; 1311 } 1312 } 1313 *dp = '\0'; 1314 if(kwarn) 1315 png_warning(png_ptr, "extra interior spaces removed from keyword"); 1316 1317 if (key_len == 0) 1318 { 1319 png_free(png_ptr, *new_key); 1320 *new_key=NULL; 1321 png_warning(png_ptr, "Zero length keyword"); 1322 } 1323 1324 if (key_len > 79) 1325 { 1326 png_warning(png_ptr, "keyword length must be 1 - 79 characters"); 1327 new_key[79] = '\0'; 1328 key_len = 79; 1329 } 1330 1331 return (key_len); 1332} 1333#endif 1334 1335#if defined(PNG_WRITE_tEXt_SUPPORTED) 1336/* write a tEXt chunk */ 1337void /* PRIVATE */ 1338png_write_tEXt(png_structp png_ptr, png_charp key, png_charp text, 1339 png_size_t text_len) 1340{ 1341#ifdef PNG_USE_LOCAL_ARRAYS 1342 PNG_tEXt; 1343#endif 1344 png_size_t key_len; 1345 png_charp new_key; 1346 1347 png_debug(1, "in png_write_tEXt\n"); 1348 if (key == NULL || (key_len = png_check_keyword(png_ptr, key, &new_key))==0) 1349 { 1350 png_warning(png_ptr, "Empty keyword in tEXt chunk"); 1351 return; 1352 } 1353 1354 if (text == NULL || *text == '\0') 1355 text_len = 0; 1356 else 1357 text_len = png_strlen(text); 1358 1359 /* make sure we include the 0 after the key */ 1360 png_write_chunk_start(png_ptr, png_tEXt, (png_uint_32)key_len+text_len+1); 1361 /* 1362 * We leave it to the application to meet PNG-1.0 requirements on the 1363 * contents of the text. PNG-1.0 through PNG-1.2 discourage the use of 1364 * any non-Latin-1 characters except for NEWLINE. ISO PNG will forbid them. 1365 * The NUL character is forbidden by PNG-1.0 through PNG-1.2 and ISO PNG. 1366 */ 1367 png_write_chunk_data(png_ptr, (png_bytep)new_key, key_len + 1); 1368 if (text_len) 1369 png_write_chunk_data(png_ptr, (png_bytep)text, text_len); 1370 1371 png_write_chunk_end(png_ptr); 1372 png_free(png_ptr, new_key); 1373} 1374#endif 1375 1376#if defined(PNG_WRITE_zTXt_SUPPORTED) 1377/* write a compressed text chunk */ 1378void /* PRIVATE */ 1379png_write_zTXt(png_structp png_ptr, png_charp key, png_charp text, 1380 png_size_t text_len, int compression) 1381{ 1382#ifdef PNG_USE_LOCAL_ARRAYS 1383 PNG_zTXt; 1384#endif 1385 png_size_t key_len; 1386 char buf[1]; 1387 png_charp new_key; 1388 compression_state comp; 1389 1390 png_debug(1, "in png_write_zTXt\n"); 1391 1392 comp.num_output_ptr = 0; 1393 comp.max_output_ptr = 0; 1394 comp.output_ptr = NULL; 1395 comp.input = NULL; 1396 comp.input_len = 0; 1397 1398 if (key == NULL || (key_len = png_check_keyword(png_ptr, key, &new_key))==0) 1399 { 1400 png_warning(png_ptr, "Empty keyword in zTXt chunk"); 1401 return; 1402 } 1403 1404 if (text == NULL || *text == '\0' || compression==PNG_TEXT_COMPRESSION_NONE) 1405 { 1406 png_write_tEXt(png_ptr, new_key, text, (png_size_t)0); 1407 png_free(png_ptr, new_key); 1408 return; 1409 } 1410 1411 text_len = png_strlen(text); 1412 1413 /* compute the compressed data; do it now for the length */ 1414 text_len = png_text_compress(png_ptr, text, text_len, compression, 1415 &comp); 1416 1417 /* write start of chunk */ 1418 png_write_chunk_start(png_ptr, png_zTXt, (png_uint_32) 1419 (key_len+text_len+2)); 1420 /* write key */ 1421 png_write_chunk_data(png_ptr, (png_bytep)new_key, key_len + 1); 1422 png_free(png_ptr, new_key); 1423 1424 buf[0] = (png_byte)compression; 1425 /* write compression */ 1426 png_write_chunk_data(png_ptr, (png_bytep)buf, (png_size_t)1); 1427 /* write the compressed data */ 1428 png_write_compressed_data_out(png_ptr, &comp); 1429 1430 /* close the chunk */ 1431 png_write_chunk_end(png_ptr); 1432} 1433#endif 1434 1435#if defined(PNG_WRITE_iTXt_SUPPORTED) 1436/* write an iTXt chunk */ 1437void /* PRIVATE */ 1438png_write_iTXt(png_structp png_ptr, int compression, png_charp key, 1439 png_charp lang, png_charp lang_key, png_charp text) 1440{ 1441#ifdef PNG_USE_LOCAL_ARRAYS 1442 PNG_iTXt; 1443#endif 1444 png_size_t lang_len, key_len, lang_key_len, text_len; 1445 png_charp new_lang, new_key; 1446 png_byte cbuf[2]; 1447 compression_state comp; 1448 1449 png_debug(1, "in png_write_iTXt\n"); 1450 1451 comp.num_output_ptr = 0; 1452 comp.max_output_ptr = 0; 1453 comp.output_ptr = NULL; 1454 comp.input = NULL; 1455 1456 if (key == NULL || (key_len = png_check_keyword(png_ptr, key, &new_key))==0) 1457 { 1458 png_warning(png_ptr, "Empty keyword in iTXt chunk"); 1459 return; 1460 } 1461 if (lang == NULL || (lang_len = png_check_keyword(png_ptr, lang, &new_lang))==0) 1462 { 1463 png_warning(png_ptr, "Empty language field in iTXt chunk"); 1464 new_lang = NULL; 1465 lang_len = 0; 1466 } 1467 1468 if (lang_key == NULL) 1469 lang_key_len = 0; 1470 else 1471 lang_key_len = png_strlen(lang_key); 1472 1473 if (text == NULL) 1474 text_len = 0; 1475 else 1476 text_len = png_strlen(text); 1477 1478 /* compute the compressed data; do it now for the length */ 1479 text_len = png_text_compress(png_ptr, text, text_len, compression-2, 1480 &comp); 1481 1482 1483 /* make sure we include the compression flag, the compression byte, 1484 * and the NULs after the key, lang, and lang_key parts */ 1485 1486 png_write_chunk_start(png_ptr, png_iTXt, 1487 (png_uint_32)( 1488 5 /* comp byte, comp flag, terminators for key, lang and lang_key */ 1489 + key_len 1490 + lang_len 1491 + lang_key_len 1492 + text_len)); 1493 1494 /* 1495 * We leave it to the application to meet PNG-1.0 requirements on the 1496 * contents of the text. PNG-1.0 through PNG-1.2 discourage the use of 1497 * any non-Latin-1 characters except for NEWLINE. ISO PNG will forbid them. 1498 * The NUL character is forbidden by PNG-1.0 through PNG-1.2 and ISO PNG. 1499 */ 1500 png_write_chunk_data(png_ptr, (png_bytep)new_key, key_len + 1); 1501 1502 /* set the compression flag */ 1503 if (compression == PNG_ITXT_COMPRESSION_NONE || \ 1504 compression == PNG_TEXT_COMPRESSION_NONE) 1505 cbuf[0] = 0; 1506 else /* compression == PNG_ITXT_COMPRESSION_zTXt */ 1507 cbuf[0] = 1; 1508 /* set the compression method */ 1509 cbuf[1] = 0; 1510 png_write_chunk_data(png_ptr, cbuf, 2); 1511 1512 cbuf[0] = 0; 1513 png_write_chunk_data(png_ptr, (new_lang ? (png_bytep)new_lang : cbuf), lang_len + 1); 1514 png_write_chunk_data(png_ptr, (lang_key ? (png_bytep)lang_key : cbuf), lang_key_len + 1); 1515 png_write_compressed_data_out(png_ptr, &comp); 1516 1517 png_write_chunk_end(png_ptr); 1518 png_free(png_ptr, new_key); 1519 png_free(png_ptr, new_lang); 1520} 1521#endif 1522 1523#if defined(PNG_WRITE_oFFs_SUPPORTED) 1524/* write the oFFs chunk */ 1525void /* PRIVATE */ 1526png_write_oFFs(png_structp png_ptr, png_int_32 x_offset, png_int_32 y_offset, 1527 int unit_type) 1528{ 1529#ifdef PNG_USE_LOCAL_ARRAYS 1530 PNG_oFFs; 1531#endif 1532 png_byte buf[9]; 1533 1534 png_debug(1, "in png_write_oFFs\n"); 1535 if (unit_type >= PNG_OFFSET_LAST) 1536 png_warning(png_ptr, "Unrecognized unit type for oFFs chunk"); 1537 1538 png_save_int_32(buf, x_offset); 1539 png_save_int_32(buf + 4, y_offset); 1540 buf[8] = (png_byte)unit_type; 1541 1542 png_write_chunk(png_ptr, png_oFFs, buf, (png_size_t)9); 1543} 1544#endif 1545#if defined(PNG_WRITE_pCAL_SUPPORTED) 1546/* write the pCAL chunk (described in the PNG extensions document) */ 1547void /* PRIVATE */ 1548png_write_pCAL(png_structp png_ptr, png_charp purpose, png_int_32 X0, 1549 png_int_32 X1, int type, int nparams, png_charp units, png_charpp params) 1550{ 1551#ifdef PNG_USE_LOCAL_ARRAYS 1552 PNG_pCAL; 1553#endif 1554 png_size_t purpose_len, units_len, total_len; 1555 png_uint_32p params_len; 1556 png_byte buf[10]; 1557 png_charp new_purpose; 1558 int i; 1559 1560 png_debug1(1, "in png_write_pCAL (%d parameters)\n", nparams); 1561 if (type >= PNG_EQUATION_LAST) 1562 png_warning(png_ptr, "Unrecognized equation type for pCAL chunk"); 1563 1564 purpose_len = png_check_keyword(png_ptr, purpose, &new_purpose) + 1; 1565 png_debug1(3, "pCAL purpose length = %d\n", (int)purpose_len); 1566 units_len = png_strlen(units) + (nparams == 0 ? 0 : 1); 1567 png_debug1(3, "pCAL units length = %d\n", (int)units_len); 1568 total_len = purpose_len + units_len + 10; 1569 1570 params_len = (png_uint_32p)png_malloc(png_ptr, (png_uint_32)(nparams 1571 *png_sizeof(png_uint_32))); 1572 1573 /* Find the length of each parameter, making sure we don't count the 1574 null terminator for the last parameter. */ 1575 for (i = 0; i < nparams; i++) 1576 { 1577 params_len[i] = png_strlen(params[i]) + (i == nparams - 1 ? 0 : 1); 1578 png_debug2(3, "pCAL parameter %d length = %lu\n", i, params_len[i]); 1579 total_len += (png_size_t)params_len[i]; 1580 } 1581 1582 png_debug1(3, "pCAL total length = %d\n", (int)total_len); 1583 png_write_chunk_start(png_ptr, png_pCAL, (png_uint_32)total_len); 1584 png_write_chunk_data(png_ptr, (png_bytep)new_purpose, purpose_len); 1585 png_save_int_32(buf, X0); 1586 png_save_int_32(buf + 4, X1); 1587 buf[8] = (png_byte)type; 1588 buf[9] = (png_byte)nparams; 1589 png_write_chunk_data(png_ptr, buf, (png_size_t)10); 1590 png_write_chunk_data(png_ptr, (png_bytep)units, (png_size_t)units_len); 1591 1592 png_free(png_ptr, new_purpose); 1593 1594 for (i = 0; i < nparams; i++) 1595 { 1596 png_write_chunk_data(png_ptr, (png_bytep)params[i], 1597 (png_size_t)params_len[i]); 1598 } 1599 1600 png_free(png_ptr, params_len); 1601 png_write_chunk_end(png_ptr); 1602} 1603#endif 1604 1605#if defined(PNG_WRITE_sCAL_SUPPORTED) 1606/* write the sCAL chunk */ 1607#if defined(PNG_FLOATING_POINT_SUPPORTED) && !defined(PNG_NO_STDIO) 1608void /* PRIVATE */ 1609png_write_sCAL(png_structp png_ptr, int unit, double width, double height) 1610{ 1611#ifdef PNG_USE_LOCAL_ARRAYS 1612 PNG_sCAL; 1613#endif 1614 char buf[64]; 1615 png_size_t total_len; 1616 1617 png_debug(1, "in png_write_sCAL\n"); 1618 1619 buf[0] = (char)unit; 1620#if defined(_WIN32_WCE) 1621/* sprintf() function is not supported on WindowsCE */ 1622 { 1623 wchar_t wc_buf[32]; 1624 size_t wc_len; 1625 swprintf(wc_buf, TEXT("%12.12e"), width); 1626 wc_len = wcslen(wc_buf); 1627 WideCharToMultiByte(CP_ACP, 0, wc_buf, -1, buf + 1, wc_len, NULL, NULL); 1628 total_len = wc_len + 2; 1629 swprintf(wc_buf, TEXT("%12.12e"), height); 1630 wc_len = wcslen(wc_buf); 1631 WideCharToMultiByte(CP_ACP, 0, wc_buf, -1, buf + total_len, wc_len, 1632 NULL, NULL); 1633 total_len += wc_len; 1634 } 1635#else 1636 png_snprintf(buf + 1, 63, "%12.12e", width); 1637 total_len = 1 + png_strlen(buf + 1) + 1; 1638 png_snprintf(buf + total_len, 64-total_len, "%12.12e", height); 1639 total_len += png_strlen(buf + total_len); 1640#endif 1641 1642 png_debug1(3, "sCAL total length = %u\n", (unsigned int)total_len); 1643 png_write_chunk(png_ptr, png_sCAL, (png_bytep)buf, total_len); 1644} 1645#else 1646#ifdef PNG_FIXED_POINT_SUPPORTED 1647void /* PRIVATE */ 1648png_write_sCAL_s(png_structp png_ptr, int unit, png_charp width, 1649 png_charp height) 1650{ 1651#ifdef PNG_USE_LOCAL_ARRAYS 1652 PNG_sCAL; 1653#endif 1654 png_byte buf[64]; 1655 png_size_t wlen, hlen, total_len; 1656 1657 png_debug(1, "in png_write_sCAL_s\n"); 1658 1659 wlen = png_strlen(width); 1660 hlen = png_strlen(height); 1661 total_len = wlen + hlen + 2; 1662 if (total_len > 64) 1663 { 1664 png_warning(png_ptr, "Can't write sCAL (buffer too small)"); 1665 return; 1666 } 1667 1668 buf[0] = (png_byte)unit; 1669 png_memcpy(buf + 1, width, wlen + 1); /* append the '\0' here */ 1670 png_memcpy(buf + wlen + 2, height, hlen); /* do NOT append the '\0' here */ 1671 1672 png_debug1(3, "sCAL total length = %u\n", (unsigned int)total_len); 1673 png_write_chunk(png_ptr, png_sCAL, buf, total_len); 1674} 1675#endif 1676#endif 1677#endif 1678 1679#if defined(PNG_WRITE_pHYs_SUPPORTED) 1680/* write the pHYs chunk */ 1681void /* PRIVATE */ 1682png_write_pHYs(png_structp png_ptr, png_uint_32 x_pixels_per_unit, 1683 png_uint_32 y_pixels_per_unit, 1684 int unit_type) 1685{ 1686#ifdef PNG_USE_LOCAL_ARRAYS 1687 PNG_pHYs; 1688#endif 1689 png_byte buf[9]; 1690 1691 png_debug(1, "in png_write_pHYs\n"); 1692 if (unit_type >= PNG_RESOLUTION_LAST) 1693 png_warning(png_ptr, "Unrecognized unit type for pHYs chunk"); 1694 1695 png_save_uint_32(buf, x_pixels_per_unit); 1696 png_save_uint_32(buf + 4, y_pixels_per_unit); 1697 buf[8] = (png_byte)unit_type; 1698 1699 png_write_chunk(png_ptr, png_pHYs, buf, (png_size_t)9); 1700} 1701#endif 1702 1703#if defined(PNG_WRITE_tIME_SUPPORTED) 1704/* Write the tIME chunk. Use either png_convert_from_struct_tm() 1705 * or png_convert_from_time_t(), or fill in the structure yourself. 1706 */ 1707void /* PRIVATE */ 1708png_write_tIME(png_structp png_ptr, png_timep mod_time) 1709{ 1710#ifdef PNG_USE_LOCAL_ARRAYS 1711 PNG_tIME; 1712#endif 1713 png_byte buf[7]; 1714 1715 png_debug(1, "in png_write_tIME\n"); 1716 if (mod_time->month > 12 || mod_time->month < 1 || 1717 mod_time->day > 31 || mod_time->day < 1 || 1718 mod_time->hour > 23 || mod_time->second > 60) 1719 { 1720 png_warning(png_ptr, "Invalid time specified for tIME chunk"); 1721 return; 1722 } 1723 1724 png_save_uint_16(buf, mod_time->year); 1725 buf[2] = mod_time->month; 1726 buf[3] = mod_time->day; 1727 buf[4] = mod_time->hour; 1728 buf[5] = mod_time->minute; 1729 buf[6] = mod_time->second; 1730 1731 png_write_chunk(png_ptr, png_tIME, buf, (png_size_t)7); 1732} 1733#endif 1734 1735/* initializes the row writing capability of libpng */ 1736void /* PRIVATE */ 1737png_write_start_row(png_structp png_ptr) 1738{ 1739#ifdef PNG_WRITE_INTERLACING_SUPPORTED 1740#ifdef PNG_USE_LOCAL_ARRAYS 1741 /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */ 1742 1743 /* start of interlace block */ 1744 int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; 1745 1746 /* offset to next interlace block */ 1747 int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; 1748 1749 /* start of interlace block in the y direction */ 1750 int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1}; 1751 1752 /* offset to next interlace block in the y direction */ 1753 int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; 1754#endif 1755#endif 1756 1757 png_size_t buf_size; 1758 1759 png_debug(1, "in png_write_start_row\n"); 1760 buf_size = (png_size_t)(PNG_ROWBYTES( 1761 png_ptr->usr_channels*png_ptr->usr_bit_depth,png_ptr->width)+1); 1762 1763 /* set up row buffer */ 1764 png_ptr->row_buf = (png_bytep)png_malloc(png_ptr, (png_uint_32)buf_size); 1765 png_ptr->row_buf[0] = PNG_FILTER_VALUE_NONE; 1766 1767#ifndef PNG_NO_WRITE_FILTERING 1768 /* set up filtering buffer, if using this filter */ 1769 if (png_ptr->do_filter & PNG_FILTER_SUB) 1770 { 1771 png_ptr->sub_row = (png_bytep)png_malloc(png_ptr, 1772 (png_ptr->rowbytes + 1)); 1773 png_ptr->sub_row[0] = PNG_FILTER_VALUE_SUB; 1774 } 1775 1776 /* We only need to keep the previous row if we are using one of these. */ 1777 if (png_ptr->do_filter & (PNG_FILTER_AVG | PNG_FILTER_UP | PNG_FILTER_PAETH)) 1778 { 1779 /* set up previous row buffer */ 1780 png_ptr->prev_row = (png_bytep)png_malloc(png_ptr, (png_uint_32)buf_size); 1781 png_memset(png_ptr->prev_row, 0, buf_size); 1782 1783 if (png_ptr->do_filter & PNG_FILTER_UP) 1784 { 1785 png_ptr->up_row = (png_bytep)png_malloc(png_ptr, 1786 (png_ptr->rowbytes + 1)); 1787 png_ptr->up_row[0] = PNG_FILTER_VALUE_UP; 1788 } 1789 1790 if (png_ptr->do_filter & PNG_FILTER_AVG) 1791 { 1792 png_ptr->avg_row = (png_bytep)png_malloc(png_ptr, 1793 (png_ptr->rowbytes + 1)); 1794 png_ptr->avg_row[0] = PNG_FILTER_VALUE_AVG; 1795 } 1796 1797 if (png_ptr->do_filter & PNG_FILTER_PAETH) 1798 { 1799 png_ptr->paeth_row = (png_bytep)png_malloc(png_ptr, 1800 (png_ptr->rowbytes + 1)); 1801 png_ptr->paeth_row[0] = PNG_FILTER_VALUE_PAETH; 1802 } 1803#endif /* PNG_NO_WRITE_FILTERING */ 1804 } 1805 1806#ifdef PNG_WRITE_INTERLACING_SUPPORTED 1807 /* if interlaced, we need to set up width and height of pass */ 1808 if (png_ptr->interlaced) 1809 { 1810 if (!(png_ptr->transformations & PNG_INTERLACE)) 1811 { 1812 png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 - 1813 png_pass_ystart[0]) / png_pass_yinc[0]; 1814 png_ptr->usr_width = (png_ptr->width + png_pass_inc[0] - 1 - 1815 png_pass_start[0]) / png_pass_inc[0]; 1816 } 1817 else 1818 { 1819 png_ptr->num_rows = png_ptr->height; 1820 png_ptr->usr_width = png_ptr->width; 1821 } 1822 } 1823 else 1824#endif 1825 { 1826 png_ptr->num_rows = png_ptr->height; 1827 png_ptr->usr_width = png_ptr->width; 1828 } 1829 png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; 1830 png_ptr->zstream.next_out = png_ptr->zbuf; 1831} 1832 1833/* Internal use only. Called when finished processing a row of data. */ 1834void /* PRIVATE */ 1835png_write_finish_row(png_structp png_ptr) 1836{ 1837#ifdef PNG_WRITE_INTERLACING_SUPPORTED 1838#ifdef PNG_USE_LOCAL_ARRAYS 1839 /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */ 1840 1841 /* start of interlace block */ 1842 int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; 1843 1844 /* offset to next interlace block */ 1845 int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; 1846 1847 /* start of interlace block in the y direction */ 1848 int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1}; 1849 1850 /* offset to next interlace block in the y direction */ 1851 int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; 1852#endif 1853#endif 1854 1855 int ret; 1856 1857 png_debug(1, "in png_write_finish_row\n"); 1858 /* next row */ 1859 png_ptr->row_number++; 1860 1861 /* see if we are done */ 1862 if (png_ptr->row_number < png_ptr->num_rows) 1863 return; 1864 1865#ifdef PNG_WRITE_INTERLACING_SUPPORTED 1866 /* if interlaced, go to next pass */ 1867 if (png_ptr->interlaced) 1868 { 1869 png_ptr->row_number = 0; 1870 if (png_ptr->transformations & PNG_INTERLACE) 1871 { 1872 png_ptr->pass++; 1873 } 1874 else 1875 { 1876 /* loop until we find a non-zero width or height pass */ 1877 do 1878 { 1879 png_ptr->pass++; 1880 if (png_ptr->pass >= 7) 1881 break; 1882 png_ptr->usr_width = (png_ptr->width + 1883 png_pass_inc[png_ptr->pass] - 1 - 1884 png_pass_start[png_ptr->pass]) / 1885 png_pass_inc[png_ptr->pass]; 1886 png_ptr->num_rows = (png_ptr->height + 1887 png_pass_yinc[png_ptr->pass] - 1 - 1888 png_pass_ystart[png_ptr->pass]) / 1889 png_pass_yinc[png_ptr->pass]; 1890 if (png_ptr->transformations & PNG_INTERLACE) 1891 break; 1892 } while (png_ptr->usr_width == 0 || png_ptr->num_rows == 0); 1893 1894 } 1895 1896 /* reset the row above the image for the next pass */ 1897 if (png_ptr->pass < 7) 1898 { 1899 if (png_ptr->prev_row != NULL) 1900 png_memset(png_ptr->prev_row, 0, 1901 (png_size_t)(PNG_ROWBYTES(png_ptr->usr_channels* 1902 png_ptr->usr_bit_depth,png_ptr->width))+1); 1903 return; 1904 } 1905 } 1906#endif 1907 1908 /* if we get here, we've just written the last row, so we need 1909 to flush the compressor */ 1910 do 1911 { 1912 /* tell the compressor we are done */ 1913 ret = deflate(&png_ptr->zstream, Z_FINISH); 1914 /* check for an error */ 1915 if (ret == Z_OK) 1916 { 1917 /* check to see if we need more room */ 1918 if (!(png_ptr->zstream.avail_out)) 1919 { 1920 png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size); 1921 png_ptr->zstream.next_out = png_ptr->zbuf; 1922 png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; 1923 } 1924 } 1925 else if (ret != Z_STREAM_END) 1926 { 1927 if (png_ptr->zstream.msg != NULL) 1928 png_error(png_ptr, png_ptr->zstream.msg); 1929 else 1930 png_error(png_ptr, "zlib error"); 1931 } 1932 } while (ret != Z_STREAM_END); 1933 1934 /* write any extra space */ 1935 if (png_ptr->zstream.avail_out < png_ptr->zbuf_size) 1936 { 1937 png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size - 1938 png_ptr->zstream.avail_out); 1939 } 1940 1941 deflateReset(&png_ptr->zstream); 1942 png_ptr->zstream.data_type = Z_BINARY; 1943} 1944 1945#if defined(PNG_WRITE_INTERLACING_SUPPORTED) 1946/* Pick out the correct pixels for the interlace pass. 1947 * The basic idea here is to go through the row with a source 1948 * pointer and a destination pointer (sp and dp), and copy the 1949 * correct pixels for the pass. As the row gets compacted, 1950 * sp will always be >= dp, so we should never overwrite anything. 1951 * See the default: case for the easiest code to understand. 1952 */ 1953void /* PRIVATE */ 1954png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass) 1955{ 1956#ifdef PNG_USE_LOCAL_ARRAYS 1957 /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */ 1958 1959 /* start of interlace block */ 1960 int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; 1961 1962 /* offset to next interlace block */ 1963 int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; 1964#endif 1965 1966 png_debug(1, "in png_do_write_interlace\n"); 1967 /* we don't have to do anything on the last pass (6) */ 1968#if defined(PNG_USELESS_TESTS_SUPPORTED) 1969 if (row != NULL && row_info != NULL && pass < 6) 1970#else 1971 if (pass < 6) 1972#endif 1973 { 1974 /* each pixel depth is handled separately */ 1975 switch (row_info->pixel_depth) 1976 { 1977 case 1: 1978 { 1979 png_bytep sp; 1980 png_bytep dp; 1981 int shift; 1982 int d; 1983 int value; 1984 png_uint_32 i; 1985 png_uint_32 row_width = row_info->width; 1986 1987 dp = row; 1988 d = 0; 1989 shift = 7; 1990 for (i = png_pass_start[pass]; i < row_width; 1991 i += png_pass_inc[pass]) 1992 { 1993 sp = row + (png_size_t)(i >> 3); 1994 value = (int)(*sp >> (7 - (int)(i & 0x07))) & 0x01; 1995 d |= (value << shift); 1996 1997 if (shift == 0) 1998 { 1999 shift = 7; 2000 *dp++ = (png_byte)d; 2001 d = 0; 2002 } 2003 else 2004 shift--; 2005 2006 } 2007 if (shift != 7) 2008 *dp = (png_byte)d; 2009 break; 2010 } 2011 case 2: 2012 { 2013 png_bytep sp; 2014 png_bytep dp; 2015 int shift; 2016 int d; 2017 int value; 2018 png_uint_32 i; 2019 png_uint_32 row_width = row_info->width; 2020 2021 dp = row; 2022 shift = 6; 2023 d = 0; 2024 for (i = png_pass_start[pass]; i < row_width; 2025 i += png_pass_inc[pass]) 2026 { 2027 sp = row + (png_size_t)(i >> 2); 2028 value = (*sp >> ((3 - (int)(i & 0x03)) << 1)) & 0x03; 2029 d |= (value << shift); 2030 2031 if (shift == 0) 2032 { 2033 shift = 6; 2034 *dp++ = (png_byte)d; 2035 d = 0; 2036 } 2037 else 2038 shift -= 2; 2039 } 2040 if (shift != 6) 2041 *dp = (png_byte)d; 2042 break; 2043 } 2044 case 4: 2045 { 2046 png_bytep sp; 2047 png_bytep dp; 2048 int shift; 2049 int d; 2050 int value; 2051 png_uint_32 i; 2052 png_uint_32 row_width = row_info->width; 2053 2054 dp = row; 2055 shift = 4; 2056 d = 0; 2057 for (i = png_pass_start[pass]; i < row_width; 2058 i += png_pass_inc[pass]) 2059 { 2060 sp = row + (png_size_t)(i >> 1); 2061 value = (*sp >> ((1 - (int)(i & 0x01)) << 2)) & 0x0f; 2062 d |= (value << shift); 2063 2064 if (shift == 0) 2065 { 2066 shift = 4; 2067 *dp++ = (png_byte)d; 2068 d = 0; 2069 } 2070 else 2071 shift -= 4; 2072 } 2073 if (shift != 4) 2074 *dp = (png_byte)d; 2075 break; 2076 } 2077 default: 2078 { 2079 png_bytep sp; 2080 png_bytep dp; 2081 png_uint_32 i; 2082 png_uint_32 row_width = row_info->width; 2083 png_size_t pixel_bytes; 2084 2085 /* start at the beginning */ 2086 dp = row; 2087 /* find out how many bytes each pixel takes up */ 2088 pixel_bytes = (row_info->pixel_depth >> 3); 2089 /* loop through the row, only looking at the pixels that 2090 matter */ 2091 for (i = png_pass_start[pass]; i < row_width; 2092 i += png_pass_inc[pass]) 2093 { 2094 /* find out where the original pixel is */ 2095 sp = row + (png_size_t)i * pixel_bytes; 2096 /* move the pixel */ 2097 if (dp != sp) 2098 png_memcpy(dp, sp, pixel_bytes); 2099 /* next pixel */ 2100 dp += pixel_bytes; 2101 } 2102 break; 2103 } 2104 } 2105 /* set new row width */ 2106 row_info->width = (row_info->width + 2107 png_pass_inc[pass] - 1 - 2108 png_pass_start[pass]) / 2109 png_pass_inc[pass]; 2110 row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, 2111 row_info->width); 2112 } 2113} 2114#endif 2115 2116/* This filters the row, chooses which filter to use, if it has not already 2117 * been specified by the application, and then writes the row out with the 2118 * chosen filter. 2119 */ 2120#define PNG_MAXSUM (((png_uint_32)(-1)) >> 1) 2121#define PNG_HISHIFT 10 2122#define PNG_LOMASK ((png_uint_32)0xffffL) 2123#define PNG_HIMASK ((png_uint_32)(~PNG_LOMASK >> PNG_HISHIFT)) 2124void /* PRIVATE */ 2125png_write_find_filter(png_structp png_ptr, png_row_infop row_info) 2126{ 2127 png_bytep best_row; 2128#ifndef PNG_NO_WRITE_FILTER 2129 png_bytep prev_row, row_buf; 2130 png_uint_32 mins, bpp; 2131 png_byte filter_to_do = png_ptr->do_filter; 2132 png_uint_32 row_bytes = row_info->rowbytes; 2133#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) 2134 int num_p_filters = (int)png_ptr->num_prev_filters; 2135#endif 2136 2137 png_debug(1, "in png_write_find_filter\n"); 2138 /* find out how many bytes offset each pixel is */ 2139 bpp = (row_info->pixel_depth + 7) >> 3; 2140 2141 prev_row = png_ptr->prev_row; 2142#endif 2143 best_row = png_ptr->row_buf; 2144#ifndef PNG_NO_WRITE_FILTER 2145 row_buf = best_row; 2146 mins = PNG_MAXSUM; 2147 2148 /* The prediction method we use is to find which method provides the 2149 * smallest value when summing the absolute values of the distances 2150 * from zero, using anything >= 128 as negative numbers. This is known 2151 * as the "minimum sum of absolute differences" heuristic. Other 2152 * heuristics are the "weighted minimum sum of absolute differences" 2153 * (experimental and can in theory improve compression), and the "zlib 2154 * predictive" method (not implemented yet), which does test compressions 2155 * of lines using different filter methods, and then chooses the 2156 * (series of) filter(s) that give minimum compressed data size (VERY 2157 * computationally expensive). 2158 * 2159 * GRR 980525: consider also 2160 * (1) minimum sum of absolute differences from running average (i.e., 2161 * keep running sum of non-absolute differences & count of bytes) 2162 * [track dispersion, too? restart average if dispersion too large?] 2163 * (1b) minimum sum of absolute differences from sliding average, probably 2164 * with window size <= deflate window (usually 32K) 2165 * (2) minimum sum of squared differences from zero or running average 2166 * (i.e., ~ root-mean-square approach) 2167 */ 2168 2169 2170 /* We don't need to test the 'no filter' case if this is the only filter 2171 * that has been chosen, as it doesn't actually do anything to the data. 2172 */ 2173 if ((filter_to_do & PNG_FILTER_NONE) && 2174 filter_to_do != PNG_FILTER_NONE) 2175 { 2176 png_bytep rp; 2177 png_uint_32 sum = 0; 2178 png_uint_32 i; 2179 int v; 2180 2181 for (i = 0, rp = row_buf + 1; i < row_bytes; i++, rp++) 2182 { 2183 v = *rp; 2184 sum += (v < 128) ? v : 256 - v; 2185 } 2186 2187#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) 2188 if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) 2189 { 2190 png_uint_32 sumhi, sumlo; 2191 int j; 2192 sumlo = sum & PNG_LOMASK; 2193 sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK; /* Gives us some footroom */ 2194 2195 /* Reduce the sum if we match any of the previous rows */ 2196 for (j = 0; j < num_p_filters; j++) 2197 { 2198 if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_NONE) 2199 { 2200 sumlo = (sumlo * png_ptr->filter_weights[j]) >> 2201 PNG_WEIGHT_SHIFT; 2202 sumhi = (sumhi * png_ptr->filter_weights[j]) >> 2203 PNG_WEIGHT_SHIFT; 2204 } 2205 } 2206 2207 /* Factor in the cost of this filter (this is here for completeness, 2208 * but it makes no sense to have a "cost" for the NONE filter, as 2209 * it has the minimum possible computational cost - none). 2210 */ 2211 sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_NONE]) >> 2212 PNG_COST_SHIFT; 2213 sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_NONE]) >> 2214 PNG_COST_SHIFT; 2215 2216 if (sumhi > PNG_HIMASK) 2217 sum = PNG_MAXSUM; 2218 else 2219 sum = (sumhi << PNG_HISHIFT) + sumlo; 2220 } 2221#endif 2222 mins = sum; 2223 } 2224 2225 /* sub filter */ 2226 if (filter_to_do == PNG_FILTER_SUB) 2227 /* it's the only filter so no testing is needed */ 2228 { 2229 png_bytep rp, lp, dp; 2230 png_uint_32 i; 2231 for (i = 0, rp = row_buf + 1, dp = png_ptr->sub_row + 1; i < bpp; 2232 i++, rp++, dp++) 2233 { 2234 *dp = *rp; 2235 } 2236 for (lp = row_buf + 1; i < row_bytes; 2237 i++, rp++, lp++, dp++) 2238 { 2239 *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff); 2240 } 2241 best_row = png_ptr->sub_row; 2242 } 2243 2244 else if (filter_to_do & PNG_FILTER_SUB) 2245 { 2246 png_bytep rp, dp, lp; 2247 png_uint_32 sum = 0, lmins = mins; 2248 png_uint_32 i; 2249 int v; 2250 2251#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) 2252 /* We temporarily increase the "minimum sum" by the factor we 2253 * would reduce the sum of this filter, so that we can do the 2254 * early exit comparison without scaling the sum each time. 2255 */ 2256 if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) 2257 { 2258 int j; 2259 png_uint_32 lmhi, lmlo; 2260 lmlo = lmins & PNG_LOMASK; 2261 lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK; 2262 2263 for (j = 0; j < num_p_filters; j++) 2264 { 2265 if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_SUB) 2266 { 2267 lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >> 2268 PNG_WEIGHT_SHIFT; 2269 lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >> 2270 PNG_WEIGHT_SHIFT; 2271 } 2272 } 2273 2274 lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >> 2275 PNG_COST_SHIFT; 2276 lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >> 2277 PNG_COST_SHIFT; 2278 2279 if (lmhi > PNG_HIMASK) 2280 lmins = PNG_MAXSUM; 2281 else 2282 lmins = (lmhi << PNG_HISHIFT) + lmlo; 2283 } 2284#endif 2285 2286 for (i = 0, rp = row_buf + 1, dp = png_ptr->sub_row + 1; i < bpp; 2287 i++, rp++, dp++) 2288 { 2289 v = *dp = *rp; 2290 2291 sum += (v < 128) ? v : 256 - v; 2292 } 2293 for (lp = row_buf + 1; i < row_bytes; 2294 i++, rp++, lp++, dp++) 2295 { 2296 v = *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff); 2297 2298 sum += (v < 128) ? v : 256 - v; 2299 2300 if (sum > lmins) /* We are already worse, don't continue. */ 2301 break; 2302 } 2303 2304#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) 2305 if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) 2306 { 2307 int j; 2308 png_uint_32 sumhi, sumlo; 2309 sumlo = sum & PNG_LOMASK; 2310 sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK; 2311 2312 for (j = 0; j < num_p_filters; j++) 2313 { 2314 if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_SUB) 2315 { 2316 sumlo = (sumlo * png_ptr->inv_filter_weights[j]) >> 2317 PNG_WEIGHT_SHIFT; 2318 sumhi = (sumhi * png_ptr->inv_filter_weights[j]) >> 2319 PNG_WEIGHT_SHIFT; 2320 } 2321 } 2322 2323 sumlo = (sumlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >> 2324 PNG_COST_SHIFT; 2325 sumhi = (sumhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >> 2326 PNG_COST_SHIFT; 2327 2328 if (sumhi > PNG_HIMASK) 2329 sum = PNG_MAXSUM; 2330 else 2331 sum = (sumhi << PNG_HISHIFT) + sumlo; 2332 } 2333#endif 2334 2335 if (sum < mins) 2336 { 2337 mins = sum; 2338 best_row = png_ptr->sub_row; 2339 } 2340 } 2341 2342 /* up filter */ 2343 if (filter_to_do == PNG_FILTER_UP) 2344 { 2345 png_bytep rp, dp, pp; 2346 png_uint_32 i; 2347 2348 for (i = 0, rp = row_buf + 1, dp = png_ptr->up_row + 1, 2349 pp = prev_row + 1; i < row_bytes; 2350 i++, rp++, pp++, dp++) 2351 { 2352 *dp = (png_byte)(((int)*rp - (int)*pp) & 0xff); 2353 } 2354 best_row = png_ptr->up_row; 2355 } 2356 2357 else if (filter_to_do & PNG_FILTER_UP) 2358 { 2359 png_bytep rp, dp, pp; 2360 png_uint_32 sum = 0, lmins = mins; 2361 png_uint_32 i; 2362 int v; 2363 2364 2365#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) 2366 if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) 2367 { 2368 int j; 2369 png_uint_32 lmhi, lmlo; 2370 lmlo = lmins & PNG_LOMASK; 2371 lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK; 2372 2373 for (j = 0; j < num_p_filters; j++) 2374 { 2375 if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_UP) 2376 { 2377 lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >> 2378 PNG_WEIGHT_SHIFT; 2379 lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >> 2380 PNG_WEIGHT_SHIFT; 2381 } 2382 } 2383 2384 lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_UP]) >> 2385 PNG_COST_SHIFT; 2386 lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_UP]) >> 2387 PNG_COST_SHIFT; 2388 2389 if (lmhi > PNG_HIMASK) 2390 lmins = PNG_MAXSUM; 2391 else 2392 lmins = (lmhi << PNG_HISHIFT) + lmlo; 2393 } 2394#endif 2395 2396 for (i = 0, rp = row_buf + 1, dp = png_ptr->up_row + 1, 2397 pp = prev_row + 1; i < row_bytes; i++) 2398 { 2399 v = *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff); 2400 2401 sum += (v < 128) ? v : 256 - v; 2402 2403 if (sum > lmins) /* We are already worse, don't continue. */ 2404 break; 2405 } 2406 2407#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) 2408 if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) 2409 { 2410 int j; 2411 png_uint_32 sumhi, sumlo; 2412 sumlo = sum & PNG_LOMASK; 2413 sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK; 2414 2415 for (j = 0; j < num_p_filters; j++) 2416 { 2417 if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_UP) 2418 { 2419 sumlo = (sumlo * png_ptr->filter_weights[j]) >> 2420 PNG_WEIGHT_SHIFT; 2421 sumhi = (sumhi * png_ptr->filter_weights[j]) >> 2422 PNG_WEIGHT_SHIFT; 2423 } 2424 } 2425 2426 sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_UP]) >> 2427 PNG_COST_SHIFT; 2428 sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_UP]) >> 2429 PNG_COST_SHIFT; 2430 2431 if (sumhi > PNG_HIMASK) 2432 sum = PNG_MAXSUM; 2433 else 2434 sum = (sumhi << PNG_HISHIFT) + sumlo; 2435 } 2436#endif 2437 2438 if (sum < mins) 2439 { 2440 mins = sum; 2441 best_row = png_ptr->up_row; 2442 } 2443 } 2444 2445 /* avg filter */ 2446 if (filter_to_do == PNG_FILTER_AVG) 2447 { 2448 png_bytep rp, dp, pp, lp; 2449 png_uint_32 i; 2450 for (i = 0, rp = row_buf + 1, dp = png_ptr->avg_row + 1, 2451 pp = prev_row + 1; i < bpp; i++) 2452 { 2453 *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff); 2454 } 2455 for (lp = row_buf + 1; i < row_bytes; i++) 2456 { 2457 *dp++ = (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2)) 2458 & 0xff); 2459 } 2460 best_row = png_ptr->avg_row; 2461 } 2462 2463 else if (filter_to_do & PNG_FILTER_AVG) 2464 { 2465 png_bytep rp, dp, pp, lp; 2466 png_uint_32 sum = 0, lmins = mins; 2467 png_uint_32 i; 2468 int v; 2469 2470#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) 2471 if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) 2472 { 2473 int j; 2474 png_uint_32 lmhi, lmlo; 2475 lmlo = lmins & PNG_LOMASK; 2476 lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK; 2477 2478 for (j = 0; j < num_p_filters; j++) 2479 { 2480 if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_AVG) 2481 { 2482 lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >> 2483 PNG_WEIGHT_SHIFT; 2484 lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >> 2485 PNG_WEIGHT_SHIFT; 2486 } 2487 } 2488 2489 lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_AVG]) >> 2490 PNG_COST_SHIFT; 2491 lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_AVG]) >> 2492 PNG_COST_SHIFT; 2493 2494 if (lmhi > PNG_HIMASK) 2495 lmins = PNG_MAXSUM; 2496 else 2497 lmins = (lmhi << PNG_HISHIFT) + lmlo; 2498 } 2499#endif 2500 2501 for (i = 0, rp = row_buf + 1, dp = png_ptr->avg_row + 1, 2502 pp = prev_row + 1; i < bpp; i++) 2503 { 2504 v = *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff); 2505 2506 sum += (v < 128) ? v : 256 - v; 2507 } 2508 for (lp = row_buf + 1; i < row_bytes; i++) 2509 { 2510 v = *dp++ = 2511 (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2)) & 0xff); 2512 2513 sum += (v < 128) ? v : 256 - v; 2514 2515 if (sum > lmins) /* We are already worse, don't continue. */ 2516 break; 2517 } 2518 2519#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) 2520 if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) 2521 { 2522 int j; 2523 png_uint_32 sumhi, sumlo; 2524 sumlo = sum & PNG_LOMASK; 2525 sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK; 2526 2527 for (j = 0; j < num_p_filters; j++) 2528 { 2529 if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_NONE) 2530 { 2531 sumlo = (sumlo * png_ptr->filter_weights[j]) >> 2532 PNG_WEIGHT_SHIFT; 2533 sumhi = (sumhi * png_ptr->filter_weights[j]) >> 2534 PNG_WEIGHT_SHIFT; 2535 } 2536 } 2537 2538 sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_AVG]) >> 2539 PNG_COST_SHIFT; 2540 sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_AVG]) >> 2541 PNG_COST_SHIFT; 2542 2543 if (sumhi > PNG_HIMASK) 2544 sum = PNG_MAXSUM; 2545 else 2546 sum = (sumhi << PNG_HISHIFT) + sumlo; 2547 } 2548#endif 2549 2550 if (sum < mins) 2551 { 2552 mins = sum; 2553 best_row = png_ptr->avg_row; 2554 } 2555 } 2556 2557 /* Paeth filter */ 2558 if (filter_to_do == PNG_FILTER_PAETH) 2559 { 2560 png_bytep rp, dp, pp, cp, lp; 2561 png_uint_32 i; 2562 for (i = 0, rp = row_buf + 1, dp = png_ptr->paeth_row + 1, 2563 pp = prev_row + 1; i < bpp; i++) 2564 { 2565 *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff); 2566 } 2567 2568 for (lp = row_buf + 1, cp = prev_row + 1; i < row_bytes; i++) 2569 { 2570 int a, b, c, pa, pb, pc, p; 2571 2572 b = *pp++; 2573 c = *cp++; 2574 a = *lp++; 2575 2576 p = b - c; 2577 pc = a - c; 2578 2579#ifdef PNG_USE_ABS 2580 pa = abs(p); 2581 pb = abs(pc); 2582 pc = abs(p + pc); 2583#else 2584 pa = p < 0 ? -p : p; 2585 pb = pc < 0 ? -pc : pc; 2586 pc = (p + pc) < 0 ? -(p + pc) : p + pc; 2587#endif 2588 2589 p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c; 2590 2591 *dp++ = (png_byte)(((int)*rp++ - p) & 0xff); 2592 } 2593 best_row = png_ptr->paeth_row; 2594 } 2595 2596 else if (filter_to_do & PNG_FILTER_PAETH) 2597 { 2598 png_bytep rp, dp, pp, cp, lp; 2599 png_uint_32 sum = 0, lmins = mins; 2600 png_uint_32 i; 2601 int v; 2602 2603#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) 2604 if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) 2605 { 2606 int j; 2607 png_uint_32 lmhi, lmlo; 2608 lmlo = lmins & PNG_LOMASK; 2609 lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK; 2610 2611 for (j = 0; j < num_p_filters; j++) 2612 { 2613 if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_PAETH) 2614 { 2615 lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >> 2616 PNG_WEIGHT_SHIFT; 2617 lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >> 2618 PNG_WEIGHT_SHIFT; 2619 } 2620 } 2621 2622 lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_PAETH]) >> 2623 PNG_COST_SHIFT; 2624 lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_PAETH]) >> 2625 PNG_COST_SHIFT; 2626 2627 if (lmhi > PNG_HIMASK) 2628 lmins = PNG_MAXSUM; 2629 else 2630 lmins = (lmhi << PNG_HISHIFT) + lmlo; 2631 } 2632#endif 2633 2634 for (i = 0, rp = row_buf + 1, dp = png_ptr->paeth_row + 1, 2635 pp = prev_row + 1; i < bpp; i++) 2636 { 2637 v = *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff); 2638 2639 sum += (v < 128) ? v : 256 - v; 2640 } 2641 2642 for (lp = row_buf + 1, cp = prev_row + 1; i < row_bytes; i++) 2643 { 2644 int a, b, c, pa, pb, pc, p; 2645 2646 b = *pp++; 2647 c = *cp++; 2648 a = *lp++; 2649 2650#ifndef PNG_SLOW_PAETH 2651 p = b - c; 2652 pc = a - c; 2653#ifdef PNG_USE_ABS 2654 pa = abs(p); 2655 pb = abs(pc); 2656 pc = abs(p + pc); 2657#else 2658 pa = p < 0 ? -p : p; 2659 pb = pc < 0 ? -pc : pc; 2660 pc = (p + pc) < 0 ? -(p + pc) : p + pc; 2661#endif 2662 p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c; 2663#else /* PNG_SLOW_PAETH */ 2664 p = a + b - c; 2665 pa = abs(p - a); 2666 pb = abs(p - b); 2667 pc = abs(p - c); 2668 if (pa <= pb && pa <= pc) 2669 p = a; 2670 else if (pb <= pc) 2671 p = b; 2672 else 2673 p = c; 2674#endif /* PNG_SLOW_PAETH */ 2675 2676 v = *dp++ = (png_byte)(((int)*rp++ - p) & 0xff); 2677 2678 sum += (v < 128) ? v : 256 - v; 2679 2680 if (sum > lmins) /* We are already worse, don't continue. */ 2681 break; 2682 } 2683 2684#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) 2685 if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) 2686 { 2687 int j; 2688 png_uint_32 sumhi, sumlo; 2689 sumlo = sum & PNG_LOMASK; 2690 sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK; 2691 2692 for (j = 0; j < num_p_filters; j++) 2693 { 2694 if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_PAETH) 2695 { 2696 sumlo = (sumlo * png_ptr->filter_weights[j]) >> 2697 PNG_WEIGHT_SHIFT; 2698 sumhi = (sumhi * png_ptr->filter_weights[j]) >> 2699 PNG_WEIGHT_SHIFT; 2700 } 2701 } 2702 2703 sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_PAETH]) >> 2704 PNG_COST_SHIFT; 2705 sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_PAETH]) >> 2706 PNG_COST_SHIFT; 2707 2708 if (sumhi > PNG_HIMASK) 2709 sum = PNG_MAXSUM; 2710 else 2711 sum = (sumhi << PNG_HISHIFT) + sumlo; 2712 } 2713#endif 2714 2715 if (sum < mins) 2716 { 2717 best_row = png_ptr->paeth_row; 2718 } 2719 } 2720#endif /* PNG_NO_WRITE_FILTER */ 2721 /* Do the actual writing of the filtered row data from the chosen filter. */ 2722 2723 png_write_filtered_row(png_ptr, best_row); 2724 2725#ifndef PNG_NO_WRITE_FILTER 2726#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) 2727 /* Save the type of filter we picked this time for future calculations */ 2728 if (png_ptr->num_prev_filters > 0) 2729 { 2730 int j; 2731 for (j = 1; j < num_p_filters; j++) 2732 { 2733 png_ptr->prev_filters[j] = png_ptr->prev_filters[j - 1]; 2734 } 2735 png_ptr->prev_filters[j] = best_row[0]; 2736 } 2737#endif 2738#endif /* PNG_NO_WRITE_FILTER */ 2739} 2740 2741 2742/* Do the actual writing of a previously filtered row. */ 2743void /* PRIVATE */ 2744png_write_filtered_row(png_structp png_ptr, png_bytep filtered_row) 2745{ 2746 png_debug(1, "in png_write_filtered_row\n"); 2747 png_debug1(2, "filter = %d\n", filtered_row[0]); 2748 /* set up the zlib input buffer */ 2749 2750 png_ptr->zstream.next_in = filtered_row; 2751 png_ptr->zstream.avail_in = (uInt)png_ptr->row_info.rowbytes + 1; 2752 /* repeat until we have compressed all the data */ 2753 do 2754 { 2755 int ret; /* return of zlib */ 2756 2757 /* compress the data */ 2758 ret = deflate(&png_ptr->zstream, Z_NO_FLUSH); 2759 /* check for compression errors */ 2760 if (ret != Z_OK) 2761 { 2762 if (png_ptr->zstream.msg != NULL) 2763 png_error(png_ptr, png_ptr->zstream.msg); 2764 else 2765 png_error(png_ptr, "zlib error"); 2766 } 2767 2768 /* see if it is time to write another IDAT */ 2769 if (!(png_ptr->zstream.avail_out)) 2770 { 2771 /* write the IDAT and reset the zlib output buffer */ 2772 png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size); 2773 png_ptr->zstream.next_out = png_ptr->zbuf; 2774 png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; 2775 } 2776 /* repeat until all data has been compressed */ 2777 } while (png_ptr->zstream.avail_in); 2778 2779 /* swap the current and previous rows */ 2780 if (png_ptr->prev_row != NULL) 2781 { 2782 png_bytep tptr; 2783 2784 tptr = png_ptr->prev_row; 2785 png_ptr->prev_row = png_ptr->row_buf; 2786 png_ptr->row_buf = tptr; 2787 } 2788 2789 /* finish row - updates counters and flushes zlib if last row */ 2790 png_write_finish_row(png_ptr); 2791 2792#if defined(PNG_WRITE_FLUSH_SUPPORTED) 2793 png_ptr->flush_rows++; 2794 2795 if (png_ptr->flush_dist > 0 && 2796 png_ptr->flush_rows >= png_ptr->flush_dist) 2797 { 2798 png_write_flush(png_ptr); 2799 } 2800#endif 2801} 2802#endif /* PNG_WRITE_SUPPORTED */ 2803