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