|
fltk 1.3.0rc3
About: FLTK (Fast Light Tool Kit) is a cross-platform C++ GUI toolkit for UNIX/Linux (X11), Microsoft Windows, and MacOS X. Release candidate.
SfR Fresh Dox: fltk-1.3.0rc3-source.tar.gz ("inofficial" and yet experimental doxygen-generated source code documentation) ![]() |
00001 00002 /* pngwutil.c - utilities to write a PNG file 00003 * 00004 * Last changed in libpng 1.2.40 [September 10, 2009] 00005 * Copyright (c) 1998-2009 Glenn Randers-Pehrson 00006 * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) 00007 * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) 00008 * 00009 * This code is released under the libpng license. 00010 * For conditions of distribution and use, see the disclaimer 00011 * and license in png.h 00012 */ 00013 00014 #define PNG_INTERNAL 00015 #include "png.h" 00016 #ifdef PNG_WRITE_SUPPORTED 00017 00018 /* Place a 32-bit number into a buffer in PNG byte order. We work 00019 * with unsigned numbers for convenience, although one supported 00020 * ancillary chunk uses signed (two's complement) numbers. 00021 */ 00022 void PNGAPI 00023 png_save_uint_32(png_bytep buf, png_uint_32 i) 00024 { 00025 buf[0] = (png_byte)((i >> 24) & 0xff); 00026 buf[1] = (png_byte)((i >> 16) & 0xff); 00027 buf[2] = (png_byte)((i >> 8) & 0xff); 00028 buf[3] = (png_byte)(i & 0xff); 00029 } 00030 00031 /* The png_save_int_32 function assumes integers are stored in two's 00032 * complement format. If this isn't the case, then this routine needs to 00033 * be modified to write data in two's complement format. 00034 */ 00035 void PNGAPI 00036 png_save_int_32(png_bytep buf, png_int_32 i) 00037 { 00038 buf[0] = (png_byte)((i >> 24) & 0xff); 00039 buf[1] = (png_byte)((i >> 16) & 0xff); 00040 buf[2] = (png_byte)((i >> 8) & 0xff); 00041 buf[3] = (png_byte)(i & 0xff); 00042 } 00043 00044 /* Place a 16-bit number into a buffer in PNG byte order. 00045 * The parameter is declared unsigned int, not png_uint_16, 00046 * just to avoid potential problems on pre-ANSI C compilers. 00047 */ 00048 void PNGAPI 00049 png_save_uint_16(png_bytep buf, unsigned int i) 00050 { 00051 buf[0] = (png_byte)((i >> 8) & 0xff); 00052 buf[1] = (png_byte)(i & 0xff); 00053 } 00054 00055 /* Simple function to write the signature. If we have already written 00056 * the magic bytes of the signature, or more likely, the PNG stream is 00057 * being embedded into another stream and doesn't need its own signature, 00058 * we should call png_set_sig_bytes() to tell libpng how many of the 00059 * bytes have already been written. 00060 */ 00061 void /* PRIVATE */ 00062 png_write_sig(png_structp png_ptr) 00063 { 00064 png_byte png_signature[8] = {137, 80, 78, 71, 13, 10, 26, 10}; 00065 00066 /* Write the rest of the 8 byte signature */ 00067 png_write_data(png_ptr, &png_signature[png_ptr->sig_bytes], 00068 (png_size_t)(8 - png_ptr->sig_bytes)); 00069 if (png_ptr->sig_bytes < 3) 00070 png_ptr->mode |= PNG_HAVE_PNG_SIGNATURE; 00071 } 00072 00073 /* Write a PNG chunk all at once. The type is an array of ASCII characters 00074 * representing the chunk name. The array must be at least 4 bytes in 00075 * length, and does not need to be null terminated. To be safe, pass the 00076 * pre-defined chunk names here, and if you need a new one, define it 00077 * where the others are defined. The length is the length of the data. 00078 * All the data must be present. If that is not possible, use the 00079 * png_write_chunk_start(), png_write_chunk_data(), and png_write_chunk_end() 00080 * functions instead. 00081 */ 00082 void PNGAPI 00083 png_write_chunk(png_structp png_ptr, png_bytep chunk_name, 00084 png_bytep data, png_size_t length) 00085 { 00086 if (png_ptr == NULL) 00087 return; 00088 png_write_chunk_start(png_ptr, chunk_name, (png_uint_32)length); 00089 png_write_chunk_data(png_ptr, data, (png_size_t)length); 00090 png_write_chunk_end(png_ptr); 00091 } 00092 00093 /* Write the start of a PNG chunk. The type is the chunk type. 00094 * The total_length is the sum of the lengths of all the data you will be 00095 * passing in png_write_chunk_data(). 00096 */ 00097 void PNGAPI 00098 png_write_chunk_start(png_structp png_ptr, png_bytep chunk_name, 00099 png_uint_32 length) 00100 { 00101 png_byte buf[8]; 00102 00103 png_debug2(0, "Writing %s chunk, length = %lu", chunk_name, 00104 (unsigned long)length); 00105 00106 if (png_ptr == NULL) 00107 return; 00108 00109 /* Write the length and the chunk name */ 00110 png_save_uint_32(buf, length); 00111 png_memcpy(buf + 4, chunk_name, 4); 00112 png_write_data(png_ptr, buf, (png_size_t)8); 00113 /* Put the chunk name into png_ptr->chunk_name */ 00114 png_memcpy(png_ptr->chunk_name, chunk_name, 4); 00115 /* Reset the crc and run it over the chunk name */ 00116 png_reset_crc(png_ptr); 00117 png_calculate_crc(png_ptr, chunk_name, (png_size_t)4); 00118 } 00119 00120 /* Write the data of a PNG chunk started with png_write_chunk_start(). 00121 * Note that multiple calls to this function are allowed, and that the 00122 * sum of the lengths from these calls *must* add up to the total_length 00123 * given to png_write_chunk_start(). 00124 */ 00125 void PNGAPI 00126 png_write_chunk_data(png_structp png_ptr, png_bytep data, png_size_t length) 00127 { 00128 /* Write the data, and run the CRC over it */ 00129 if (png_ptr == NULL) 00130 return; 00131 if (data != NULL && length > 0) 00132 { 00133 png_write_data(png_ptr, data, length); 00134 /* Update the CRC after writing the data, 00135 * in case that the user I/O routine alters it. 00136 */ 00137 png_calculate_crc(png_ptr, data, length); 00138 } 00139 } 00140 00141 /* Finish a chunk started with png_write_chunk_start(). */ 00142 void PNGAPI 00143 png_write_chunk_end(png_structp png_ptr) 00144 { 00145 png_byte buf[4]; 00146 00147 if (png_ptr == NULL) return; 00148 00149 /* Write the crc in a single operation */ 00150 png_save_uint_32(buf, png_ptr->crc); 00151 00152 png_write_data(png_ptr, buf, (png_size_t)4); 00153 } 00154 00155 #if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_iCCP_SUPPORTED) 00156 /* This pair of functions encapsulates the operation of (a) compressing a 00157 * text string, and (b) issuing it later as a series of chunk data writes. 00158 * The compression_state structure is shared context for these functions 00159 * set up by the caller in order to make the whole mess thread-safe. 00160 */ 00161 00162 typedef struct 00163 { 00164 char *input; /* The uncompressed input data */ 00165 int input_len; /* Its length */ 00166 int num_output_ptr; /* Number of output pointers used */ 00167 int max_output_ptr; /* Size of output_ptr */ 00168 png_charpp output_ptr; /* Array of pointers to output */ 00169 } compression_state; 00170 00171 /* Compress given text into storage in the png_ptr structure */ 00172 static int /* PRIVATE */ 00173 png_text_compress(png_structp png_ptr, 00174 png_charp text, png_size_t text_len, int compression, 00175 compression_state *comp) 00176 { 00177 int ret; 00178 00179 comp->num_output_ptr = 0; 00180 comp->max_output_ptr = 0; 00181 comp->output_ptr = NULL; 00182 comp->input = NULL; 00183 comp->input_len = 0; 00184 00185 /* We may just want to pass the text right through */ 00186 if (compression == PNG_TEXT_COMPRESSION_NONE) 00187 { 00188 comp->input = text; 00189 comp->input_len = text_len; 00190 return((int)text_len); 00191 } 00192 00193 if (compression >= PNG_TEXT_COMPRESSION_LAST) 00194 { 00195 #if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE) 00196 char msg[50]; 00197 png_snprintf(msg, 50, "Unknown compression type %d", compression); 00198 png_warning(png_ptr, msg); 00199 #else 00200 png_warning(png_ptr, "Unknown compression type"); 00201 #endif 00202 } 00203 00204 /* We can't write the chunk until we find out how much data we have, 00205 * which means we need to run the compressor first and save the 00206 * output. This shouldn't be a problem, as the vast majority of 00207 * comments should be reasonable, but we will set up an array of 00208 * malloc'd pointers to be sure. 00209 * 00210 * If we knew the application was well behaved, we could simplify this 00211 * greatly by assuming we can always malloc an output buffer large 00212 * enough to hold the compressed text ((1001 * text_len / 1000) + 12) 00213 * and malloc this directly. The only time this would be a bad idea is 00214 * if we can't malloc more than 64K and we have 64K of random input 00215 * data, or if the input string is incredibly large (although this 00216 * wouldn't cause a failure, just a slowdown due to swapping). 00217 */ 00218 00219 /* Set up the compression buffers */ 00220 png_ptr->zstream.avail_in = (uInt)text_len; 00221 png_ptr->zstream.next_in = (Bytef *)text; 00222 png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; 00223 png_ptr->zstream.next_out = (Bytef *)png_ptr->zbuf; 00224 00225 /* This is the same compression loop as in png_write_row() */ 00226 do 00227 { 00228 /* Compress the data */ 00229 ret = deflate(&png_ptr->zstream, Z_NO_FLUSH); 00230 if (ret != Z_OK) 00231 { 00232 /* Error */ 00233 if (png_ptr->zstream.msg != NULL) 00234 png_error(png_ptr, png_ptr->zstream.msg); 00235 else 00236 png_error(png_ptr, "zlib error"); 00237 } 00238 /* Check to see if we need more room */ 00239 if (!(png_ptr->zstream.avail_out)) 00240 { 00241 /* Make sure the output array has room */ 00242 if (comp->num_output_ptr >= comp->max_output_ptr) 00243 { 00244 int old_max; 00245 00246 old_max = comp->max_output_ptr; 00247 comp->max_output_ptr = comp->num_output_ptr + 4; 00248 if (comp->output_ptr != NULL) 00249 { 00250 png_charpp old_ptr; 00251 00252 old_ptr = comp->output_ptr; 00253 comp->output_ptr = (png_charpp)png_malloc(png_ptr, 00254 (png_uint_32) 00255 (comp->max_output_ptr * png_sizeof(png_charpp))); 00256 png_memcpy(comp->output_ptr, old_ptr, old_max 00257 * png_sizeof(png_charp)); 00258 png_free(png_ptr, old_ptr); 00259 } 00260 else 00261 comp->output_ptr = (png_charpp)png_malloc(png_ptr, 00262 (png_uint_32) 00263 (comp->max_output_ptr * png_sizeof(png_charp))); 00264 } 00265 00266 /* Save the data */ 00267 comp->output_ptr[comp->num_output_ptr] = 00268 (png_charp)png_malloc(png_ptr, 00269 (png_uint_32)png_ptr->zbuf_size); 00270 png_memcpy(comp->output_ptr[comp->num_output_ptr], png_ptr->zbuf, 00271 png_ptr->zbuf_size); 00272 comp->num_output_ptr++; 00273 00274 /* and reset the buffer */ 00275 png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; 00276 png_ptr->zstream.next_out = png_ptr->zbuf; 00277 } 00278 /* Continue until we don't have any more to compress */ 00279 } while (png_ptr->zstream.avail_in); 00280 00281 /* Finish the compression */ 00282 do 00283 { 00284 /* Tell zlib we are finished */ 00285 ret = deflate(&png_ptr->zstream, Z_FINISH); 00286 00287 if (ret == Z_OK) 00288 { 00289 /* Check to see if we need more room */ 00290 if (!(png_ptr->zstream.avail_out)) 00291 { 00292 /* Check to make sure our output array has room */ 00293 if (comp->num_output_ptr >= comp->max_output_ptr) 00294 { 00295 int old_max; 00296 00297 old_max = comp->max_output_ptr; 00298 comp->max_output_ptr = comp->num_output_ptr + 4; 00299 if (comp->output_ptr != NULL) 00300 { 00301 png_charpp old_ptr; 00302 00303 old_ptr = comp->output_ptr; 00304 /* This could be optimized to realloc() */ 00305 comp->output_ptr = (png_charpp)png_malloc(png_ptr, 00306 (png_uint_32)(comp->max_output_ptr * 00307 png_sizeof(png_charp))); 00308 png_memcpy(comp->output_ptr, old_ptr, 00309 old_max * png_sizeof(png_charp)); 00310 png_free(png_ptr, old_ptr); 00311 } 00312 else 00313 comp->output_ptr = (png_charpp)png_malloc(png_ptr, 00314 (png_uint_32)(comp->max_output_ptr * 00315 png_sizeof(png_charp))); 00316 } 00317 00318 /* Save the data */ 00319 comp->output_ptr[comp->num_output_ptr] = 00320 (png_charp)png_malloc(png_ptr, 00321 (png_uint_32)png_ptr->zbuf_size); 00322 png_memcpy(comp->output_ptr[comp->num_output_ptr], png_ptr->zbuf, 00323 png_ptr->zbuf_size); 00324 comp->num_output_ptr++; 00325 00326 /* and reset the buffer pointers */ 00327 png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; 00328 png_ptr->zstream.next_out = png_ptr->zbuf; 00329 } 00330 } 00331 else if (ret != Z_STREAM_END) 00332 { 00333 /* We got an error */ 00334 if (png_ptr->zstream.msg != NULL) 00335 png_error(png_ptr, png_ptr->zstream.msg); 00336 else 00337 png_error(png_ptr, "zlib error"); 00338 } 00339 } while (ret != Z_STREAM_END); 00340 00341 /* Text length is number of buffers plus last buffer */ 00342 text_len = png_ptr->zbuf_size * comp->num_output_ptr; 00343 if (png_ptr->zstream.avail_out < png_ptr->zbuf_size) 00344 text_len += png_ptr->zbuf_size - (png_size_t)png_ptr->zstream.avail_out; 00345 00346 return((int)text_len); 00347 } 00348 00349 /* Ship the compressed text out via chunk writes */ 00350 static void /* PRIVATE */ 00351 png_write_compressed_data_out(png_structp png_ptr, compression_state *comp) 00352 { 00353 int i; 00354 00355 /* Handle the no-compression case */ 00356 if (comp->input) 00357 { 00358 png_write_chunk_data(png_ptr, (png_bytep)comp->input, 00359 (png_size_t)comp->input_len); 00360 return; 00361 } 00362 00363 /* Write saved output buffers, if any */ 00364 for (i = 0; i < comp->num_output_ptr; i++) 00365 { 00366 png_write_chunk_data(png_ptr, (png_bytep)comp->output_ptr[i], 00367 (png_size_t)png_ptr->zbuf_size); 00368 png_free(png_ptr, comp->output_ptr[i]); 00369 comp->output_ptr[i]=NULL; 00370 } 00371 if (comp->max_output_ptr != 0) 00372 png_free(png_ptr, comp->output_ptr); 00373 comp->output_ptr=NULL; 00374 /* Write anything left in zbuf */ 00375 if (png_ptr->zstream.avail_out < (png_uint_32)png_ptr->zbuf_size) 00376 png_write_chunk_data(png_ptr, png_ptr->zbuf, 00377 (png_size_t)(png_ptr->zbuf_size - png_ptr->zstream.avail_out)); 00378 00379 /* Reset zlib for another zTXt/iTXt or image data */ 00380 deflateReset(&png_ptr->zstream); 00381 png_ptr->zstream.data_type = Z_BINARY; 00382 } 00383 #endif 00384 00385 /* Write the IHDR chunk, and update the png_struct with the necessary 00386 * information. Note that the rest of this code depends upon this 00387 * information being correct. 00388 */ 00389 void /* PRIVATE */ 00390 png_write_IHDR(png_structp png_ptr, png_uint_32 width, png_uint_32 height, 00391 int bit_depth, int color_type, int compression_type, int filter_type, 00392 int interlace_type) 00393 { 00394 #ifdef PNG_USE_LOCAL_ARRAYS 00395 PNG_IHDR; 00396 #endif 00397 int ret; 00398 00399 png_byte buf[13]; /* Buffer to store the IHDR info */ 00400 00401 png_debug(1, "in png_write_IHDR"); 00402 00403 /* Check that we have valid input data from the application info */ 00404 switch (color_type) 00405 { 00406 case PNG_COLOR_TYPE_GRAY: 00407 switch (bit_depth) 00408 { 00409 case 1: 00410 case 2: 00411 case 4: 00412 case 8: 00413 case 16: png_ptr->channels = 1; break; 00414 default: png_error(png_ptr, "Invalid bit depth for grayscale image"); 00415 } 00416 break; 00417 case PNG_COLOR_TYPE_RGB: 00418 if (bit_depth != 8 && bit_depth != 16) 00419 png_error(png_ptr, "Invalid bit depth for RGB image"); 00420 png_ptr->channels = 3; 00421 break; 00422 case PNG_COLOR_TYPE_PALETTE: 00423 switch (bit_depth) 00424 { 00425 case 1: 00426 case 2: 00427 case 4: 00428 case 8: png_ptr->channels = 1; break; 00429 default: png_error(png_ptr, "Invalid bit depth for paletted image"); 00430 } 00431 break; 00432 case PNG_COLOR_TYPE_GRAY_ALPHA: 00433 if (bit_depth != 8 && bit_depth != 16) 00434 png_error(png_ptr, "Invalid bit depth for grayscale+alpha image"); 00435 png_ptr->channels = 2; 00436 break; 00437 case PNG_COLOR_TYPE_RGB_ALPHA: 00438 if (bit_depth != 8 && bit_depth != 16) 00439 png_error(png_ptr, "Invalid bit depth for RGBA image"); 00440 png_ptr->channels = 4; 00441 break; 00442 default: 00443 png_error(png_ptr, "Invalid image color type specified"); 00444 } 00445 00446 if (compression_type != PNG_COMPRESSION_TYPE_BASE) 00447 { 00448 png_warning(png_ptr, "Invalid compression type specified"); 00449 compression_type = PNG_COMPRESSION_TYPE_BASE; 00450 } 00451 00452 /* Write filter_method 64 (intrapixel differencing) only if 00453 * 1. Libpng was compiled with PNG_MNG_FEATURES_SUPPORTED and 00454 * 2. Libpng did not write a PNG signature (this filter_method is only 00455 * used in PNG datastreams that are embedded in MNG datastreams) and 00456 * 3. The application called png_permit_mng_features with a mask that 00457 * included PNG_FLAG_MNG_FILTER_64 and 00458 * 4. The filter_method is 64 and 00459 * 5. The color_type is RGB or RGBA 00460 */ 00461 if ( 00462 #if defined(PNG_MNG_FEATURES_SUPPORTED) 00463 !((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) && 00464 ((png_ptr->mode&PNG_HAVE_PNG_SIGNATURE) == 0) && 00465 (color_type == PNG_COLOR_TYPE_RGB || 00466 color_type == PNG_COLOR_TYPE_RGB_ALPHA) && 00467 (filter_type == PNG_INTRAPIXEL_DIFFERENCING)) && 00468 #endif 00469 filter_type != PNG_FILTER_TYPE_BASE) 00470 { 00471 png_warning(png_ptr, "Invalid filter type specified"); 00472 filter_type = PNG_FILTER_TYPE_BASE; 00473 } 00474 00475 #ifdef PNG_WRITE_INTERLACING_SUPPORTED 00476 if (interlace_type != PNG_INTERLACE_NONE && 00477 interlace_type != PNG_INTERLACE_ADAM7) 00478 { 00479 png_warning(png_ptr, "Invalid interlace type specified"); 00480 interlace_type = PNG_INTERLACE_ADAM7; 00481 } 00482 #else 00483 interlace_type=PNG_INTERLACE_NONE; 00484 #endif 00485 00486 /* Save the relevent information */ 00487 png_ptr->bit_depth = (png_byte)bit_depth; 00488 png_ptr->color_type = (png_byte)color_type; 00489 png_ptr->interlaced = (png_byte)interlace_type; 00490 #if defined(PNG_MNG_FEATURES_SUPPORTED) 00491 png_ptr->filter_type = (png_byte)filter_type; 00492 #endif 00493 png_ptr->compression_type = (png_byte)compression_type; 00494 png_ptr->width = width; 00495 png_ptr->height = height; 00496 00497 png_ptr->pixel_depth = (png_byte)(bit_depth * png_ptr->channels); 00498 png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth, width); 00499 /* Set the usr info, so any transformations can modify it */ 00500 png_ptr->usr_width = png_ptr->width; 00501 png_ptr->usr_bit_depth = png_ptr->bit_depth; 00502 png_ptr->usr_channels = png_ptr->channels; 00503 00504 /* Pack the header information into the buffer */ 00505 png_save_uint_32(buf, width); 00506 png_save_uint_32(buf + 4, height); 00507 buf[8] = (png_byte)bit_depth; 00508 buf[9] = (png_byte)color_type; 00509 buf[10] = (png_byte)compression_type; 00510 buf[11] = (png_byte)filter_type; 00511 buf[12] = (png_byte)interlace_type; 00512 00513 /* Write the chunk */ 00514 png_write_chunk(png_ptr, (png_bytep)png_IHDR, buf, (png_size_t)13); 00515 00516 /* Initialize zlib with PNG info */ 00517 png_ptr->zstream.zalloc = png_zalloc; 00518 png_ptr->zstream.zfree = png_zfree; 00519 png_ptr->zstream.opaque = (voidpf)png_ptr; 00520 if (!(png_ptr->do_filter)) 00521 { 00522 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE || 00523 png_ptr->bit_depth < 8) 00524 png_ptr->do_filter = PNG_FILTER_NONE; 00525 else 00526 png_ptr->do_filter = PNG_ALL_FILTERS; 00527 } 00528 if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_STRATEGY)) 00529 { 00530 if (png_ptr->do_filter != PNG_FILTER_NONE) 00531 png_ptr->zlib_strategy = Z_FILTERED; 00532 else 00533 png_ptr->zlib_strategy = Z_DEFAULT_STRATEGY; 00534 } 00535 if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_LEVEL)) 00536 png_ptr->zlib_level = Z_DEFAULT_COMPRESSION; 00537 if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_MEM_LEVEL)) 00538 png_ptr->zlib_mem_level = 8; 00539 if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_WINDOW_BITS)) 00540 png_ptr->zlib_window_bits = 15; 00541 if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_METHOD)) 00542 png_ptr->zlib_method = 8; 00543 ret = deflateInit2(&png_ptr->zstream, png_ptr->zlib_level, 00544 png_ptr->zlib_method, png_ptr->zlib_window_bits, 00545 png_ptr->zlib_mem_level, png_ptr->zlib_strategy); 00546 if (ret != Z_OK) 00547 { 00548 if (ret == Z_VERSION_ERROR) png_error(png_ptr, 00549 "zlib failed to initialize compressor -- version error"); 00550 if (ret == Z_STREAM_ERROR) png_error(png_ptr, 00551 "zlib failed to initialize compressor -- stream error"); 00552 if (ret == Z_MEM_ERROR) png_error(png_ptr, 00553 "zlib failed to initialize compressor -- mem error"); 00554 png_error(png_ptr, "zlib failed to initialize compressor"); 00555 } 00556 png_ptr->zstream.next_out = png_ptr->zbuf; 00557 png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; 00558 /* libpng is not interested in zstream.data_type */ 00559 /* Set it to a predefined value, to avoid its evaluation inside zlib */ 00560 png_ptr->zstream.data_type = Z_BINARY; 00561 00562 png_ptr->mode = PNG_HAVE_IHDR; 00563 } 00564 00565 /* Write the palette. We are careful not to trust png_color to be in the 00566 * correct order for PNG, so people can redefine it to any convenient 00567 * structure. 00568 */ 00569 void /* PRIVATE */ 00570 png_write_PLTE(png_structp png_ptr, png_colorp palette, png_uint_32 num_pal) 00571 { 00572 #ifdef PNG_USE_LOCAL_ARRAYS 00573 PNG_PLTE; 00574 #endif 00575 png_uint_32 i; 00576 png_colorp pal_ptr; 00577 png_byte buf[3]; 00578 00579 png_debug(1, "in png_write_PLTE"); 00580 00581 if (( 00582 #if defined(PNG_MNG_FEATURES_SUPPORTED) 00583 !(png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE) && 00584 #endif 00585 num_pal == 0) || num_pal > 256) 00586 { 00587 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) 00588 { 00589 png_error(png_ptr, "Invalid number of colors in palette"); 00590 } 00591 else 00592 { 00593 png_warning(png_ptr, "Invalid number of colors in palette"); 00594 return; 00595 } 00596 } 00597 00598 if (!(png_ptr->color_type&PNG_COLOR_MASK_COLOR)) 00599 { 00600 png_warning(png_ptr, 00601 "Ignoring request to write a PLTE chunk in grayscale PNG"); 00602 return; 00603 } 00604 00605 png_ptr->num_palette = (png_uint_16)num_pal; 00606 png_debug1(3, "num_palette = %d", png_ptr->num_palette); 00607 00608 png_write_chunk_start(png_ptr, (png_bytep)png_PLTE, 00609 (png_uint_32)(num_pal * 3)); 00610 #ifndef PNG_NO_POINTER_INDEXING 00611 for (i = 0, pal_ptr = palette; i < num_pal; i++, pal_ptr++) 00612 { 00613 buf[0] = pal_ptr->red; 00614 buf[1] = pal_ptr->green; 00615 buf[2] = pal_ptr->blue; 00616 png_write_chunk_data(png_ptr, buf, (png_size_t)3); 00617 } 00618 #else 00619 /* This is a little slower but some buggy compilers need to do this instead */ 00620 pal_ptr=palette; 00621 for (i = 0; i < num_pal; i++) 00622 { 00623 buf[0] = pal_ptr[i].red; 00624 buf[1] = pal_ptr[i].green; 00625 buf[2] = pal_ptr[i].blue; 00626 png_write_chunk_data(png_ptr, buf, (png_size_t)3); 00627 } 00628 #endif 00629 png_write_chunk_end(png_ptr); 00630 png_ptr->mode |= PNG_HAVE_PLTE; 00631 } 00632 00633 /* Write an IDAT chunk */ 00634 void /* PRIVATE */ 00635 png_write_IDAT(png_structp png_ptr, png_bytep data, png_size_t length) 00636 { 00637 #ifdef PNG_USE_LOCAL_ARRAYS 00638 PNG_IDAT; 00639 #endif 00640 00641 png_debug(1, "in png_write_IDAT"); 00642 00643 /* Optimize the CMF field in the zlib stream. */ 00644 /* This hack of the zlib stream is compliant to the stream specification. */ 00645 if (!(png_ptr->mode & PNG_HAVE_IDAT) && 00646 png_ptr->compression_type == PNG_COMPRESSION_TYPE_BASE) 00647 { 00648 unsigned int z_cmf = data[0]; /* zlib compression method and flags */ 00649 if ((z_cmf & 0x0f) == 8 && (z_cmf & 0xf0) <= 0x70) 00650 { 00651 /* Avoid memory underflows and multiplication overflows. 00652 * 00653 * The conditions below are practically always satisfied; 00654 * however, they still must be checked. 00655 */ 00656 if (length >= 2 && 00657 png_ptr->height < 16384 && png_ptr->width < 16384) 00658 { 00659 png_uint_32 uncompressed_idat_size = png_ptr->height * 00660 ((png_ptr->width * 00661 png_ptr->channels * png_ptr->bit_depth + 15) >> 3); 00662 unsigned int z_cinfo = z_cmf >> 4; 00663 unsigned int half_z_window_size = 1 << (z_cinfo + 7); 00664 while (uncompressed_idat_size <= half_z_window_size && 00665 half_z_window_size >= 256) 00666 { 00667 z_cinfo--; 00668 half_z_window_size >>= 1; 00669 } 00670 z_cmf = (z_cmf & 0x0f) | (z_cinfo << 4); 00671 if (data[0] != (png_byte)z_cmf) 00672 { 00673 data[0] = (png_byte)z_cmf; 00674 data[1] &= 0xe0; 00675 data[1] += (png_byte)(0x1f - ((z_cmf << 8) + data[1]) % 0x1f); 00676 } 00677 } 00678 } 00679 else 00680 png_error(png_ptr, 00681 "Invalid zlib compression method or flags in IDAT"); 00682 } 00683 00684 png_write_chunk(png_ptr, (png_bytep)png_IDAT, data, length); 00685 png_ptr->mode |= PNG_HAVE_IDAT; 00686 } 00687 00688 /* Write an IEND chunk */ 00689 void /* PRIVATE */ 00690 png_write_IEND(png_structp png_ptr) 00691 { 00692 #ifdef PNG_USE_LOCAL_ARRAYS 00693 PNG_IEND; 00694 #endif 00695 00696 png_debug(1, "in png_write_IEND"); 00697 00698 png_write_chunk(png_ptr, (png_bytep)png_IEND, png_bytep_NULL, 00699 (png_size_t)0); 00700 png_ptr->mode |= PNG_HAVE_IEND; 00701 } 00702 00703 #if defined(PNG_WRITE_gAMA_SUPPORTED) 00704 /* Write a gAMA chunk */ 00705 #ifdef PNG_FLOATING_POINT_SUPPORTED 00706 void /* PRIVATE */ 00707 png_write_gAMA(png_structp png_ptr, double file_gamma) 00708 { 00709 #ifdef PNG_USE_LOCAL_ARRAYS 00710 PNG_gAMA; 00711 #endif 00712 png_uint_32 igamma; 00713 png_byte buf[4]; 00714 00715 png_debug(1, "in png_write_gAMA"); 00716 00717 /* file_gamma is saved in 1/100,000ths */ 00718 igamma = (png_uint_32)(file_gamma * 100000.0 + 0.5); 00719 png_save_uint_32(buf, igamma); 00720 png_write_chunk(png_ptr, (png_bytep)png_gAMA, buf, (png_size_t)4); 00721 } 00722 #endif 00723 #ifdef PNG_FIXED_POINT_SUPPORTED 00724 void /* PRIVATE */ 00725 png_write_gAMA_fixed(png_structp png_ptr, png_fixed_point file_gamma) 00726 { 00727 #ifdef PNG_USE_LOCAL_ARRAYS 00728 PNG_gAMA; 00729 #endif 00730 png_byte buf[4]; 00731 00732 png_debug(1, "in png_write_gAMA"); 00733 00734 /* file_gamma is saved in 1/100,000ths */ 00735 png_save_uint_32(buf, (png_uint_32)file_gamma); 00736 png_write_chunk(png_ptr, (png_bytep)png_gAMA, buf, (png_size_t)4); 00737 } 00738 #endif 00739 #endif 00740 00741 #if defined(PNG_WRITE_sRGB_SUPPORTED) 00742 /* Write a sRGB chunk */ 00743 void /* PRIVATE */ 00744 png_write_sRGB(png_structp png_ptr, int srgb_intent) 00745 { 00746 #ifdef PNG_USE_LOCAL_ARRAYS 00747 PNG_sRGB; 00748 #endif 00749 png_byte buf[1]; 00750 00751 png_debug(1, "in png_write_sRGB"); 00752 00753 if (srgb_intent >= PNG_sRGB_INTENT_LAST) 00754 png_warning(png_ptr, 00755 "Invalid sRGB rendering intent specified"); 00756 buf[0]=(png_byte)srgb_intent; 00757 png_write_chunk(png_ptr, (png_bytep)png_sRGB, buf, (png_size_t)1); 00758 } 00759 #endif 00760 00761 #if defined(PNG_WRITE_iCCP_SUPPORTED) 00762 /* Write an iCCP chunk */ 00763 void /* PRIVATE */ 00764 png_write_iCCP(png_structp png_ptr, png_charp name, int compression_type, 00765 png_charp profile, int profile_len) 00766 { 00767 #ifdef PNG_USE_LOCAL_ARRAYS 00768 PNG_iCCP; 00769 #endif 00770 png_size_t name_len; 00771 png_charp new_name; 00772 compression_state comp; 00773 int embedded_profile_len = 0; 00774 00775 png_debug(1, "in png_write_iCCP"); 00776 00777 comp.num_output_ptr = 0; 00778 comp.max_output_ptr = 0; 00779 comp.output_ptr = NULL; 00780 comp.input = NULL; 00781 comp.input_len = 0; 00782 00783 if ((name_len = png_check_keyword(png_ptr, name, 00784 &new_name)) == 0) 00785 return; 00786 00787 if (compression_type != PNG_COMPRESSION_TYPE_BASE) 00788 png_warning(png_ptr, "Unknown compression type in iCCP chunk"); 00789 00790 if (profile == NULL) 00791 profile_len = 0; 00792 00793 if (profile_len > 3) 00794 embedded_profile_len = 00795 ((*( (png_bytep)profile ))<<24) | 00796 ((*( (png_bytep)profile + 1))<<16) | 00797 ((*( (png_bytep)profile + 2))<< 8) | 00798 ((*( (png_bytep)profile + 3)) ); 00799 00800 if (embedded_profile_len < 0) 00801 { 00802 png_warning(png_ptr, 00803 "Embedded profile length in iCCP chunk is negative"); 00804 png_free(png_ptr, new_name); 00805 return; 00806 } 00807 00808 if (profile_len < embedded_profile_len) 00809 { 00810 png_warning(png_ptr, 00811 "Embedded profile length too large in iCCP chunk"); 00812 png_free(png_ptr, new_name); 00813 return; 00814 } 00815 00816 if (profile_len > embedded_profile_len) 00817 { 00818 png_warning(png_ptr, 00819 "Truncating profile to actual length in iCCP chunk"); 00820 profile_len = embedded_profile_len; 00821 } 00822 00823 if (profile_len) 00824 profile_len = png_text_compress(png_ptr, profile, 00825 (png_size_t)profile_len, PNG_COMPRESSION_TYPE_BASE, &comp); 00826 00827 /* Make sure we include the NULL after the name and the compression type */ 00828 png_write_chunk_start(png_ptr, (png_bytep)png_iCCP, 00829 (png_uint_32)(name_len + profile_len + 2)); 00830 new_name[name_len + 1] = 0x00; 00831 png_write_chunk_data(png_ptr, (png_bytep)new_name, 00832 (png_size_t)(name_len + 2)); 00833 00834 if (profile_len) 00835 png_write_compressed_data_out(png_ptr, &comp); 00836 00837 png_write_chunk_end(png_ptr); 00838 png_free(png_ptr, new_name); 00839 } 00840 #endif 00841 00842 #if defined(PNG_WRITE_sPLT_SUPPORTED) 00843 /* Write a sPLT chunk */ 00844 void /* PRIVATE */ 00845 png_write_sPLT(png_structp png_ptr, png_sPLT_tp spalette) 00846 { 00847 #ifdef PNG_USE_LOCAL_ARRAYS 00848 PNG_sPLT; 00849 #endif 00850 png_size_t name_len; 00851 png_charp new_name; 00852 png_byte entrybuf[10]; 00853 int entry_size = (spalette->depth == 8 ? 6 : 10); 00854 int palette_size = entry_size * spalette->nentries; 00855 png_sPLT_entryp ep; 00856 #ifdef PNG_NO_POINTER_INDEXING 00857 int i; 00858 #endif 00859 00860 png_debug(1, "in png_write_sPLT"); 00861 00862 if ((name_len = png_check_keyword(png_ptr,spalette->name, &new_name))==0) 00863 return; 00864 00865 /* Make sure we include the NULL after the name */ 00866 png_write_chunk_start(png_ptr, (png_bytep)png_sPLT, 00867 (png_uint_32)(name_len + 2 + palette_size)); 00868 png_write_chunk_data(png_ptr, (png_bytep)new_name, 00869 (png_size_t)(name_len + 1)); 00870 png_write_chunk_data(png_ptr, (png_bytep)&spalette->depth, (png_size_t)1); 00871 00872 /* Loop through each palette entry, writing appropriately */ 00873 #ifndef PNG_NO_POINTER_INDEXING 00874 for (ep = spalette->entries; ep<spalette->entries + spalette->nentries; ep++) 00875 { 00876 if (spalette->depth == 8) 00877 { 00878 entrybuf[0] = (png_byte)ep->red; 00879 entrybuf[1] = (png_byte)ep->green; 00880 entrybuf[2] = (png_byte)ep->blue; 00881 entrybuf[3] = (png_byte)ep->alpha; 00882 png_save_uint_16(entrybuf + 4, ep->frequency); 00883 } 00884 else 00885 { 00886 png_save_uint_16(entrybuf + 0, ep->red); 00887 png_save_uint_16(entrybuf + 2, ep->green); 00888 png_save_uint_16(entrybuf + 4, ep->blue); 00889 png_save_uint_16(entrybuf + 6, ep->alpha); 00890 png_save_uint_16(entrybuf + 8, ep->frequency); 00891 } 00892 png_write_chunk_data(png_ptr, entrybuf, (png_size_t)entry_size); 00893 } 00894 #else 00895 ep=spalette->entries; 00896 for (i=0; i>spalette->nentries; i++) 00897 { 00898 if (spalette->depth == 8) 00899 { 00900 entrybuf[0] = (png_byte)ep[i].red; 00901 entrybuf[1] = (png_byte)ep[i].green; 00902 entrybuf[2] = (png_byte)ep[i].blue; 00903 entrybuf[3] = (png_byte)ep[i].alpha; 00904 png_save_uint_16(entrybuf + 4, ep[i].frequency); 00905 } 00906 else 00907 { 00908 png_save_uint_16(entrybuf + 0, ep[i].red); 00909 png_save_uint_16(entrybuf + 2, ep[i].green); 00910 png_save_uint_16(entrybuf + 4, ep[i].blue); 00911 png_save_uint_16(entrybuf + 6, ep[i].alpha); 00912 png_save_uint_16(entrybuf + 8, ep[i].frequency); 00913 } 00914 png_write_chunk_data(png_ptr, entrybuf, (png_size_t)entry_size); 00915 } 00916 #endif 00917 00918 png_write_chunk_end(png_ptr); 00919 png_free(png_ptr, new_name); 00920 } 00921 #endif 00922 00923 #if defined(PNG_WRITE_sBIT_SUPPORTED) 00924 /* Write the sBIT chunk */ 00925 void /* PRIVATE */ 00926 png_write_sBIT(png_structp png_ptr, png_color_8p sbit, int color_type) 00927 { 00928 #ifdef PNG_USE_LOCAL_ARRAYS 00929 PNG_sBIT; 00930 #endif 00931 png_byte buf[4]; 00932 png_size_t size; 00933 00934 png_debug(1, "in png_write_sBIT"); 00935 00936 /* Make sure we don't depend upon the order of PNG_COLOR_8 */ 00937 if (color_type & PNG_COLOR_MASK_COLOR) 00938 { 00939 png_byte maxbits; 00940 00941 maxbits = (png_byte)(color_type==PNG_COLOR_TYPE_PALETTE ? 8 : 00942 png_ptr->usr_bit_depth); 00943 if (sbit->red == 0 || sbit->red > maxbits || 00944 sbit->green == 0 || sbit->green > maxbits || 00945 sbit->blue == 0 || sbit->blue > maxbits) 00946 { 00947 png_warning(png_ptr, "Invalid sBIT depth specified"); 00948 return; 00949 } 00950 buf[0] = sbit->red; 00951 buf[1] = sbit->green; 00952 buf[2] = sbit->blue; 00953 size = 3; 00954 } 00955 else 00956 { 00957 if (sbit->gray == 0 || sbit->gray > png_ptr->usr_bit_depth) 00958 { 00959 png_warning(png_ptr, "Invalid sBIT depth specified"); 00960 return; 00961 } 00962 buf[0] = sbit->gray; 00963 size = 1; 00964 } 00965 00966 if (color_type & PNG_COLOR_MASK_ALPHA) 00967 { 00968 if (sbit->alpha == 0 || sbit->alpha > png_ptr->usr_bit_depth) 00969 { 00970 png_warning(png_ptr, "Invalid sBIT depth specified"); 00971 return; 00972 } 00973 buf[size++] = sbit->alpha; 00974 } 00975 00976 png_write_chunk(png_ptr, (png_bytep)png_sBIT, buf, size); 00977 } 00978 #endif 00979 00980 #if defined(PNG_WRITE_cHRM_SUPPORTED) 00981 /* Write the cHRM chunk */ 00982 #ifdef PNG_FLOATING_POINT_SUPPORTED 00983 void /* PRIVATE */ 00984 png_write_cHRM(png_structp png_ptr, double white_x, double white_y, 00985 double red_x, double red_y, double green_x, double green_y, 00986 double blue_x, double blue_y) 00987 { 00988 #ifdef PNG_USE_LOCAL_ARRAYS 00989 PNG_cHRM; 00990 #endif 00991 png_byte buf[32]; 00992 00993 png_fixed_point int_white_x, int_white_y, int_red_x, int_red_y, 00994 int_green_x, int_green_y, int_blue_x, int_blue_y; 00995 00996 png_debug(1, "in png_write_cHRM"); 00997 00998 int_white_x = (png_uint_32)(white_x * 100000.0 + 0.5); 00999 int_white_y = (png_uint_32)(white_y * 100000.0 + 0.5); 01000 int_red_x = (png_uint_32)(red_x * 100000.0 + 0.5); 01001 int_red_y = (png_uint_32)(red_y * 100000.0 + 0.5); 01002 int_green_x = (png_uint_32)(green_x * 100000.0 + 0.5); 01003 int_green_y = (png_uint_32)(green_y * 100000.0 + 0.5); 01004 int_blue_x = (png_uint_32)(blue_x * 100000.0 + 0.5); 01005 int_blue_y = (png_uint_32)(blue_y * 100000.0 + 0.5); 01006 01007 #if !defined(PNG_NO_CHECK_cHRM) 01008 if (png_check_cHRM_fixed(png_ptr, int_white_x, int_white_y, 01009 int_red_x, int_red_y, int_green_x, int_green_y, int_blue_x, int_blue_y)) 01010 #endif 01011 { 01012 /* Each value is saved in 1/100,000ths */ 01013 01014 png_save_uint_32(buf, int_white_x); 01015 png_save_uint_32(buf + 4, int_white_y); 01016 01017 png_save_uint_32(buf + 8, int_red_x); 01018 png_save_uint_32(buf + 12, int_red_y); 01019 01020 png_save_uint_32(buf + 16, int_green_x); 01021 png_save_uint_32(buf + 20, int_green_y); 01022 01023 png_save_uint_32(buf + 24, int_blue_x); 01024 png_save_uint_32(buf + 28, int_blue_y); 01025 01026 png_write_chunk(png_ptr, (png_bytep)png_cHRM, buf, (png_size_t)32); 01027 } 01028 } 01029 #endif 01030 #ifdef PNG_FIXED_POINT_SUPPORTED 01031 void /* PRIVATE */ 01032 png_write_cHRM_fixed(png_structp png_ptr, png_fixed_point white_x, 01033 png_fixed_point white_y, png_fixed_point red_x, png_fixed_point red_y, 01034 png_fixed_point green_x, png_fixed_point green_y, png_fixed_point blue_x, 01035 png_fixed_point blue_y) 01036 { 01037 #ifdef PNG_USE_LOCAL_ARRAYS 01038 PNG_cHRM; 01039 #endif 01040 png_byte buf[32]; 01041 01042 png_debug(1, "in png_write_cHRM"); 01043 01044 /* Each value is saved in 1/100,000ths */ 01045 #if !defined(PNG_NO_CHECK_cHRM) 01046 if (png_check_cHRM_fixed(png_ptr, white_x, white_y, red_x, red_y, 01047 green_x, green_y, blue_x, blue_y)) 01048 #endif 01049 { 01050 png_save_uint_32(buf, (png_uint_32)white_x); 01051 png_save_uint_32(buf + 4, (png_uint_32)white_y); 01052 01053 png_save_uint_32(buf + 8, (png_uint_32)red_x); 01054 png_save_uint_32(buf + 12, (png_uint_32)red_y); 01055 01056 png_save_uint_32(buf + 16, (png_uint_32)green_x); 01057 png_save_uint_32(buf + 20, (png_uint_32)green_y); 01058 01059 png_save_uint_32(buf + 24, (png_uint_32)blue_x); 01060 png_save_uint_32(buf + 28, (png_uint_32)blue_y); 01061 01062 png_write_chunk(png_ptr, (png_bytep)png_cHRM, buf, (png_size_t)32); 01063 } 01064 } 01065 #endif 01066 #endif 01067 01068 #if defined(PNG_WRITE_tRNS_SUPPORTED) 01069 /* Write the tRNS chunk */ 01070 void /* PRIVATE */ 01071 png_write_tRNS(png_structp png_ptr, png_bytep trans, png_color_16p tran, 01072 int num_trans, int color_type) 01073 { 01074 #ifdef PNG_USE_LOCAL_ARRAYS 01075 PNG_tRNS; 01076 #endif 01077 png_byte buf[6]; 01078 01079 png_debug(1, "in png_write_tRNS"); 01080 01081 if (color_type == PNG_COLOR_TYPE_PALETTE) 01082 { 01083 if (num_trans <= 0 || num_trans > (int)png_ptr->num_palette) 01084 { 01085 png_warning(png_ptr, "Invalid number of transparent colors specified"); 01086 return; 01087 } 01088 /* Write the chunk out as it is */ 01089 png_write_chunk(png_ptr, (png_bytep)png_tRNS, trans, 01090 (png_size_t)num_trans); 01091 } 01092 else if (color_type == PNG_COLOR_TYPE_GRAY) 01093 { 01094 /* One 16 bit value */ 01095 if (tran->gray >= (1 << png_ptr->bit_depth)) 01096 { 01097 png_warning(png_ptr, 01098 "Ignoring attempt to write tRNS chunk out-of-range for bit_depth"); 01099 return; 01100 } 01101 png_save_uint_16(buf, tran->gray); 01102 png_write_chunk(png_ptr, (png_bytep)png_tRNS, buf, (png_size_t)2); 01103 } 01104 else if (color_type == PNG_COLOR_TYPE_RGB) 01105 { 01106 /* Three 16 bit values */ 01107 png_save_uint_16(buf, tran->red); 01108 png_save_uint_16(buf + 2, tran->green); 01109 png_save_uint_16(buf + 4, tran->blue); 01110 if (png_ptr->bit_depth == 8 && (buf[0] | buf[2] | buf[4])) 01111 { 01112 png_warning(png_ptr, 01113 "Ignoring attempt to write 16-bit tRNS chunk when bit_depth is 8"); 01114 return; 01115 } 01116 png_write_chunk(png_ptr, (png_bytep)png_tRNS, buf, (png_size_t)6); 01117 } 01118 else 01119 { 01120 png_warning(png_ptr, "Can't write tRNS with an alpha channel"); 01121 } 01122 } 01123 #endif 01124 01125 #if defined(PNG_WRITE_bKGD_SUPPORTED) 01126 /* Write the background chunk */ 01127 void /* PRIVATE */ 01128 png_write_bKGD(png_structp png_ptr, png_color_16p back, int color_type) 01129 { 01130 #ifdef PNG_USE_LOCAL_ARRAYS 01131 PNG_bKGD; 01132 #endif 01133 png_byte buf[6]; 01134 01135 png_debug(1, "in png_write_bKGD"); 01136 01137 if (color_type == PNG_COLOR_TYPE_PALETTE) 01138 { 01139 if ( 01140 #if defined(PNG_MNG_FEATURES_SUPPORTED) 01141 (png_ptr->num_palette || 01142 (!(png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE))) && 01143 #endif 01144 back->index >= png_ptr->num_palette) 01145 { 01146 png_warning(png_ptr, "Invalid background palette index"); 01147 return; 01148 } 01149 buf[0] = back->index; 01150 png_write_chunk(png_ptr, (png_bytep)png_bKGD, buf, (png_size_t)1); 01151 } 01152 else if (color_type & PNG_COLOR_MASK_COLOR) 01153 { 01154 png_save_uint_16(buf, back->red); 01155 png_save_uint_16(buf + 2, back->green); 01156 png_save_uint_16(buf + 4, back->blue); 01157 if (png_ptr->bit_depth == 8 && (buf[0] | buf[2] | buf[4])) 01158 { 01159 png_warning(png_ptr, 01160 "Ignoring attempt to write 16-bit bKGD chunk when bit_depth is 8"); 01161 return; 01162 } 01163 png_write_chunk(png_ptr, (png_bytep)png_bKGD, buf, (png_size_t)6); 01164 } 01165 else 01166 { 01167 if (back->gray >= (1 << png_ptr->bit_depth)) 01168 { 01169 png_warning(png_ptr, 01170 "Ignoring attempt to write bKGD chunk out-of-range for bit_depth"); 01171 return; 01172 } 01173 png_save_uint_16(buf, back->gray); 01174 png_write_chunk(png_ptr, (png_bytep)png_bKGD, buf, (png_size_t)2); 01175 } 01176 } 01177 #endif 01178 01179 #if defined(PNG_WRITE_hIST_SUPPORTED) 01180 /* Write the histogram */ 01181 void /* PRIVATE */ 01182 png_write_hIST(png_structp png_ptr, png_uint_16p hist, int num_hist) 01183 { 01184 #ifdef PNG_USE_LOCAL_ARRAYS 01185 PNG_hIST; 01186 #endif 01187 int i; 01188 png_byte buf[3]; 01189 01190 png_debug(1, "in png_write_hIST"); 01191 01192 if (num_hist > (int)png_ptr->num_palette) 01193 { 01194 png_debug2(3, "num_hist = %d, num_palette = %d", num_hist, 01195 png_ptr->num_palette); 01196 png_warning(png_ptr, "Invalid number of histogram entries specified"); 01197 return; 01198 } 01199 01200 png_write_chunk_start(png_ptr, (png_bytep)png_hIST, 01201 (png_uint_32)(num_hist * 2)); 01202 for (i = 0; i < num_hist; i++) 01203 { 01204 png_save_uint_16(buf, hist[i]); 01205 png_write_chunk_data(png_ptr, buf, (png_size_t)2); 01206 } 01207 png_write_chunk_end(png_ptr); 01208 } 01209 #endif 01210 01211 #if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_pCAL_SUPPORTED) || \ 01212 defined(PNG_WRITE_iCCP_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED) 01213 /* Check that the tEXt or zTXt keyword is valid per PNG 1.0 specification, 01214 * and if invalid, correct the keyword rather than discarding the entire 01215 * chunk. The PNG 1.0 specification requires keywords 1-79 characters in 01216 * length, forbids leading or trailing whitespace, multiple internal spaces, 01217 * and the non-break space (0x80) from ISO 8859-1. Returns keyword length. 01218 * 01219 * The new_key is allocated to hold the corrected keyword and must be freed 01220 * by the calling routine. This avoids problems with trying to write to 01221 * static keywords without having to have duplicate copies of the strings. 01222 */ 01223 png_size_t /* PRIVATE */ 01224 png_check_keyword(png_structp png_ptr, png_charp key, png_charpp new_key) 01225 { 01226 png_size_t key_len; 01227 png_charp kp, dp; 01228 int kflag; 01229 int kwarn=0; 01230 01231 png_debug(1, "in png_check_keyword"); 01232 01233 *new_key = NULL; 01234 01235 if (key == NULL || (key_len = png_strlen(key)) == 0) 01236 { 01237 png_warning(png_ptr, "zero length keyword"); 01238 return ((png_size_t)0); 01239 } 01240 01241 png_debug1(2, "Keyword to be checked is '%s'", key); 01242 01243 *new_key = (png_charp)png_malloc_warn(png_ptr, (png_uint_32)(key_len + 2)); 01244 if (*new_key == NULL) 01245 { 01246 png_warning(png_ptr, "Out of memory while procesing keyword"); 01247 return ((png_size_t)0); 01248 } 01249 01250 /* Replace non-printing characters with a blank and print a warning */ 01251 for (kp = key, dp = *new_key; *kp != '\0'; kp++, dp++) 01252 { 01253 if ((png_byte)*kp < 0x20 || 01254 ((png_byte)*kp > 0x7E && (png_byte)*kp < 0xA1)) 01255 { 01256 #if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE) 01257 char msg[40]; 01258 01259 png_snprintf(msg, 40, 01260 "invalid keyword character 0x%02X", (png_byte)*kp); 01261 png_warning(png_ptr, msg); 01262 #else 01263 png_warning(png_ptr, "invalid character in keyword"); 01264 #endif 01265 *dp = ' '; 01266 } 01267 else 01268 { 01269 *dp = *kp; 01270 } 01271 } 01272 *dp = '\0'; 01273 01274 /* Remove any trailing white space. */ 01275 kp = *new_key + key_len - 1; 01276 if (*kp == ' ') 01277 { 01278 png_warning(png_ptr, "trailing spaces removed from keyword"); 01279 01280 while (*kp == ' ') 01281 { 01282 *(kp--) = '\0'; 01283 key_len--; 01284 } 01285 } 01286 01287 /* Remove any leading white space. */ 01288 kp = *new_key; 01289 if (*kp == ' ') 01290 { 01291 png_warning(png_ptr, "leading spaces removed from keyword"); 01292 01293 while (*kp == ' ') 01294 { 01295 kp++; 01296 key_len--; 01297 } 01298 } 01299 01300 png_debug1(2, "Checking for multiple internal spaces in '%s'", kp); 01301 01302 /* Remove multiple internal spaces. */ 01303 for (kflag = 0, dp = *new_key; *kp != '\0'; kp++) 01304 { 01305 if (*kp == ' ' && kflag == 0) 01306 { 01307 *(dp++) = *kp; 01308 kflag = 1; 01309 } 01310 else if (*kp == ' ') 01311 { 01312 key_len--; 01313 kwarn=1; 01314 } 01315 else 01316 { 01317 *(dp++) = *kp; 01318 kflag = 0; 01319 } 01320 } 01321 *dp = '\0'; 01322 if (kwarn) 01323 png_warning(png_ptr, "extra interior spaces removed from keyword"); 01324 01325 if (key_len == 0) 01326 { 01327 png_free(png_ptr, *new_key); 01328 *new_key=NULL; 01329 png_warning(png_ptr, "Zero length keyword"); 01330 } 01331 01332 if (key_len > 79) 01333 { 01334 png_warning(png_ptr, "keyword length must be 1 - 79 characters"); 01335 (*new_key)[79] = '\0'; 01336 key_len = 79; 01337 } 01338 01339 return (key_len); 01340 } 01341 #endif 01342 01343 #if defined(PNG_WRITE_tEXt_SUPPORTED) 01344 /* Write a tEXt chunk */ 01345 void /* PRIVATE */ 01346 png_write_tEXt(png_structp png_ptr, png_charp key, png_charp text, 01347 png_size_t text_len) 01348 { 01349 #ifdef PNG_USE_LOCAL_ARRAYS 01350 PNG_tEXt; 01351 #endif 01352 png_size_t key_len; 01353 png_charp new_key; 01354 01355 png_debug(1, "in png_write_tEXt"); 01356 01357 if ((key_len = png_check_keyword(png_ptr, key, &new_key))==0) 01358 return; 01359 01360 if (text == NULL || *text == '\0') 01361 text_len = 0; 01362 else 01363 text_len = png_strlen(text); 01364 01365 /* Make sure we include the 0 after the key */ 01366 png_write_chunk_start(png_ptr, (png_bytep)png_tEXt, 01367 (png_uint_32)(key_len + text_len + 1)); 01368 /* 01369 * We leave it to the application to meet PNG-1.0 requirements on the 01370 * contents of the text. PNG-1.0 through PNG-1.2 discourage the use of 01371 * any non-Latin-1 characters except for NEWLINE. ISO PNG will forbid them. 01372 * The NUL character is forbidden by PNG-1.0 through PNG-1.2 and ISO PNG. 01373 */ 01374 png_write_chunk_data(png_ptr, (png_bytep)new_key, 01375 (png_size_t)(key_len + 1)); 01376 if (text_len) 01377 png_write_chunk_data(png_ptr, (png_bytep)text, (png_size_t)text_len); 01378 01379 png_write_chunk_end(png_ptr); 01380 png_free(png_ptr, new_key); 01381 } 01382 #endif 01383 01384 #if defined(PNG_WRITE_zTXt_SUPPORTED) 01385 /* Write a compressed text chunk */ 01386 void /* PRIVATE */ 01387 png_write_zTXt(png_structp png_ptr, png_charp key, png_charp text, 01388 png_size_t text_len, int compression) 01389 { 01390 #ifdef PNG_USE_LOCAL_ARRAYS 01391 PNG_zTXt; 01392 #endif 01393 png_size_t key_len; 01394 char buf[1]; 01395 png_charp new_key; 01396 compression_state comp; 01397 01398 png_debug(1, "in png_write_zTXt"); 01399 01400 comp.num_output_ptr = 0; 01401 comp.max_output_ptr = 0; 01402 comp.output_ptr = NULL; 01403 comp.input = NULL; 01404 comp.input_len = 0; 01405 01406 if ((key_len = png_check_keyword(png_ptr, key, &new_key))==0) 01407 { 01408 png_free(png_ptr, new_key); 01409 return; 01410 } 01411 01412 if (text == NULL || *text == '\0' || compression==PNG_TEXT_COMPRESSION_NONE) 01413 { 01414 png_write_tEXt(png_ptr, new_key, text, (png_size_t)0); 01415 png_free(png_ptr, new_key); 01416 return; 01417 } 01418 01419 text_len = png_strlen(text); 01420 01421 /* Compute the compressed data; do it now for the length */ 01422 text_len = png_text_compress(png_ptr, text, text_len, compression, 01423 &comp); 01424 01425 /* Write start of chunk */ 01426 png_write_chunk_start(png_ptr, (png_bytep)png_zTXt, 01427 (png_uint_32)(key_len+text_len + 2)); 01428 /* Write key */ 01429 png_write_chunk_data(png_ptr, (png_bytep)new_key, 01430 (png_size_t)(key_len + 1)); 01431 png_free(png_ptr, new_key); 01432 01433 buf[0] = (png_byte)compression; 01434 /* Write compression */ 01435 png_write_chunk_data(png_ptr, (png_bytep)buf, (png_size_t)1); 01436 /* Write the compressed data */ 01437 png_write_compressed_data_out(png_ptr, &comp); 01438 01439 /* Close the chunk */ 01440 png_write_chunk_end(png_ptr); 01441 } 01442 #endif 01443 01444 #if defined(PNG_WRITE_iTXt_SUPPORTED) 01445 /* Write an iTXt chunk */ 01446 void /* PRIVATE */ 01447 png_write_iTXt(png_structp png_ptr, int compression, png_charp key, 01448 png_charp lang, png_charp lang_key, png_charp text) 01449 { 01450 #ifdef PNG_USE_LOCAL_ARRAYS 01451 PNG_iTXt; 01452 #endif 01453 png_size_t lang_len, key_len, lang_key_len, text_len; 01454 png_charp new_lang; 01455 png_charp new_key = NULL; 01456 png_byte cbuf[2]; 01457 compression_state comp; 01458 01459 png_debug(1, "in png_write_iTXt"); 01460 01461 comp.num_output_ptr = 0; 01462 comp.max_output_ptr = 0; 01463 comp.output_ptr = NULL; 01464 comp.input = NULL; 01465 01466 if ((key_len = png_check_keyword(png_ptr, key, &new_key))==0) 01467 return; 01468 01469 if ((lang_len = png_check_keyword(png_ptr, lang, &new_lang))==0) 01470 { 01471 png_warning(png_ptr, "Empty language field in iTXt chunk"); 01472 new_lang = NULL; 01473 lang_len = 0; 01474 } 01475 01476 if (lang_key == NULL) 01477 lang_key_len = 0; 01478 else 01479 lang_key_len = png_strlen(lang_key); 01480 01481 if (text == NULL) 01482 text_len = 0; 01483 else 01484 text_len = png_strlen(text); 01485 01486 /* Compute the compressed data; do it now for the length */ 01487 text_len = png_text_compress(png_ptr, text, text_len, compression-2, 01488 &comp); 01489 01490 01491 /* Make sure we include the compression flag, the compression byte, 01492 * and the NULs after the key, lang, and lang_key parts */ 01493 01494 png_write_chunk_start(png_ptr, (png_bytep)png_iTXt, 01495 (png_uint_32)( 01496 5 /* comp byte, comp flag, terminators for key, lang and lang_key */ 01497 + key_len 01498 + lang_len 01499 + lang_key_len 01500 + text_len)); 01501 01502 /* We leave it to the application to meet PNG-1.0 requirements on the 01503 * contents of the text. PNG-1.0 through PNG-1.2 discourage the use of 01504 * any non-Latin-1 characters except for NEWLINE. ISO PNG will forbid them. 01505 * The NUL character is forbidden by PNG-1.0 through PNG-1.2 and ISO PNG. 01506 */ 01507 png_write_chunk_data(png_ptr, (png_bytep)new_key, 01508 (png_size_t)(key_len + 1)); 01509 01510 /* Set the compression flag */ 01511 if (compression == PNG_ITXT_COMPRESSION_NONE || \ 01512 compression == PNG_TEXT_COMPRESSION_NONE) 01513 cbuf[0] = 0; 01514 else /* compression == PNG_ITXT_COMPRESSION_zTXt */ 01515 cbuf[0] = 1; 01516 /* Set the compression method */ 01517 cbuf[1] = 0; 01518 png_write_chunk_data(png_ptr, cbuf, (png_size_t)2); 01519 01520 cbuf[0] = 0; 01521 png_write_chunk_data(png_ptr, (new_lang ? (png_bytep)new_lang : cbuf), 01522 (png_size_t)(lang_len + 1)); 01523 png_write_chunk_data(png_ptr, (lang_key ? (png_bytep)lang_key : cbuf), 01524 (png_size_t)(lang_key_len + 1)); 01525 png_write_compressed_data_out(png_ptr, &comp); 01526 01527 png_write_chunk_end(png_ptr); 01528 png_free(png_ptr, new_key); 01529 png_free(png_ptr, new_lang); 01530 } 01531 #endif 01532 01533 #if defined(PNG_WRITE_oFFs_SUPPORTED) 01534 /* Write the oFFs chunk */ 01535 void /* PRIVATE */ 01536 png_write_oFFs(png_structp png_ptr, png_int_32 x_offset, png_int_32 y_offset, 01537 int unit_type) 01538 { 01539 #ifdef PNG_USE_LOCAL_ARRAYS 01540 PNG_oFFs; 01541 #endif 01542 png_byte buf[9]; 01543 01544 png_debug(1, "in png_write_oFFs"); 01545 01546 if (unit_type >= PNG_OFFSET_LAST) 01547 png_warning(png_ptr, "Unrecognized unit type for oFFs chunk"); 01548 01549 png_save_int_32(buf, x_offset); 01550 png_save_int_32(buf + 4, y_offset); 01551 buf[8] = (png_byte)unit_type; 01552 01553 png_write_chunk(png_ptr, (png_bytep)png_oFFs, buf, (png_size_t)9); 01554 } 01555 #endif 01556 #if defined(PNG_WRITE_pCAL_SUPPORTED) 01557 /* Write the pCAL chunk (described in the PNG extensions document) */ 01558 void /* PRIVATE */ 01559 png_write_pCAL(png_structp png_ptr, png_charp purpose, png_int_32 X0, 01560 png_int_32 X1, int type, int nparams, png_charp units, png_charpp params) 01561 { 01562 #ifdef PNG_USE_LOCAL_ARRAYS 01563 PNG_pCAL; 01564 #endif 01565 png_size_t purpose_len, units_len, total_len; 01566 png_uint_32p params_len; 01567 png_byte buf[10]; 01568 png_charp new_purpose; 01569 int i; 01570 01571 png_debug1(1, "in png_write_pCAL (%d parameters)", nparams); 01572 01573 if (type >= PNG_EQUATION_LAST) 01574 png_warning(png_ptr, "Unrecognized equation type for pCAL chunk"); 01575 01576 purpose_len = png_check_keyword(png_ptr, purpose, &new_purpose) + 1; 01577 png_debug1(3, "pCAL purpose length = %d", (int)purpose_len); 01578 units_len = png_strlen(units) + (nparams == 0 ? 0 : 1); 01579 png_debug1(3, "pCAL units length = %d", (int)units_len); 01580 total_len = purpose_len + units_len + 10; 01581 01582 params_len = (png_uint_32p)png_malloc(png_ptr, 01583 (png_uint_32)(nparams * png_sizeof(png_uint_32))); 01584 01585 /* Find the length of each parameter, making sure we don't count the 01586 null terminator for the last parameter. */ 01587 for (i = 0; i < nparams; i++) 01588 { 01589 params_len[i] = png_strlen(params[i]) + (i == nparams - 1 ? 0 : 1); 01590 png_debug2(3, "pCAL parameter %d length = %lu", i, 01591 (unsigned long) params_len[i]); 01592 total_len += (png_size_t)params_len[i]; 01593 } 01594 01595 png_debug1(3, "pCAL total length = %d", (int)total_len); 01596 png_write_chunk_start(png_ptr, (png_bytep)png_pCAL, (png_uint_32)total_len); 01597 png_write_chunk_data(png_ptr, (png_bytep)new_purpose, 01598 (png_size_t)purpose_len); 01599 png_save_int_32(buf, X0); 01600 png_save_int_32(buf + 4, X1); 01601 buf[8] = (png_byte)type; 01602 buf[9] = (png_byte)nparams; 01603 png_write_chunk_data(png_ptr, buf, (png_size_t)10); 01604 png_write_chunk_data(png_ptr, (png_bytep)units, (png_size_t)units_len); 01605 01606 png_free(png_ptr, new_purpose); 01607 01608 for (i = 0; i < nparams; i++) 01609 { 01610 png_write_chunk_data(png_ptr, (png_bytep)params[i], 01611 (png_size_t)params_len[i]); 01612 } 01613 01614 png_free(png_ptr, params_len); 01615 png_write_chunk_end(png_ptr); 01616 } 01617 #endif 01618 01619 #if defined(PNG_WRITE_sCAL_SUPPORTED) 01620 /* Write the sCAL chunk */ 01621 #if defined(PNG_FLOATING_POINT_SUPPORTED) && !defined(PNG_NO_STDIO) 01622 void /* PRIVATE */ 01623 png_write_sCAL(png_structp png_ptr, int unit, double width, double height) 01624 { 01625 #ifdef PNG_USE_LOCAL_ARRAYS 01626 PNG_sCAL; 01627 #endif 01628 char buf[64]; 01629 png_size_t total_len; 01630 01631 png_debug(1, "in png_write_sCAL"); 01632 01633 buf[0] = (char)unit; 01634 #if defined(_WIN32_WCE) 01635 /* sprintf() function is not supported on WindowsCE */ 01636 { 01637 wchar_t wc_buf[32]; 01638 size_t wc_len; 01639 swprintf(wc_buf, TEXT("%12.12e"), width); 01640 wc_len = wcslen(wc_buf); 01641 WideCharToMultiByte(CP_ACP, 0, wc_buf, -1, buf + 1, wc_len, NULL, NULL); 01642 total_len = wc_len + 2; 01643 swprintf(wc_buf, TEXT("%12.12e"), height); 01644 wc_len = wcslen(wc_buf); 01645 WideCharToMultiByte(CP_ACP, 0, wc_buf, -1, buf + total_len, wc_len, 01646 NULL, NULL); 01647 total_len += wc_len; 01648 } 01649 #else 01650 png_snprintf(buf + 1, 63, "%12.12e", width); 01651 total_len = 1 + png_strlen(buf + 1) + 1; 01652 png_snprintf(buf + total_len, 64-total_len, "%12.12e", height); 01653 total_len += png_strlen(buf + total_len); 01654 #endif 01655 01656 png_debug1(3, "sCAL total length = %u", (unsigned int)total_len); 01657 png_write_chunk(png_ptr, (png_bytep)png_sCAL, (png_bytep)buf, total_len); 01658 } 01659 #else 01660 #ifdef PNG_FIXED_POINT_SUPPORTED 01661 void /* PRIVATE */ 01662 png_write_sCAL_s(png_structp png_ptr, int unit, png_charp width, 01663 png_charp height) 01664 { 01665 #ifdef PNG_USE_LOCAL_ARRAYS 01666 PNG_sCAL; 01667 #endif 01668 png_byte buf[64]; 01669 png_size_t wlen, hlen, total_len; 01670 01671 png_debug(1, "in png_write_sCAL_s"); 01672 01673 wlen = png_strlen(width); 01674 hlen = png_strlen(height); 01675 total_len = wlen + hlen + 2; 01676 if (total_len > 64) 01677 { 01678 png_warning(png_ptr, "Can't write sCAL (buffer too small)"); 01679 return; 01680 } 01681 01682 buf[0] = (png_byte)unit; 01683 png_memcpy(buf + 1, width, wlen + 1); /* Append the '\0' here */ 01684 png_memcpy(buf + wlen + 2, height, hlen); /* Do NOT append the '\0' here */ 01685 01686 png_debug1(3, "sCAL total length = %u", (unsigned int)total_len); 01687 png_write_chunk(png_ptr, (png_bytep)png_sCAL, buf, total_len); 01688 } 01689 #endif 01690 #endif 01691 #endif 01692 01693 #if defined(PNG_WRITE_pHYs_SUPPORTED) 01694 /* Write the pHYs chunk */ 01695 void /* PRIVATE */ 01696 png_write_pHYs(png_structp png_ptr, png_uint_32 x_pixels_per_unit, 01697 png_uint_32 y_pixels_per_unit, 01698 int unit_type) 01699 { 01700 #ifdef PNG_USE_LOCAL_ARRAYS 01701 PNG_pHYs; 01702 #endif 01703 png_byte buf[9]; 01704 01705 png_debug(1, "in png_write_pHYs"); 01706 01707 if (unit_type >= PNG_RESOLUTION_LAST) 01708 png_warning(png_ptr, "Unrecognized unit type for pHYs chunk"); 01709 01710 png_save_uint_32(buf, x_pixels_per_unit); 01711 png_save_uint_32(buf + 4, y_pixels_per_unit); 01712 buf[8] = (png_byte)unit_type; 01713 01714 png_write_chunk(png_ptr, (png_bytep)png_pHYs, buf, (png_size_t)9); 01715 } 01716 #endif 01717 01718 #if defined(PNG_WRITE_tIME_SUPPORTED) 01719 /* Write the tIME chunk. Use either png_convert_from_struct_tm() 01720 * or png_convert_from_time_t(), or fill in the structure yourself. 01721 */ 01722 void /* PRIVATE */ 01723 png_write_tIME(png_structp png_ptr, png_timep mod_time) 01724 { 01725 #ifdef PNG_USE_LOCAL_ARRAYS 01726 PNG_tIME; 01727 #endif 01728 png_byte buf[7]; 01729 01730 png_debug(1, "in png_write_tIME"); 01731 01732 if (mod_time->month > 12 || mod_time->month < 1 || 01733 mod_time->day > 31 || mod_time->day < 1 || 01734 mod_time->hour > 23 || mod_time->second > 60) 01735 { 01736 png_warning(png_ptr, "Invalid time specified for tIME chunk"); 01737 return; 01738 } 01739 01740 png_save_uint_16(buf, mod_time->year); 01741 buf[2] = mod_time->month; 01742 buf[3] = mod_time->day; 01743 buf[4] = mod_time->hour; 01744 buf[5] = mod_time->minute; 01745 buf[6] = mod_time->second; 01746 01747 png_write_chunk(png_ptr, (png_bytep)png_tIME, buf, (png_size_t)7); 01748 } 01749 #endif 01750 01751 /* Initializes the row writing capability of libpng */ 01752 void /* PRIVATE */ 01753 png_write_start_row(png_structp png_ptr) 01754 { 01755 #ifdef PNG_WRITE_INTERLACING_SUPPORTED 01756 #ifdef PNG_USE_LOCAL_ARRAYS 01757 /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ 01758 01759 /* Start of interlace block */ 01760 int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; 01761 01762 /* Offset to next interlace block */ 01763 int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; 01764 01765 /* Start of interlace block in the y direction */ 01766 int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1}; 01767 01768 /* Offset to next interlace block in the y direction */ 01769 int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; 01770 #endif 01771 #endif 01772 01773 png_size_t buf_size; 01774 01775 png_debug(1, "in png_write_start_row"); 01776 01777 buf_size = (png_size_t)(PNG_ROWBYTES( 01778 png_ptr->usr_channels*png_ptr->usr_bit_depth, png_ptr->width) + 1); 01779 01780 /* Set up row buffer */ 01781 png_ptr->row_buf = (png_bytep)png_malloc(png_ptr, 01782 (png_uint_32)buf_size); 01783 png_ptr->row_buf[0] = PNG_FILTER_VALUE_NONE; 01784 01785 #ifndef PNG_NO_WRITE_FILTER 01786 /* Set up filtering buffer, if using this filter */ 01787 if (png_ptr->do_filter & PNG_FILTER_SUB) 01788 { 01789 png_ptr->sub_row = (png_bytep)png_malloc(png_ptr, 01790 (png_uint_32)(png_ptr->rowbytes + 1)); 01791 png_ptr->sub_row[0] = PNG_FILTER_VALUE_SUB; 01792 } 01793 01794 /* We only need to keep the previous row if we are using one of these. */ 01795 if (png_ptr->do_filter & (PNG_FILTER_AVG | PNG_FILTER_UP | PNG_FILTER_PAETH)) 01796 { 01797 /* Set up previous row buffer */ 01798 png_ptr->prev_row = (png_bytep)png_malloc(png_ptr, 01799 (png_uint_32)buf_size); 01800 png_memset(png_ptr->prev_row, 0, buf_size); 01801 01802 if (png_ptr->do_filter & PNG_FILTER_UP) 01803 { 01804 png_ptr->up_row = (png_bytep)png_malloc(png_ptr, 01805 (png_uint_32)(png_ptr->rowbytes + 1)); 01806 png_ptr->up_row[0] = PNG_FILTER_VALUE_UP; 01807 } 01808 01809 if (png_ptr->do_filter & PNG_FILTER_AVG) 01810 { 01811 png_ptr->avg_row = (png_bytep)png_malloc(png_ptr, 01812 (png_uint_32)(png_ptr->rowbytes + 1)); 01813 png_ptr->avg_row[0] = PNG_FILTER_VALUE_AVG; 01814 } 01815 01816 if (png_ptr->do_filter & PNG_FILTER_PAETH) 01817 { 01818 png_ptr->paeth_row = (png_bytep)png_malloc(png_ptr, 01819 (png_uint_32)(png_ptr->rowbytes + 1)); 01820 png_ptr->paeth_row[0] = PNG_FILTER_VALUE_PAETH; 01821 } 01822 } 01823 #endif /* PNG_NO_WRITE_FILTER */ 01824 01825 #ifdef PNG_WRITE_INTERLACING_SUPPORTED 01826 /* If interlaced, we need to set up width and height of pass */ 01827 if (png_ptr->interlaced) 01828 { 01829 if (!(png_ptr->transformations & PNG_INTERLACE)) 01830 { 01831 png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 - 01832 png_pass_ystart[0]) / png_pass_yinc[0]; 01833 png_ptr->usr_width = (png_ptr->width + png_pass_inc[0] - 1 - 01834 png_pass_start[0]) / png_pass_inc[0]; 01835 } 01836 else 01837 { 01838 png_ptr->num_rows = png_ptr->height; 01839 png_ptr->usr_width = png_ptr->width; 01840 } 01841 } 01842 else 01843 #endif 01844 { 01845 png_ptr->num_rows = png_ptr->height; 01846 png_ptr->usr_width = png_ptr->width; 01847 } 01848 png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; 01849 png_ptr->zstream.next_out = png_ptr->zbuf; 01850 } 01851 01852 /* Internal use only. Called when finished processing a row of data. */ 01853 void /* PRIVATE */ 01854 png_write_finish_row(png_structp png_ptr) 01855 { 01856 #ifdef PNG_WRITE_INTERLACING_SUPPORTED 01857 #ifdef PNG_USE_LOCAL_ARRAYS 01858 /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ 01859 01860 /* Start of interlace block */ 01861 int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; 01862 01863 /* Offset to next interlace block */ 01864 int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; 01865 01866 /* Start of interlace block in the y direction */ 01867 int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1}; 01868 01869 /* Offset to next interlace block in the y direction */ 01870 int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; 01871 #endif 01872 #endif 01873 01874 int ret; 01875 01876 png_debug(1, "in png_write_finish_row"); 01877 01878 /* Next row */ 01879 png_ptr->row_number++; 01880 01881 /* See if we are done */ 01882 if (png_ptr->row_number < png_ptr->num_rows) 01883 return; 01884 01885 #ifdef PNG_WRITE_INTERLACING_SUPPORTED 01886 /* If interlaced, go to next pass */ 01887 if (png_ptr->interlaced) 01888 { 01889 png_ptr->row_number = 0; 01890 if (png_ptr->transformations & PNG_INTERLACE) 01891 { 01892 png_ptr->pass++; 01893 } 01894 else 01895 { 01896 /* Loop until we find a non-zero width or height pass */ 01897 do 01898 { 01899 png_ptr->pass++; 01900 if (png_ptr->pass >= 7) 01901 break; 01902 png_ptr->usr_width = (png_ptr->width + 01903 png_pass_inc[png_ptr->pass] - 1 - 01904 png_pass_start[png_ptr->pass]) / 01905 png_pass_inc[png_ptr->pass]; 01906 png_ptr->num_rows = (png_ptr->height + 01907 png_pass_yinc[png_ptr->pass] - 1 - 01908 png_pass_ystart[png_ptr->pass]) / 01909 png_pass_yinc[png_ptr->pass]; 01910 if (png_ptr->transformations & PNG_INTERLACE) 01911 break; 01912 } while (png_ptr->usr_width == 0 || png_ptr->num_rows == 0); 01913 01914 } 01915 01916 /* Reset the row above the image for the next pass */ 01917 if (png_ptr->pass < 7) 01918 { 01919 if (png_ptr->prev_row != NULL) 01920 png_memset(png_ptr->prev_row, 0, 01921 (png_size_t)(PNG_ROWBYTES(png_ptr->usr_channels* 01922 png_ptr->usr_bit_depth, png_ptr->width)) + 1); 01923 return; 01924 } 01925 } 01926 #endif 01927 01928 /* If we get here, we've just written the last row, so we need 01929 to flush the compressor */ 01930 do 01931 { 01932 /* Tell the compressor we are done */ 01933 ret = deflate(&png_ptr->zstream, Z_FINISH); 01934 /* Check for an error */ 01935 if (ret == Z_OK) 01936 { 01937 /* Check to see if we need more room */ 01938 if (!(png_ptr->zstream.avail_out)) 01939 { 01940 png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size); 01941 png_ptr->zstream.next_out = png_ptr->zbuf; 01942 png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; 01943 } 01944 } 01945 else if (ret != Z_STREAM_END) 01946 { 01947 if (png_ptr->zstream.msg != NULL) 01948 png_error(png_ptr, png_ptr->zstream.msg); 01949 else 01950 png_error(png_ptr, "zlib error"); 01951 } 01952 } while (ret != Z_STREAM_END); 01953 01954 /* Write any extra space */ 01955 if (png_ptr->zstream.avail_out < png_ptr->zbuf_size) 01956 { 01957 png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size - 01958 png_ptr->zstream.avail_out); 01959 } 01960 01961 deflateReset(&png_ptr->zstream); 01962 png_ptr->zstream.data_type = Z_BINARY; 01963 } 01964 01965 #if defined(PNG_WRITE_INTERLACING_SUPPORTED) 01966 /* Pick out the correct pixels for the interlace pass. 01967 * The basic idea here is to go through the row with a source 01968 * pointer and a destination pointer (sp and dp), and copy the 01969 * correct pixels for the pass. As the row gets compacted, 01970 * sp will always be >= dp, so we should never overwrite anything. 01971 * See the default: case for the easiest code to understand. 01972 */ 01973 void /* PRIVATE */ 01974 png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass) 01975 { 01976 #ifdef PNG_USE_LOCAL_ARRAYS 01977 /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ 01978 01979 /* Start of interlace block */ 01980 int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; 01981 01982 /* Offset to next interlace block */ 01983 int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; 01984 #endif 01985 01986 png_debug(1, "in png_do_write_interlace"); 01987 01988 /* We don't have to do anything on the last pass (6) */ 01989 #if defined(PNG_USELESS_TESTS_SUPPORTED) 01990 if (row != NULL && row_info != NULL && pass < 6) 01991 #else 01992 if (pass < 6) 01993 #endif 01994 { 01995 /* Each pixel depth is handled separately */ 01996 switch (row_info->pixel_depth) 01997 { 01998 case 1: 01999 { 02000 png_bytep sp; 02001 png_bytep dp; 02002 int shift; 02003 int d; 02004 int value; 02005 png_uint_32 i; 02006 png_uint_32 row_width = row_info->width; 02007 02008 dp = row; 02009 d = 0; 02010 shift = 7; 02011 for (i = png_pass_start[pass]; i < row_width; 02012 i += png_pass_inc[pass]) 02013 { 02014 sp = row + (png_size_t)(i >> 3); 02015 value = (int)(*sp >> (7 - (int)(i & 0x07))) & 0x01; 02016 d |= (value << shift); 02017 02018 if (shift == 0) 02019 { 02020 shift = 7; 02021 *dp++ = (png_byte)d; 02022 d = 0; 02023 } 02024 else 02025 shift--; 02026 02027 } 02028 if (shift != 7) 02029 *dp = (png_byte)d; 02030 break; 02031 } 02032 case 2: 02033 { 02034 png_bytep sp; 02035 png_bytep dp; 02036 int shift; 02037 int d; 02038 int value; 02039 png_uint_32 i; 02040 png_uint_32 row_width = row_info->width; 02041 02042 dp = row; 02043 shift = 6; 02044 d = 0; 02045 for (i = png_pass_start[pass]; i < row_width; 02046 i += png_pass_inc[pass]) 02047 { 02048 sp = row + (png_size_t)(i >> 2); 02049 value = (*sp >> ((3 - (int)(i & 0x03)) << 1)) & 0x03; 02050 d |= (value << shift); 02051 02052 if (shift == 0) 02053 { 02054 shift = 6; 02055 *dp++ = (png_byte)d; 02056 d = 0; 02057 } 02058 else 02059 shift -= 2; 02060 } 02061 if (shift != 6) 02062 *dp = (png_byte)d; 02063 break; 02064 } 02065 case 4: 02066 { 02067 png_bytep sp; 02068 png_bytep dp; 02069 int shift; 02070 int d; 02071 int value; 02072 png_uint_32 i; 02073 png_uint_32 row_width = row_info->width; 02074 02075 dp = row; 02076 shift = 4; 02077 d = 0; 02078 for (i = png_pass_start[pass]; i < row_width; 02079 i += png_pass_inc[pass]) 02080 { 02081 sp = row + (png_size_t)(i >> 1); 02082 value = (*sp >> ((1 - (int)(i & 0x01)) << 2)) & 0x0f; 02083 d |= (value << shift); 02084 02085 if (shift == 0) 02086 { 02087 shift = 4; 02088 *dp++ = (png_byte)d; 02089 d = 0; 02090 } 02091 else 02092 shift -= 4; 02093 } 02094 if (shift != 4) 02095 *dp = (png_byte)d; 02096 break; 02097 } 02098 default: 02099 { 02100 png_bytep sp; 02101 png_bytep dp; 02102 png_uint_32 i; 02103 png_uint_32 row_width = row_info->width; 02104 png_size_t pixel_bytes; 02105 02106 /* Start at the beginning */ 02107 dp = row; 02108 /* Find out how many bytes each pixel takes up */ 02109 pixel_bytes = (row_info->pixel_depth >> 3); 02110 /* Loop through the row, only looking at the pixels that 02111 matter */ 02112 for (i = png_pass_start[pass]; i < row_width; 02113 i += png_pass_inc[pass]) 02114 { 02115 /* Find out where the original pixel is */ 02116 sp = row + (png_size_t)i * pixel_bytes; 02117 /* Move the pixel */ 02118 if (dp != sp) 02119 png_memcpy(dp, sp, pixel_bytes); 02120 /* Next pixel */ 02121 dp += pixel_bytes; 02122 } 02123 break; 02124 } 02125 } 02126 /* Set new row width */ 02127 row_info->width = (row_info->width + 02128 png_pass_inc[pass] - 1 - 02129 png_pass_start[pass]) / 02130 png_pass_inc[pass]; 02131 row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, 02132 row_info->width); 02133 } 02134 } 02135 #endif 02136 02137 /* This filters the row, chooses which filter to use, if it has not already 02138 * been specified by the application, and then writes the row out with the 02139 * chosen filter. 02140 */ 02141 #define PNG_MAXSUM (((png_uint_32)(-1)) >> 1) 02142 #define PNG_HISHIFT 10 02143 #define PNG_LOMASK ((png_uint_32)0xffffL) 02144 #define PNG_HIMASK ((png_uint_32)(~PNG_LOMASK >> PNG_HISHIFT)) 02145 void /* PRIVATE */ 02146 png_write_find_filter(png_structp png_ptr, png_row_infop row_info) 02147 { 02148 png_bytep best_row; 02149 #ifndef PNG_NO_WRITE_FILTER 02150 png_bytep prev_row, row_buf; 02151 png_uint_32 mins, bpp; 02152 png_byte filter_to_do = png_ptr->do_filter; 02153 png_uint_32 row_bytes = row_info->rowbytes; 02154 #ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED 02155 int num_p_filters = (int)png_ptr->num_prev_filters; 02156 #endif 02157 02158 png_debug(1, "in png_write_find_filter"); 02159 02160 /* Find out how many bytes offset each pixel is */ 02161 bpp = (row_info->pixel_depth + 7) >> 3; 02162 02163 prev_row = png_ptr->prev_row; 02164 #endif 02165 best_row = png_ptr->row_buf; 02166 #ifndef PNG_NO_WRITE_FILTER 02167 row_buf = best_row; 02168 mins = PNG_MAXSUM; 02169 02170 /* The prediction method we use is to find which method provides the 02171 * smallest value when summing the absolute values of the distances 02172 * from zero, using anything >= 128 as negative numbers. This is known 02173 * as the "minimum sum of absolute differences" heuristic. Other 02174 * heuristics are the "weighted minimum sum of absolute differences" 02175 * (experimental and can in theory improve compression), and the "zlib 02176 * predictive" method (not implemented yet), which does test compressions 02177 * of lines using different filter methods, and then chooses the 02178 * (series of) filter(s) that give minimum compressed data size (VERY 02179 * computationally expensive). 02180 * 02181 * GRR 980525: consider also 02182 * (1) minimum sum of absolute differences from running average (i.e., 02183 * keep running sum of non-absolute differences & count of bytes) 02184 * [track dispersion, too? restart average if dispersion too large?] 02185 * (1b) minimum sum of absolute differences from sliding average, probably 02186 * with window size <= deflate window (usually 32K) 02187 * (2) minimum sum of squared differences from zero or running average 02188 * (i.e., ~ root-mean-square approach) 02189 */ 02190 02191 02192 /* We don't need to test the 'no filter' case if this is the only filter 02193 * that has been chosen, as it doesn't actually do anything to the data. 02194 */ 02195 if ((filter_to_do & PNG_FILTER_NONE) && 02196 filter_to_do != PNG_FILTER_NONE) 02197 { 02198 png_bytep rp; 02199 png_uint_32 sum = 0; 02200 png_uint_32 i; 02201 int v; 02202 02203 for (i = 0, rp = row_buf + 1; i < row_bytes; i++, rp++) 02204 { 02205 v = *rp; 02206 sum += (v < 128) ? v : 256 - v; 02207 } 02208 02209 #if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) 02210 if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) 02211 { 02212 png_uint_32 sumhi, sumlo; 02213 int j; 02214 sumlo = sum & PNG_LOMASK; 02215 sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK; /* Gives us some footroom */ 02216 02217 /* Reduce the sum if we match any of the previous rows */ 02218 for (j = 0; j < num_p_filters; j++) 02219 { 02220 if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_NONE) 02221 { 02222 sumlo = (sumlo * png_ptr->filter_weights[j]) >> 02223 PNG_WEIGHT_SHIFT; 02224 sumhi = (sumhi * png_ptr->filter_weights[j]) >> 02225 PNG_WEIGHT_SHIFT; 02226 } 02227 } 02228 02229 /* Factor in the cost of this filter (this is here for completeness, 02230 * but it makes no sense to have a "cost" for the NONE filter, as 02231 * it has the minimum possible computational cost - none). 02232 */ 02233 sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_NONE]) >> 02234 PNG_COST_SHIFT; 02235 sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_NONE]) >> 02236 PNG_COST_SHIFT; 02237 02238 if (sumhi > PNG_HIMASK) 02239 sum = PNG_MAXSUM; 02240 else 02241 sum = (sumhi << PNG_HISHIFT) + sumlo; 02242 } 02243 #endif 02244 mins = sum; 02245 } 02246 02247 /* Sub filter */ 02248 if (filter_to_do == PNG_FILTER_SUB) 02249 /* It's the only filter so no testing is needed */ 02250 { 02251 png_bytep rp, lp, dp; 02252 png_uint_32 i; 02253 for (i = 0, rp = row_buf + 1, dp = png_ptr->sub_row + 1; i < bpp; 02254 i++, rp++, dp++) 02255 { 02256 *dp = *rp; 02257 } 02258 for (lp = row_buf + 1; i < row_bytes; 02259 i++, rp++, lp++, dp++) 02260 { 02261 *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff); 02262 } 02263 best_row = png_ptr->sub_row; 02264 } 02265 02266 else if (filter_to_do & PNG_FILTER_SUB) 02267 { 02268 png_bytep rp, dp, lp; 02269 png_uint_32 sum = 0, lmins = mins; 02270 png_uint_32 i; 02271 int v; 02272 02273 #if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) 02274 /* We temporarily increase the "minimum sum" by the factor we 02275 * would reduce the sum of this filter, so that we can do the 02276 * early exit comparison without scaling the sum each time. 02277 */ 02278 if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) 02279 { 02280 int j; 02281 png_uint_32 lmhi, lmlo; 02282 lmlo = lmins & PNG_LOMASK; 02283 lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK; 02284 02285 for (j = 0; j < num_p_filters; j++) 02286 { 02287 if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_SUB) 02288 { 02289 lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >> 02290 PNG_WEIGHT_SHIFT; 02291 lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >> 02292 PNG_WEIGHT_SHIFT; 02293 } 02294 } 02295 02296 lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >> 02297 PNG_COST_SHIFT; 02298 lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >> 02299 PNG_COST_SHIFT; 02300 02301 if (lmhi > PNG_HIMASK) 02302 lmins = PNG_MAXSUM; 02303 else 02304 lmins = (lmhi << PNG_HISHIFT) + lmlo; 02305 } 02306 #endif 02307 02308 for (i = 0, rp = row_buf + 1, dp = png_ptr->sub_row + 1; i < bpp; 02309 i++, rp++, dp++) 02310 { 02311 v = *dp = *rp; 02312 02313 sum += (v < 128) ? v : 256 - v; 02314 } 02315 for (lp = row_buf + 1; i < row_bytes; 02316 i++, rp++, lp++, dp++) 02317 { 02318 v = *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff); 02319 02320 sum += (v < 128) ? v : 256 - v; 02321 02322 if (sum > lmins) /* We are already worse, don't continue. */ 02323 break; 02324 } 02325 02326 #if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) 02327 if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) 02328 { 02329 int j; 02330 png_uint_32 sumhi, sumlo; 02331 sumlo = sum & PNG_LOMASK; 02332 sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK; 02333 02334 for (j = 0; j < num_p_filters; j++) 02335 { 02336 if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_SUB) 02337 { 02338 sumlo = (sumlo * png_ptr->inv_filter_weights[j]) >> 02339 PNG_WEIGHT_SHIFT; 02340 sumhi = (sumhi * png_ptr->inv_filter_weights[j]) >> 02341 PNG_WEIGHT_SHIFT; 02342 } 02343 } 02344 02345 sumlo = (sumlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >> 02346 PNG_COST_SHIFT; 02347 sumhi = (sumhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >> 02348 PNG_COST_SHIFT; 02349 02350 if (sumhi > PNG_HIMASK) 02351 sum = PNG_MAXSUM; 02352 else 02353 sum = (sumhi << PNG_HISHIFT) + sumlo; 02354 } 02355 #endif 02356 02357 if (sum < mins) 02358 { 02359 mins = sum; 02360 best_row = png_ptr->sub_row; 02361 } 02362 } 02363 02364 /* Up filter */ 02365 if (filter_to_do == PNG_FILTER_UP) 02366 { 02367 png_bytep rp, dp, pp; 02368 png_uint_32 i; 02369 02370 for (i = 0, rp = row_buf + 1, dp = png_ptr->up_row + 1, 02371 pp = prev_row + 1; i < row_bytes; 02372 i++, rp++, pp++, dp++) 02373 { 02374 *dp = (png_byte)(((int)*rp - (int)*pp) & 0xff); 02375 } 02376 best_row = png_ptr->up_row; 02377 } 02378 02379 else if (filter_to_do & PNG_FILTER_UP) 02380 { 02381 png_bytep rp, dp, pp; 02382 png_uint_32 sum = 0, lmins = mins; 02383 png_uint_32 i; 02384 int v; 02385 02386 02387 #if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) 02388 if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) 02389 { 02390 int j; 02391 png_uint_32 lmhi, lmlo; 02392 lmlo = lmins & PNG_LOMASK; 02393 lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK; 02394 02395 for (j = 0; j < num_p_filters; j++) 02396 { 02397 if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_UP) 02398 { 02399 lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >> 02400 PNG_WEIGHT_SHIFT; 02401 lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >> 02402 PNG_WEIGHT_SHIFT; 02403 } 02404 } 02405 02406 lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_UP]) >> 02407 PNG_COST_SHIFT; 02408 lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_UP]) >> 02409 PNG_COST_SHIFT; 02410 02411 if (lmhi > PNG_HIMASK) 02412 lmins = PNG_MAXSUM; 02413 else 02414 lmins = (lmhi << PNG_HISHIFT) + lmlo; 02415 } 02416 #endif 02417 02418 for (i = 0, rp = row_buf + 1, dp = png_ptr->up_row + 1, 02419 pp = prev_row + 1; i < row_bytes; i++) 02420 { 02421 v = *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff); 02422 02423 sum += (v < 128) ? v : 256 - v; 02424 02425 if (sum > lmins) /* We are already worse, don't continue. */ 02426 break; 02427 } 02428 02429 #if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) 02430 if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) 02431 { 02432 int j; 02433 png_uint_32 sumhi, sumlo; 02434 sumlo = sum & PNG_LOMASK; 02435 sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK; 02436 02437 for (j = 0; j < num_p_filters; j++) 02438 { 02439 if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_UP) 02440 { 02441 sumlo = (sumlo * png_ptr->filter_weights[j]) >> 02442 PNG_WEIGHT_SHIFT; 02443 sumhi = (sumhi * png_ptr->filter_weights[j]) >> 02444 PNG_WEIGHT_SHIFT; 02445 } 02446 } 02447 02448 sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_UP]) >> 02449 PNG_COST_SHIFT; 02450 sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_UP]) >> 02451 PNG_COST_SHIFT; 02452 02453 if (sumhi > PNG_HIMASK) 02454 sum = PNG_MAXSUM; 02455 else 02456 sum = (sumhi << PNG_HISHIFT) + sumlo; 02457 } 02458 #endif 02459 02460 if (sum < mins) 02461 { 02462 mins = sum; 02463 best_row = png_ptr->up_row; 02464 } 02465 } 02466 02467 /* Avg filter */ 02468 if (filter_to_do == PNG_FILTER_AVG) 02469 { 02470 png_bytep rp, dp, pp, lp; 02471 png_uint_32 i; 02472 for (i = 0, rp = row_buf + 1, dp = png_ptr->avg_row + 1, 02473 pp = prev_row + 1; i < bpp; i++) 02474 { 02475 *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff); 02476 } 02477 for (lp = row_buf + 1; i < row_bytes; i++) 02478 { 02479 *dp++ = (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2)) 02480 & 0xff); 02481 } 02482 best_row = png_ptr->avg_row; 02483 } 02484 02485 else if (filter_to_do & PNG_FILTER_AVG) 02486 { 02487 png_bytep rp, dp, pp, lp; 02488 png_uint_32 sum = 0, lmins = mins; 02489 png_uint_32 i; 02490 int v; 02491 02492 #if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) 02493 if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) 02494 { 02495 int j; 02496 png_uint_32 lmhi, lmlo; 02497 lmlo = lmins & PNG_LOMASK; 02498 lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK; 02499 02500 for (j = 0; j < num_p_filters; j++) 02501 { 02502 if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_AVG) 02503 { 02504 lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >> 02505 PNG_WEIGHT_SHIFT; 02506 lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >> 02507 PNG_WEIGHT_SHIFT; 02508 } 02509 } 02510 02511 lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_AVG]) >> 02512 PNG_COST_SHIFT; 02513 lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_AVG]) >> 02514 PNG_COST_SHIFT; 02515 02516 if (lmhi > PNG_HIMASK) 02517 lmins = PNG_MAXSUM; 02518 else 02519 lmins = (lmhi << PNG_HISHIFT) + lmlo; 02520 } 02521 #endif 02522 02523 for (i = 0, rp = row_buf + 1, dp = png_ptr->avg_row + 1, 02524 pp = prev_row + 1; i < bpp; i++) 02525 { 02526 v = *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff); 02527 02528 sum += (v < 128) ? v : 256 - v; 02529 } 02530 for (lp = row_buf + 1; i < row_bytes; i++) 02531 { 02532 v = *dp++ = 02533 (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2)) & 0xff); 02534 02535 sum += (v < 128) ? v : 256 - v; 02536 02537 if (sum > lmins) /* We are already worse, don't continue. */ 02538 break; 02539 } 02540 02541 #if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) 02542 if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) 02543 { 02544 int j; 02545 png_uint_32 sumhi, sumlo; 02546 sumlo = sum & PNG_LOMASK; 02547 sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK; 02548 02549 for (j = 0; j < num_p_filters; j++) 02550 { 02551 if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_NONE) 02552 { 02553 sumlo = (sumlo * png_ptr->filter_weights[j]) >> 02554 PNG_WEIGHT_SHIFT; 02555 sumhi = (sumhi * png_ptr->filter_weights[j]) >> 02556 PNG_WEIGHT_SHIFT; 02557 } 02558 } 02559 02560 sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_AVG]) >> 02561 PNG_COST_SHIFT; 02562 sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_AVG]) >> 02563 PNG_COST_SHIFT; 02564 02565 if (sumhi > PNG_HIMASK) 02566 sum = PNG_MAXSUM; 02567 else 02568 sum = (sumhi << PNG_HISHIFT) + sumlo; 02569 } 02570 #endif 02571 02572 if (sum < mins) 02573 { 02574 mins = sum; 02575 best_row = png_ptr->avg_row; 02576 } 02577 } 02578 02579 /* Paeth filter */ 02580 if (filter_to_do == PNG_FILTER_PAETH) 02581 { 02582 png_bytep rp, dp, pp, cp, lp; 02583 png_uint_32 i; 02584 for (i = 0, rp = row_buf + 1, dp = png_ptr->paeth_row + 1, 02585 pp = prev_row + 1; i < bpp; i++) 02586 { 02587 *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff); 02588 } 02589 02590 for (lp = row_buf + 1, cp = prev_row + 1; i < row_bytes; i++) 02591 { 02592 int a, b, c, pa, pb, pc, p; 02593 02594 b = *pp++; 02595 c = *cp++; 02596 a = *lp++; 02597 02598 p = b - c; 02599 pc = a - c; 02600 02601 #ifdef PNG_USE_ABS 02602 pa = abs(p); 02603 pb = abs(pc); 02604 pc = abs(p + pc); 02605 #else 02606 pa = p < 0 ? -p : p; 02607 pb = pc < 0 ? -pc : pc; 02608 pc = (p + pc) < 0 ? -(p + pc) : p + pc; 02609 #endif 02610 02611 p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c; 02612 02613 *dp++ = (png_byte)(((int)*rp++ - p) & 0xff); 02614 } 02615 best_row = png_ptr->paeth_row; 02616 } 02617 02618 else if (filter_to_do & PNG_FILTER_PAETH) 02619 { 02620 png_bytep rp, dp, pp, cp, lp; 02621 png_uint_32 sum = 0, lmins = mins; 02622 png_uint_32 i; 02623 int v; 02624 02625 #if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) 02626 if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) 02627 { 02628 int j; 02629 png_uint_32 lmhi, lmlo; 02630 lmlo = lmins & PNG_LOMASK; 02631 lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK; 02632 02633 for (j = 0; j < num_p_filters; j++) 02634 { 02635 if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_PAETH) 02636 { 02637 lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >> 02638 PNG_WEIGHT_SHIFT; 02639 lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >> 02640 PNG_WEIGHT_SHIFT; 02641 } 02642 } 02643 02644 lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_PAETH]) >> 02645 PNG_COST_SHIFT; 02646 lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_PAETH]) >> 02647 PNG_COST_SHIFT; 02648 02649 if (lmhi > PNG_HIMASK) 02650 lmins = PNG_MAXSUM; 02651 else 02652 lmins = (lmhi << PNG_HISHIFT) + lmlo; 02653 } 02654 #endif 02655 02656 for (i = 0, rp = row_buf + 1, dp = png_ptr->paeth_row + 1, 02657 pp = prev_row + 1; i < bpp; i++) 02658 { 02659 v = *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff); 02660 02661 sum += (v < 128) ? v : 256 - v; 02662 } 02663 02664 for (lp = row_buf + 1, cp = prev_row + 1; i < row_bytes; i++) 02665 { 02666 int a, b, c, pa, pb, pc, p; 02667 02668 b = *pp++; 02669 c = *cp++; 02670 a = *lp++; 02671 02672 #ifndef PNG_SLOW_PAETH 02673 p = b - c; 02674 pc = a - c; 02675 #ifdef PNG_USE_ABS 02676 pa = abs(p); 02677 pb = abs(pc); 02678 pc = abs(p + pc); 02679 #else 02680 pa = p < 0 ? -p : p; 02681 pb = pc < 0 ? -pc : pc; 02682 pc = (p + pc) < 0 ? -(p + pc) : p + pc; 02683 #endif 02684 p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c; 02685 #else /* PNG_SLOW_PAETH */ 02686 p = a + b - c; 02687 pa = abs(p - a); 02688 pb = abs(p - b); 02689 pc = abs(p - c); 02690 if (pa <= pb && pa <= pc) 02691 p = a; 02692 else if (pb <= pc) 02693 p = b; 02694 else 02695 p = c; 02696 #endif /* PNG_SLOW_PAETH */ 02697 02698 v = *dp++ = (png_byte)(((int)*rp++ - p) & 0xff); 02699 02700 sum += (v < 128) ? v : 256 - v; 02701 02702 if (sum > lmins) /* We are already worse, don't continue. */ 02703 break; 02704 } 02705 02706 #if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) 02707 if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) 02708 { 02709 int j; 02710 png_uint_32 sumhi, sumlo; 02711 sumlo = sum & PNG_LOMASK; 02712 sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK; 02713 02714 for (j = 0; j < num_p_filters; j++) 02715 { 02716 if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_PAETH) 02717 { 02718 sumlo = (sumlo * png_ptr->filter_weights[j]) >> 02719 PNG_WEIGHT_SHIFT; 02720 sumhi = (sumhi * png_ptr->filter_weights[j]) >> 02721 PNG_WEIGHT_SHIFT; 02722 } 02723 } 02724 02725 sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_PAETH]) >> 02726 PNG_COST_SHIFT; 02727 sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_PAETH]) >> 02728 PNG_COST_SHIFT; 02729 02730 if (sumhi > PNG_HIMASK) 02731 sum = PNG_MAXSUM; 02732 else 02733 sum = (sumhi << PNG_HISHIFT) + sumlo; 02734 } 02735 #endif 02736 02737 if (sum < mins) 02738 { 02739 best_row = png_ptr->paeth_row; 02740 } 02741 } 02742 #endif /* PNG_NO_WRITE_FILTER */ 02743 /* Do the actual writing of the filtered row data from the chosen filter. */ 02744 02745 png_write_filtered_row(png_ptr, best_row); 02746 02747 #ifndef PNG_NO_WRITE_FILTER 02748 #if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) 02749 /* Save the type of filter we picked this time for future calculations */ 02750 if (png_ptr->num_prev_filters > 0) 02751 { 02752 int j; 02753 for (j = 1; j < num_p_filters; j++) 02754 { 02755 png_ptr->prev_filters[j] = png_ptr->prev_filters[j - 1]; 02756 } 02757 png_ptr->prev_filters[j] = best_row[0]; 02758 } 02759 #endif 02760 #endif /* PNG_NO_WRITE_FILTER */ 02761 } 02762 02763 02764 /* Do the actual writing of a previously filtered row. */ 02765 void /* PRIVATE */ 02766 png_write_filtered_row(png_structp png_ptr, png_bytep filtered_row) 02767 { 02768 png_debug(1, "in png_write_filtered_row"); 02769 02770 png_debug1(2, "filter = %d", filtered_row[0]); 02771 /* Set up the zlib input buffer */ 02772 02773 png_ptr->zstream.next_in = filtered_row; 02774 png_ptr->zstream.avail_in = (uInt)png_ptr->row_info.rowbytes + 1; 02775 /* Repeat until we have compressed all the data */ 02776 do 02777 { 02778 int ret; /* Return of zlib */ 02779 02780 /* Compress the data */ 02781 ret = deflate(&png_ptr->zstream, Z_NO_FLUSH); 02782 /* Check for compression errors */ 02783 if (ret != Z_OK) 02784 { 02785 if (png_ptr->zstream.msg != NULL) 02786 png_error(png_ptr, png_ptr->zstream.msg); 02787 else 02788 png_error(png_ptr, "zlib error"); 02789 } 02790 02791 /* See if it is time to write another IDAT */ 02792 if (!(png_ptr->zstream.avail_out)) 02793 { 02794 /* Write the IDAT and reset the zlib output buffer */ 02795 png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size); 02796 png_ptr->zstream.next_out = png_ptr->zbuf; 02797 png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; 02798 } 02799 /* Repeat until all data has been compressed */ 02800 } while (png_ptr->zstream.avail_in); 02801 02802 /* Swap the current and previous rows */ 02803 if (png_ptr->prev_row != NULL) 02804 { 02805 png_bytep tptr; 02806 02807 tptr = png_ptr->prev_row; 02808 png_ptr->prev_row = png_ptr->row_buf; 02809 png_ptr->row_buf = tptr; 02810 } 02811 02812 /* Finish row - updates counters and flushes zlib if last row */ 02813 png_write_finish_row(png_ptr); 02814 02815 #if defined(PNG_WRITE_FLUSH_SUPPORTED) 02816 png_ptr->flush_rows++; 02817 02818 if (png_ptr->flush_dist > 0 && 02819 png_ptr->flush_rows >= png_ptr->flush_dist) 02820 { 02821 png_write_flush(png_ptr); 02822 } 02823 #endif 02824 } 02825 #endif /* PNG_WRITE_SUPPORTED */