vrshoot
diff libs/libpng/pngwutil.c @ 0:b2f14e535253
initial commit
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Sat, 01 Feb 2014 19:58:19 +0200 |
parents | |
children |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/libs/libpng/pngwutil.c Sat Feb 01 19:58:19 2014 +0200 1.3 @@ -0,0 +1,2827 @@ 1.4 + 1.5 +/* pngwutil.c - utilities to write a PNG file 1.6 + * 1.7 + * Last changed in libpng 1.2.30 [August 15, 2008] 1.8 + * For conditions of distribution and use, see copyright notice in png.h 1.9 + * Copyright (c) 1998-2008 Glenn Randers-Pehrson 1.10 + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) 1.11 + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) 1.12 + */ 1.13 + 1.14 +#define PNG_INTERNAL 1.15 +#include "png.h" 1.16 +#ifdef PNG_WRITE_SUPPORTED 1.17 + 1.18 +/* Place a 32-bit number into a buffer in PNG byte order. We work 1.19 + * with unsigned numbers for convenience, although one supported 1.20 + * ancillary chunk uses signed (two's complement) numbers. 1.21 + */ 1.22 +void PNGAPI 1.23 +png_save_uint_32(png_bytep buf, png_uint_32 i) 1.24 +{ 1.25 + buf[0] = (png_byte)((i >> 24) & 0xff); 1.26 + buf[1] = (png_byte)((i >> 16) & 0xff); 1.27 + buf[2] = (png_byte)((i >> 8) & 0xff); 1.28 + buf[3] = (png_byte)(i & 0xff); 1.29 +} 1.30 + 1.31 +/* The png_save_int_32 function assumes integers are stored in two's 1.32 + * complement format. If this isn't the case, then this routine needs to 1.33 + * be modified to write data in two's complement format. 1.34 + */ 1.35 +void PNGAPI 1.36 +png_save_int_32(png_bytep buf, png_int_32 i) 1.37 +{ 1.38 + buf[0] = (png_byte)((i >> 24) & 0xff); 1.39 + buf[1] = (png_byte)((i >> 16) & 0xff); 1.40 + buf[2] = (png_byte)((i >> 8) & 0xff); 1.41 + buf[3] = (png_byte)(i & 0xff); 1.42 +} 1.43 + 1.44 +/* Place a 16-bit number into a buffer in PNG byte order. 1.45 + * The parameter is declared unsigned int, not png_uint_16, 1.46 + * just to avoid potential problems on pre-ANSI C compilers. 1.47 + */ 1.48 +void PNGAPI 1.49 +png_save_uint_16(png_bytep buf, unsigned int i) 1.50 +{ 1.51 + buf[0] = (png_byte)((i >> 8) & 0xff); 1.52 + buf[1] = (png_byte)(i & 0xff); 1.53 +} 1.54 + 1.55 +/* Simple function to write the signature. If we have already written 1.56 + * the magic bytes of the signature, or more likely, the PNG stream is 1.57 + * being embedded into another stream and doesn't need its own signature, 1.58 + * we should call png_set_sig_bytes() to tell libpng how many of the 1.59 + * bytes have already been written. 1.60 + */ 1.61 +void /* PRIVATE */ 1.62 +png_write_sig(png_structp png_ptr) 1.63 +{ 1.64 + png_byte png_signature[8] = {137, 80, 78, 71, 13, 10, 26, 10}; 1.65 + 1.66 + /* write the rest of the 8 byte signature */ 1.67 + png_write_data(png_ptr, &png_signature[png_ptr->sig_bytes], 1.68 + (png_size_t)(8 - png_ptr->sig_bytes)); 1.69 + if (png_ptr->sig_bytes < 3) 1.70 + png_ptr->mode |= PNG_HAVE_PNG_SIGNATURE; 1.71 +} 1.72 + 1.73 +/* Write a PNG chunk all at once. The type is an array of ASCII characters 1.74 + * representing the chunk name. The array must be at least 4 bytes in 1.75 + * length, and does not need to be null terminated. To be safe, pass the 1.76 + * pre-defined chunk names here, and if you need a new one, define it 1.77 + * where the others are defined. The length is the length of the data. 1.78 + * All the data must be present. If that is not possible, use the 1.79 + * png_write_chunk_start(), png_write_chunk_data(), and png_write_chunk_end() 1.80 + * functions instead. 1.81 + */ 1.82 +void PNGAPI 1.83 +png_write_chunk(png_structp png_ptr, png_bytep chunk_name, 1.84 + png_bytep data, png_size_t length) 1.85 +{ 1.86 + if (png_ptr == NULL) return; 1.87 + png_write_chunk_start(png_ptr, chunk_name, (png_uint_32)length); 1.88 + png_write_chunk_data(png_ptr, data, (png_size_t)length); 1.89 + png_write_chunk_end(png_ptr); 1.90 +} 1.91 + 1.92 +/* Write the start of a PNG chunk. The type is the chunk type. 1.93 + * The total_length is the sum of the lengths of all the data you will be 1.94 + * passing in png_write_chunk_data(). 1.95 + */ 1.96 +void PNGAPI 1.97 +png_write_chunk_start(png_structp png_ptr, png_bytep chunk_name, 1.98 + png_uint_32 length) 1.99 +{ 1.100 + png_byte buf[8]; 1.101 + 1.102 + png_debug2(0, "Writing %s chunk, length = %lu\n", chunk_name, 1.103 + (unsigned long)length); 1.104 + if (png_ptr == NULL) return; 1.105 + 1.106 + /* write the length and the chunk name */ 1.107 + png_save_uint_32(buf, length); 1.108 + png_memcpy(buf + 4, chunk_name, 4); 1.109 + png_write_data(png_ptr, buf, (png_size_t)8); 1.110 + /* put the chunk name into png_ptr->chunk_name */ 1.111 + png_memcpy(png_ptr->chunk_name, chunk_name, 4); 1.112 + /* reset the crc and run it over the chunk name */ 1.113 + png_reset_crc(png_ptr); 1.114 + png_calculate_crc(png_ptr, chunk_name, (png_size_t)4); 1.115 +} 1.116 + 1.117 +/* Write the data of a PNG chunk started with png_write_chunk_start(). 1.118 + * Note that multiple calls to this function are allowed, and that the 1.119 + * sum of the lengths from these calls *must* add up to the total_length 1.120 + * given to png_write_chunk_start(). 1.121 + */ 1.122 +void PNGAPI 1.123 +png_write_chunk_data(png_structp png_ptr, png_bytep data, png_size_t length) 1.124 +{ 1.125 + /* write the data, and run the CRC over it */ 1.126 + if (png_ptr == NULL) return; 1.127 + if (data != NULL && length > 0) 1.128 + { 1.129 + png_write_data(png_ptr, data, length); 1.130 + /* update the CRC after writing the data, 1.131 + * in case that the user I/O routine alters it. 1.132 + */ 1.133 + png_calculate_crc(png_ptr, data, length); 1.134 + } 1.135 +} 1.136 + 1.137 +/* Finish a chunk started with png_write_chunk_start(). */ 1.138 +void PNGAPI 1.139 +png_write_chunk_end(png_structp png_ptr) 1.140 +{ 1.141 + png_byte buf[4]; 1.142 + 1.143 + if (png_ptr == NULL) return; 1.144 + 1.145 + /* write the crc in a single operation */ 1.146 + png_save_uint_32(buf, png_ptr->crc); 1.147 + 1.148 + png_write_data(png_ptr, buf, (png_size_t)4); 1.149 +} 1.150 + 1.151 +#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_iCCP_SUPPORTED) 1.152 +/* 1.153 + * This pair of functions encapsulates the operation of (a) compressing a 1.154 + * text string, and (b) issuing it later as a series of chunk data writes. 1.155 + * The compression_state structure is shared context for these functions 1.156 + * set up by the caller in order to make the whole mess thread-safe. 1.157 + */ 1.158 + 1.159 +typedef struct 1.160 +{ 1.161 + char *input; /* the uncompressed input data */ 1.162 + int input_len; /* its length */ 1.163 + int num_output_ptr; /* number of output pointers used */ 1.164 + int max_output_ptr; /* size of output_ptr */ 1.165 + png_charpp output_ptr; /* array of pointers to output */ 1.166 +} compression_state; 1.167 + 1.168 +/* compress given text into storage in the png_ptr structure */ 1.169 +static int /* PRIVATE */ 1.170 +png_text_compress(png_structp png_ptr, 1.171 + png_charp text, png_size_t text_len, int compression, 1.172 + compression_state *comp) 1.173 +{ 1.174 + int ret; 1.175 + 1.176 + comp->num_output_ptr = 0; 1.177 + comp->max_output_ptr = 0; 1.178 + comp->output_ptr = NULL; 1.179 + comp->input = NULL; 1.180 + comp->input_len = 0; 1.181 + 1.182 + /* we may just want to pass the text right through */ 1.183 + if (compression == PNG_TEXT_COMPRESSION_NONE) 1.184 + { 1.185 + comp->input = text; 1.186 + comp->input_len = text_len; 1.187 + return((int)text_len); 1.188 + } 1.189 + 1.190 + if (compression >= PNG_TEXT_COMPRESSION_LAST) 1.191 + { 1.192 +#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE) 1.193 + char msg[50]; 1.194 + png_snprintf(msg, 50, "Unknown compression type %d", compression); 1.195 + png_warning(png_ptr, msg); 1.196 +#else 1.197 + png_warning(png_ptr, "Unknown compression type"); 1.198 +#endif 1.199 + } 1.200 + 1.201 + /* We can't write the chunk until we find out how much data we have, 1.202 + * which means we need to run the compressor first and save the 1.203 + * output. This shouldn't be a problem, as the vast majority of 1.204 + * comments should be reasonable, but we will set up an array of 1.205 + * malloc'd pointers to be sure. 1.206 + * 1.207 + * If we knew the application was well behaved, we could simplify this 1.208 + * greatly by assuming we can always malloc an output buffer large 1.209 + * enough to hold the compressed text ((1001 * text_len / 1000) + 12) 1.210 + * and malloc this directly. The only time this would be a bad idea is 1.211 + * if we can't malloc more than 64K and we have 64K of random input 1.212 + * data, or if the input string is incredibly large (although this 1.213 + * wouldn't cause a failure, just a slowdown due to swapping). 1.214 + */ 1.215 + 1.216 + /* set up the compression buffers */ 1.217 + png_ptr->zstream.avail_in = (uInt)text_len; 1.218 + png_ptr->zstream.next_in = (Bytef *)text; 1.219 + png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; 1.220 + png_ptr->zstream.next_out = (Bytef *)png_ptr->zbuf; 1.221 + 1.222 + /* this is the same compression loop as in png_write_row() */ 1.223 + do 1.224 + { 1.225 + /* compress the data */ 1.226 + ret = deflate(&png_ptr->zstream, Z_NO_FLUSH); 1.227 + if (ret != Z_OK) 1.228 + { 1.229 + /* error */ 1.230 + if (png_ptr->zstream.msg != NULL) 1.231 + png_error(png_ptr, png_ptr->zstream.msg); 1.232 + else 1.233 + png_error(png_ptr, "zlib error"); 1.234 + } 1.235 + /* check to see if we need more room */ 1.236 + if (!(png_ptr->zstream.avail_out)) 1.237 + { 1.238 + /* make sure the output array has room */ 1.239 + if (comp->num_output_ptr >= comp->max_output_ptr) 1.240 + { 1.241 + int old_max; 1.242 + 1.243 + old_max = comp->max_output_ptr; 1.244 + comp->max_output_ptr = comp->num_output_ptr + 4; 1.245 + if (comp->output_ptr != NULL) 1.246 + { 1.247 + png_charpp old_ptr; 1.248 + 1.249 + old_ptr = comp->output_ptr; 1.250 + comp->output_ptr = (png_charpp)png_malloc(png_ptr, 1.251 + (png_uint_32) 1.252 + (comp->max_output_ptr * png_sizeof(png_charpp))); 1.253 + png_memcpy(comp->output_ptr, old_ptr, old_max 1.254 + * png_sizeof(png_charp)); 1.255 + png_free(png_ptr, old_ptr); 1.256 + } 1.257 + else 1.258 + comp->output_ptr = (png_charpp)png_malloc(png_ptr, 1.259 + (png_uint_32) 1.260 + (comp->max_output_ptr * png_sizeof(png_charp))); 1.261 + } 1.262 + 1.263 + /* save the data */ 1.264 + comp->output_ptr[comp->num_output_ptr] = 1.265 + (png_charp)png_malloc(png_ptr, 1.266 + (png_uint_32)png_ptr->zbuf_size); 1.267 + png_memcpy(comp->output_ptr[comp->num_output_ptr], png_ptr->zbuf, 1.268 + png_ptr->zbuf_size); 1.269 + comp->num_output_ptr++; 1.270 + 1.271 + /* and reset the buffer */ 1.272 + png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; 1.273 + png_ptr->zstream.next_out = png_ptr->zbuf; 1.274 + } 1.275 + /* continue until we don't have any more to compress */ 1.276 + } while (png_ptr->zstream.avail_in); 1.277 + 1.278 + /* finish the compression */ 1.279 + do 1.280 + { 1.281 + /* tell zlib we are finished */ 1.282 + ret = deflate(&png_ptr->zstream, Z_FINISH); 1.283 + 1.284 + if (ret == Z_OK) 1.285 + { 1.286 + /* check to see if we need more room */ 1.287 + if (!(png_ptr->zstream.avail_out)) 1.288 + { 1.289 + /* check to make sure our output array has room */ 1.290 + if (comp->num_output_ptr >= comp->max_output_ptr) 1.291 + { 1.292 + int old_max; 1.293 + 1.294 + old_max = comp->max_output_ptr; 1.295 + comp->max_output_ptr = comp->num_output_ptr + 4; 1.296 + if (comp->output_ptr != NULL) 1.297 + { 1.298 + png_charpp old_ptr; 1.299 + 1.300 + old_ptr = comp->output_ptr; 1.301 + /* This could be optimized to realloc() */ 1.302 + comp->output_ptr = (png_charpp)png_malloc(png_ptr, 1.303 + (png_uint_32)(comp->max_output_ptr * 1.304 + png_sizeof(png_charp))); 1.305 + png_memcpy(comp->output_ptr, old_ptr, 1.306 + old_max * png_sizeof(png_charp)); 1.307 + png_free(png_ptr, old_ptr); 1.308 + } 1.309 + else 1.310 + comp->output_ptr = (png_charpp)png_malloc(png_ptr, 1.311 + (png_uint_32)(comp->max_output_ptr * 1.312 + png_sizeof(png_charp))); 1.313 + } 1.314 + 1.315 + /* save off the data */ 1.316 + comp->output_ptr[comp->num_output_ptr] = 1.317 + (png_charp)png_malloc(png_ptr, 1.318 + (png_uint_32)png_ptr->zbuf_size); 1.319 + png_memcpy(comp->output_ptr[comp->num_output_ptr], png_ptr->zbuf, 1.320 + png_ptr->zbuf_size); 1.321 + comp->num_output_ptr++; 1.322 + 1.323 + /* and reset the buffer pointers */ 1.324 + png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; 1.325 + png_ptr->zstream.next_out = png_ptr->zbuf; 1.326 + } 1.327 + } 1.328 + else if (ret != Z_STREAM_END) 1.329 + { 1.330 + /* we got an error */ 1.331 + if (png_ptr->zstream.msg != NULL) 1.332 + png_error(png_ptr, png_ptr->zstream.msg); 1.333 + else 1.334 + png_error(png_ptr, "zlib error"); 1.335 + } 1.336 + } while (ret != Z_STREAM_END); 1.337 + 1.338 + /* text length is number of buffers plus last buffer */ 1.339 + text_len = png_ptr->zbuf_size * comp->num_output_ptr; 1.340 + if (png_ptr->zstream.avail_out < png_ptr->zbuf_size) 1.341 + text_len += png_ptr->zbuf_size - (png_size_t)png_ptr->zstream.avail_out; 1.342 + 1.343 + return((int)text_len); 1.344 +} 1.345 + 1.346 +/* ship the compressed text out via chunk writes */ 1.347 +static void /* PRIVATE */ 1.348 +png_write_compressed_data_out(png_structp png_ptr, compression_state *comp) 1.349 +{ 1.350 + int i; 1.351 + 1.352 + /* handle the no-compression case */ 1.353 + if (comp->input) 1.354 + { 1.355 + png_write_chunk_data(png_ptr, (png_bytep)comp->input, 1.356 + (png_size_t)comp->input_len); 1.357 + return; 1.358 + } 1.359 + 1.360 + /* write saved output buffers, if any */ 1.361 + for (i = 0; i < comp->num_output_ptr; i++) 1.362 + { 1.363 + png_write_chunk_data(png_ptr, (png_bytep)comp->output_ptr[i], 1.364 + (png_size_t)png_ptr->zbuf_size); 1.365 + png_free(png_ptr, comp->output_ptr[i]); 1.366 + comp->output_ptr[i]=NULL; 1.367 + } 1.368 + if (comp->max_output_ptr != 0) 1.369 + png_free(png_ptr, comp->output_ptr); 1.370 + comp->output_ptr=NULL; 1.371 + /* write anything left in zbuf */ 1.372 + if (png_ptr->zstream.avail_out < (png_uint_32)png_ptr->zbuf_size) 1.373 + png_write_chunk_data(png_ptr, png_ptr->zbuf, 1.374 + (png_size_t)(png_ptr->zbuf_size - png_ptr->zstream.avail_out)); 1.375 + 1.376 + /* reset zlib for another zTXt/iTXt or image data */ 1.377 + deflateReset(&png_ptr->zstream); 1.378 + png_ptr->zstream.data_type = Z_BINARY; 1.379 +} 1.380 +#endif 1.381 + 1.382 +/* Write the IHDR chunk, and update the png_struct with the necessary 1.383 + * information. Note that the rest of this code depends upon this 1.384 + * information being correct. 1.385 + */ 1.386 +void /* PRIVATE */ 1.387 +png_write_IHDR(png_structp png_ptr, png_uint_32 width, png_uint_32 height, 1.388 + int bit_depth, int color_type, int compression_type, int filter_type, 1.389 + int interlace_type) 1.390 +{ 1.391 +#ifdef PNG_USE_LOCAL_ARRAYS 1.392 + PNG_IHDR; 1.393 +#endif 1.394 + int ret; 1.395 + 1.396 + png_byte buf[13]; /* buffer to store the IHDR info */ 1.397 + 1.398 + png_debug(1, "in png_write_IHDR\n"); 1.399 + /* Check that we have valid input data from the application info */ 1.400 + switch (color_type) 1.401 + { 1.402 + case PNG_COLOR_TYPE_GRAY: 1.403 + switch (bit_depth) 1.404 + { 1.405 + case 1: 1.406 + case 2: 1.407 + case 4: 1.408 + case 8: 1.409 + case 16: png_ptr->channels = 1; break; 1.410 + default: png_error(png_ptr, "Invalid bit depth for grayscale image"); 1.411 + } 1.412 + break; 1.413 + case PNG_COLOR_TYPE_RGB: 1.414 + if (bit_depth != 8 && bit_depth != 16) 1.415 + png_error(png_ptr, "Invalid bit depth for RGB image"); 1.416 + png_ptr->channels = 3; 1.417 + break; 1.418 + case PNG_COLOR_TYPE_PALETTE: 1.419 + switch (bit_depth) 1.420 + { 1.421 + case 1: 1.422 + case 2: 1.423 + case 4: 1.424 + case 8: png_ptr->channels = 1; break; 1.425 + default: png_error(png_ptr, "Invalid bit depth for paletted image"); 1.426 + } 1.427 + break; 1.428 + case PNG_COLOR_TYPE_GRAY_ALPHA: 1.429 + if (bit_depth != 8 && bit_depth != 16) 1.430 + png_error(png_ptr, "Invalid bit depth for grayscale+alpha image"); 1.431 + png_ptr->channels = 2; 1.432 + break; 1.433 + case PNG_COLOR_TYPE_RGB_ALPHA: 1.434 + if (bit_depth != 8 && bit_depth != 16) 1.435 + png_error(png_ptr, "Invalid bit depth for RGBA image"); 1.436 + png_ptr->channels = 4; 1.437 + break; 1.438 + default: 1.439 + png_error(png_ptr, "Invalid image color type specified"); 1.440 + } 1.441 + 1.442 + if (compression_type != PNG_COMPRESSION_TYPE_BASE) 1.443 + { 1.444 + png_warning(png_ptr, "Invalid compression type specified"); 1.445 + compression_type = PNG_COMPRESSION_TYPE_BASE; 1.446 + } 1.447 + 1.448 + /* Write filter_method 64 (intrapixel differencing) only if 1.449 + * 1. Libpng was compiled with PNG_MNG_FEATURES_SUPPORTED and 1.450 + * 2. Libpng did not write a PNG signature (this filter_method is only 1.451 + * used in PNG datastreams that are embedded in MNG datastreams) and 1.452 + * 3. The application called png_permit_mng_features with a mask that 1.453 + * included PNG_FLAG_MNG_FILTER_64 and 1.454 + * 4. The filter_method is 64 and 1.455 + * 5. The color_type is RGB or RGBA 1.456 + */ 1.457 + if ( 1.458 +#if defined(PNG_MNG_FEATURES_SUPPORTED) 1.459 + !((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) && 1.460 + ((png_ptr->mode&PNG_HAVE_PNG_SIGNATURE) == 0) && 1.461 + (color_type == PNG_COLOR_TYPE_RGB || 1.462 + color_type == PNG_COLOR_TYPE_RGB_ALPHA) && 1.463 + (filter_type == PNG_INTRAPIXEL_DIFFERENCING)) && 1.464 +#endif 1.465 + filter_type != PNG_FILTER_TYPE_BASE) 1.466 + { 1.467 + png_warning(png_ptr, "Invalid filter type specified"); 1.468 + filter_type = PNG_FILTER_TYPE_BASE; 1.469 + } 1.470 + 1.471 +#ifdef PNG_WRITE_INTERLACING_SUPPORTED 1.472 + if (interlace_type != PNG_INTERLACE_NONE && 1.473 + interlace_type != PNG_INTERLACE_ADAM7) 1.474 + { 1.475 + png_warning(png_ptr, "Invalid interlace type specified"); 1.476 + interlace_type = PNG_INTERLACE_ADAM7; 1.477 + } 1.478 +#else 1.479 + interlace_type=PNG_INTERLACE_NONE; 1.480 +#endif 1.481 + 1.482 + /* save off the relevent information */ 1.483 + png_ptr->bit_depth = (png_byte)bit_depth; 1.484 + png_ptr->color_type = (png_byte)color_type; 1.485 + png_ptr->interlaced = (png_byte)interlace_type; 1.486 +#if defined(PNG_MNG_FEATURES_SUPPORTED) 1.487 + png_ptr->filter_type = (png_byte)filter_type; 1.488 +#endif 1.489 + png_ptr->compression_type = (png_byte)compression_type; 1.490 + png_ptr->width = width; 1.491 + png_ptr->height = height; 1.492 + 1.493 + png_ptr->pixel_depth = (png_byte)(bit_depth * png_ptr->channels); 1.494 + png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth, width); 1.495 + /* set the usr info, so any transformations can modify it */ 1.496 + png_ptr->usr_width = png_ptr->width; 1.497 + png_ptr->usr_bit_depth = png_ptr->bit_depth; 1.498 + png_ptr->usr_channels = png_ptr->channels; 1.499 + 1.500 + /* pack the header information into the buffer */ 1.501 + png_save_uint_32(buf, width); 1.502 + png_save_uint_32(buf + 4, height); 1.503 + buf[8] = (png_byte)bit_depth; 1.504 + buf[9] = (png_byte)color_type; 1.505 + buf[10] = (png_byte)compression_type; 1.506 + buf[11] = (png_byte)filter_type; 1.507 + buf[12] = (png_byte)interlace_type; 1.508 + 1.509 + /* write the chunk */ 1.510 + png_write_chunk(png_ptr, (png_bytep)png_IHDR, buf, (png_size_t)13); 1.511 + 1.512 + /* initialize zlib with PNG info */ 1.513 + png_ptr->zstream.zalloc = png_zalloc; 1.514 + png_ptr->zstream.zfree = png_zfree; 1.515 + png_ptr->zstream.opaque = (voidpf)png_ptr; 1.516 + if (!(png_ptr->do_filter)) 1.517 + { 1.518 + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE || 1.519 + png_ptr->bit_depth < 8) 1.520 + png_ptr->do_filter = PNG_FILTER_NONE; 1.521 + else 1.522 + png_ptr->do_filter = PNG_ALL_FILTERS; 1.523 + } 1.524 + if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_STRATEGY)) 1.525 + { 1.526 + if (png_ptr->do_filter != PNG_FILTER_NONE) 1.527 + png_ptr->zlib_strategy = Z_FILTERED; 1.528 + else 1.529 + png_ptr->zlib_strategy = Z_DEFAULT_STRATEGY; 1.530 + } 1.531 + if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_LEVEL)) 1.532 + png_ptr->zlib_level = Z_DEFAULT_COMPRESSION; 1.533 + if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_MEM_LEVEL)) 1.534 + png_ptr->zlib_mem_level = 8; 1.535 + if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_WINDOW_BITS)) 1.536 + png_ptr->zlib_window_bits = 15; 1.537 + if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_METHOD)) 1.538 + png_ptr->zlib_method = 8; 1.539 + ret = deflateInit2(&png_ptr->zstream, png_ptr->zlib_level, 1.540 + png_ptr->zlib_method, png_ptr->zlib_window_bits, 1.541 + png_ptr->zlib_mem_level, png_ptr->zlib_strategy); 1.542 + if (ret != Z_OK) 1.543 + { 1.544 + if (ret == Z_VERSION_ERROR) png_error(png_ptr, 1.545 + "zlib failed to initialize compressor -- version error"); 1.546 + if (ret == Z_STREAM_ERROR) png_error(png_ptr, 1.547 + "zlib failed to initialize compressor -- stream error"); 1.548 + if (ret == Z_MEM_ERROR) png_error(png_ptr, 1.549 + "zlib failed to initialize compressor -- mem error"); 1.550 + png_error(png_ptr, "zlib failed to initialize compressor"); 1.551 + } 1.552 + png_ptr->zstream.next_out = png_ptr->zbuf; 1.553 + png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; 1.554 + /* libpng is not interested in zstream.data_type */ 1.555 + /* set it to a predefined value, to avoid its evaluation inside zlib */ 1.556 + png_ptr->zstream.data_type = Z_BINARY; 1.557 + 1.558 + png_ptr->mode = PNG_HAVE_IHDR; 1.559 +} 1.560 + 1.561 +/* write the palette. We are careful not to trust png_color to be in the 1.562 + * correct order for PNG, so people can redefine it to any convenient 1.563 + * structure. 1.564 + */ 1.565 +void /* PRIVATE */ 1.566 +png_write_PLTE(png_structp png_ptr, png_colorp palette, png_uint_32 num_pal) 1.567 +{ 1.568 +#ifdef PNG_USE_LOCAL_ARRAYS 1.569 + PNG_PLTE; 1.570 +#endif 1.571 + png_uint_32 i; 1.572 + png_colorp pal_ptr; 1.573 + png_byte buf[3]; 1.574 + 1.575 + png_debug(1, "in png_write_PLTE\n"); 1.576 + if (( 1.577 +#if defined(PNG_MNG_FEATURES_SUPPORTED) 1.578 + !(png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE) && 1.579 +#endif 1.580 + num_pal == 0) || num_pal > 256) 1.581 + { 1.582 + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) 1.583 + { 1.584 + png_error(png_ptr, "Invalid number of colors in palette"); 1.585 + } 1.586 + else 1.587 + { 1.588 + png_warning(png_ptr, "Invalid number of colors in palette"); 1.589 + return; 1.590 + } 1.591 + } 1.592 + 1.593 + if (!(png_ptr->color_type&PNG_COLOR_MASK_COLOR)) 1.594 + { 1.595 + png_warning(png_ptr, 1.596 + "Ignoring request to write a PLTE chunk in grayscale PNG"); 1.597 + return; 1.598 + } 1.599 + 1.600 + png_ptr->num_palette = (png_uint_16)num_pal; 1.601 + png_debug1(3, "num_palette = %d\n", png_ptr->num_palette); 1.602 + 1.603 + png_write_chunk_start(png_ptr, (png_bytep)png_PLTE, 1.604 + (png_uint_32)(num_pal * 3)); 1.605 +#ifndef PNG_NO_POINTER_INDEXING 1.606 + for (i = 0, pal_ptr = palette; i < num_pal; i++, pal_ptr++) 1.607 + { 1.608 + buf[0] = pal_ptr->red; 1.609 + buf[1] = pal_ptr->green; 1.610 + buf[2] = pal_ptr->blue; 1.611 + png_write_chunk_data(png_ptr, buf, (png_size_t)3); 1.612 + } 1.613 +#else 1.614 + /* This is a little slower but some buggy compilers need to do this instead */ 1.615 + pal_ptr=palette; 1.616 + for (i = 0; i < num_pal; i++) 1.617 + { 1.618 + buf[0] = pal_ptr[i].red; 1.619 + buf[1] = pal_ptr[i].green; 1.620 + buf[2] = pal_ptr[i].blue; 1.621 + png_write_chunk_data(png_ptr, buf, (png_size_t)3); 1.622 + } 1.623 +#endif 1.624 + png_write_chunk_end(png_ptr); 1.625 + png_ptr->mode |= PNG_HAVE_PLTE; 1.626 +} 1.627 + 1.628 +/* write an IDAT chunk */ 1.629 +void /* PRIVATE */ 1.630 +png_write_IDAT(png_structp png_ptr, png_bytep data, png_size_t length) 1.631 +{ 1.632 +#ifdef PNG_USE_LOCAL_ARRAYS 1.633 + PNG_IDAT; 1.634 +#endif 1.635 + png_debug(1, "in png_write_IDAT\n"); 1.636 + 1.637 + /* Optimize the CMF field in the zlib stream. */ 1.638 + /* This hack of the zlib stream is compliant to the stream specification. */ 1.639 + if (!(png_ptr->mode & PNG_HAVE_IDAT) && 1.640 + png_ptr->compression_type == PNG_COMPRESSION_TYPE_BASE) 1.641 + { 1.642 + unsigned int z_cmf = data[0]; /* zlib compression method and flags */ 1.643 + if ((z_cmf & 0x0f) == 8 && (z_cmf & 0xf0) <= 0x70) 1.644 + { 1.645 + /* Avoid memory underflows and multiplication overflows. */ 1.646 + /* The conditions below are practically always satisfied; 1.647 + however, they still must be checked. */ 1.648 + if (length >= 2 && 1.649 + png_ptr->height < 16384 && png_ptr->width < 16384) 1.650 + { 1.651 + png_uint_32 uncompressed_idat_size = png_ptr->height * 1.652 + ((png_ptr->width * 1.653 + png_ptr->channels * png_ptr->bit_depth + 15) >> 3); 1.654 + unsigned int z_cinfo = z_cmf >> 4; 1.655 + unsigned int half_z_window_size = 1 << (z_cinfo + 7); 1.656 + while (uncompressed_idat_size <= half_z_window_size && 1.657 + half_z_window_size >= 256) 1.658 + { 1.659 + z_cinfo--; 1.660 + half_z_window_size >>= 1; 1.661 + } 1.662 + z_cmf = (z_cmf & 0x0f) | (z_cinfo << 4); 1.663 + if (data[0] != (png_byte)z_cmf) 1.664 + { 1.665 + data[0] = (png_byte)z_cmf; 1.666 + data[1] &= 0xe0; 1.667 + data[1] += (png_byte)(0x1f - ((z_cmf << 8) + data[1]) % 0x1f); 1.668 + } 1.669 + } 1.670 + } 1.671 + else 1.672 + png_error(png_ptr, 1.673 + "Invalid zlib compression method or flags in IDAT"); 1.674 + } 1.675 + 1.676 + png_write_chunk(png_ptr, (png_bytep)png_IDAT, data, length); 1.677 + png_ptr->mode |= PNG_HAVE_IDAT; 1.678 +} 1.679 + 1.680 +/* write an IEND chunk */ 1.681 +void /* PRIVATE */ 1.682 +png_write_IEND(png_structp png_ptr) 1.683 +{ 1.684 +#ifdef PNG_USE_LOCAL_ARRAYS 1.685 + PNG_IEND; 1.686 +#endif 1.687 + png_debug(1, "in png_write_IEND\n"); 1.688 + png_write_chunk(png_ptr, (png_bytep)png_IEND, png_bytep_NULL, 1.689 + (png_size_t)0); 1.690 + png_ptr->mode |= PNG_HAVE_IEND; 1.691 +} 1.692 + 1.693 +#if defined(PNG_WRITE_gAMA_SUPPORTED) 1.694 +/* write a gAMA chunk */ 1.695 +#ifdef PNG_FLOATING_POINT_SUPPORTED 1.696 +void /* PRIVATE */ 1.697 +png_write_gAMA(png_structp png_ptr, double file_gamma) 1.698 +{ 1.699 +#ifdef PNG_USE_LOCAL_ARRAYS 1.700 + PNG_gAMA; 1.701 +#endif 1.702 + png_uint_32 igamma; 1.703 + png_byte buf[4]; 1.704 + 1.705 + png_debug(1, "in png_write_gAMA\n"); 1.706 + /* file_gamma is saved in 1/100,000ths */ 1.707 + igamma = (png_uint_32)(file_gamma * 100000.0 + 0.5); 1.708 + png_save_uint_32(buf, igamma); 1.709 + png_write_chunk(png_ptr, (png_bytep)png_gAMA, buf, (png_size_t)4); 1.710 +} 1.711 +#endif 1.712 +#ifdef PNG_FIXED_POINT_SUPPORTED 1.713 +void /* PRIVATE */ 1.714 +png_write_gAMA_fixed(png_structp png_ptr, png_fixed_point file_gamma) 1.715 +{ 1.716 +#ifdef PNG_USE_LOCAL_ARRAYS 1.717 + PNG_gAMA; 1.718 +#endif 1.719 + png_byte buf[4]; 1.720 + 1.721 + png_debug(1, "in png_write_gAMA\n"); 1.722 + /* file_gamma is saved in 1/100,000ths */ 1.723 + png_save_uint_32(buf, (png_uint_32)file_gamma); 1.724 + png_write_chunk(png_ptr, (png_bytep)png_gAMA, buf, (png_size_t)4); 1.725 +} 1.726 +#endif 1.727 +#endif 1.728 + 1.729 +#if defined(PNG_WRITE_sRGB_SUPPORTED) 1.730 +/* write a sRGB chunk */ 1.731 +void /* PRIVATE */ 1.732 +png_write_sRGB(png_structp png_ptr, int srgb_intent) 1.733 +{ 1.734 +#ifdef PNG_USE_LOCAL_ARRAYS 1.735 + PNG_sRGB; 1.736 +#endif 1.737 + png_byte buf[1]; 1.738 + 1.739 + png_debug(1, "in png_write_sRGB\n"); 1.740 + if (srgb_intent >= PNG_sRGB_INTENT_LAST) 1.741 + png_warning(png_ptr, 1.742 + "Invalid sRGB rendering intent specified"); 1.743 + buf[0]=(png_byte)srgb_intent; 1.744 + png_write_chunk(png_ptr, (png_bytep)png_sRGB, buf, (png_size_t)1); 1.745 +} 1.746 +#endif 1.747 + 1.748 +#if defined(PNG_WRITE_iCCP_SUPPORTED) 1.749 +/* write an iCCP chunk */ 1.750 +void /* PRIVATE */ 1.751 +png_write_iCCP(png_structp png_ptr, png_charp name, int compression_type, 1.752 + png_charp profile, int profile_len) 1.753 +{ 1.754 +#ifdef PNG_USE_LOCAL_ARRAYS 1.755 + PNG_iCCP; 1.756 +#endif 1.757 + png_size_t name_len; 1.758 + png_charp new_name; 1.759 + compression_state comp; 1.760 + int embedded_profile_len = 0; 1.761 + 1.762 + png_debug(1, "in png_write_iCCP\n"); 1.763 + 1.764 + comp.num_output_ptr = 0; 1.765 + comp.max_output_ptr = 0; 1.766 + comp.output_ptr = NULL; 1.767 + comp.input = NULL; 1.768 + comp.input_len = 0; 1.769 + 1.770 + if (name == NULL || (name_len = png_check_keyword(png_ptr, name, 1.771 + &new_name)) == 0) 1.772 + { 1.773 + png_warning(png_ptr, "Empty keyword in iCCP chunk"); 1.774 + return; 1.775 + } 1.776 + 1.777 + if (compression_type != PNG_COMPRESSION_TYPE_BASE) 1.778 + png_warning(png_ptr, "Unknown compression type in iCCP chunk"); 1.779 + 1.780 + if (profile == NULL) 1.781 + profile_len = 0; 1.782 + 1.783 + if (profile_len > 3) 1.784 + embedded_profile_len = 1.785 + ((*( (png_bytep)profile ))<<24) | 1.786 + ((*( (png_bytep)profile + 1))<<16) | 1.787 + ((*( (png_bytep)profile + 2))<< 8) | 1.788 + ((*( (png_bytep)profile + 3)) ); 1.789 + 1.790 + if (profile_len < embedded_profile_len) 1.791 + { 1.792 + png_warning(png_ptr, 1.793 + "Embedded profile length too large in iCCP chunk"); 1.794 + return; 1.795 + } 1.796 + 1.797 + if (profile_len > embedded_profile_len) 1.798 + { 1.799 + png_warning(png_ptr, 1.800 + "Truncating profile to actual length in iCCP chunk"); 1.801 + profile_len = embedded_profile_len; 1.802 + } 1.803 + 1.804 + if (profile_len) 1.805 + profile_len = png_text_compress(png_ptr, profile, 1.806 + (png_size_t)profile_len, PNG_COMPRESSION_TYPE_BASE, &comp); 1.807 + 1.808 + /* make sure we include the NULL after the name and the compression type */ 1.809 + png_write_chunk_start(png_ptr, (png_bytep)png_iCCP, 1.810 + (png_uint_32)(name_len + profile_len + 2)); 1.811 + new_name[name_len + 1] = 0x00; 1.812 + png_write_chunk_data(png_ptr, (png_bytep)new_name, 1.813 + (png_size_t)(name_len + 2)); 1.814 + 1.815 + if (profile_len) 1.816 + png_write_compressed_data_out(png_ptr, &comp); 1.817 + 1.818 + png_write_chunk_end(png_ptr); 1.819 + png_free(png_ptr, new_name); 1.820 +} 1.821 +#endif 1.822 + 1.823 +#if defined(PNG_WRITE_sPLT_SUPPORTED) 1.824 +/* write a sPLT chunk */ 1.825 +void /* PRIVATE */ 1.826 +png_write_sPLT(png_structp png_ptr, png_sPLT_tp spalette) 1.827 +{ 1.828 +#ifdef PNG_USE_LOCAL_ARRAYS 1.829 + PNG_sPLT; 1.830 +#endif 1.831 + png_size_t name_len; 1.832 + png_charp new_name; 1.833 + png_byte entrybuf[10]; 1.834 + int entry_size = (spalette->depth == 8 ? 6 : 10); 1.835 + int palette_size = entry_size * spalette->nentries; 1.836 + png_sPLT_entryp ep; 1.837 +#ifdef PNG_NO_POINTER_INDEXING 1.838 + int i; 1.839 +#endif 1.840 + 1.841 + png_debug(1, "in png_write_sPLT\n"); 1.842 + if (spalette->name == NULL || (name_len = png_check_keyword(png_ptr, 1.843 + spalette->name, &new_name))==0) 1.844 + { 1.845 + png_warning(png_ptr, "Empty keyword in sPLT chunk"); 1.846 + return; 1.847 + } 1.848 + 1.849 + /* make sure we include the NULL after the name */ 1.850 + png_write_chunk_start(png_ptr, (png_bytep)png_sPLT, 1.851 + (png_uint_32)(name_len + 2 + palette_size)); 1.852 + png_write_chunk_data(png_ptr, (png_bytep)new_name, 1.853 + (png_size_t)(name_len + 1)); 1.854 + png_write_chunk_data(png_ptr, (png_bytep)&spalette->depth, (png_size_t)1); 1.855 + 1.856 + /* loop through each palette entry, writing appropriately */ 1.857 +#ifndef PNG_NO_POINTER_INDEXING 1.858 + for (ep = spalette->entries; ep<spalette->entries + spalette->nentries; ep++) 1.859 + { 1.860 + if (spalette->depth == 8) 1.861 + { 1.862 + entrybuf[0] = (png_byte)ep->red; 1.863 + entrybuf[1] = (png_byte)ep->green; 1.864 + entrybuf[2] = (png_byte)ep->blue; 1.865 + entrybuf[3] = (png_byte)ep->alpha; 1.866 + png_save_uint_16(entrybuf + 4, ep->frequency); 1.867 + } 1.868 + else 1.869 + { 1.870 + png_save_uint_16(entrybuf + 0, ep->red); 1.871 + png_save_uint_16(entrybuf + 2, ep->green); 1.872 + png_save_uint_16(entrybuf + 4, ep->blue); 1.873 + png_save_uint_16(entrybuf + 6, ep->alpha); 1.874 + png_save_uint_16(entrybuf + 8, ep->frequency); 1.875 + } 1.876 + png_write_chunk_data(png_ptr, entrybuf, (png_size_t)entry_size); 1.877 + } 1.878 +#else 1.879 + ep=spalette->entries; 1.880 + for (i=0; i>spalette->nentries; i++) 1.881 + { 1.882 + if (spalette->depth == 8) 1.883 + { 1.884 + entrybuf[0] = (png_byte)ep[i].red; 1.885 + entrybuf[1] = (png_byte)ep[i].green; 1.886 + entrybuf[2] = (png_byte)ep[i].blue; 1.887 + entrybuf[3] = (png_byte)ep[i].alpha; 1.888 + png_save_uint_16(entrybuf + 4, ep[i].frequency); 1.889 + } 1.890 + else 1.891 + { 1.892 + png_save_uint_16(entrybuf + 0, ep[i].red); 1.893 + png_save_uint_16(entrybuf + 2, ep[i].green); 1.894 + png_save_uint_16(entrybuf + 4, ep[i].blue); 1.895 + png_save_uint_16(entrybuf + 6, ep[i].alpha); 1.896 + png_save_uint_16(entrybuf + 8, ep[i].frequency); 1.897 + } 1.898 + png_write_chunk_data(png_ptr, entrybuf, (png_size_t)entry_size); 1.899 + } 1.900 +#endif 1.901 + 1.902 + png_write_chunk_end(png_ptr); 1.903 + png_free(png_ptr, new_name); 1.904 +} 1.905 +#endif 1.906 + 1.907 +#if defined(PNG_WRITE_sBIT_SUPPORTED) 1.908 +/* write the sBIT chunk */ 1.909 +void /* PRIVATE */ 1.910 +png_write_sBIT(png_structp png_ptr, png_color_8p sbit, int color_type) 1.911 +{ 1.912 +#ifdef PNG_USE_LOCAL_ARRAYS 1.913 + PNG_sBIT; 1.914 +#endif 1.915 + png_byte buf[4]; 1.916 + png_size_t size; 1.917 + 1.918 + png_debug(1, "in png_write_sBIT\n"); 1.919 + /* make sure we don't depend upon the order of PNG_COLOR_8 */ 1.920 + if (color_type & PNG_COLOR_MASK_COLOR) 1.921 + { 1.922 + png_byte maxbits; 1.923 + 1.924 + maxbits = (png_byte)(color_type==PNG_COLOR_TYPE_PALETTE ? 8 : 1.925 + png_ptr->usr_bit_depth); 1.926 + if (sbit->red == 0 || sbit->red > maxbits || 1.927 + sbit->green == 0 || sbit->green > maxbits || 1.928 + sbit->blue == 0 || sbit->blue > maxbits) 1.929 + { 1.930 + png_warning(png_ptr, "Invalid sBIT depth specified"); 1.931 + return; 1.932 + } 1.933 + buf[0] = sbit->red; 1.934 + buf[1] = sbit->green; 1.935 + buf[2] = sbit->blue; 1.936 + size = 3; 1.937 + } 1.938 + else 1.939 + { 1.940 + if (sbit->gray == 0 || sbit->gray > png_ptr->usr_bit_depth) 1.941 + { 1.942 + png_warning(png_ptr, "Invalid sBIT depth specified"); 1.943 + return; 1.944 + } 1.945 + buf[0] = sbit->gray; 1.946 + size = 1; 1.947 + } 1.948 + 1.949 + if (color_type & PNG_COLOR_MASK_ALPHA) 1.950 + { 1.951 + if (sbit->alpha == 0 || sbit->alpha > png_ptr->usr_bit_depth) 1.952 + { 1.953 + png_warning(png_ptr, "Invalid sBIT depth specified"); 1.954 + return; 1.955 + } 1.956 + buf[size++] = sbit->alpha; 1.957 + } 1.958 + 1.959 + png_write_chunk(png_ptr, (png_bytep)png_sBIT, buf, size); 1.960 +} 1.961 +#endif 1.962 + 1.963 +#if defined(PNG_WRITE_cHRM_SUPPORTED) 1.964 +/* write the cHRM chunk */ 1.965 +#ifdef PNG_FLOATING_POINT_SUPPORTED 1.966 +void /* PRIVATE */ 1.967 +png_write_cHRM(png_structp png_ptr, double white_x, double white_y, 1.968 + double red_x, double red_y, double green_x, double green_y, 1.969 + double blue_x, double blue_y) 1.970 +{ 1.971 +#ifdef PNG_USE_LOCAL_ARRAYS 1.972 + PNG_cHRM; 1.973 +#endif 1.974 + png_byte buf[32]; 1.975 + png_uint_32 itemp; 1.976 + 1.977 + png_debug(1, "in png_write_cHRM\n"); 1.978 + /* each value is saved in 1/100,000ths */ 1.979 + if (white_x < 0 || white_x > 0.8 || white_y < 0 || white_y > 0.8 || 1.980 + white_x + white_y > 1.0) 1.981 + { 1.982 + png_warning(png_ptr, "Invalid cHRM white point specified"); 1.983 +#if !defined(PNG_NO_CONSOLE_IO) 1.984 + fprintf(stderr, "white_x=%f, white_y=%f\n", white_x, white_y); 1.985 +#endif 1.986 + return; 1.987 + } 1.988 + itemp = (png_uint_32)(white_x * 100000.0 + 0.5); 1.989 + png_save_uint_32(buf, itemp); 1.990 + itemp = (png_uint_32)(white_y * 100000.0 + 0.5); 1.991 + png_save_uint_32(buf + 4, itemp); 1.992 + 1.993 + if (red_x < 0 || red_y < 0 || red_x + red_y > 1.0) 1.994 + { 1.995 + png_warning(png_ptr, "Invalid cHRM red point specified"); 1.996 + return; 1.997 + } 1.998 + itemp = (png_uint_32)(red_x * 100000.0 + 0.5); 1.999 + png_save_uint_32(buf + 8, itemp); 1.1000 + itemp = (png_uint_32)(red_y * 100000.0 + 0.5); 1.1001 + png_save_uint_32(buf + 12, itemp); 1.1002 + 1.1003 + if (green_x < 0 || green_y < 0 || green_x + green_y > 1.0) 1.1004 + { 1.1005 + png_warning(png_ptr, "Invalid cHRM green point specified"); 1.1006 + return; 1.1007 + } 1.1008 + itemp = (png_uint_32)(green_x * 100000.0 + 0.5); 1.1009 + png_save_uint_32(buf + 16, itemp); 1.1010 + itemp = (png_uint_32)(green_y * 100000.0 + 0.5); 1.1011 + png_save_uint_32(buf + 20, itemp); 1.1012 + 1.1013 + if (blue_x < 0 || blue_y < 0 || blue_x + blue_y > 1.0) 1.1014 + { 1.1015 + png_warning(png_ptr, "Invalid cHRM blue point specified"); 1.1016 + return; 1.1017 + } 1.1018 + itemp = (png_uint_32)(blue_x * 100000.0 + 0.5); 1.1019 + png_save_uint_32(buf + 24, itemp); 1.1020 + itemp = (png_uint_32)(blue_y * 100000.0 + 0.5); 1.1021 + png_save_uint_32(buf + 28, itemp); 1.1022 + 1.1023 + png_write_chunk(png_ptr, (png_bytep)png_cHRM, buf, (png_size_t)32); 1.1024 +} 1.1025 +#endif 1.1026 +#ifdef PNG_FIXED_POINT_SUPPORTED 1.1027 +void /* PRIVATE */ 1.1028 +png_write_cHRM_fixed(png_structp png_ptr, png_fixed_point white_x, 1.1029 + png_fixed_point white_y, png_fixed_point red_x, png_fixed_point red_y, 1.1030 + png_fixed_point green_x, png_fixed_point green_y, png_fixed_point blue_x, 1.1031 + png_fixed_point blue_y) 1.1032 +{ 1.1033 +#ifdef PNG_USE_LOCAL_ARRAYS 1.1034 + PNG_cHRM; 1.1035 +#endif 1.1036 + png_byte buf[32]; 1.1037 + 1.1038 + png_debug(1, "in png_write_cHRM\n"); 1.1039 + /* each value is saved in 1/100,000ths */ 1.1040 + if (white_x > 80000L || white_y > 80000L || white_x + white_y > 100000L) 1.1041 + { 1.1042 + png_warning(png_ptr, "Invalid fixed cHRM white point specified"); 1.1043 +#if !defined(PNG_NO_CONSOLE_IO) 1.1044 + fprintf(stderr, "white_x=%ld, white_y=%ld\n", (unsigned long)white_x, 1.1045 + (unsigned long)white_y); 1.1046 +#endif 1.1047 + return; 1.1048 + } 1.1049 + png_save_uint_32(buf, (png_uint_32)white_x); 1.1050 + png_save_uint_32(buf + 4, (png_uint_32)white_y); 1.1051 + 1.1052 + if (red_x + red_y > 100000L) 1.1053 + { 1.1054 + png_warning(png_ptr, "Invalid cHRM fixed red point specified"); 1.1055 + return; 1.1056 + } 1.1057 + png_save_uint_32(buf + 8, (png_uint_32)red_x); 1.1058 + png_save_uint_32(buf + 12, (png_uint_32)red_y); 1.1059 + 1.1060 + if (green_x + green_y > 100000L) 1.1061 + { 1.1062 + png_warning(png_ptr, "Invalid fixed cHRM green point specified"); 1.1063 + return; 1.1064 + } 1.1065 + png_save_uint_32(buf + 16, (png_uint_32)green_x); 1.1066 + png_save_uint_32(buf + 20, (png_uint_32)green_y); 1.1067 + 1.1068 + if (blue_x + blue_y > 100000L) 1.1069 + { 1.1070 + png_warning(png_ptr, "Invalid fixed cHRM blue point specified"); 1.1071 + return; 1.1072 + } 1.1073 + png_save_uint_32(buf + 24, (png_uint_32)blue_x); 1.1074 + png_save_uint_32(buf + 28, (png_uint_32)blue_y); 1.1075 + 1.1076 + png_write_chunk(png_ptr, (png_bytep)png_cHRM, buf, (png_size_t)32); 1.1077 +} 1.1078 +#endif 1.1079 +#endif 1.1080 + 1.1081 +#if defined(PNG_WRITE_tRNS_SUPPORTED) 1.1082 +/* write the tRNS chunk */ 1.1083 +void /* PRIVATE */ 1.1084 +png_write_tRNS(png_structp png_ptr, png_bytep trans, png_color_16p tran, 1.1085 + int num_trans, int color_type) 1.1086 +{ 1.1087 +#ifdef PNG_USE_LOCAL_ARRAYS 1.1088 + PNG_tRNS; 1.1089 +#endif 1.1090 + png_byte buf[6]; 1.1091 + 1.1092 + png_debug(1, "in png_write_tRNS\n"); 1.1093 + if (color_type == PNG_COLOR_TYPE_PALETTE) 1.1094 + { 1.1095 + if (num_trans <= 0 || num_trans > (int)png_ptr->num_palette) 1.1096 + { 1.1097 + png_warning(png_ptr, "Invalid number of transparent colors specified"); 1.1098 + return; 1.1099 + } 1.1100 + /* write the chunk out as it is */ 1.1101 + png_write_chunk(png_ptr, (png_bytep)png_tRNS, trans, 1.1102 + (png_size_t)num_trans); 1.1103 + } 1.1104 + else if (color_type == PNG_COLOR_TYPE_GRAY) 1.1105 + { 1.1106 + /* one 16 bit value */ 1.1107 + if (tran->gray >= (1 << png_ptr->bit_depth)) 1.1108 + { 1.1109 + png_warning(png_ptr, 1.1110 + "Ignoring attempt to write tRNS chunk out-of-range for bit_depth"); 1.1111 + return; 1.1112 + } 1.1113 + png_save_uint_16(buf, tran->gray); 1.1114 + png_write_chunk(png_ptr, (png_bytep)png_tRNS, buf, (png_size_t)2); 1.1115 + } 1.1116 + else if (color_type == PNG_COLOR_TYPE_RGB) 1.1117 + { 1.1118 + /* three 16 bit values */ 1.1119 + png_save_uint_16(buf, tran->red); 1.1120 + png_save_uint_16(buf + 2, tran->green); 1.1121 + png_save_uint_16(buf + 4, tran->blue); 1.1122 + if (png_ptr->bit_depth == 8 && (buf[0] | buf[2] | buf[4])) 1.1123 + { 1.1124 + png_warning(png_ptr, 1.1125 + "Ignoring attempt to write 16-bit tRNS chunk when bit_depth is 8"); 1.1126 + return; 1.1127 + } 1.1128 + png_write_chunk(png_ptr, (png_bytep)png_tRNS, buf, (png_size_t)6); 1.1129 + } 1.1130 + else 1.1131 + { 1.1132 + png_warning(png_ptr, "Can't write tRNS with an alpha channel"); 1.1133 + } 1.1134 +} 1.1135 +#endif 1.1136 + 1.1137 +#if defined(PNG_WRITE_bKGD_SUPPORTED) 1.1138 +/* write the background chunk */ 1.1139 +void /* PRIVATE */ 1.1140 +png_write_bKGD(png_structp png_ptr, png_color_16p back, int color_type) 1.1141 +{ 1.1142 +#ifdef PNG_USE_LOCAL_ARRAYS 1.1143 + PNG_bKGD; 1.1144 +#endif 1.1145 + png_byte buf[6]; 1.1146 + 1.1147 + png_debug(1, "in png_write_bKGD\n"); 1.1148 + if (color_type == PNG_COLOR_TYPE_PALETTE) 1.1149 + { 1.1150 + if ( 1.1151 +#if defined(PNG_MNG_FEATURES_SUPPORTED) 1.1152 + (png_ptr->num_palette || 1.1153 + (!(png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE))) && 1.1154 +#endif 1.1155 + back->index > png_ptr->num_palette) 1.1156 + { 1.1157 + png_warning(png_ptr, "Invalid background palette index"); 1.1158 + return; 1.1159 + } 1.1160 + buf[0] = back->index; 1.1161 + png_write_chunk(png_ptr, (png_bytep)png_bKGD, buf, (png_size_t)1); 1.1162 + } 1.1163 + else if (color_type & PNG_COLOR_MASK_COLOR) 1.1164 + { 1.1165 + png_save_uint_16(buf, back->red); 1.1166 + png_save_uint_16(buf + 2, back->green); 1.1167 + png_save_uint_16(buf + 4, back->blue); 1.1168 + if (png_ptr->bit_depth == 8 && (buf[0] | buf[2] | buf[4])) 1.1169 + { 1.1170 + png_warning(png_ptr, 1.1171 + "Ignoring attempt to write 16-bit bKGD chunk when bit_depth is 8"); 1.1172 + return; 1.1173 + } 1.1174 + png_write_chunk(png_ptr, (png_bytep)png_bKGD, buf, (png_size_t)6); 1.1175 + } 1.1176 + else 1.1177 + { 1.1178 + if (back->gray >= (1 << png_ptr->bit_depth)) 1.1179 + { 1.1180 + png_warning(png_ptr, 1.1181 + "Ignoring attempt to write bKGD chunk out-of-range for bit_depth"); 1.1182 + return; 1.1183 + } 1.1184 + png_save_uint_16(buf, back->gray); 1.1185 + png_write_chunk(png_ptr, (png_bytep)png_bKGD, buf, (png_size_t)2); 1.1186 + } 1.1187 +} 1.1188 +#endif 1.1189 + 1.1190 +#if defined(PNG_WRITE_hIST_SUPPORTED) 1.1191 +/* write the histogram */ 1.1192 +void /* PRIVATE */ 1.1193 +png_write_hIST(png_structp png_ptr, png_uint_16p hist, int num_hist) 1.1194 +{ 1.1195 +#ifdef PNG_USE_LOCAL_ARRAYS 1.1196 + PNG_hIST; 1.1197 +#endif 1.1198 + int i; 1.1199 + png_byte buf[3]; 1.1200 + 1.1201 + png_debug(1, "in png_write_hIST\n"); 1.1202 + if (num_hist > (int)png_ptr->num_palette) 1.1203 + { 1.1204 + png_debug2(3, "num_hist = %d, num_palette = %d\n", num_hist, 1.1205 + png_ptr->num_palette); 1.1206 + png_warning(png_ptr, "Invalid number of histogram entries specified"); 1.1207 + return; 1.1208 + } 1.1209 + 1.1210 + png_write_chunk_start(png_ptr, (png_bytep)png_hIST, 1.1211 + (png_uint_32)(num_hist * 2)); 1.1212 + for (i = 0; i < num_hist; i++) 1.1213 + { 1.1214 + png_save_uint_16(buf, hist[i]); 1.1215 + png_write_chunk_data(png_ptr, buf, (png_size_t)2); 1.1216 + } 1.1217 + png_write_chunk_end(png_ptr); 1.1218 +} 1.1219 +#endif 1.1220 + 1.1221 +#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_pCAL_SUPPORTED) || \ 1.1222 + defined(PNG_WRITE_iCCP_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED) 1.1223 +/* Check that the tEXt or zTXt keyword is valid per PNG 1.0 specification, 1.1224 + * and if invalid, correct the keyword rather than discarding the entire 1.1225 + * chunk. The PNG 1.0 specification requires keywords 1-79 characters in 1.1226 + * length, forbids leading or trailing whitespace, multiple internal spaces, 1.1227 + * and the non-break space (0x80) from ISO 8859-1. Returns keyword length. 1.1228 + * 1.1229 + * The new_key is allocated to hold the corrected keyword and must be freed 1.1230 + * by the calling routine. This avoids problems with trying to write to 1.1231 + * static keywords without having to have duplicate copies of the strings. 1.1232 + */ 1.1233 +png_size_t /* PRIVATE */ 1.1234 +png_check_keyword(png_structp png_ptr, png_charp key, png_charpp new_key) 1.1235 +{ 1.1236 + png_size_t key_len; 1.1237 + png_charp kp, dp; 1.1238 + int kflag; 1.1239 + int kwarn=0; 1.1240 + 1.1241 + png_debug(1, "in png_check_keyword\n"); 1.1242 + *new_key = NULL; 1.1243 + 1.1244 + if (key == NULL || (key_len = png_strlen(key)) == 0) 1.1245 + { 1.1246 + png_warning(png_ptr, "zero length keyword"); 1.1247 + return ((png_size_t)0); 1.1248 + } 1.1249 + 1.1250 + png_debug1(2, "Keyword to be checked is '%s'\n", key); 1.1251 + 1.1252 + *new_key = (png_charp)png_malloc_warn(png_ptr, (png_uint_32)(key_len + 2)); 1.1253 + if (*new_key == NULL) 1.1254 + { 1.1255 + png_warning(png_ptr, "Out of memory while procesing keyword"); 1.1256 + return ((png_size_t)0); 1.1257 + } 1.1258 + 1.1259 + /* Replace non-printing characters with a blank and print a warning */ 1.1260 + for (kp = key, dp = *new_key; *kp != '\0'; kp++, dp++) 1.1261 + { 1.1262 + if ((png_byte)*kp < 0x20 || 1.1263 + ((png_byte)*kp > 0x7E && (png_byte)*kp < 0xA1)) 1.1264 + { 1.1265 +#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE) 1.1266 + char msg[40]; 1.1267 + 1.1268 + png_snprintf(msg, 40, 1.1269 + "invalid keyword character 0x%02X", (png_byte)*kp); 1.1270 + png_warning(png_ptr, msg); 1.1271 +#else 1.1272 + png_warning(png_ptr, "invalid character in keyword"); 1.1273 +#endif 1.1274 + *dp = ' '; 1.1275 + } 1.1276 + else 1.1277 + { 1.1278 + *dp = *kp; 1.1279 + } 1.1280 + } 1.1281 + *dp = '\0'; 1.1282 + 1.1283 + /* Remove any trailing white space. */ 1.1284 + kp = *new_key + key_len - 1; 1.1285 + if (*kp == ' ') 1.1286 + { 1.1287 + png_warning(png_ptr, "trailing spaces removed from keyword"); 1.1288 + 1.1289 + while (*kp == ' ') 1.1290 + { 1.1291 + *(kp--) = '\0'; 1.1292 + key_len--; 1.1293 + } 1.1294 + } 1.1295 + 1.1296 + /* Remove any leading white space. */ 1.1297 + kp = *new_key; 1.1298 + if (*kp == ' ') 1.1299 + { 1.1300 + png_warning(png_ptr, "leading spaces removed from keyword"); 1.1301 + 1.1302 + while (*kp == ' ') 1.1303 + { 1.1304 + kp++; 1.1305 + key_len--; 1.1306 + } 1.1307 + } 1.1308 + 1.1309 + png_debug1(2, "Checking for multiple internal spaces in '%s'\n", kp); 1.1310 + 1.1311 + /* Remove multiple internal spaces. */ 1.1312 + for (kflag = 0, dp = *new_key; *kp != '\0'; kp++) 1.1313 + { 1.1314 + if (*kp == ' ' && kflag == 0) 1.1315 + { 1.1316 + *(dp++) = *kp; 1.1317 + kflag = 1; 1.1318 + } 1.1319 + else if (*kp == ' ') 1.1320 + { 1.1321 + key_len--; 1.1322 + kwarn=1; 1.1323 + } 1.1324 + else 1.1325 + { 1.1326 + *(dp++) = *kp; 1.1327 + kflag = 0; 1.1328 + } 1.1329 + } 1.1330 + *dp = '\0'; 1.1331 + if (kwarn) 1.1332 + png_warning(png_ptr, "extra interior spaces removed from keyword"); 1.1333 + 1.1334 + if (key_len == 0) 1.1335 + { 1.1336 + png_free(png_ptr, *new_key); 1.1337 + *new_key=NULL; 1.1338 + png_warning(png_ptr, "Zero length keyword"); 1.1339 + } 1.1340 + 1.1341 + if (key_len > 79) 1.1342 + { 1.1343 + png_warning(png_ptr, "keyword length must be 1 - 79 characters"); 1.1344 + new_key[79] = '\0'; 1.1345 + key_len = 79; 1.1346 + } 1.1347 + 1.1348 + return (key_len); 1.1349 +} 1.1350 +#endif 1.1351 + 1.1352 +#if defined(PNG_WRITE_tEXt_SUPPORTED) 1.1353 +/* write a tEXt chunk */ 1.1354 +void /* PRIVATE */ 1.1355 +png_write_tEXt(png_structp png_ptr, png_charp key, png_charp text, 1.1356 + png_size_t text_len) 1.1357 +{ 1.1358 +#ifdef PNG_USE_LOCAL_ARRAYS 1.1359 + PNG_tEXt; 1.1360 +#endif 1.1361 + png_size_t key_len; 1.1362 + png_charp new_key; 1.1363 + 1.1364 + png_debug(1, "in png_write_tEXt\n"); 1.1365 + if (key == NULL || (key_len = png_check_keyword(png_ptr, key, &new_key))==0) 1.1366 + { 1.1367 + png_warning(png_ptr, "Empty keyword in tEXt chunk"); 1.1368 + return; 1.1369 + } 1.1370 + 1.1371 + if (text == NULL || *text == '\0') 1.1372 + text_len = 0; 1.1373 + else 1.1374 + text_len = png_strlen(text); 1.1375 + 1.1376 + /* make sure we include the 0 after the key */ 1.1377 + png_write_chunk_start(png_ptr, (png_bytep)png_tEXt, 1.1378 + (png_uint_32)(key_len + text_len + 1)); 1.1379 + /* 1.1380 + * We leave it to the application to meet PNG-1.0 requirements on the 1.1381 + * contents of the text. PNG-1.0 through PNG-1.2 discourage the use of 1.1382 + * any non-Latin-1 characters except for NEWLINE. ISO PNG will forbid them. 1.1383 + * The NUL character is forbidden by PNG-1.0 through PNG-1.2 and ISO PNG. 1.1384 + */ 1.1385 + png_write_chunk_data(png_ptr, (png_bytep)new_key, 1.1386 + (png_size_t)(key_len + 1)); 1.1387 + if (text_len) 1.1388 + png_write_chunk_data(png_ptr, (png_bytep)text, (png_size_t)text_len); 1.1389 + 1.1390 + png_write_chunk_end(png_ptr); 1.1391 + png_free(png_ptr, new_key); 1.1392 +} 1.1393 +#endif 1.1394 + 1.1395 +#if defined(PNG_WRITE_zTXt_SUPPORTED) 1.1396 +/* write a compressed text chunk */ 1.1397 +void /* PRIVATE */ 1.1398 +png_write_zTXt(png_structp png_ptr, png_charp key, png_charp text, 1.1399 + png_size_t text_len, int compression) 1.1400 +{ 1.1401 +#ifdef PNG_USE_LOCAL_ARRAYS 1.1402 + PNG_zTXt; 1.1403 +#endif 1.1404 + png_size_t key_len; 1.1405 + char buf[1]; 1.1406 + png_charp new_key; 1.1407 + compression_state comp; 1.1408 + 1.1409 + png_debug(1, "in png_write_zTXt\n"); 1.1410 + 1.1411 + comp.num_output_ptr = 0; 1.1412 + comp.max_output_ptr = 0; 1.1413 + comp.output_ptr = NULL; 1.1414 + comp.input = NULL; 1.1415 + comp.input_len = 0; 1.1416 + 1.1417 + if (key == NULL || (key_len = png_check_keyword(png_ptr, key, &new_key))==0) 1.1418 + { 1.1419 + png_warning(png_ptr, "Empty keyword in zTXt chunk"); 1.1420 + png_free(png_ptr, new_key); 1.1421 + return; 1.1422 + } 1.1423 + 1.1424 + if (text == NULL || *text == '\0' || compression==PNG_TEXT_COMPRESSION_NONE) 1.1425 + { 1.1426 + png_write_tEXt(png_ptr, new_key, text, (png_size_t)0); 1.1427 + png_free(png_ptr, new_key); 1.1428 + return; 1.1429 + } 1.1430 + 1.1431 + text_len = png_strlen(text); 1.1432 + 1.1433 + /* compute the compressed data; do it now for the length */ 1.1434 + text_len = png_text_compress(png_ptr, text, text_len, compression, 1.1435 + &comp); 1.1436 + 1.1437 + /* write start of chunk */ 1.1438 + png_write_chunk_start(png_ptr, (png_bytep)png_zTXt, 1.1439 + (png_uint_32)(key_len+text_len + 2)); 1.1440 + /* write key */ 1.1441 + png_write_chunk_data(png_ptr, (png_bytep)new_key, 1.1442 + (png_size_t)(key_len + 1)); 1.1443 + png_free(png_ptr, new_key); 1.1444 + 1.1445 + buf[0] = (png_byte)compression; 1.1446 + /* write compression */ 1.1447 + png_write_chunk_data(png_ptr, (png_bytep)buf, (png_size_t)1); 1.1448 + /* write the compressed data */ 1.1449 + png_write_compressed_data_out(png_ptr, &comp); 1.1450 + 1.1451 + /* close the chunk */ 1.1452 + png_write_chunk_end(png_ptr); 1.1453 +} 1.1454 +#endif 1.1455 + 1.1456 +#if defined(PNG_WRITE_iTXt_SUPPORTED) 1.1457 +/* write an iTXt chunk */ 1.1458 +void /* PRIVATE */ 1.1459 +png_write_iTXt(png_structp png_ptr, int compression, png_charp key, 1.1460 + png_charp lang, png_charp lang_key, png_charp text) 1.1461 +{ 1.1462 +#ifdef PNG_USE_LOCAL_ARRAYS 1.1463 + PNG_iTXt; 1.1464 +#endif 1.1465 + png_size_t lang_len, key_len, lang_key_len, text_len; 1.1466 + png_charp new_lang, new_key; 1.1467 + png_byte cbuf[2]; 1.1468 + compression_state comp; 1.1469 + 1.1470 + png_debug(1, "in png_write_iTXt\n"); 1.1471 + 1.1472 + comp.num_output_ptr = 0; 1.1473 + comp.max_output_ptr = 0; 1.1474 + comp.output_ptr = NULL; 1.1475 + comp.input = NULL; 1.1476 + 1.1477 + if (key == NULL || (key_len = png_check_keyword(png_ptr, key, &new_key))==0) 1.1478 + { 1.1479 + png_warning(png_ptr, "Empty keyword in iTXt chunk"); 1.1480 + return; 1.1481 + } 1.1482 + if (lang == NULL || (lang_len = png_check_keyword(png_ptr, lang, &new_lang))==0) 1.1483 + { 1.1484 + png_warning(png_ptr, "Empty language field in iTXt chunk"); 1.1485 + new_lang = NULL; 1.1486 + lang_len = 0; 1.1487 + } 1.1488 + 1.1489 + if (lang_key == NULL) 1.1490 + lang_key_len = 0; 1.1491 + else 1.1492 + lang_key_len = png_strlen(lang_key); 1.1493 + 1.1494 + if (text == NULL) 1.1495 + text_len = 0; 1.1496 + else 1.1497 + text_len = png_strlen(text); 1.1498 + 1.1499 + /* compute the compressed data; do it now for the length */ 1.1500 + text_len = png_text_compress(png_ptr, text, text_len, compression-2, 1.1501 + &comp); 1.1502 + 1.1503 + 1.1504 + /* make sure we include the compression flag, the compression byte, 1.1505 + * and the NULs after the key, lang, and lang_key parts */ 1.1506 + 1.1507 + png_write_chunk_start(png_ptr, (png_bytep)png_iTXt, 1.1508 + (png_uint_32)( 1.1509 + 5 /* comp byte, comp flag, terminators for key, lang and lang_key */ 1.1510 + + key_len 1.1511 + + lang_len 1.1512 + + lang_key_len 1.1513 + + text_len)); 1.1514 + 1.1515 + /* 1.1516 + * We leave it to the application to meet PNG-1.0 requirements on the 1.1517 + * contents of the text. PNG-1.0 through PNG-1.2 discourage the use of 1.1518 + * any non-Latin-1 characters except for NEWLINE. ISO PNG will forbid them. 1.1519 + * The NUL character is forbidden by PNG-1.0 through PNG-1.2 and ISO PNG. 1.1520 + */ 1.1521 + png_write_chunk_data(png_ptr, (png_bytep)new_key, 1.1522 + (png_size_t)(key_len + 1)); 1.1523 + 1.1524 + /* set the compression flag */ 1.1525 + if (compression == PNG_ITXT_COMPRESSION_NONE || \ 1.1526 + compression == PNG_TEXT_COMPRESSION_NONE) 1.1527 + cbuf[0] = 0; 1.1528 + else /* compression == PNG_ITXT_COMPRESSION_zTXt */ 1.1529 + cbuf[0] = 1; 1.1530 + /* set the compression method */ 1.1531 + cbuf[1] = 0; 1.1532 + png_write_chunk_data(png_ptr, cbuf, (png_size_t)2); 1.1533 + 1.1534 + cbuf[0] = 0; 1.1535 + png_write_chunk_data(png_ptr, (new_lang ? (png_bytep)new_lang : cbuf), 1.1536 + (png_size_t)(lang_len + 1)); 1.1537 + png_write_chunk_data(png_ptr, (lang_key ? (png_bytep)lang_key : cbuf), 1.1538 + (png_size_t)(lang_key_len + 1)); 1.1539 + png_write_compressed_data_out(png_ptr, &comp); 1.1540 + 1.1541 + png_write_chunk_end(png_ptr); 1.1542 + png_free(png_ptr, new_key); 1.1543 + png_free(png_ptr, new_lang); 1.1544 +} 1.1545 +#endif 1.1546 + 1.1547 +#if defined(PNG_WRITE_oFFs_SUPPORTED) 1.1548 +/* write the oFFs chunk */ 1.1549 +void /* PRIVATE */ 1.1550 +png_write_oFFs(png_structp png_ptr, png_int_32 x_offset, png_int_32 y_offset, 1.1551 + int unit_type) 1.1552 +{ 1.1553 +#ifdef PNG_USE_LOCAL_ARRAYS 1.1554 + PNG_oFFs; 1.1555 +#endif 1.1556 + png_byte buf[9]; 1.1557 + 1.1558 + png_debug(1, "in png_write_oFFs\n"); 1.1559 + if (unit_type >= PNG_OFFSET_LAST) 1.1560 + png_warning(png_ptr, "Unrecognized unit type for oFFs chunk"); 1.1561 + 1.1562 + png_save_int_32(buf, x_offset); 1.1563 + png_save_int_32(buf + 4, y_offset); 1.1564 + buf[8] = (png_byte)unit_type; 1.1565 + 1.1566 + png_write_chunk(png_ptr, (png_bytep)png_oFFs, buf, (png_size_t)9); 1.1567 +} 1.1568 +#endif 1.1569 +#if defined(PNG_WRITE_pCAL_SUPPORTED) 1.1570 +/* write the pCAL chunk (described in the PNG extensions document) */ 1.1571 +void /* PRIVATE */ 1.1572 +png_write_pCAL(png_structp png_ptr, png_charp purpose, png_int_32 X0, 1.1573 + png_int_32 X1, int type, int nparams, png_charp units, png_charpp params) 1.1574 +{ 1.1575 +#ifdef PNG_USE_LOCAL_ARRAYS 1.1576 + PNG_pCAL; 1.1577 +#endif 1.1578 + png_size_t purpose_len, units_len, total_len; 1.1579 + png_uint_32p params_len; 1.1580 + png_byte buf[10]; 1.1581 + png_charp new_purpose; 1.1582 + int i; 1.1583 + 1.1584 + png_debug1(1, "in png_write_pCAL (%d parameters)\n", nparams); 1.1585 + if (type >= PNG_EQUATION_LAST) 1.1586 + png_warning(png_ptr, "Unrecognized equation type for pCAL chunk"); 1.1587 + 1.1588 + purpose_len = png_check_keyword(png_ptr, purpose, &new_purpose) + 1; 1.1589 + png_debug1(3, "pCAL purpose length = %d\n", (int)purpose_len); 1.1590 + units_len = png_strlen(units) + (nparams == 0 ? 0 : 1); 1.1591 + png_debug1(3, "pCAL units length = %d\n", (int)units_len); 1.1592 + total_len = purpose_len + units_len + 10; 1.1593 + 1.1594 + params_len = (png_uint_32p)png_malloc(png_ptr, 1.1595 + (png_uint_32)(nparams * png_sizeof(png_uint_32))); 1.1596 + 1.1597 + /* Find the length of each parameter, making sure we don't count the 1.1598 + null terminator for the last parameter. */ 1.1599 + for (i = 0; i < nparams; i++) 1.1600 + { 1.1601 + params_len[i] = png_strlen(params[i]) + (i == nparams - 1 ? 0 : 1); 1.1602 + png_debug2(3, "pCAL parameter %d length = %lu\n", i, 1.1603 + (unsigned long) params_len[i]); 1.1604 + total_len += (png_size_t)params_len[i]; 1.1605 + } 1.1606 + 1.1607 + png_debug1(3, "pCAL total length = %d\n", (int)total_len); 1.1608 + png_write_chunk_start(png_ptr, (png_bytep)png_pCAL, (png_uint_32)total_len); 1.1609 + png_write_chunk_data(png_ptr, (png_bytep)new_purpose, 1.1610 + (png_size_t)purpose_len); 1.1611 + png_save_int_32(buf, X0); 1.1612 + png_save_int_32(buf + 4, X1); 1.1613 + buf[8] = (png_byte)type; 1.1614 + buf[9] = (png_byte)nparams; 1.1615 + png_write_chunk_data(png_ptr, buf, (png_size_t)10); 1.1616 + png_write_chunk_data(png_ptr, (png_bytep)units, (png_size_t)units_len); 1.1617 + 1.1618 + png_free(png_ptr, new_purpose); 1.1619 + 1.1620 + for (i = 0; i < nparams; i++) 1.1621 + { 1.1622 + png_write_chunk_data(png_ptr, (png_bytep)params[i], 1.1623 + (png_size_t)params_len[i]); 1.1624 + } 1.1625 + 1.1626 + png_free(png_ptr, params_len); 1.1627 + png_write_chunk_end(png_ptr); 1.1628 +} 1.1629 +#endif 1.1630 + 1.1631 +#if defined(PNG_WRITE_sCAL_SUPPORTED) 1.1632 +/* write the sCAL chunk */ 1.1633 +#if defined(PNG_FLOATING_POINT_SUPPORTED) && !defined(PNG_NO_STDIO) 1.1634 +void /* PRIVATE */ 1.1635 +png_write_sCAL(png_structp png_ptr, int unit, double width, double height) 1.1636 +{ 1.1637 +#ifdef PNG_USE_LOCAL_ARRAYS 1.1638 + PNG_sCAL; 1.1639 +#endif 1.1640 + char buf[64]; 1.1641 + png_size_t total_len; 1.1642 + 1.1643 + png_debug(1, "in png_write_sCAL\n"); 1.1644 + 1.1645 + buf[0] = (char)unit; 1.1646 +#if defined(_WIN32_WCE) 1.1647 +/* sprintf() function is not supported on WindowsCE */ 1.1648 + { 1.1649 + wchar_t wc_buf[32]; 1.1650 + size_t wc_len; 1.1651 + swprintf(wc_buf, TEXT("%12.12e"), width); 1.1652 + wc_len = wcslen(wc_buf); 1.1653 + WideCharToMultiByte(CP_ACP, 0, wc_buf, -1, buf + 1, wc_len, NULL, NULL); 1.1654 + total_len = wc_len + 2; 1.1655 + swprintf(wc_buf, TEXT("%12.12e"), height); 1.1656 + wc_len = wcslen(wc_buf); 1.1657 + WideCharToMultiByte(CP_ACP, 0, wc_buf, -1, buf + total_len, wc_len, 1.1658 + NULL, NULL); 1.1659 + total_len += wc_len; 1.1660 + } 1.1661 +#else 1.1662 + png_snprintf(buf + 1, 63, "%12.12e", width); 1.1663 + total_len = 1 + png_strlen(buf + 1) + 1; 1.1664 + png_snprintf(buf + total_len, 64-total_len, "%12.12e", height); 1.1665 + total_len += png_strlen(buf + total_len); 1.1666 +#endif 1.1667 + 1.1668 + png_debug1(3, "sCAL total length = %u\n", (unsigned int)total_len); 1.1669 + png_write_chunk(png_ptr, (png_bytep)png_sCAL, (png_bytep)buf, total_len); 1.1670 +} 1.1671 +#else 1.1672 +#ifdef PNG_FIXED_POINT_SUPPORTED 1.1673 +void /* PRIVATE */ 1.1674 +png_write_sCAL_s(png_structp png_ptr, int unit, png_charp width, 1.1675 + png_charp height) 1.1676 +{ 1.1677 +#ifdef PNG_USE_LOCAL_ARRAYS 1.1678 + PNG_sCAL; 1.1679 +#endif 1.1680 + png_byte buf[64]; 1.1681 + png_size_t wlen, hlen, total_len; 1.1682 + 1.1683 + png_debug(1, "in png_write_sCAL_s\n"); 1.1684 + 1.1685 + wlen = png_strlen(width); 1.1686 + hlen = png_strlen(height); 1.1687 + total_len = wlen + hlen + 2; 1.1688 + if (total_len > 64) 1.1689 + { 1.1690 + png_warning(png_ptr, "Can't write sCAL (buffer too small)"); 1.1691 + return; 1.1692 + } 1.1693 + 1.1694 + buf[0] = (png_byte)unit; 1.1695 + png_memcpy(buf + 1, width, wlen + 1); /* append the '\0' here */ 1.1696 + png_memcpy(buf + wlen + 2, height, hlen); /* do NOT append the '\0' here */ 1.1697 + 1.1698 + png_debug1(3, "sCAL total length = %u\n", (unsigned int)total_len); 1.1699 + png_write_chunk(png_ptr, (png_bytep)png_sCAL, buf, total_len); 1.1700 +} 1.1701 +#endif 1.1702 +#endif 1.1703 +#endif 1.1704 + 1.1705 +#if defined(PNG_WRITE_pHYs_SUPPORTED) 1.1706 +/* write the pHYs chunk */ 1.1707 +void /* PRIVATE */ 1.1708 +png_write_pHYs(png_structp png_ptr, png_uint_32 x_pixels_per_unit, 1.1709 + png_uint_32 y_pixels_per_unit, 1.1710 + int unit_type) 1.1711 +{ 1.1712 +#ifdef PNG_USE_LOCAL_ARRAYS 1.1713 + PNG_pHYs; 1.1714 +#endif 1.1715 + png_byte buf[9]; 1.1716 + 1.1717 + png_debug(1, "in png_write_pHYs\n"); 1.1718 + if (unit_type >= PNG_RESOLUTION_LAST) 1.1719 + png_warning(png_ptr, "Unrecognized unit type for pHYs chunk"); 1.1720 + 1.1721 + png_save_uint_32(buf, x_pixels_per_unit); 1.1722 + png_save_uint_32(buf + 4, y_pixels_per_unit); 1.1723 + buf[8] = (png_byte)unit_type; 1.1724 + 1.1725 + png_write_chunk(png_ptr, (png_bytep)png_pHYs, buf, (png_size_t)9); 1.1726 +} 1.1727 +#endif 1.1728 + 1.1729 +#if defined(PNG_WRITE_tIME_SUPPORTED) 1.1730 +/* Write the tIME chunk. Use either png_convert_from_struct_tm() 1.1731 + * or png_convert_from_time_t(), or fill in the structure yourself. 1.1732 + */ 1.1733 +void /* PRIVATE */ 1.1734 +png_write_tIME(png_structp png_ptr, png_timep mod_time) 1.1735 +{ 1.1736 +#ifdef PNG_USE_LOCAL_ARRAYS 1.1737 + PNG_tIME; 1.1738 +#endif 1.1739 + png_byte buf[7]; 1.1740 + 1.1741 + png_debug(1, "in png_write_tIME\n"); 1.1742 + if (mod_time->month > 12 || mod_time->month < 1 || 1.1743 + mod_time->day > 31 || mod_time->day < 1 || 1.1744 + mod_time->hour > 23 || mod_time->second > 60) 1.1745 + { 1.1746 + png_warning(png_ptr, "Invalid time specified for tIME chunk"); 1.1747 + return; 1.1748 + } 1.1749 + 1.1750 + png_save_uint_16(buf, mod_time->year); 1.1751 + buf[2] = mod_time->month; 1.1752 + buf[3] = mod_time->day; 1.1753 + buf[4] = mod_time->hour; 1.1754 + buf[5] = mod_time->minute; 1.1755 + buf[6] = mod_time->second; 1.1756 + 1.1757 + png_write_chunk(png_ptr, (png_bytep)png_tIME, buf, (png_size_t)7); 1.1758 +} 1.1759 +#endif 1.1760 + 1.1761 +/* initializes the row writing capability of libpng */ 1.1762 +void /* PRIVATE */ 1.1763 +png_write_start_row(png_structp png_ptr) 1.1764 +{ 1.1765 +#ifdef PNG_WRITE_INTERLACING_SUPPORTED 1.1766 +#ifdef PNG_USE_LOCAL_ARRAYS 1.1767 + /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */ 1.1768 + 1.1769 + /* start of interlace block */ 1.1770 + int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; 1.1771 + 1.1772 + /* offset to next interlace block */ 1.1773 + int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; 1.1774 + 1.1775 + /* start of interlace block in the y direction */ 1.1776 + int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1}; 1.1777 + 1.1778 + /* offset to next interlace block in the y direction */ 1.1779 + int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; 1.1780 +#endif 1.1781 +#endif 1.1782 + 1.1783 + png_size_t buf_size; 1.1784 + 1.1785 + png_debug(1, "in png_write_start_row\n"); 1.1786 + buf_size = (png_size_t)(PNG_ROWBYTES( 1.1787 + png_ptr->usr_channels*png_ptr->usr_bit_depth, png_ptr->width) + 1); 1.1788 + 1.1789 + /* set up row buffer */ 1.1790 + png_ptr->row_buf = (png_bytep)png_malloc(png_ptr, 1.1791 + (png_uint_32)buf_size); 1.1792 + png_ptr->row_buf[0] = PNG_FILTER_VALUE_NONE; 1.1793 + 1.1794 +#ifndef PNG_NO_WRITE_FILTER 1.1795 + /* set up filtering buffer, if using this filter */ 1.1796 + if (png_ptr->do_filter & PNG_FILTER_SUB) 1.1797 + { 1.1798 + png_ptr->sub_row = (png_bytep)png_malloc(png_ptr, 1.1799 + (png_uint_32)(png_ptr->rowbytes + 1)); 1.1800 + png_ptr->sub_row[0] = PNG_FILTER_VALUE_SUB; 1.1801 + } 1.1802 + 1.1803 + /* We only need to keep the previous row if we are using one of these. */ 1.1804 + if (png_ptr->do_filter & (PNG_FILTER_AVG | PNG_FILTER_UP | PNG_FILTER_PAETH)) 1.1805 + { 1.1806 + /* set up previous row buffer */ 1.1807 + png_ptr->prev_row = (png_bytep)png_malloc(png_ptr, 1.1808 + (png_uint_32)buf_size); 1.1809 + png_memset(png_ptr->prev_row, 0, buf_size); 1.1810 + 1.1811 + if (png_ptr->do_filter & PNG_FILTER_UP) 1.1812 + { 1.1813 + png_ptr->up_row = (png_bytep)png_malloc(png_ptr, 1.1814 + (png_uint_32)(png_ptr->rowbytes + 1)); 1.1815 + png_ptr->up_row[0] = PNG_FILTER_VALUE_UP; 1.1816 + } 1.1817 + 1.1818 + if (png_ptr->do_filter & PNG_FILTER_AVG) 1.1819 + { 1.1820 + png_ptr->avg_row = (png_bytep)png_malloc(png_ptr, 1.1821 + (png_uint_32)(png_ptr->rowbytes + 1)); 1.1822 + png_ptr->avg_row[0] = PNG_FILTER_VALUE_AVG; 1.1823 + } 1.1824 + 1.1825 + if (png_ptr->do_filter & PNG_FILTER_PAETH) 1.1826 + { 1.1827 + png_ptr->paeth_row = (png_bytep)png_malloc(png_ptr, 1.1828 + (png_uint_32)(png_ptr->rowbytes + 1)); 1.1829 + png_ptr->paeth_row[0] = PNG_FILTER_VALUE_PAETH; 1.1830 + } 1.1831 + } 1.1832 +#endif /* PNG_NO_WRITE_FILTER */ 1.1833 + 1.1834 +#ifdef PNG_WRITE_INTERLACING_SUPPORTED 1.1835 + /* if interlaced, we need to set up width and height of pass */ 1.1836 + if (png_ptr->interlaced) 1.1837 + { 1.1838 + if (!(png_ptr->transformations & PNG_INTERLACE)) 1.1839 + { 1.1840 + png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 - 1.1841 + png_pass_ystart[0]) / png_pass_yinc[0]; 1.1842 + png_ptr->usr_width = (png_ptr->width + png_pass_inc[0] - 1 - 1.1843 + png_pass_start[0]) / png_pass_inc[0]; 1.1844 + } 1.1845 + else 1.1846 + { 1.1847 + png_ptr->num_rows = png_ptr->height; 1.1848 + png_ptr->usr_width = png_ptr->width; 1.1849 + } 1.1850 + } 1.1851 + else 1.1852 +#endif 1.1853 + { 1.1854 + png_ptr->num_rows = png_ptr->height; 1.1855 + png_ptr->usr_width = png_ptr->width; 1.1856 + } 1.1857 + png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; 1.1858 + png_ptr->zstream.next_out = png_ptr->zbuf; 1.1859 +} 1.1860 + 1.1861 +/* Internal use only. Called when finished processing a row of data. */ 1.1862 +void /* PRIVATE */ 1.1863 +png_write_finish_row(png_structp png_ptr) 1.1864 +{ 1.1865 +#ifdef PNG_WRITE_INTERLACING_SUPPORTED 1.1866 +#ifdef PNG_USE_LOCAL_ARRAYS 1.1867 + /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */ 1.1868 + 1.1869 + /* start of interlace block */ 1.1870 + int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; 1.1871 + 1.1872 + /* offset to next interlace block */ 1.1873 + int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; 1.1874 + 1.1875 + /* start of interlace block in the y direction */ 1.1876 + int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1}; 1.1877 + 1.1878 + /* offset to next interlace block in the y direction */ 1.1879 + int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; 1.1880 +#endif 1.1881 +#endif 1.1882 + 1.1883 + int ret; 1.1884 + 1.1885 + png_debug(1, "in png_write_finish_row\n"); 1.1886 + /* next row */ 1.1887 + png_ptr->row_number++; 1.1888 + 1.1889 + /* see if we are done */ 1.1890 + if (png_ptr->row_number < png_ptr->num_rows) 1.1891 + return; 1.1892 + 1.1893 +#ifdef PNG_WRITE_INTERLACING_SUPPORTED 1.1894 + /* if interlaced, go to next pass */ 1.1895 + if (png_ptr->interlaced) 1.1896 + { 1.1897 + png_ptr->row_number = 0; 1.1898 + if (png_ptr->transformations & PNG_INTERLACE) 1.1899 + { 1.1900 + png_ptr->pass++; 1.1901 + } 1.1902 + else 1.1903 + { 1.1904 + /* loop until we find a non-zero width or height pass */ 1.1905 + do 1.1906 + { 1.1907 + png_ptr->pass++; 1.1908 + if (png_ptr->pass >= 7) 1.1909 + break; 1.1910 + png_ptr->usr_width = (png_ptr->width + 1.1911 + png_pass_inc[png_ptr->pass] - 1 - 1.1912 + png_pass_start[png_ptr->pass]) / 1.1913 + png_pass_inc[png_ptr->pass]; 1.1914 + png_ptr->num_rows = (png_ptr->height + 1.1915 + png_pass_yinc[png_ptr->pass] - 1 - 1.1916 + png_pass_ystart[png_ptr->pass]) / 1.1917 + png_pass_yinc[png_ptr->pass]; 1.1918 + if (png_ptr->transformations & PNG_INTERLACE) 1.1919 + break; 1.1920 + } while (png_ptr->usr_width == 0 || png_ptr->num_rows == 0); 1.1921 + 1.1922 + } 1.1923 + 1.1924 + /* reset the row above the image for the next pass */ 1.1925 + if (png_ptr->pass < 7) 1.1926 + { 1.1927 + if (png_ptr->prev_row != NULL) 1.1928 + png_memset(png_ptr->prev_row, 0, 1.1929 + (png_size_t)(PNG_ROWBYTES(png_ptr->usr_channels* 1.1930 + png_ptr->usr_bit_depth, png_ptr->width)) + 1); 1.1931 + return; 1.1932 + } 1.1933 + } 1.1934 +#endif 1.1935 + 1.1936 + /* if we get here, we've just written the last row, so we need 1.1937 + to flush the compressor */ 1.1938 + do 1.1939 + { 1.1940 + /* tell the compressor we are done */ 1.1941 + ret = deflate(&png_ptr->zstream, Z_FINISH); 1.1942 + /* check for an error */ 1.1943 + if (ret == Z_OK) 1.1944 + { 1.1945 + /* check to see if we need more room */ 1.1946 + if (!(png_ptr->zstream.avail_out)) 1.1947 + { 1.1948 + png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size); 1.1949 + png_ptr->zstream.next_out = png_ptr->zbuf; 1.1950 + png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; 1.1951 + } 1.1952 + } 1.1953 + else if (ret != Z_STREAM_END) 1.1954 + { 1.1955 + if (png_ptr->zstream.msg != NULL) 1.1956 + png_error(png_ptr, png_ptr->zstream.msg); 1.1957 + else 1.1958 + png_error(png_ptr, "zlib error"); 1.1959 + } 1.1960 + } while (ret != Z_STREAM_END); 1.1961 + 1.1962 + /* write any extra space */ 1.1963 + if (png_ptr->zstream.avail_out < png_ptr->zbuf_size) 1.1964 + { 1.1965 + png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size - 1.1966 + png_ptr->zstream.avail_out); 1.1967 + } 1.1968 + 1.1969 + deflateReset(&png_ptr->zstream); 1.1970 + png_ptr->zstream.data_type = Z_BINARY; 1.1971 +} 1.1972 + 1.1973 +#if defined(PNG_WRITE_INTERLACING_SUPPORTED) 1.1974 +/* Pick out the correct pixels for the interlace pass. 1.1975 + * The basic idea here is to go through the row with a source 1.1976 + * pointer and a destination pointer (sp and dp), and copy the 1.1977 + * correct pixels for the pass. As the row gets compacted, 1.1978 + * sp will always be >= dp, so we should never overwrite anything. 1.1979 + * See the default: case for the easiest code to understand. 1.1980 + */ 1.1981 +void /* PRIVATE */ 1.1982 +png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass) 1.1983 +{ 1.1984 +#ifdef PNG_USE_LOCAL_ARRAYS 1.1985 + /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */ 1.1986 + 1.1987 + /* start of interlace block */ 1.1988 + int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; 1.1989 + 1.1990 + /* offset to next interlace block */ 1.1991 + int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; 1.1992 +#endif 1.1993 + 1.1994 + png_debug(1, "in png_do_write_interlace\n"); 1.1995 + /* we don't have to do anything on the last pass (6) */ 1.1996 +#if defined(PNG_USELESS_TESTS_SUPPORTED) 1.1997 + if (row != NULL && row_info != NULL && pass < 6) 1.1998 +#else 1.1999 + if (pass < 6) 1.2000 +#endif 1.2001 + { 1.2002 + /* each pixel depth is handled separately */ 1.2003 + switch (row_info->pixel_depth) 1.2004 + { 1.2005 + case 1: 1.2006 + { 1.2007 + png_bytep sp; 1.2008 + png_bytep dp; 1.2009 + int shift; 1.2010 + int d; 1.2011 + int value; 1.2012 + png_uint_32 i; 1.2013 + png_uint_32 row_width = row_info->width; 1.2014 + 1.2015 + dp = row; 1.2016 + d = 0; 1.2017 + shift = 7; 1.2018 + for (i = png_pass_start[pass]; i < row_width; 1.2019 + i += png_pass_inc[pass]) 1.2020 + { 1.2021 + sp = row + (png_size_t)(i >> 3); 1.2022 + value = (int)(*sp >> (7 - (int)(i & 0x07))) & 0x01; 1.2023 + d |= (value << shift); 1.2024 + 1.2025 + if (shift == 0) 1.2026 + { 1.2027 + shift = 7; 1.2028 + *dp++ = (png_byte)d; 1.2029 + d = 0; 1.2030 + } 1.2031 + else 1.2032 + shift--; 1.2033 + 1.2034 + } 1.2035 + if (shift != 7) 1.2036 + *dp = (png_byte)d; 1.2037 + break; 1.2038 + } 1.2039 + case 2: 1.2040 + { 1.2041 + png_bytep sp; 1.2042 + png_bytep dp; 1.2043 + int shift; 1.2044 + int d; 1.2045 + int value; 1.2046 + png_uint_32 i; 1.2047 + png_uint_32 row_width = row_info->width; 1.2048 + 1.2049 + dp = row; 1.2050 + shift = 6; 1.2051 + d = 0; 1.2052 + for (i = png_pass_start[pass]; i < row_width; 1.2053 + i += png_pass_inc[pass]) 1.2054 + { 1.2055 + sp = row + (png_size_t)(i >> 2); 1.2056 + value = (*sp >> ((3 - (int)(i & 0x03)) << 1)) & 0x03; 1.2057 + d |= (value << shift); 1.2058 + 1.2059 + if (shift == 0) 1.2060 + { 1.2061 + shift = 6; 1.2062 + *dp++ = (png_byte)d; 1.2063 + d = 0; 1.2064 + } 1.2065 + else 1.2066 + shift -= 2; 1.2067 + } 1.2068 + if (shift != 6) 1.2069 + *dp = (png_byte)d; 1.2070 + break; 1.2071 + } 1.2072 + case 4: 1.2073 + { 1.2074 + png_bytep sp; 1.2075 + png_bytep dp; 1.2076 + int shift; 1.2077 + int d; 1.2078 + int value; 1.2079 + png_uint_32 i; 1.2080 + png_uint_32 row_width = row_info->width; 1.2081 + 1.2082 + dp = row; 1.2083 + shift = 4; 1.2084 + d = 0; 1.2085 + for (i = png_pass_start[pass]; i < row_width; 1.2086 + i += png_pass_inc[pass]) 1.2087 + { 1.2088 + sp = row + (png_size_t)(i >> 1); 1.2089 + value = (*sp >> ((1 - (int)(i & 0x01)) << 2)) & 0x0f; 1.2090 + d |= (value << shift); 1.2091 + 1.2092 + if (shift == 0) 1.2093 + { 1.2094 + shift = 4; 1.2095 + *dp++ = (png_byte)d; 1.2096 + d = 0; 1.2097 + } 1.2098 + else 1.2099 + shift -= 4; 1.2100 + } 1.2101 + if (shift != 4) 1.2102 + *dp = (png_byte)d; 1.2103 + break; 1.2104 + } 1.2105 + default: 1.2106 + { 1.2107 + png_bytep sp; 1.2108 + png_bytep dp; 1.2109 + png_uint_32 i; 1.2110 + png_uint_32 row_width = row_info->width; 1.2111 + png_size_t pixel_bytes; 1.2112 + 1.2113 + /* start at the beginning */ 1.2114 + dp = row; 1.2115 + /* find out how many bytes each pixel takes up */ 1.2116 + pixel_bytes = (row_info->pixel_depth >> 3); 1.2117 + /* loop through the row, only looking at the pixels that 1.2118 + matter */ 1.2119 + for (i = png_pass_start[pass]; i < row_width; 1.2120 + i += png_pass_inc[pass]) 1.2121 + { 1.2122 + /* find out where the original pixel is */ 1.2123 + sp = row + (png_size_t)i * pixel_bytes; 1.2124 + /* move the pixel */ 1.2125 + if (dp != sp) 1.2126 + png_memcpy(dp, sp, pixel_bytes); 1.2127 + /* next pixel */ 1.2128 + dp += pixel_bytes; 1.2129 + } 1.2130 + break; 1.2131 + } 1.2132 + } 1.2133 + /* set new row width */ 1.2134 + row_info->width = (row_info->width + 1.2135 + png_pass_inc[pass] - 1 - 1.2136 + png_pass_start[pass]) / 1.2137 + png_pass_inc[pass]; 1.2138 + row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, 1.2139 + row_info->width); 1.2140 + } 1.2141 +} 1.2142 +#endif 1.2143 + 1.2144 +/* This filters the row, chooses which filter to use, if it has not already 1.2145 + * been specified by the application, and then writes the row out with the 1.2146 + * chosen filter. 1.2147 + */ 1.2148 +#define PNG_MAXSUM (((png_uint_32)(-1)) >> 1) 1.2149 +#define PNG_HISHIFT 10 1.2150 +#define PNG_LOMASK ((png_uint_32)0xffffL) 1.2151 +#define PNG_HIMASK ((png_uint_32)(~PNG_LOMASK >> PNG_HISHIFT)) 1.2152 +void /* PRIVATE */ 1.2153 +png_write_find_filter(png_structp png_ptr, png_row_infop row_info) 1.2154 +{ 1.2155 + png_bytep best_row; 1.2156 +#ifndef PNG_NO_WRITE_FILTER 1.2157 + png_bytep prev_row, row_buf; 1.2158 + png_uint_32 mins, bpp; 1.2159 + png_byte filter_to_do = png_ptr->do_filter; 1.2160 + png_uint_32 row_bytes = row_info->rowbytes; 1.2161 +#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) 1.2162 + int num_p_filters = (int)png_ptr->num_prev_filters; 1.2163 +#endif 1.2164 + 1.2165 + png_debug(1, "in png_write_find_filter\n"); 1.2166 + /* find out how many bytes offset each pixel is */ 1.2167 + bpp = (row_info->pixel_depth + 7) >> 3; 1.2168 + 1.2169 + prev_row = png_ptr->prev_row; 1.2170 +#endif 1.2171 + best_row = png_ptr->row_buf; 1.2172 +#ifndef PNG_NO_WRITE_FILTER 1.2173 + row_buf = best_row; 1.2174 + mins = PNG_MAXSUM; 1.2175 + 1.2176 + /* The prediction method we use is to find which method provides the 1.2177 + * smallest value when summing the absolute values of the distances 1.2178 + * from zero, using anything >= 128 as negative numbers. This is known 1.2179 + * as the "minimum sum of absolute differences" heuristic. Other 1.2180 + * heuristics are the "weighted minimum sum of absolute differences" 1.2181 + * (experimental and can in theory improve compression), and the "zlib 1.2182 + * predictive" method (not implemented yet), which does test compressions 1.2183 + * of lines using different filter methods, and then chooses the 1.2184 + * (series of) filter(s) that give minimum compressed data size (VERY 1.2185 + * computationally expensive). 1.2186 + * 1.2187 + * GRR 980525: consider also 1.2188 + * (1) minimum sum of absolute differences from running average (i.e., 1.2189 + * keep running sum of non-absolute differences & count of bytes) 1.2190 + * [track dispersion, too? restart average if dispersion too large?] 1.2191 + * (1b) minimum sum of absolute differences from sliding average, probably 1.2192 + * with window size <= deflate window (usually 32K) 1.2193 + * (2) minimum sum of squared differences from zero or running average 1.2194 + * (i.e., ~ root-mean-square approach) 1.2195 + */ 1.2196 + 1.2197 + 1.2198 + /* We don't need to test the 'no filter' case if this is the only filter 1.2199 + * that has been chosen, as it doesn't actually do anything to the data. 1.2200 + */ 1.2201 + if ((filter_to_do & PNG_FILTER_NONE) && 1.2202 + filter_to_do != PNG_FILTER_NONE) 1.2203 + { 1.2204 + png_bytep rp; 1.2205 + png_uint_32 sum = 0; 1.2206 + png_uint_32 i; 1.2207 + int v; 1.2208 + 1.2209 + for (i = 0, rp = row_buf + 1; i < row_bytes; i++, rp++) 1.2210 + { 1.2211 + v = *rp; 1.2212 + sum += (v < 128) ? v : 256 - v; 1.2213 + } 1.2214 + 1.2215 +#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) 1.2216 + if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) 1.2217 + { 1.2218 + png_uint_32 sumhi, sumlo; 1.2219 + int j; 1.2220 + sumlo = sum & PNG_LOMASK; 1.2221 + sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK; /* Gives us some footroom */ 1.2222 + 1.2223 + /* Reduce the sum if we match any of the previous rows */ 1.2224 + for (j = 0; j < num_p_filters; j++) 1.2225 + { 1.2226 + if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_NONE) 1.2227 + { 1.2228 + sumlo = (sumlo * png_ptr->filter_weights[j]) >> 1.2229 + PNG_WEIGHT_SHIFT; 1.2230 + sumhi = (sumhi * png_ptr->filter_weights[j]) >> 1.2231 + PNG_WEIGHT_SHIFT; 1.2232 + } 1.2233 + } 1.2234 + 1.2235 + /* Factor in the cost of this filter (this is here for completeness, 1.2236 + * but it makes no sense to have a "cost" for the NONE filter, as 1.2237 + * it has the minimum possible computational cost - none). 1.2238 + */ 1.2239 + sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_NONE]) >> 1.2240 + PNG_COST_SHIFT; 1.2241 + sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_NONE]) >> 1.2242 + PNG_COST_SHIFT; 1.2243 + 1.2244 + if (sumhi > PNG_HIMASK) 1.2245 + sum = PNG_MAXSUM; 1.2246 + else 1.2247 + sum = (sumhi << PNG_HISHIFT) + sumlo; 1.2248 + } 1.2249 +#endif 1.2250 + mins = sum; 1.2251 + } 1.2252 + 1.2253 + /* sub filter */ 1.2254 + if (filter_to_do == PNG_FILTER_SUB) 1.2255 + /* it's the only filter so no testing is needed */ 1.2256 + { 1.2257 + png_bytep rp, lp, dp; 1.2258 + png_uint_32 i; 1.2259 + for (i = 0, rp = row_buf + 1, dp = png_ptr->sub_row + 1; i < bpp; 1.2260 + i++, rp++, dp++) 1.2261 + { 1.2262 + *dp = *rp; 1.2263 + } 1.2264 + for (lp = row_buf + 1; i < row_bytes; 1.2265 + i++, rp++, lp++, dp++) 1.2266 + { 1.2267 + *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff); 1.2268 + } 1.2269 + best_row = png_ptr->sub_row; 1.2270 + } 1.2271 + 1.2272 + else if (filter_to_do & PNG_FILTER_SUB) 1.2273 + { 1.2274 + png_bytep rp, dp, lp; 1.2275 + png_uint_32 sum = 0, lmins = mins; 1.2276 + png_uint_32 i; 1.2277 + int v; 1.2278 + 1.2279 +#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) 1.2280 + /* We temporarily increase the "minimum sum" by the factor we 1.2281 + * would reduce the sum of this filter, so that we can do the 1.2282 + * early exit comparison without scaling the sum each time. 1.2283 + */ 1.2284 + if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) 1.2285 + { 1.2286 + int j; 1.2287 + png_uint_32 lmhi, lmlo; 1.2288 + lmlo = lmins & PNG_LOMASK; 1.2289 + lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK; 1.2290 + 1.2291 + for (j = 0; j < num_p_filters; j++) 1.2292 + { 1.2293 + if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_SUB) 1.2294 + { 1.2295 + lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >> 1.2296 + PNG_WEIGHT_SHIFT; 1.2297 + lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >> 1.2298 + PNG_WEIGHT_SHIFT; 1.2299 + } 1.2300 + } 1.2301 + 1.2302 + lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >> 1.2303 + PNG_COST_SHIFT; 1.2304 + lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >> 1.2305 + PNG_COST_SHIFT; 1.2306 + 1.2307 + if (lmhi > PNG_HIMASK) 1.2308 + lmins = PNG_MAXSUM; 1.2309 + else 1.2310 + lmins = (lmhi << PNG_HISHIFT) + lmlo; 1.2311 + } 1.2312 +#endif 1.2313 + 1.2314 + for (i = 0, rp = row_buf + 1, dp = png_ptr->sub_row + 1; i < bpp; 1.2315 + i++, rp++, dp++) 1.2316 + { 1.2317 + v = *dp = *rp; 1.2318 + 1.2319 + sum += (v < 128) ? v : 256 - v; 1.2320 + } 1.2321 + for (lp = row_buf + 1; i < row_bytes; 1.2322 + i++, rp++, lp++, dp++) 1.2323 + { 1.2324 + v = *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff); 1.2325 + 1.2326 + sum += (v < 128) ? v : 256 - v; 1.2327 + 1.2328 + if (sum > lmins) /* We are already worse, don't continue. */ 1.2329 + break; 1.2330 + } 1.2331 + 1.2332 +#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) 1.2333 + if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) 1.2334 + { 1.2335 + int j; 1.2336 + png_uint_32 sumhi, sumlo; 1.2337 + sumlo = sum & PNG_LOMASK; 1.2338 + sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK; 1.2339 + 1.2340 + for (j = 0; j < num_p_filters; j++) 1.2341 + { 1.2342 + if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_SUB) 1.2343 + { 1.2344 + sumlo = (sumlo * png_ptr->inv_filter_weights[j]) >> 1.2345 + PNG_WEIGHT_SHIFT; 1.2346 + sumhi = (sumhi * png_ptr->inv_filter_weights[j]) >> 1.2347 + PNG_WEIGHT_SHIFT; 1.2348 + } 1.2349 + } 1.2350 + 1.2351 + sumlo = (sumlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >> 1.2352 + PNG_COST_SHIFT; 1.2353 + sumhi = (sumhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >> 1.2354 + PNG_COST_SHIFT; 1.2355 + 1.2356 + if (sumhi > PNG_HIMASK) 1.2357 + sum = PNG_MAXSUM; 1.2358 + else 1.2359 + sum = (sumhi << PNG_HISHIFT) + sumlo; 1.2360 + } 1.2361 +#endif 1.2362 + 1.2363 + if (sum < mins) 1.2364 + { 1.2365 + mins = sum; 1.2366 + best_row = png_ptr->sub_row; 1.2367 + } 1.2368 + } 1.2369 + 1.2370 + /* up filter */ 1.2371 + if (filter_to_do == PNG_FILTER_UP) 1.2372 + { 1.2373 + png_bytep rp, dp, pp; 1.2374 + png_uint_32 i; 1.2375 + 1.2376 + for (i = 0, rp = row_buf + 1, dp = png_ptr->up_row + 1, 1.2377 + pp = prev_row + 1; i < row_bytes; 1.2378 + i++, rp++, pp++, dp++) 1.2379 + { 1.2380 + *dp = (png_byte)(((int)*rp - (int)*pp) & 0xff); 1.2381 + } 1.2382 + best_row = png_ptr->up_row; 1.2383 + } 1.2384 + 1.2385 + else if (filter_to_do & PNG_FILTER_UP) 1.2386 + { 1.2387 + png_bytep rp, dp, pp; 1.2388 + png_uint_32 sum = 0, lmins = mins; 1.2389 + png_uint_32 i; 1.2390 + int v; 1.2391 + 1.2392 + 1.2393 +#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) 1.2394 + if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) 1.2395 + { 1.2396 + int j; 1.2397 + png_uint_32 lmhi, lmlo; 1.2398 + lmlo = lmins & PNG_LOMASK; 1.2399 + lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK; 1.2400 + 1.2401 + for (j = 0; j < num_p_filters; j++) 1.2402 + { 1.2403 + if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_UP) 1.2404 + { 1.2405 + lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >> 1.2406 + PNG_WEIGHT_SHIFT; 1.2407 + lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >> 1.2408 + PNG_WEIGHT_SHIFT; 1.2409 + } 1.2410 + } 1.2411 + 1.2412 + lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_UP]) >> 1.2413 + PNG_COST_SHIFT; 1.2414 + lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_UP]) >> 1.2415 + PNG_COST_SHIFT; 1.2416 + 1.2417 + if (lmhi > PNG_HIMASK) 1.2418 + lmins = PNG_MAXSUM; 1.2419 + else 1.2420 + lmins = (lmhi << PNG_HISHIFT) + lmlo; 1.2421 + } 1.2422 +#endif 1.2423 + 1.2424 + for (i = 0, rp = row_buf + 1, dp = png_ptr->up_row + 1, 1.2425 + pp = prev_row + 1; i < row_bytes; i++) 1.2426 + { 1.2427 + v = *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff); 1.2428 + 1.2429 + sum += (v < 128) ? v : 256 - v; 1.2430 + 1.2431 + if (sum > lmins) /* We are already worse, don't continue. */ 1.2432 + break; 1.2433 + } 1.2434 + 1.2435 +#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) 1.2436 + if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) 1.2437 + { 1.2438 + int j; 1.2439 + png_uint_32 sumhi, sumlo; 1.2440 + sumlo = sum & PNG_LOMASK; 1.2441 + sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK; 1.2442 + 1.2443 + for (j = 0; j < num_p_filters; j++) 1.2444 + { 1.2445 + if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_UP) 1.2446 + { 1.2447 + sumlo = (sumlo * png_ptr->filter_weights[j]) >> 1.2448 + PNG_WEIGHT_SHIFT; 1.2449 + sumhi = (sumhi * png_ptr->filter_weights[j]) >> 1.2450 + PNG_WEIGHT_SHIFT; 1.2451 + } 1.2452 + } 1.2453 + 1.2454 + sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_UP]) >> 1.2455 + PNG_COST_SHIFT; 1.2456 + sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_UP]) >> 1.2457 + PNG_COST_SHIFT; 1.2458 + 1.2459 + if (sumhi > PNG_HIMASK) 1.2460 + sum = PNG_MAXSUM; 1.2461 + else 1.2462 + sum = (sumhi << PNG_HISHIFT) + sumlo; 1.2463 + } 1.2464 +#endif 1.2465 + 1.2466 + if (sum < mins) 1.2467 + { 1.2468 + mins = sum; 1.2469 + best_row = png_ptr->up_row; 1.2470 + } 1.2471 + } 1.2472 + 1.2473 + /* avg filter */ 1.2474 + if (filter_to_do == PNG_FILTER_AVG) 1.2475 + { 1.2476 + png_bytep rp, dp, pp, lp; 1.2477 + png_uint_32 i; 1.2478 + for (i = 0, rp = row_buf + 1, dp = png_ptr->avg_row + 1, 1.2479 + pp = prev_row + 1; i < bpp; i++) 1.2480 + { 1.2481 + *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff); 1.2482 + } 1.2483 + for (lp = row_buf + 1; i < row_bytes; i++) 1.2484 + { 1.2485 + *dp++ = (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2)) 1.2486 + & 0xff); 1.2487 + } 1.2488 + best_row = png_ptr->avg_row; 1.2489 + } 1.2490 + 1.2491 + else if (filter_to_do & PNG_FILTER_AVG) 1.2492 + { 1.2493 + png_bytep rp, dp, pp, lp; 1.2494 + png_uint_32 sum = 0, lmins = mins; 1.2495 + png_uint_32 i; 1.2496 + int v; 1.2497 + 1.2498 +#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) 1.2499 + if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) 1.2500 + { 1.2501 + int j; 1.2502 + png_uint_32 lmhi, lmlo; 1.2503 + lmlo = lmins & PNG_LOMASK; 1.2504 + lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK; 1.2505 + 1.2506 + for (j = 0; j < num_p_filters; j++) 1.2507 + { 1.2508 + if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_AVG) 1.2509 + { 1.2510 + lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >> 1.2511 + PNG_WEIGHT_SHIFT; 1.2512 + lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >> 1.2513 + PNG_WEIGHT_SHIFT; 1.2514 + } 1.2515 + } 1.2516 + 1.2517 + lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_AVG]) >> 1.2518 + PNG_COST_SHIFT; 1.2519 + lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_AVG]) >> 1.2520 + PNG_COST_SHIFT; 1.2521 + 1.2522 + if (lmhi > PNG_HIMASK) 1.2523 + lmins = PNG_MAXSUM; 1.2524 + else 1.2525 + lmins = (lmhi << PNG_HISHIFT) + lmlo; 1.2526 + } 1.2527 +#endif 1.2528 + 1.2529 + for (i = 0, rp = row_buf + 1, dp = png_ptr->avg_row + 1, 1.2530 + pp = prev_row + 1; i < bpp; i++) 1.2531 + { 1.2532 + v = *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff); 1.2533 + 1.2534 + sum += (v < 128) ? v : 256 - v; 1.2535 + } 1.2536 + for (lp = row_buf + 1; i < row_bytes; i++) 1.2537 + { 1.2538 + v = *dp++ = 1.2539 + (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2)) & 0xff); 1.2540 + 1.2541 + sum += (v < 128) ? v : 256 - v; 1.2542 + 1.2543 + if (sum > lmins) /* We are already worse, don't continue. */ 1.2544 + break; 1.2545 + } 1.2546 + 1.2547 +#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) 1.2548 + if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) 1.2549 + { 1.2550 + int j; 1.2551 + png_uint_32 sumhi, sumlo; 1.2552 + sumlo = sum & PNG_LOMASK; 1.2553 + sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK; 1.2554 + 1.2555 + for (j = 0; j < num_p_filters; j++) 1.2556 + { 1.2557 + if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_NONE) 1.2558 + { 1.2559 + sumlo = (sumlo * png_ptr->filter_weights[j]) >> 1.2560 + PNG_WEIGHT_SHIFT; 1.2561 + sumhi = (sumhi * png_ptr->filter_weights[j]) >> 1.2562 + PNG_WEIGHT_SHIFT; 1.2563 + } 1.2564 + } 1.2565 + 1.2566 + sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_AVG]) >> 1.2567 + PNG_COST_SHIFT; 1.2568 + sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_AVG]) >> 1.2569 + PNG_COST_SHIFT; 1.2570 + 1.2571 + if (sumhi > PNG_HIMASK) 1.2572 + sum = PNG_MAXSUM; 1.2573 + else 1.2574 + sum = (sumhi << PNG_HISHIFT) + sumlo; 1.2575 + } 1.2576 +#endif 1.2577 + 1.2578 + if (sum < mins) 1.2579 + { 1.2580 + mins = sum; 1.2581 + best_row = png_ptr->avg_row; 1.2582 + } 1.2583 + } 1.2584 + 1.2585 + /* Paeth filter */ 1.2586 + if (filter_to_do == PNG_FILTER_PAETH) 1.2587 + { 1.2588 + png_bytep rp, dp, pp, cp, lp; 1.2589 + png_uint_32 i; 1.2590 + for (i = 0, rp = row_buf + 1, dp = png_ptr->paeth_row + 1, 1.2591 + pp = prev_row + 1; i < bpp; i++) 1.2592 + { 1.2593 + *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff); 1.2594 + } 1.2595 + 1.2596 + for (lp = row_buf + 1, cp = prev_row + 1; i < row_bytes; i++) 1.2597 + { 1.2598 + int a, b, c, pa, pb, pc, p; 1.2599 + 1.2600 + b = *pp++; 1.2601 + c = *cp++; 1.2602 + a = *lp++; 1.2603 + 1.2604 + p = b - c; 1.2605 + pc = a - c; 1.2606 + 1.2607 +#ifdef PNG_USE_ABS 1.2608 + pa = abs(p); 1.2609 + pb = abs(pc); 1.2610 + pc = abs(p + pc); 1.2611 +#else 1.2612 + pa = p < 0 ? -p : p; 1.2613 + pb = pc < 0 ? -pc : pc; 1.2614 + pc = (p + pc) < 0 ? -(p + pc) : p + pc; 1.2615 +#endif 1.2616 + 1.2617 + p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c; 1.2618 + 1.2619 + *dp++ = (png_byte)(((int)*rp++ - p) & 0xff); 1.2620 + } 1.2621 + best_row = png_ptr->paeth_row; 1.2622 + } 1.2623 + 1.2624 + else if (filter_to_do & PNG_FILTER_PAETH) 1.2625 + { 1.2626 + png_bytep rp, dp, pp, cp, lp; 1.2627 + png_uint_32 sum = 0, lmins = mins; 1.2628 + png_uint_32 i; 1.2629 + int v; 1.2630 + 1.2631 +#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) 1.2632 + if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) 1.2633 + { 1.2634 + int j; 1.2635 + png_uint_32 lmhi, lmlo; 1.2636 + lmlo = lmins & PNG_LOMASK; 1.2637 + lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK; 1.2638 + 1.2639 + for (j = 0; j < num_p_filters; j++) 1.2640 + { 1.2641 + if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_PAETH) 1.2642 + { 1.2643 + lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >> 1.2644 + PNG_WEIGHT_SHIFT; 1.2645 + lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >> 1.2646 + PNG_WEIGHT_SHIFT; 1.2647 + } 1.2648 + } 1.2649 + 1.2650 + lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_PAETH]) >> 1.2651 + PNG_COST_SHIFT; 1.2652 + lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_PAETH]) >> 1.2653 + PNG_COST_SHIFT; 1.2654 + 1.2655 + if (lmhi > PNG_HIMASK) 1.2656 + lmins = PNG_MAXSUM; 1.2657 + else 1.2658 + lmins = (lmhi << PNG_HISHIFT) + lmlo; 1.2659 + } 1.2660 +#endif 1.2661 + 1.2662 + for (i = 0, rp = row_buf + 1, dp = png_ptr->paeth_row + 1, 1.2663 + pp = prev_row + 1; i < bpp; i++) 1.2664 + { 1.2665 + v = *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff); 1.2666 + 1.2667 + sum += (v < 128) ? v : 256 - v; 1.2668 + } 1.2669 + 1.2670 + for (lp = row_buf + 1, cp = prev_row + 1; i < row_bytes; i++) 1.2671 + { 1.2672 + int a, b, c, pa, pb, pc, p; 1.2673 + 1.2674 + b = *pp++; 1.2675 + c = *cp++; 1.2676 + a = *lp++; 1.2677 + 1.2678 +#ifndef PNG_SLOW_PAETH 1.2679 + p = b - c; 1.2680 + pc = a - c; 1.2681 +#ifdef PNG_USE_ABS 1.2682 + pa = abs(p); 1.2683 + pb = abs(pc); 1.2684 + pc = abs(p + pc); 1.2685 +#else 1.2686 + pa = p < 0 ? -p : p; 1.2687 + pb = pc < 0 ? -pc : pc; 1.2688 + pc = (p + pc) < 0 ? -(p + pc) : p + pc; 1.2689 +#endif 1.2690 + p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c; 1.2691 +#else /* PNG_SLOW_PAETH */ 1.2692 + p = a + b - c; 1.2693 + pa = abs(p - a); 1.2694 + pb = abs(p - b); 1.2695 + pc = abs(p - c); 1.2696 + if (pa <= pb && pa <= pc) 1.2697 + p = a; 1.2698 + else if (pb <= pc) 1.2699 + p = b; 1.2700 + else 1.2701 + p = c; 1.2702 +#endif /* PNG_SLOW_PAETH */ 1.2703 + 1.2704 + v = *dp++ = (png_byte)(((int)*rp++ - p) & 0xff); 1.2705 + 1.2706 + sum += (v < 128) ? v : 256 - v; 1.2707 + 1.2708 + if (sum > lmins) /* We are already worse, don't continue. */ 1.2709 + break; 1.2710 + } 1.2711 + 1.2712 +#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) 1.2713 + if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) 1.2714 + { 1.2715 + int j; 1.2716 + png_uint_32 sumhi, sumlo; 1.2717 + sumlo = sum & PNG_LOMASK; 1.2718 + sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK; 1.2719 + 1.2720 + for (j = 0; j < num_p_filters; j++) 1.2721 + { 1.2722 + if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_PAETH) 1.2723 + { 1.2724 + sumlo = (sumlo * png_ptr->filter_weights[j]) >> 1.2725 + PNG_WEIGHT_SHIFT; 1.2726 + sumhi = (sumhi * png_ptr->filter_weights[j]) >> 1.2727 + PNG_WEIGHT_SHIFT; 1.2728 + } 1.2729 + } 1.2730 + 1.2731 + sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_PAETH]) >> 1.2732 + PNG_COST_SHIFT; 1.2733 + sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_PAETH]) >> 1.2734 + PNG_COST_SHIFT; 1.2735 + 1.2736 + if (sumhi > PNG_HIMASK) 1.2737 + sum = PNG_MAXSUM; 1.2738 + else 1.2739 + sum = (sumhi << PNG_HISHIFT) + sumlo; 1.2740 + } 1.2741 +#endif 1.2742 + 1.2743 + if (sum < mins) 1.2744 + { 1.2745 + best_row = png_ptr->paeth_row; 1.2746 + } 1.2747 + } 1.2748 +#endif /* PNG_NO_WRITE_FILTER */ 1.2749 + /* Do the actual writing of the filtered row data from the chosen filter. */ 1.2750 + 1.2751 + png_write_filtered_row(png_ptr, best_row); 1.2752 + 1.2753 +#ifndef PNG_NO_WRITE_FILTER 1.2754 +#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) 1.2755 + /* Save the type of filter we picked this time for future calculations */ 1.2756 + if (png_ptr->num_prev_filters > 0) 1.2757 + { 1.2758 + int j; 1.2759 + for (j = 1; j < num_p_filters; j++) 1.2760 + { 1.2761 + png_ptr->prev_filters[j] = png_ptr->prev_filters[j - 1]; 1.2762 + } 1.2763 + png_ptr->prev_filters[j] = best_row[0]; 1.2764 + } 1.2765 +#endif 1.2766 +#endif /* PNG_NO_WRITE_FILTER */ 1.2767 +} 1.2768 + 1.2769 + 1.2770 +/* Do the actual writing of a previously filtered row. */ 1.2771 +void /* PRIVATE */ 1.2772 +png_write_filtered_row(png_structp png_ptr, png_bytep filtered_row) 1.2773 +{ 1.2774 + png_debug(1, "in png_write_filtered_row\n"); 1.2775 + png_debug1(2, "filter = %d\n", filtered_row[0]); 1.2776 + /* set up the zlib input buffer */ 1.2777 + 1.2778 + png_ptr->zstream.next_in = filtered_row; 1.2779 + png_ptr->zstream.avail_in = (uInt)png_ptr->row_info.rowbytes + 1; 1.2780 + /* repeat until we have compressed all the data */ 1.2781 + do 1.2782 + { 1.2783 + int ret; /* return of zlib */ 1.2784 + 1.2785 + /* compress the data */ 1.2786 + ret = deflate(&png_ptr->zstream, Z_NO_FLUSH); 1.2787 + /* check for compression errors */ 1.2788 + if (ret != Z_OK) 1.2789 + { 1.2790 + if (png_ptr->zstream.msg != NULL) 1.2791 + png_error(png_ptr, png_ptr->zstream.msg); 1.2792 + else 1.2793 + png_error(png_ptr, "zlib error"); 1.2794 + } 1.2795 + 1.2796 + /* see if it is time to write another IDAT */ 1.2797 + if (!(png_ptr->zstream.avail_out)) 1.2798 + { 1.2799 + /* write the IDAT and reset the zlib output buffer */ 1.2800 + png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size); 1.2801 + png_ptr->zstream.next_out = png_ptr->zbuf; 1.2802 + png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; 1.2803 + } 1.2804 + /* repeat until all data has been compressed */ 1.2805 + } while (png_ptr->zstream.avail_in); 1.2806 + 1.2807 + /* swap the current and previous rows */ 1.2808 + if (png_ptr->prev_row != NULL) 1.2809 + { 1.2810 + png_bytep tptr; 1.2811 + 1.2812 + tptr = png_ptr->prev_row; 1.2813 + png_ptr->prev_row = png_ptr->row_buf; 1.2814 + png_ptr->row_buf = tptr; 1.2815 + } 1.2816 + 1.2817 + /* finish row - updates counters and flushes zlib if last row */ 1.2818 + png_write_finish_row(png_ptr); 1.2819 + 1.2820 +#if defined(PNG_WRITE_FLUSH_SUPPORTED) 1.2821 + png_ptr->flush_rows++; 1.2822 + 1.2823 + if (png_ptr->flush_dist > 0 && 1.2824 + png_ptr->flush_rows >= png_ptr->flush_dist) 1.2825 + { 1.2826 + png_write_flush(png_ptr); 1.2827 + } 1.2828 +#endif 1.2829 +} 1.2830 +#endif /* PNG_WRITE_SUPPORTED */