media/libpng/pngwutil.c

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

michael@0 1
michael@0 2 /* pngwutil.c - utilities to write a PNG file
michael@0 3 *
michael@0 4 * Last changed in libpng 1.6.2 [April 25, 2013]
michael@0 5 * Copyright (c) 1998-2013 Glenn Randers-Pehrson
michael@0 6 * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
michael@0 7 * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
michael@0 8 *
michael@0 9 * This code is released under the libpng license.
michael@0 10 * For conditions of distribution and use, see the disclaimer
michael@0 11 * and license in png.h
michael@0 12 */
michael@0 13
michael@0 14 #include "pngpriv.h"
michael@0 15
michael@0 16 #ifdef PNG_WRITE_SUPPORTED
michael@0 17
michael@0 18 #ifdef PNG_WRITE_INT_FUNCTIONS_SUPPORTED
michael@0 19 /* Place a 32-bit number into a buffer in PNG byte order. We work
michael@0 20 * with unsigned numbers for convenience, although one supported
michael@0 21 * ancillary chunk uses signed (two's complement) numbers.
michael@0 22 */
michael@0 23 void PNGAPI
michael@0 24 png_save_uint_32(png_bytep buf, png_uint_32 i)
michael@0 25 {
michael@0 26 buf[0] = (png_byte)((i >> 24) & 0xff);
michael@0 27 buf[1] = (png_byte)((i >> 16) & 0xff);
michael@0 28 buf[2] = (png_byte)((i >> 8) & 0xff);
michael@0 29 buf[3] = (png_byte)(i & 0xff);
michael@0 30 }
michael@0 31
michael@0 32 /* Place a 16-bit number into a buffer in PNG byte order.
michael@0 33 * The parameter is declared unsigned int, not png_uint_16,
michael@0 34 * just to avoid potential problems on pre-ANSI C compilers.
michael@0 35 */
michael@0 36 void PNGAPI
michael@0 37 png_save_uint_16(png_bytep buf, unsigned int i)
michael@0 38 {
michael@0 39 buf[0] = (png_byte)((i >> 8) & 0xff);
michael@0 40 buf[1] = (png_byte)(i & 0xff);
michael@0 41 }
michael@0 42 #endif
michael@0 43
michael@0 44 /* Simple function to write the signature. If we have already written
michael@0 45 * the magic bytes of the signature, or more likely, the PNG stream is
michael@0 46 * being embedded into another stream and doesn't need its own signature,
michael@0 47 * we should call png_set_sig_bytes() to tell libpng how many of the
michael@0 48 * bytes have already been written.
michael@0 49 */
michael@0 50 void PNGAPI
michael@0 51 png_write_sig(png_structrp png_ptr)
michael@0 52 {
michael@0 53 png_byte png_signature[8] = {137, 80, 78, 71, 13, 10, 26, 10};
michael@0 54
michael@0 55 #ifdef PNG_IO_STATE_SUPPORTED
michael@0 56 /* Inform the I/O callback that the signature is being written */
michael@0 57 png_ptr->io_state = PNG_IO_WRITING | PNG_IO_SIGNATURE;
michael@0 58 #endif
michael@0 59
michael@0 60 /* Write the rest of the 8 byte signature */
michael@0 61 png_write_data(png_ptr, &png_signature[png_ptr->sig_bytes],
michael@0 62 (png_size_t)(8 - png_ptr->sig_bytes));
michael@0 63
michael@0 64 if (png_ptr->sig_bytes < 3)
michael@0 65 png_ptr->mode |= PNG_HAVE_PNG_SIGNATURE;
michael@0 66 }
michael@0 67
michael@0 68 /* Write the start of a PNG chunk. The type is the chunk type.
michael@0 69 * The total_length is the sum of the lengths of all the data you will be
michael@0 70 * passing in png_write_chunk_data().
michael@0 71 */
michael@0 72 static void
michael@0 73 png_write_chunk_header(png_structrp png_ptr, png_uint_32 chunk_name,
michael@0 74 png_uint_32 length)
michael@0 75 {
michael@0 76 png_byte buf[8];
michael@0 77
michael@0 78 #if defined(PNG_DEBUG) && (PNG_DEBUG > 0)
michael@0 79 PNG_CSTRING_FROM_CHUNK(buf, chunk_name);
michael@0 80 png_debug2(0, "Writing %s chunk, length = %lu", buf, (unsigned long)length);
michael@0 81 #endif
michael@0 82
michael@0 83 if (png_ptr == NULL)
michael@0 84 return;
michael@0 85
michael@0 86 #ifdef PNG_IO_STATE_SUPPORTED
michael@0 87 /* Inform the I/O callback that the chunk header is being written.
michael@0 88 * PNG_IO_CHUNK_HDR requires a single I/O call.
michael@0 89 */
michael@0 90 png_ptr->io_state = PNG_IO_WRITING | PNG_IO_CHUNK_HDR;
michael@0 91 #endif
michael@0 92
michael@0 93 /* Write the length and the chunk name */
michael@0 94 png_save_uint_32(buf, length);
michael@0 95 png_save_uint_32(buf + 4, chunk_name);
michael@0 96 png_write_data(png_ptr, buf, 8);
michael@0 97
michael@0 98 /* Put the chunk name into png_ptr->chunk_name */
michael@0 99 png_ptr->chunk_name = chunk_name;
michael@0 100
michael@0 101 /* Reset the crc and run it over the chunk name */
michael@0 102 png_reset_crc(png_ptr);
michael@0 103
michael@0 104 png_calculate_crc(png_ptr, buf + 4, 4);
michael@0 105
michael@0 106 #ifdef PNG_IO_STATE_SUPPORTED
michael@0 107 /* Inform the I/O callback that chunk data will (possibly) be written.
michael@0 108 * PNG_IO_CHUNK_DATA does NOT require a specific number of I/O calls.
michael@0 109 */
michael@0 110 png_ptr->io_state = PNG_IO_WRITING | PNG_IO_CHUNK_DATA;
michael@0 111 #endif
michael@0 112 }
michael@0 113
michael@0 114 void PNGAPI
michael@0 115 png_write_chunk_start(png_structrp png_ptr, png_const_bytep chunk_string,
michael@0 116 png_uint_32 length)
michael@0 117 {
michael@0 118 png_write_chunk_header(png_ptr, PNG_CHUNK_FROM_STRING(chunk_string), length);
michael@0 119 }
michael@0 120
michael@0 121 /* Write the data of a PNG chunk started with png_write_chunk_header().
michael@0 122 * Note that multiple calls to this function are allowed, and that the
michael@0 123 * sum of the lengths from these calls *must* add up to the total_length
michael@0 124 * given to png_write_chunk_header().
michael@0 125 */
michael@0 126 void PNGAPI
michael@0 127 png_write_chunk_data(png_structrp png_ptr, png_const_bytep data,
michael@0 128 png_size_t length)
michael@0 129 {
michael@0 130 /* Write the data, and run the CRC over it */
michael@0 131 if (png_ptr == NULL)
michael@0 132 return;
michael@0 133
michael@0 134 if (data != NULL && length > 0)
michael@0 135 {
michael@0 136 png_write_data(png_ptr, data, length);
michael@0 137
michael@0 138 /* Update the CRC after writing the data,
michael@0 139 * in case that the user I/O routine alters it.
michael@0 140 */
michael@0 141 png_calculate_crc(png_ptr, data, length);
michael@0 142 }
michael@0 143 }
michael@0 144
michael@0 145 /* Finish a chunk started with png_write_chunk_header(). */
michael@0 146 void PNGAPI
michael@0 147 png_write_chunk_end(png_structrp png_ptr)
michael@0 148 {
michael@0 149 png_byte buf[4];
michael@0 150
michael@0 151 if (png_ptr == NULL) return;
michael@0 152
michael@0 153 #ifdef PNG_IO_STATE_SUPPORTED
michael@0 154 /* Inform the I/O callback that the chunk CRC is being written.
michael@0 155 * PNG_IO_CHUNK_CRC requires a single I/O function call.
michael@0 156 */
michael@0 157 png_ptr->io_state = PNG_IO_WRITING | PNG_IO_CHUNK_CRC;
michael@0 158 #endif
michael@0 159
michael@0 160 /* Write the crc in a single operation */
michael@0 161 png_save_uint_32(buf, png_ptr->crc);
michael@0 162
michael@0 163 png_write_data(png_ptr, buf, (png_size_t)4);
michael@0 164 }
michael@0 165
michael@0 166 /* Write a PNG chunk all at once. The type is an array of ASCII characters
michael@0 167 * representing the chunk name. The array must be at least 4 bytes in
michael@0 168 * length, and does not need to be null terminated. To be safe, pass the
michael@0 169 * pre-defined chunk names here, and if you need a new one, define it
michael@0 170 * where the others are defined. The length is the length of the data.
michael@0 171 * All the data must be present. If that is not possible, use the
michael@0 172 * png_write_chunk_start(), png_write_chunk_data(), and png_write_chunk_end()
michael@0 173 * functions instead.
michael@0 174 */
michael@0 175 static void
michael@0 176 png_write_complete_chunk(png_structrp png_ptr, png_uint_32 chunk_name,
michael@0 177 png_const_bytep data, png_size_t length)
michael@0 178 {
michael@0 179 if (png_ptr == NULL)
michael@0 180 return;
michael@0 181
michael@0 182 /* On 64 bit architectures 'length' may not fit in a png_uint_32. */
michael@0 183 if (length > PNG_UINT_31_MAX)
michael@0 184 png_error(png_ptr, "length exceeds PNG maxima");
michael@0 185
michael@0 186 png_write_chunk_header(png_ptr, chunk_name, (png_uint_32)length);
michael@0 187 png_write_chunk_data(png_ptr, data, length);
michael@0 188 png_write_chunk_end(png_ptr);
michael@0 189 }
michael@0 190
michael@0 191 /* This is the API that calls the internal function above. */
michael@0 192 void PNGAPI
michael@0 193 png_write_chunk(png_structrp png_ptr, png_const_bytep chunk_string,
michael@0 194 png_const_bytep data, png_size_t length)
michael@0 195 {
michael@0 196 png_write_complete_chunk(png_ptr, PNG_CHUNK_FROM_STRING(chunk_string), data,
michael@0 197 length);
michael@0 198 }
michael@0 199
michael@0 200 /* This is used below to find the size of an image to pass to png_deflate_claim,
michael@0 201 * so it only needs to be accurate if the size is less than 16384 bytes (the
michael@0 202 * point at which a lower LZ window size can be used.)
michael@0 203 */
michael@0 204 static png_alloc_size_t
michael@0 205 png_image_size(png_structrp png_ptr)
michael@0 206 {
michael@0 207 /* Only return sizes up to the maximum of a png_uint_32, do this by limiting
michael@0 208 * the width and height used to 15 bits.
michael@0 209 */
michael@0 210 png_uint_32 h = png_ptr->height;
michael@0 211
michael@0 212 if (png_ptr->rowbytes < 32768 && h < 32768)
michael@0 213 {
michael@0 214 if (png_ptr->interlaced)
michael@0 215 {
michael@0 216 /* Interlacing makes the image larger because of the replication of
michael@0 217 * both the filter byte and the padding to a byte boundary.
michael@0 218 */
michael@0 219 png_uint_32 w = png_ptr->width;
michael@0 220 unsigned int pd = png_ptr->pixel_depth;
michael@0 221 png_alloc_size_t cb_base;
michael@0 222 int pass;
michael@0 223
michael@0 224 for (cb_base=0, pass=0; pass<=6; ++pass)
michael@0 225 {
michael@0 226 png_uint_32 pw = PNG_PASS_COLS(w, pass);
michael@0 227
michael@0 228 if (pw > 0)
michael@0 229 cb_base += (PNG_ROWBYTES(pd, pw)+1) * PNG_PASS_ROWS(h, pass);
michael@0 230 }
michael@0 231
michael@0 232 return cb_base;
michael@0 233 }
michael@0 234
michael@0 235 else
michael@0 236 return (png_ptr->rowbytes+1) * h;
michael@0 237 }
michael@0 238
michael@0 239 else
michael@0 240 return 0xffffffffU;
michael@0 241 }
michael@0 242
michael@0 243 #ifdef PNG_WRITE_OPTIMIZE_CMF_SUPPORTED
michael@0 244 /* This is the code to hack the first two bytes of the deflate stream (the
michael@0 245 * deflate header) to correct the windowBits value to match the actual data
michael@0 246 * size. Note that the second argument is the *uncompressed* size but the
michael@0 247 * first argument is the *compressed* data (and it must be deflate
michael@0 248 * compressed.)
michael@0 249 */
michael@0 250 static void
michael@0 251 optimize_cmf(png_bytep data, png_alloc_size_t data_size)
michael@0 252 {
michael@0 253 /* Optimize the CMF field in the zlib stream. The resultant zlib stream is
michael@0 254 * still compliant to the stream specification.
michael@0 255 */
michael@0 256 if (data_size <= 16384) /* else windowBits must be 15 */
michael@0 257 {
michael@0 258 unsigned int z_cmf = data[0]; /* zlib compression method and flags */
michael@0 259
michael@0 260 if ((z_cmf & 0x0f) == 8 && (z_cmf & 0xf0) <= 0x70)
michael@0 261 {
michael@0 262 unsigned int z_cinfo;
michael@0 263 unsigned int half_z_window_size;
michael@0 264
michael@0 265 z_cinfo = z_cmf >> 4;
michael@0 266 half_z_window_size = 1U << (z_cinfo + 7);
michael@0 267
michael@0 268 if (data_size <= half_z_window_size) /* else no change */
michael@0 269 {
michael@0 270 unsigned int tmp;
michael@0 271
michael@0 272 do
michael@0 273 {
michael@0 274 half_z_window_size >>= 1;
michael@0 275 --z_cinfo;
michael@0 276 }
michael@0 277 while (z_cinfo > 0 && data_size <= half_z_window_size);
michael@0 278
michael@0 279 z_cmf = (z_cmf & 0x0f) | (z_cinfo << 4);
michael@0 280
michael@0 281 data[0] = (png_byte)z_cmf;
michael@0 282 tmp = data[1] & 0xe0;
michael@0 283 tmp += 0x1f - ((z_cmf << 8) + tmp) % 0x1f;
michael@0 284 data[1] = (png_byte)tmp;
michael@0 285 }
michael@0 286 }
michael@0 287 }
michael@0 288 }
michael@0 289 #else
michael@0 290 # define optimize_cmf(dp,dl) ((void)0)
michael@0 291 #endif /* PNG_WRITE_OPTIMIZE_CMF_SUPPORTED */
michael@0 292
michael@0 293 /* Initialize the compressor for the appropriate type of compression. */
michael@0 294 static int
michael@0 295 png_deflate_claim(png_structrp png_ptr, png_uint_32 owner,
michael@0 296 png_alloc_size_t data_size)
michael@0 297 {
michael@0 298 if (png_ptr->zowner != 0)
michael@0 299 {
michael@0 300 char msg[64];
michael@0 301
michael@0 302 PNG_STRING_FROM_CHUNK(msg, owner);
michael@0 303 msg[4] = ':';
michael@0 304 msg[5] = ' ';
michael@0 305 PNG_STRING_FROM_CHUNK(msg+6, png_ptr->zowner);
michael@0 306 /* So the message that results is "<chunk> using zstream"; this is an
michael@0 307 * internal error, but is very useful for debugging. i18n requirements
michael@0 308 * are minimal.
michael@0 309 */
michael@0 310 (void)png_safecat(msg, (sizeof msg), 10, " using zstream");
michael@0 311 # if PNG_LIBPNG_BUILD_BASE_TYPE >= PNG_LIBPNG_BUILD_RC
michael@0 312 png_warning(png_ptr, msg);
michael@0 313
michael@0 314 /* Attempt sane error recovery */
michael@0 315 if (png_ptr->zowner == png_IDAT) /* don't steal from IDAT */
michael@0 316 {
michael@0 317 png_ptr->zstream.msg = PNGZ_MSG_CAST("in use by IDAT");
michael@0 318 return Z_STREAM_ERROR;
michael@0 319 }
michael@0 320
michael@0 321 png_ptr->zowner = 0;
michael@0 322 # else
michael@0 323 png_error(png_ptr, msg);
michael@0 324 # endif
michael@0 325 }
michael@0 326
michael@0 327 {
michael@0 328 int level = png_ptr->zlib_level;
michael@0 329 int method = png_ptr->zlib_method;
michael@0 330 int windowBits = png_ptr->zlib_window_bits;
michael@0 331 int memLevel = png_ptr->zlib_mem_level;
michael@0 332 int strategy; /* set below */
michael@0 333 int ret; /* zlib return code */
michael@0 334
michael@0 335 if (owner == png_IDAT)
michael@0 336 {
michael@0 337 if (png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_STRATEGY)
michael@0 338 strategy = png_ptr->zlib_strategy;
michael@0 339
michael@0 340 else if (png_ptr->do_filter != PNG_FILTER_NONE)
michael@0 341 strategy = PNG_Z_DEFAULT_STRATEGY;
michael@0 342
michael@0 343 else
michael@0 344 strategy = PNG_Z_DEFAULT_NOFILTER_STRATEGY;
michael@0 345 }
michael@0 346
michael@0 347 else
michael@0 348 {
michael@0 349 # ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED
michael@0 350 level = png_ptr->zlib_text_level;
michael@0 351 method = png_ptr->zlib_text_method;
michael@0 352 windowBits = png_ptr->zlib_text_window_bits;
michael@0 353 memLevel = png_ptr->zlib_text_mem_level;
michael@0 354 strategy = png_ptr->zlib_text_strategy;
michael@0 355 # else
michael@0 356 /* If customization is not supported the values all come from the
michael@0 357 * IDAT values except for the strategy, which is fixed to the
michael@0 358 * default. (This is the pre-1.6.0 behavior too, although it was
michael@0 359 * implemented in a very different way.)
michael@0 360 */
michael@0 361 strategy = Z_DEFAULT_STRATEGY;
michael@0 362 # endif
michael@0 363 }
michael@0 364
michael@0 365 /* Adjust 'windowBits' down if larger than 'data_size'; to stop this
michael@0 366 * happening just pass 32768 as the data_size parameter. Notice that zlib
michael@0 367 * requires an extra 262 bytes in the window in addition to the data to be
michael@0 368 * able to see the whole of the data, so if data_size+262 takes us to the
michael@0 369 * next windowBits size we need to fix up the value later. (Because even
michael@0 370 * though deflate needs the extra window, inflate does not!)
michael@0 371 */
michael@0 372 if (data_size <= 16384)
michael@0 373 {
michael@0 374 /* IMPLEMENTATION NOTE: this 'half_window_size' stuff is only here to
michael@0 375 * work round a Microsoft Visual C misbehavior which, contrary to C-90,
michael@0 376 * widens the result of the following shift to 64-bits if (and,
michael@0 377 * apparently, only if) it is used in a test.
michael@0 378 */
michael@0 379 unsigned int half_window_size = 1U << (windowBits-1);
michael@0 380
michael@0 381 while (data_size + 262 <= half_window_size)
michael@0 382 {
michael@0 383 half_window_size >>= 1;
michael@0 384 --windowBits;
michael@0 385 }
michael@0 386 }
michael@0 387
michael@0 388 /* Check against the previous initialized values, if any. */
michael@0 389 if ((png_ptr->flags & PNG_FLAG_ZSTREAM_INITIALIZED) &&
michael@0 390 (png_ptr->zlib_set_level != level ||
michael@0 391 png_ptr->zlib_set_method != method ||
michael@0 392 png_ptr->zlib_set_window_bits != windowBits ||
michael@0 393 png_ptr->zlib_set_mem_level != memLevel ||
michael@0 394 png_ptr->zlib_set_strategy != strategy))
michael@0 395 {
michael@0 396 if (deflateEnd(&png_ptr->zstream) != Z_OK)
michael@0 397 png_warning(png_ptr, "deflateEnd failed (ignored)");
michael@0 398
michael@0 399 png_ptr->flags &= ~PNG_FLAG_ZSTREAM_INITIALIZED;
michael@0 400 }
michael@0 401
michael@0 402 /* For safety clear out the input and output pointers (currently zlib
michael@0 403 * doesn't use them on Init, but it might in the future).
michael@0 404 */
michael@0 405 png_ptr->zstream.next_in = NULL;
michael@0 406 png_ptr->zstream.avail_in = 0;
michael@0 407 png_ptr->zstream.next_out = NULL;
michael@0 408 png_ptr->zstream.avail_out = 0;
michael@0 409
michael@0 410 /* Now initialize if required, setting the new parameters, otherwise just
michael@0 411 * to a simple reset to the previous parameters.
michael@0 412 */
michael@0 413 if (png_ptr->flags & PNG_FLAG_ZSTREAM_INITIALIZED)
michael@0 414 ret = deflateReset(&png_ptr->zstream);
michael@0 415
michael@0 416 else
michael@0 417 {
michael@0 418 ret = deflateInit2(&png_ptr->zstream, level, method, windowBits,
michael@0 419 memLevel, strategy);
michael@0 420
michael@0 421 if (ret == Z_OK)
michael@0 422 png_ptr->flags |= PNG_FLAG_ZSTREAM_INITIALIZED;
michael@0 423 }
michael@0 424
michael@0 425 /* The return code is from either deflateReset or deflateInit2; they have
michael@0 426 * pretty much the same set of error codes.
michael@0 427 */
michael@0 428 if (ret == Z_OK)
michael@0 429 png_ptr->zowner = owner;
michael@0 430
michael@0 431 else
michael@0 432 png_zstream_error(png_ptr, ret);
michael@0 433
michael@0 434 return ret;
michael@0 435 }
michael@0 436 }
michael@0 437
michael@0 438 /* Clean up (or trim) a linked list of compression buffers. */
michael@0 439 void /* PRIVATE */
michael@0 440 png_free_buffer_list(png_structrp png_ptr, png_compression_bufferp *listp)
michael@0 441 {
michael@0 442 png_compression_bufferp list = *listp;
michael@0 443
michael@0 444 if (list != NULL)
michael@0 445 {
michael@0 446 *listp = NULL;
michael@0 447
michael@0 448 do
michael@0 449 {
michael@0 450 png_compression_bufferp next = list->next;
michael@0 451
michael@0 452 png_free(png_ptr, list);
michael@0 453 list = next;
michael@0 454 }
michael@0 455 while (list != NULL);
michael@0 456 }
michael@0 457 }
michael@0 458
michael@0 459 #ifdef PNG_WRITE_COMPRESSED_TEXT_SUPPORTED
michael@0 460 /* This pair of functions encapsulates the operation of (a) compressing a
michael@0 461 * text string, and (b) issuing it later as a series of chunk data writes.
michael@0 462 * The compression_state structure is shared context for these functions
michael@0 463 * set up by the caller to allow access to the relevant local variables.
michael@0 464 *
michael@0 465 * compression_buffer (new in 1.6.0) is just a linked list of zbuffer_size
michael@0 466 * temporary buffers. From 1.6.0 it is retained in png_struct so that it will
michael@0 467 * be correctly freed in the event of a write error (previous implementations
michael@0 468 * just leaked memory.)
michael@0 469 */
michael@0 470 typedef struct
michael@0 471 {
michael@0 472 png_const_bytep input; /* The uncompressed input data */
michael@0 473 png_alloc_size_t input_len; /* Its length */
michael@0 474 png_uint_32 output_len; /* Final compressed length */
michael@0 475 png_byte output[1024]; /* First block of output */
michael@0 476 } compression_state;
michael@0 477
michael@0 478 static void
michael@0 479 png_text_compress_init(compression_state *comp, png_const_bytep input,
michael@0 480 png_alloc_size_t input_len)
michael@0 481 {
michael@0 482 comp->input = input;
michael@0 483 comp->input_len = input_len;
michael@0 484 comp->output_len = 0;
michael@0 485 }
michael@0 486
michael@0 487 /* Compress the data in the compression state input */
michael@0 488 static int
michael@0 489 png_text_compress(png_structrp png_ptr, png_uint_32 chunk_name,
michael@0 490 compression_state *comp, png_uint_32 prefix_len)
michael@0 491 {
michael@0 492 int ret;
michael@0 493
michael@0 494 /* To find the length of the output it is necessary to first compress the
michael@0 495 * input, the result is buffered rather than using the two-pass algorithm
michael@0 496 * that is used on the inflate side; deflate is assumed to be slower and a
michael@0 497 * PNG writer is assumed to have more memory available than a PNG reader.
michael@0 498 *
michael@0 499 * IMPLEMENTATION NOTE: the zlib API deflateBound() can be used to find an
michael@0 500 * upper limit on the output size, but it is always bigger than the input
michael@0 501 * size so it is likely to be more efficient to use this linked-list
michael@0 502 * approach.
michael@0 503 */
michael@0 504 ret = png_deflate_claim(png_ptr, chunk_name, comp->input_len);
michael@0 505
michael@0 506 if (ret != Z_OK)
michael@0 507 return ret;
michael@0 508
michael@0 509 /* Set up the compression buffers, we need a loop here to avoid overflowing a
michael@0 510 * uInt. Use ZLIB_IO_MAX to limit the input. The output is always limited
michael@0 511 * by the output buffer size, so there is no need to check that. Since this
michael@0 512 * is ANSI-C we know that an 'int', hence a uInt, is always at least 16 bits
michael@0 513 * in size.
michael@0 514 */
michael@0 515 {
michael@0 516 png_compression_bufferp *end = &png_ptr->zbuffer_list;
michael@0 517 png_alloc_size_t input_len = comp->input_len; /* may be zero! */
michael@0 518 png_uint_32 output_len;
michael@0 519
michael@0 520 /* zlib updates these for us: */
michael@0 521 png_ptr->zstream.next_in = PNGZ_INPUT_CAST(comp->input);
michael@0 522 png_ptr->zstream.avail_in = 0; /* Set below */
michael@0 523 png_ptr->zstream.next_out = comp->output;
michael@0 524 png_ptr->zstream.avail_out = (sizeof comp->output);
michael@0 525
michael@0 526 output_len = png_ptr->zstream.avail_out;
michael@0 527
michael@0 528 do
michael@0 529 {
michael@0 530 uInt avail_in = ZLIB_IO_MAX;
michael@0 531
michael@0 532 if (avail_in > input_len)
michael@0 533 avail_in = (uInt)input_len;
michael@0 534
michael@0 535 input_len -= avail_in;
michael@0 536
michael@0 537 png_ptr->zstream.avail_in = avail_in;
michael@0 538
michael@0 539 if (png_ptr->zstream.avail_out == 0)
michael@0 540 {
michael@0 541 png_compression_buffer *next;
michael@0 542
michael@0 543 /* Chunk data is limited to 2^31 bytes in length, so the prefix
michael@0 544 * length must be counted here.
michael@0 545 */
michael@0 546 if (output_len + prefix_len > PNG_UINT_31_MAX)
michael@0 547 {
michael@0 548 ret = Z_MEM_ERROR;
michael@0 549 break;
michael@0 550 }
michael@0 551
michael@0 552 /* Need a new (malloc'ed) buffer, but there may be one present
michael@0 553 * already.
michael@0 554 */
michael@0 555 next = *end;
michael@0 556 if (next == NULL)
michael@0 557 {
michael@0 558 next = png_voidcast(png_compression_bufferp, png_malloc_base
michael@0 559 (png_ptr, PNG_COMPRESSION_BUFFER_SIZE(png_ptr)));
michael@0 560
michael@0 561 if (next == NULL)
michael@0 562 {
michael@0 563 ret = Z_MEM_ERROR;
michael@0 564 break;
michael@0 565 }
michael@0 566
michael@0 567 /* Link in this buffer (so that it will be freed later) */
michael@0 568 next->next = NULL;
michael@0 569 *end = next;
michael@0 570 }
michael@0 571
michael@0 572 png_ptr->zstream.next_out = next->output;
michael@0 573 png_ptr->zstream.avail_out = png_ptr->zbuffer_size;
michael@0 574 output_len += png_ptr->zstream.avail_out;
michael@0 575
michael@0 576 /* Move 'end' to the next buffer pointer. */
michael@0 577 end = &next->next;
michael@0 578 }
michael@0 579
michael@0 580 /* Compress the data */
michael@0 581 ret = deflate(&png_ptr->zstream,
michael@0 582 input_len > 0 ? Z_NO_FLUSH : Z_FINISH);
michael@0 583
michael@0 584 /* Claw back input data that was not consumed (because avail_in is
michael@0 585 * reset above every time round the loop).
michael@0 586 */
michael@0 587 input_len += png_ptr->zstream.avail_in;
michael@0 588 png_ptr->zstream.avail_in = 0; /* safety */
michael@0 589 }
michael@0 590 while (ret == Z_OK);
michael@0 591
michael@0 592 /* There may be some space left in the last output buffer, this needs to
michael@0 593 * be subtracted from output_len.
michael@0 594 */
michael@0 595 output_len -= png_ptr->zstream.avail_out;
michael@0 596 png_ptr->zstream.avail_out = 0; /* safety */
michael@0 597 comp->output_len = output_len;
michael@0 598
michael@0 599 /* Now double check the output length, put in a custom message if it is
michael@0 600 * too long. Otherwise ensure the z_stream::msg pointer is set to
michael@0 601 * something.
michael@0 602 */
michael@0 603 if (output_len + prefix_len >= PNG_UINT_31_MAX)
michael@0 604 {
michael@0 605 png_ptr->zstream.msg = PNGZ_MSG_CAST("compressed data too long");
michael@0 606 ret = Z_MEM_ERROR;
michael@0 607 }
michael@0 608
michael@0 609 else
michael@0 610 png_zstream_error(png_ptr, ret);
michael@0 611
michael@0 612 /* Reset zlib for another zTXt/iTXt or image data */
michael@0 613 png_ptr->zowner = 0;
michael@0 614
michael@0 615 /* The only success case is Z_STREAM_END, input_len must be 0, if not this
michael@0 616 * is an internal error.
michael@0 617 */
michael@0 618 if (ret == Z_STREAM_END && input_len == 0)
michael@0 619 {
michael@0 620 /* Fix up the deflate header, if required */
michael@0 621 optimize_cmf(comp->output, comp->input_len);
michael@0 622
michael@0 623 /* But Z_OK is returned, not Z_STREAM_END; this allows the claim
michael@0 624 * function above to return Z_STREAM_END on an error (though it never
michael@0 625 * does in the current versions of zlib.)
michael@0 626 */
michael@0 627 return Z_OK;
michael@0 628 }
michael@0 629
michael@0 630 else
michael@0 631 return ret;
michael@0 632 }
michael@0 633 }
michael@0 634
michael@0 635 /* Ship the compressed text out via chunk writes */
michael@0 636 static void
michael@0 637 png_write_compressed_data_out(png_structrp png_ptr, compression_state *comp)
michael@0 638 {
michael@0 639 png_uint_32 output_len = comp->output_len;
michael@0 640 png_const_bytep output = comp->output;
michael@0 641 png_uint_32 avail = (sizeof comp->output);
michael@0 642 png_compression_buffer *next = png_ptr->zbuffer_list;
michael@0 643
michael@0 644 for (;;)
michael@0 645 {
michael@0 646 if (avail > output_len)
michael@0 647 avail = output_len;
michael@0 648
michael@0 649 png_write_chunk_data(png_ptr, output, avail);
michael@0 650
michael@0 651 output_len -= avail;
michael@0 652
michael@0 653 if (output_len == 0 || next == NULL)
michael@0 654 break;
michael@0 655
michael@0 656 avail = png_ptr->zbuffer_size;
michael@0 657 output = next->output;
michael@0 658 next = next->next;
michael@0 659 }
michael@0 660
michael@0 661 /* This is an internal error; 'next' must have been NULL! */
michael@0 662 if (output_len > 0)
michael@0 663 png_error(png_ptr, "error writing ancillary chunked compressed data");
michael@0 664 }
michael@0 665 #endif /* PNG_WRITE_COMPRESSED_TEXT_SUPPORTED */
michael@0 666
michael@0 667 #if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_pCAL_SUPPORTED) || \
michael@0 668 defined(PNG_WRITE_iCCP_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED)
michael@0 669 /* Check that the tEXt or zTXt keyword is valid per PNG 1.0 specification,
michael@0 670 * and if invalid, correct the keyword rather than discarding the entire
michael@0 671 * chunk. The PNG 1.0 specification requires keywords 1-79 characters in
michael@0 672 * length, forbids leading or trailing whitespace, multiple internal spaces,
michael@0 673 * and the non-break space (0x80) from ISO 8859-1. Returns keyword length.
michael@0 674 *
michael@0 675 * The 'new_key' buffer must be 80 characters in size (for the keyword plus a
michael@0 676 * trailing '\0'). If this routine returns 0 then there was no keyword, or a
michael@0 677 * valid one could not be generated, and the caller must png_error.
michael@0 678 */
michael@0 679 static png_uint_32
michael@0 680 png_check_keyword(png_structrp png_ptr, png_const_charp key, png_bytep new_key)
michael@0 681 {
michael@0 682 png_const_charp orig_key = key;
michael@0 683 png_uint_32 key_len = 0;
michael@0 684 int bad_character = 0;
michael@0 685 int space = 1;
michael@0 686
michael@0 687 png_debug(1, "in png_check_keyword");
michael@0 688
michael@0 689 if (key == NULL)
michael@0 690 {
michael@0 691 *new_key = 0;
michael@0 692 return 0;
michael@0 693 }
michael@0 694
michael@0 695 while (*key && key_len < 79)
michael@0 696 {
michael@0 697 png_byte ch = (png_byte)(0xff & *key++);
michael@0 698
michael@0 699 if ((ch > 32 && ch <= 126) || (ch >= 161 /*&& ch <= 255*/))
michael@0 700 *new_key++ = ch, ++key_len, space = 0;
michael@0 701
michael@0 702 else if (!space)
michael@0 703 {
michael@0 704 /* A space or an invalid character when one wasn't seen immediately
michael@0 705 * before; output just a space.
michael@0 706 */
michael@0 707 *new_key++ = 32, ++key_len, space = 1;
michael@0 708
michael@0 709 /* If the character was not a space then it is invalid. */
michael@0 710 if (ch != 32)
michael@0 711 bad_character = ch;
michael@0 712 }
michael@0 713
michael@0 714 else if (!bad_character)
michael@0 715 bad_character = ch; /* just skip it, record the first error */
michael@0 716 }
michael@0 717
michael@0 718 if (key_len > 0 && space) /* trailing space */
michael@0 719 {
michael@0 720 --key_len, --new_key;
michael@0 721 if (!bad_character)
michael@0 722 bad_character = 32;
michael@0 723 }
michael@0 724
michael@0 725 /* Terminate the keyword */
michael@0 726 *new_key = 0;
michael@0 727
michael@0 728 if (key_len == 0)
michael@0 729 return 0;
michael@0 730
michael@0 731 /* Try to only output one warning per keyword: */
michael@0 732 if (*key) /* keyword too long */
michael@0 733 png_warning(png_ptr, "keyword truncated");
michael@0 734
michael@0 735 else if (bad_character)
michael@0 736 {
michael@0 737 PNG_WARNING_PARAMETERS(p)
michael@0 738
michael@0 739 png_warning_parameter(p, 1, orig_key);
michael@0 740 png_warning_parameter_signed(p, 2, PNG_NUMBER_FORMAT_02x, bad_character);
michael@0 741
michael@0 742 png_formatted_warning(png_ptr, p, "keyword \"@1\": bad character '0x@2'");
michael@0 743 }
michael@0 744
michael@0 745 return key_len;
michael@0 746 }
michael@0 747 #endif
michael@0 748
michael@0 749 /* Write the IHDR chunk, and update the png_struct with the necessary
michael@0 750 * information. Note that the rest of this code depends upon this
michael@0 751 * information being correct.
michael@0 752 */
michael@0 753 void /* PRIVATE */
michael@0 754 png_write_IHDR(png_structrp png_ptr, png_uint_32 width, png_uint_32 height,
michael@0 755 int bit_depth, int color_type, int compression_type, int filter_type,
michael@0 756 int interlace_type)
michael@0 757 {
michael@0 758 png_byte buf[13]; /* Buffer to store the IHDR info */
michael@0 759
michael@0 760 png_debug(1, "in png_write_IHDR");
michael@0 761
michael@0 762 /* Check that we have valid input data from the application info */
michael@0 763 switch (color_type)
michael@0 764 {
michael@0 765 case PNG_COLOR_TYPE_GRAY:
michael@0 766 switch (bit_depth)
michael@0 767 {
michael@0 768 case 1:
michael@0 769 case 2:
michael@0 770 case 4:
michael@0 771 case 8:
michael@0 772 #ifdef PNG_WRITE_16BIT_SUPPORTED
michael@0 773 case 16:
michael@0 774 #endif
michael@0 775 png_ptr->channels = 1; break;
michael@0 776
michael@0 777 default:
michael@0 778 png_error(png_ptr,
michael@0 779 "Invalid bit depth for grayscale image");
michael@0 780 }
michael@0 781 break;
michael@0 782
michael@0 783 case PNG_COLOR_TYPE_RGB:
michael@0 784 #ifdef PNG_WRITE_16BIT_SUPPORTED
michael@0 785 if (bit_depth != 8 && bit_depth != 16)
michael@0 786 #else
michael@0 787 if (bit_depth != 8)
michael@0 788 #endif
michael@0 789 png_error(png_ptr, "Invalid bit depth for RGB image");
michael@0 790
michael@0 791 png_ptr->channels = 3;
michael@0 792 break;
michael@0 793
michael@0 794 case PNG_COLOR_TYPE_PALETTE:
michael@0 795 switch (bit_depth)
michael@0 796 {
michael@0 797 case 1:
michael@0 798 case 2:
michael@0 799 case 4:
michael@0 800 case 8:
michael@0 801 png_ptr->channels = 1;
michael@0 802 break;
michael@0 803
michael@0 804 default:
michael@0 805 png_error(png_ptr, "Invalid bit depth for paletted image");
michael@0 806 }
michael@0 807 break;
michael@0 808
michael@0 809 case PNG_COLOR_TYPE_GRAY_ALPHA:
michael@0 810 if (bit_depth != 8 && bit_depth != 16)
michael@0 811 png_error(png_ptr, "Invalid bit depth for grayscale+alpha image");
michael@0 812
michael@0 813 png_ptr->channels = 2;
michael@0 814 break;
michael@0 815
michael@0 816 case PNG_COLOR_TYPE_RGB_ALPHA:
michael@0 817 #ifdef PNG_WRITE_16BIT_SUPPORTED
michael@0 818 if (bit_depth != 8 && bit_depth != 16)
michael@0 819 #else
michael@0 820 if (bit_depth != 8)
michael@0 821 #endif
michael@0 822 png_error(png_ptr, "Invalid bit depth for RGBA image");
michael@0 823
michael@0 824 png_ptr->channels = 4;
michael@0 825 break;
michael@0 826
michael@0 827 default:
michael@0 828 png_error(png_ptr, "Invalid image color type specified");
michael@0 829 }
michael@0 830
michael@0 831 if (compression_type != PNG_COMPRESSION_TYPE_BASE)
michael@0 832 {
michael@0 833 png_warning(png_ptr, "Invalid compression type specified");
michael@0 834 compression_type = PNG_COMPRESSION_TYPE_BASE;
michael@0 835 }
michael@0 836
michael@0 837 /* Write filter_method 64 (intrapixel differencing) only if
michael@0 838 * 1. Libpng was compiled with PNG_MNG_FEATURES_SUPPORTED and
michael@0 839 * 2. Libpng did not write a PNG signature (this filter_method is only
michael@0 840 * used in PNG datastreams that are embedded in MNG datastreams) and
michael@0 841 * 3. The application called png_permit_mng_features with a mask that
michael@0 842 * included PNG_FLAG_MNG_FILTER_64 and
michael@0 843 * 4. The filter_method is 64 and
michael@0 844 * 5. The color_type is RGB or RGBA
michael@0 845 */
michael@0 846 if (
michael@0 847 #ifdef PNG_MNG_FEATURES_SUPPORTED
michael@0 848 !((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) &&
michael@0 849 ((png_ptr->mode&PNG_HAVE_PNG_SIGNATURE) == 0) &&
michael@0 850 (color_type == PNG_COLOR_TYPE_RGB ||
michael@0 851 color_type == PNG_COLOR_TYPE_RGB_ALPHA) &&
michael@0 852 (filter_type == PNG_INTRAPIXEL_DIFFERENCING)) &&
michael@0 853 #endif
michael@0 854 filter_type != PNG_FILTER_TYPE_BASE)
michael@0 855 {
michael@0 856 png_warning(png_ptr, "Invalid filter type specified");
michael@0 857 filter_type = PNG_FILTER_TYPE_BASE;
michael@0 858 }
michael@0 859
michael@0 860 #ifdef PNG_WRITE_INTERLACING_SUPPORTED
michael@0 861 if (interlace_type != PNG_INTERLACE_NONE &&
michael@0 862 interlace_type != PNG_INTERLACE_ADAM7)
michael@0 863 {
michael@0 864 png_warning(png_ptr, "Invalid interlace type specified");
michael@0 865 interlace_type = PNG_INTERLACE_ADAM7;
michael@0 866 }
michael@0 867 #else
michael@0 868 interlace_type=PNG_INTERLACE_NONE;
michael@0 869 #endif
michael@0 870
michael@0 871 /* Save the relevent information */
michael@0 872 png_ptr->bit_depth = (png_byte)bit_depth;
michael@0 873 png_ptr->color_type = (png_byte)color_type;
michael@0 874 png_ptr->interlaced = (png_byte)interlace_type;
michael@0 875 #ifdef PNG_MNG_FEATURES_SUPPORTED
michael@0 876 png_ptr->filter_type = (png_byte)filter_type;
michael@0 877 #endif
michael@0 878 png_ptr->compression_type = (png_byte)compression_type;
michael@0 879 png_ptr->width = width;
michael@0 880 png_ptr->height = height;
michael@0 881
michael@0 882 png_ptr->pixel_depth = (png_byte)(bit_depth * png_ptr->channels);
michael@0 883 png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth, width);
michael@0 884 /* Set the usr info, so any transformations can modify it */
michael@0 885 png_ptr->usr_width = png_ptr->width;
michael@0 886 png_ptr->usr_bit_depth = png_ptr->bit_depth;
michael@0 887 png_ptr->usr_channels = png_ptr->channels;
michael@0 888
michael@0 889 /* Pack the header information into the buffer */
michael@0 890 png_save_uint_32(buf, width);
michael@0 891 png_save_uint_32(buf + 4, height);
michael@0 892 buf[8] = (png_byte)bit_depth;
michael@0 893 buf[9] = (png_byte)color_type;
michael@0 894 buf[10] = (png_byte)compression_type;
michael@0 895 buf[11] = (png_byte)filter_type;
michael@0 896 buf[12] = (png_byte)interlace_type;
michael@0 897
michael@0 898 /* Write the chunk */
michael@0 899 png_write_complete_chunk(png_ptr, png_IHDR, buf, (png_size_t)13);
michael@0 900
michael@0 901 #ifdef PNG_WRITE_APNG_SUPPORTED
michael@0 902 png_ptr->first_frame_width = width;
michael@0 903 png_ptr->first_frame_height = height;
michael@0 904 #endif
michael@0 905
michael@0 906 if (!(png_ptr->do_filter))
michael@0 907 {
michael@0 908 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE ||
michael@0 909 png_ptr->bit_depth < 8)
michael@0 910 png_ptr->do_filter = PNG_FILTER_NONE;
michael@0 911
michael@0 912 else
michael@0 913 png_ptr->do_filter = PNG_ALL_FILTERS;
michael@0 914 }
michael@0 915
michael@0 916 png_ptr->mode = PNG_HAVE_IHDR; /* not READY_FOR_ZTXT */
michael@0 917 }
michael@0 918
michael@0 919 /* Write the palette. We are careful not to trust png_color to be in the
michael@0 920 * correct order for PNG, so people can redefine it to any convenient
michael@0 921 * structure.
michael@0 922 */
michael@0 923 void /* PRIVATE */
michael@0 924 png_write_PLTE(png_structrp png_ptr, png_const_colorp palette,
michael@0 925 png_uint_32 num_pal)
michael@0 926 {
michael@0 927 png_uint_32 i;
michael@0 928 png_const_colorp pal_ptr;
michael@0 929 png_byte buf[3];
michael@0 930
michael@0 931 png_debug(1, "in png_write_PLTE");
michael@0 932
michael@0 933 if ((
michael@0 934 #ifdef PNG_MNG_FEATURES_SUPPORTED
michael@0 935 !(png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE) &&
michael@0 936 #endif
michael@0 937 num_pal == 0) || num_pal > 256)
michael@0 938 {
michael@0 939 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
michael@0 940 {
michael@0 941 png_error(png_ptr, "Invalid number of colors in palette");
michael@0 942 }
michael@0 943
michael@0 944 else
michael@0 945 {
michael@0 946 png_warning(png_ptr, "Invalid number of colors in palette");
michael@0 947 return;
michael@0 948 }
michael@0 949 }
michael@0 950
michael@0 951 if (!(png_ptr->color_type&PNG_COLOR_MASK_COLOR))
michael@0 952 {
michael@0 953 png_warning(png_ptr,
michael@0 954 "Ignoring request to write a PLTE chunk in grayscale PNG");
michael@0 955
michael@0 956 return;
michael@0 957 }
michael@0 958
michael@0 959 png_ptr->num_palette = (png_uint_16)num_pal;
michael@0 960 png_debug1(3, "num_palette = %d", png_ptr->num_palette);
michael@0 961
michael@0 962 png_write_chunk_header(png_ptr, png_PLTE, (png_uint_32)(num_pal * 3));
michael@0 963 #ifdef PNG_POINTER_INDEXING_SUPPORTED
michael@0 964
michael@0 965 for (i = 0, pal_ptr = palette; i < num_pal; i++, pal_ptr++)
michael@0 966 {
michael@0 967 buf[0] = pal_ptr->red;
michael@0 968 buf[1] = pal_ptr->green;
michael@0 969 buf[2] = pal_ptr->blue;
michael@0 970 png_write_chunk_data(png_ptr, buf, (png_size_t)3);
michael@0 971 }
michael@0 972
michael@0 973 #else
michael@0 974 /* This is a little slower but some buggy compilers need to do this
michael@0 975 * instead
michael@0 976 */
michael@0 977 pal_ptr=palette;
michael@0 978
michael@0 979 for (i = 0; i < num_pal; i++)
michael@0 980 {
michael@0 981 buf[0] = pal_ptr[i].red;
michael@0 982 buf[1] = pal_ptr[i].green;
michael@0 983 buf[2] = pal_ptr[i].blue;
michael@0 984 png_write_chunk_data(png_ptr, buf, (png_size_t)3);
michael@0 985 }
michael@0 986
michael@0 987 #endif
michael@0 988 png_write_chunk_end(png_ptr);
michael@0 989 png_ptr->mode |= PNG_HAVE_PLTE;
michael@0 990 }
michael@0 991
michael@0 992 /* This is similar to png_text_compress, above, except that it does not require
michael@0 993 * all of the data at once and, instead of buffering the compressed result,
michael@0 994 * writes it as IDAT chunks. Unlike png_text_compress it *can* png_error out
michael@0 995 * because it calls the write interface. As a result it does its own error
michael@0 996 * reporting and does not return an error code. In the event of error it will
michael@0 997 * just call png_error. The input data length may exceed 32-bits. The 'flush'
michael@0 998 * parameter is exactly the same as that to deflate, with the following
michael@0 999 * meanings:
michael@0 1000 *
michael@0 1001 * Z_NO_FLUSH: normal incremental output of compressed data
michael@0 1002 * Z_SYNC_FLUSH: do a SYNC_FLUSH, used by png_write_flush
michael@0 1003 * Z_FINISH: this is the end of the input, do a Z_FINISH and clean up
michael@0 1004 *
michael@0 1005 * The routine manages the acquire and release of the png_ptr->zstream by
michael@0 1006 * checking and (at the end) clearing png_ptr->zowner, it does some sanity
michael@0 1007 * checks on the 'mode' flags while doing this.
michael@0 1008 */
michael@0 1009 void /* PRIVATE */
michael@0 1010 png_compress_IDAT(png_structrp png_ptr, png_const_bytep input,
michael@0 1011 png_alloc_size_t input_len, int flush)
michael@0 1012 {
michael@0 1013 if (png_ptr->zowner != png_IDAT)
michael@0 1014 {
michael@0 1015 /* First time. Ensure we have a temporary buffer for compression and
michael@0 1016 * trim the buffer list if it has more than one entry to free memory.
michael@0 1017 * If 'WRITE_COMPRESSED_TEXT' is not set the list will never have been
michael@0 1018 * created at this point, but the check here is quick and safe.
michael@0 1019 */
michael@0 1020 if (png_ptr->zbuffer_list == NULL)
michael@0 1021 {
michael@0 1022 png_ptr->zbuffer_list = png_voidcast(png_compression_bufferp,
michael@0 1023 png_malloc(png_ptr, PNG_COMPRESSION_BUFFER_SIZE(png_ptr)));
michael@0 1024 png_ptr->zbuffer_list->next = NULL;
michael@0 1025 }
michael@0 1026
michael@0 1027 else
michael@0 1028 png_free_buffer_list(png_ptr, &png_ptr->zbuffer_list->next);
michael@0 1029
michael@0 1030 /* It is a terminal error if we can't claim the zstream. */
michael@0 1031 if (png_deflate_claim(png_ptr, png_IDAT, png_image_size(png_ptr)) != Z_OK)
michael@0 1032 png_error(png_ptr, png_ptr->zstream.msg);
michael@0 1033
michael@0 1034 /* The output state is maintained in png_ptr->zstream, so it must be
michael@0 1035 * initialized here after the claim.
michael@0 1036 */
michael@0 1037 png_ptr->zstream.next_out = png_ptr->zbuffer_list->output;
michael@0 1038 png_ptr->zstream.avail_out = png_ptr->zbuffer_size;
michael@0 1039 }
michael@0 1040
michael@0 1041 /* Now loop reading and writing until all the input is consumed or an error
michael@0 1042 * terminates the operation. The _out values are maintained across calls to
michael@0 1043 * this function, but the input must be reset each time.
michael@0 1044 */
michael@0 1045 png_ptr->zstream.next_in = PNGZ_INPUT_CAST(input);
michael@0 1046 png_ptr->zstream.avail_in = 0; /* set below */
michael@0 1047 for (;;)
michael@0 1048 {
michael@0 1049 int ret;
michael@0 1050
michael@0 1051 /* INPUT: from the row data */
michael@0 1052 uInt avail = ZLIB_IO_MAX;
michael@0 1053
michael@0 1054 if (avail > input_len)
michael@0 1055 avail = (uInt)input_len; /* safe because of the check */
michael@0 1056
michael@0 1057 png_ptr->zstream.avail_in = avail;
michael@0 1058 input_len -= avail;
michael@0 1059
michael@0 1060 ret = deflate(&png_ptr->zstream, input_len > 0 ? Z_NO_FLUSH : flush);
michael@0 1061
michael@0 1062 /* Include as-yet unconsumed input */
michael@0 1063 input_len += png_ptr->zstream.avail_in;
michael@0 1064 png_ptr->zstream.avail_in = 0;
michael@0 1065
michael@0 1066 /* OUTPUT: write complete IDAT chunks when avail_out drops to zero, note
michael@0 1067 * that these two zstream fields are preserved across the calls, therefore
michael@0 1068 * there is no need to set these up on entry to the loop.
michael@0 1069 */
michael@0 1070 if (png_ptr->zstream.avail_out == 0)
michael@0 1071 {
michael@0 1072 png_bytep data = png_ptr->zbuffer_list->output;
michael@0 1073 uInt size = png_ptr->zbuffer_size;
michael@0 1074
michael@0 1075 /* Write an IDAT containing the data then reset the buffer. The
michael@0 1076 * first IDAT may need deflate header optimization.
michael@0 1077 */
michael@0 1078 # ifdef PNG_WRITE_OPTIMIZE_CMF_SUPPORTED
michael@0 1079 if (!(png_ptr->mode & PNG_HAVE_IDAT) &&
michael@0 1080 png_ptr->compression_type == PNG_COMPRESSION_TYPE_BASE)
michael@0 1081 optimize_cmf(data, png_image_size(png_ptr));
michael@0 1082 # endif
michael@0 1083
michael@0 1084 # ifdef PNG_WRITE_APNG_SUPPORTED
michael@0 1085 if (png_ptr->num_frames_written == 0)
michael@0 1086 # endif
michael@0 1087 png_write_complete_chunk(png_ptr, png_IDAT, data, size);
michael@0 1088 # ifdef PNG_WRITE_APNG_SUPPORTED
michael@0 1089 else
michael@0 1090 png_write_fdAT(png_ptr, data, size);
michael@0 1091 # endif /* PNG_WRITE_APNG_SUPPORTED */
michael@0 1092
michael@0 1093 png_ptr->mode |= PNG_HAVE_IDAT;
michael@0 1094
michael@0 1095 png_ptr->zstream.next_out = data;
michael@0 1096 png_ptr->zstream.avail_out = size;
michael@0 1097
michael@0 1098 /* For SYNC_FLUSH or FINISH it is essential to keep calling zlib with
michael@0 1099 * the same flush parameter until it has finished output, for NO_FLUSH
michael@0 1100 * it doesn't matter.
michael@0 1101 */
michael@0 1102 if (ret == Z_OK && flush != Z_NO_FLUSH)
michael@0 1103 continue;
michael@0 1104 }
michael@0 1105
michael@0 1106 /* The order of these checks doesn't matter much; it just effect which
michael@0 1107 * possible error might be detected if multiple things go wrong at once.
michael@0 1108 */
michael@0 1109 if (ret == Z_OK) /* most likely return code! */
michael@0 1110 {
michael@0 1111 /* If all the input has been consumed then just return. If Z_FINISH
michael@0 1112 * was used as the flush parameter something has gone wrong if we get
michael@0 1113 * here.
michael@0 1114 */
michael@0 1115 if (input_len == 0)
michael@0 1116 {
michael@0 1117 if (flush == Z_FINISH)
michael@0 1118 png_error(png_ptr, "Z_OK on Z_FINISH with output space");
michael@0 1119
michael@0 1120 return;
michael@0 1121 }
michael@0 1122 }
michael@0 1123
michael@0 1124 else if (ret == Z_STREAM_END && flush == Z_FINISH)
michael@0 1125 {
michael@0 1126 /* This is the end of the IDAT data; any pending output must be
michael@0 1127 * flushed. For small PNG files we may still be at the beginning.
michael@0 1128 */
michael@0 1129 png_bytep data = png_ptr->zbuffer_list->output;
michael@0 1130 uInt size = png_ptr->zbuffer_size - png_ptr->zstream.avail_out;
michael@0 1131
michael@0 1132 # ifdef PNG_WRITE_OPTIMIZE_CMF_SUPPORTED
michael@0 1133 if (!(png_ptr->mode & PNG_HAVE_IDAT) &&
michael@0 1134 png_ptr->compression_type == PNG_COMPRESSION_TYPE_BASE)
michael@0 1135 optimize_cmf(data, png_image_size(png_ptr));
michael@0 1136 # endif
michael@0 1137
michael@0 1138 # ifdef PNG_WRITE_APNG_SUPPORTED
michael@0 1139 if (png_ptr->num_frames_written == 0)
michael@0 1140 # endif
michael@0 1141 png_write_complete_chunk(png_ptr, png_IDAT, data, size);
michael@0 1142 # ifdef PNG_WRITE_APNG_SUPPORTED
michael@0 1143 else
michael@0 1144 png_write_fdAT(png_ptr, data, size);
michael@0 1145 # endif /* PNG_WRITE_APNG_SUPPORTED */
michael@0 1146
michael@0 1147 png_ptr->zstream.avail_out = 0;
michael@0 1148 png_ptr->zstream.next_out = NULL;
michael@0 1149 png_ptr->mode |= PNG_HAVE_IDAT | PNG_AFTER_IDAT;
michael@0 1150
michael@0 1151 png_ptr->zowner = 0; /* Release the stream */
michael@0 1152 return;
michael@0 1153 }
michael@0 1154
michael@0 1155 else
michael@0 1156 {
michael@0 1157 /* This is an error condition. */
michael@0 1158 png_zstream_error(png_ptr, ret);
michael@0 1159 png_error(png_ptr, png_ptr->zstream.msg);
michael@0 1160 }
michael@0 1161 }
michael@0 1162 }
michael@0 1163
michael@0 1164 /* Write an IEND chunk */
michael@0 1165 void /* PRIVATE */
michael@0 1166 png_write_IEND(png_structrp png_ptr)
michael@0 1167 {
michael@0 1168 png_debug(1, "in png_write_IEND");
michael@0 1169
michael@0 1170 png_write_complete_chunk(png_ptr, png_IEND, NULL, (png_size_t)0);
michael@0 1171 png_ptr->mode |= PNG_HAVE_IEND;
michael@0 1172 }
michael@0 1173
michael@0 1174 #ifdef PNG_WRITE_gAMA_SUPPORTED
michael@0 1175 /* Write a gAMA chunk */
michael@0 1176 void /* PRIVATE */
michael@0 1177 png_write_gAMA_fixed(png_structrp png_ptr, png_fixed_point file_gamma)
michael@0 1178 {
michael@0 1179 png_byte buf[4];
michael@0 1180
michael@0 1181 png_debug(1, "in png_write_gAMA");
michael@0 1182
michael@0 1183 /* file_gamma is saved in 1/100,000ths */
michael@0 1184 png_save_uint_32(buf, (png_uint_32)file_gamma);
michael@0 1185 png_write_complete_chunk(png_ptr, png_gAMA, buf, (png_size_t)4);
michael@0 1186 }
michael@0 1187 #endif
michael@0 1188
michael@0 1189 #ifdef PNG_WRITE_sRGB_SUPPORTED
michael@0 1190 /* Write a sRGB chunk */
michael@0 1191 void /* PRIVATE */
michael@0 1192 png_write_sRGB(png_structrp png_ptr, int srgb_intent)
michael@0 1193 {
michael@0 1194 png_byte buf[1];
michael@0 1195
michael@0 1196 png_debug(1, "in png_write_sRGB");
michael@0 1197
michael@0 1198 if (srgb_intent >= PNG_sRGB_INTENT_LAST)
michael@0 1199 png_warning(png_ptr,
michael@0 1200 "Invalid sRGB rendering intent specified");
michael@0 1201
michael@0 1202 buf[0]=(png_byte)srgb_intent;
michael@0 1203 png_write_complete_chunk(png_ptr, png_sRGB, buf, (png_size_t)1);
michael@0 1204 }
michael@0 1205 #endif
michael@0 1206
michael@0 1207 #ifdef PNG_WRITE_iCCP_SUPPORTED
michael@0 1208 /* Write an iCCP chunk */
michael@0 1209 void /* PRIVATE */
michael@0 1210 png_write_iCCP(png_structrp png_ptr, png_const_charp name,
michael@0 1211 png_const_bytep profile)
michael@0 1212 {
michael@0 1213 png_uint_32 name_len;
michael@0 1214 png_uint_32 profile_len;
michael@0 1215 png_byte new_name[81]; /* 1 byte for the compression byte */
michael@0 1216 compression_state comp;
michael@0 1217
michael@0 1218 png_debug(1, "in png_write_iCCP");
michael@0 1219
michael@0 1220 /* These are all internal problems: the profile should have been checked
michael@0 1221 * before when it was stored.
michael@0 1222 */
michael@0 1223 if (profile == NULL)
michael@0 1224 png_error(png_ptr, "No profile for iCCP chunk"); /* internal error */
michael@0 1225
michael@0 1226 profile_len = png_get_uint_32(profile);
michael@0 1227
michael@0 1228 if (profile_len < 132)
michael@0 1229 png_error(png_ptr, "ICC profile too short");
michael@0 1230
michael@0 1231 if (profile_len & 0x03)
michael@0 1232 png_error(png_ptr, "ICC profile length invalid (not a multiple of 4)");
michael@0 1233
michael@0 1234 {
michael@0 1235 png_uint_32 embedded_profile_len = png_get_uint_32(profile);
michael@0 1236
michael@0 1237 if (profile_len != embedded_profile_len)
michael@0 1238 png_error(png_ptr, "Profile length does not match profile");
michael@0 1239 }
michael@0 1240
michael@0 1241 name_len = png_check_keyword(png_ptr, name, new_name);
michael@0 1242
michael@0 1243 if (name_len == 0)
michael@0 1244 png_error(png_ptr, "iCCP: invalid keyword");
michael@0 1245
michael@0 1246 new_name[++name_len] = PNG_COMPRESSION_TYPE_BASE;
michael@0 1247
michael@0 1248 /* Make sure we include the NULL after the name and the compression type */
michael@0 1249 ++name_len;
michael@0 1250
michael@0 1251 png_text_compress_init(&comp, profile, profile_len);
michael@0 1252
michael@0 1253 /* Allow for keyword terminator and compression byte */
michael@0 1254 if (png_text_compress(png_ptr, png_iCCP, &comp, name_len) != Z_OK)
michael@0 1255 png_error(png_ptr, png_ptr->zstream.msg);
michael@0 1256
michael@0 1257 png_write_chunk_header(png_ptr, png_iCCP, name_len + comp.output_len);
michael@0 1258
michael@0 1259 png_write_chunk_data(png_ptr, new_name, name_len);
michael@0 1260
michael@0 1261 png_write_compressed_data_out(png_ptr, &comp);
michael@0 1262
michael@0 1263 png_write_chunk_end(png_ptr);
michael@0 1264 }
michael@0 1265 #endif
michael@0 1266
michael@0 1267 #ifdef PNG_WRITE_sPLT_SUPPORTED
michael@0 1268 /* Write a sPLT chunk */
michael@0 1269 void /* PRIVATE */
michael@0 1270 png_write_sPLT(png_structrp png_ptr, png_const_sPLT_tp spalette)
michael@0 1271 {
michael@0 1272 png_uint_32 name_len;
michael@0 1273 png_byte new_name[80];
michael@0 1274 png_byte entrybuf[10];
michael@0 1275 png_size_t entry_size = (spalette->depth == 8 ? 6 : 10);
michael@0 1276 png_size_t palette_size = entry_size * spalette->nentries;
michael@0 1277 png_sPLT_entryp ep;
michael@0 1278 #ifndef PNG_POINTER_INDEXING_SUPPORTED
michael@0 1279 int i;
michael@0 1280 #endif
michael@0 1281
michael@0 1282 png_debug(1, "in png_write_sPLT");
michael@0 1283
michael@0 1284 name_len = png_check_keyword(png_ptr, spalette->name, new_name);
michael@0 1285
michael@0 1286 if (name_len == 0)
michael@0 1287 png_error(png_ptr, "sPLT: invalid keyword");
michael@0 1288
michael@0 1289 /* Make sure we include the NULL after the name */
michael@0 1290 png_write_chunk_header(png_ptr, png_sPLT,
michael@0 1291 (png_uint_32)(name_len + 2 + palette_size));
michael@0 1292
michael@0 1293 png_write_chunk_data(png_ptr, (png_bytep)new_name,
michael@0 1294 (png_size_t)(name_len + 1));
michael@0 1295
michael@0 1296 png_write_chunk_data(png_ptr, &spalette->depth, (png_size_t)1);
michael@0 1297
michael@0 1298 /* Loop through each palette entry, writing appropriately */
michael@0 1299 #ifdef PNG_POINTER_INDEXING_SUPPORTED
michael@0 1300 for (ep = spalette->entries; ep<spalette->entries + spalette->nentries; ep++)
michael@0 1301 {
michael@0 1302 if (spalette->depth == 8)
michael@0 1303 {
michael@0 1304 entrybuf[0] = (png_byte)ep->red;
michael@0 1305 entrybuf[1] = (png_byte)ep->green;
michael@0 1306 entrybuf[2] = (png_byte)ep->blue;
michael@0 1307 entrybuf[3] = (png_byte)ep->alpha;
michael@0 1308 png_save_uint_16(entrybuf + 4, ep->frequency);
michael@0 1309 }
michael@0 1310
michael@0 1311 else
michael@0 1312 {
michael@0 1313 png_save_uint_16(entrybuf + 0, ep->red);
michael@0 1314 png_save_uint_16(entrybuf + 2, ep->green);
michael@0 1315 png_save_uint_16(entrybuf + 4, ep->blue);
michael@0 1316 png_save_uint_16(entrybuf + 6, ep->alpha);
michael@0 1317 png_save_uint_16(entrybuf + 8, ep->frequency);
michael@0 1318 }
michael@0 1319
michael@0 1320 png_write_chunk_data(png_ptr, entrybuf, entry_size);
michael@0 1321 }
michael@0 1322 #else
michael@0 1323 ep=spalette->entries;
michael@0 1324 for (i = 0; i>spalette->nentries; i++)
michael@0 1325 {
michael@0 1326 if (spalette->depth == 8)
michael@0 1327 {
michael@0 1328 entrybuf[0] = (png_byte)ep[i].red;
michael@0 1329 entrybuf[1] = (png_byte)ep[i].green;
michael@0 1330 entrybuf[2] = (png_byte)ep[i].blue;
michael@0 1331 entrybuf[3] = (png_byte)ep[i].alpha;
michael@0 1332 png_save_uint_16(entrybuf + 4, ep[i].frequency);
michael@0 1333 }
michael@0 1334
michael@0 1335 else
michael@0 1336 {
michael@0 1337 png_save_uint_16(entrybuf + 0, ep[i].red);
michael@0 1338 png_save_uint_16(entrybuf + 2, ep[i].green);
michael@0 1339 png_save_uint_16(entrybuf + 4, ep[i].blue);
michael@0 1340 png_save_uint_16(entrybuf + 6, ep[i].alpha);
michael@0 1341 png_save_uint_16(entrybuf + 8, ep[i].frequency);
michael@0 1342 }
michael@0 1343
michael@0 1344 png_write_chunk_data(png_ptr, entrybuf, entry_size);
michael@0 1345 }
michael@0 1346 #endif
michael@0 1347
michael@0 1348 png_write_chunk_end(png_ptr);
michael@0 1349 }
michael@0 1350 #endif
michael@0 1351
michael@0 1352 #ifdef PNG_WRITE_sBIT_SUPPORTED
michael@0 1353 /* Write the sBIT chunk */
michael@0 1354 void /* PRIVATE */
michael@0 1355 png_write_sBIT(png_structrp png_ptr, png_const_color_8p sbit, int color_type)
michael@0 1356 {
michael@0 1357 png_byte buf[4];
michael@0 1358 png_size_t size;
michael@0 1359
michael@0 1360 png_debug(1, "in png_write_sBIT");
michael@0 1361
michael@0 1362 /* Make sure we don't depend upon the order of PNG_COLOR_8 */
michael@0 1363 if (color_type & PNG_COLOR_MASK_COLOR)
michael@0 1364 {
michael@0 1365 png_byte maxbits;
michael@0 1366
michael@0 1367 maxbits = (png_byte)(color_type==PNG_COLOR_TYPE_PALETTE ? 8 :
michael@0 1368 png_ptr->usr_bit_depth);
michael@0 1369
michael@0 1370 if (sbit->red == 0 || sbit->red > maxbits ||
michael@0 1371 sbit->green == 0 || sbit->green > maxbits ||
michael@0 1372 sbit->blue == 0 || sbit->blue > maxbits)
michael@0 1373 {
michael@0 1374 png_warning(png_ptr, "Invalid sBIT depth specified");
michael@0 1375 return;
michael@0 1376 }
michael@0 1377
michael@0 1378 buf[0] = sbit->red;
michael@0 1379 buf[1] = sbit->green;
michael@0 1380 buf[2] = sbit->blue;
michael@0 1381 size = 3;
michael@0 1382 }
michael@0 1383
michael@0 1384 else
michael@0 1385 {
michael@0 1386 if (sbit->gray == 0 || sbit->gray > png_ptr->usr_bit_depth)
michael@0 1387 {
michael@0 1388 png_warning(png_ptr, "Invalid sBIT depth specified");
michael@0 1389 return;
michael@0 1390 }
michael@0 1391
michael@0 1392 buf[0] = sbit->gray;
michael@0 1393 size = 1;
michael@0 1394 }
michael@0 1395
michael@0 1396 if (color_type & PNG_COLOR_MASK_ALPHA)
michael@0 1397 {
michael@0 1398 if (sbit->alpha == 0 || sbit->alpha > png_ptr->usr_bit_depth)
michael@0 1399 {
michael@0 1400 png_warning(png_ptr, "Invalid sBIT depth specified");
michael@0 1401 return;
michael@0 1402 }
michael@0 1403
michael@0 1404 buf[size++] = sbit->alpha;
michael@0 1405 }
michael@0 1406
michael@0 1407 png_write_complete_chunk(png_ptr, png_sBIT, buf, size);
michael@0 1408 }
michael@0 1409 #endif
michael@0 1410
michael@0 1411 #ifdef PNG_WRITE_cHRM_SUPPORTED
michael@0 1412 /* Write the cHRM chunk */
michael@0 1413 void /* PRIVATE */
michael@0 1414 png_write_cHRM_fixed(png_structrp png_ptr, const png_xy *xy)
michael@0 1415 {
michael@0 1416 png_byte buf[32];
michael@0 1417
michael@0 1418 png_debug(1, "in png_write_cHRM");
michael@0 1419
michael@0 1420 /* Each value is saved in 1/100,000ths */
michael@0 1421 png_save_int_32(buf, xy->whitex);
michael@0 1422 png_save_int_32(buf + 4, xy->whitey);
michael@0 1423
michael@0 1424 png_save_int_32(buf + 8, xy->redx);
michael@0 1425 png_save_int_32(buf + 12, xy->redy);
michael@0 1426
michael@0 1427 png_save_int_32(buf + 16, xy->greenx);
michael@0 1428 png_save_int_32(buf + 20, xy->greeny);
michael@0 1429
michael@0 1430 png_save_int_32(buf + 24, xy->bluex);
michael@0 1431 png_save_int_32(buf + 28, xy->bluey);
michael@0 1432
michael@0 1433 png_write_complete_chunk(png_ptr, png_cHRM, buf, 32);
michael@0 1434 }
michael@0 1435 #endif
michael@0 1436
michael@0 1437 #ifdef PNG_WRITE_tRNS_SUPPORTED
michael@0 1438 /* Write the tRNS chunk */
michael@0 1439 void /* PRIVATE */
michael@0 1440 png_write_tRNS(png_structrp png_ptr, png_const_bytep trans_alpha,
michael@0 1441 png_const_color_16p tran, int num_trans, int color_type)
michael@0 1442 {
michael@0 1443 png_byte buf[6];
michael@0 1444
michael@0 1445 png_debug(1, "in png_write_tRNS");
michael@0 1446
michael@0 1447 if (color_type == PNG_COLOR_TYPE_PALETTE)
michael@0 1448 {
michael@0 1449 if (num_trans <= 0 || num_trans > (int)png_ptr->num_palette)
michael@0 1450 {
michael@0 1451 png_app_warning(png_ptr,
michael@0 1452 "Invalid number of transparent colors specified");
michael@0 1453 return;
michael@0 1454 }
michael@0 1455
michael@0 1456 /* Write the chunk out as it is */
michael@0 1457 png_write_complete_chunk(png_ptr, png_tRNS, trans_alpha,
michael@0 1458 (png_size_t)num_trans);
michael@0 1459 }
michael@0 1460
michael@0 1461 else if (color_type == PNG_COLOR_TYPE_GRAY)
michael@0 1462 {
michael@0 1463 /* One 16 bit value */
michael@0 1464 if (tran->gray >= (1 << png_ptr->bit_depth))
michael@0 1465 {
michael@0 1466 png_app_warning(png_ptr,
michael@0 1467 "Ignoring attempt to write tRNS chunk out-of-range for bit_depth");
michael@0 1468
michael@0 1469 return;
michael@0 1470 }
michael@0 1471
michael@0 1472 png_save_uint_16(buf, tran->gray);
michael@0 1473 png_write_complete_chunk(png_ptr, png_tRNS, buf, (png_size_t)2);
michael@0 1474 }
michael@0 1475
michael@0 1476 else if (color_type == PNG_COLOR_TYPE_RGB)
michael@0 1477 {
michael@0 1478 /* Three 16 bit values */
michael@0 1479 png_save_uint_16(buf, tran->red);
michael@0 1480 png_save_uint_16(buf + 2, tran->green);
michael@0 1481 png_save_uint_16(buf + 4, tran->blue);
michael@0 1482 #ifdef PNG_WRITE_16BIT_SUPPORTED
michael@0 1483 if (png_ptr->bit_depth == 8 && (buf[0] | buf[2] | buf[4]))
michael@0 1484 #else
michael@0 1485 if (buf[0] | buf[2] | buf[4])
michael@0 1486 #endif
michael@0 1487 {
michael@0 1488 png_app_warning(png_ptr,
michael@0 1489 "Ignoring attempt to write 16-bit tRNS chunk when bit_depth is 8");
michael@0 1490 return;
michael@0 1491 }
michael@0 1492
michael@0 1493 png_write_complete_chunk(png_ptr, png_tRNS, buf, (png_size_t)6);
michael@0 1494 }
michael@0 1495
michael@0 1496 else
michael@0 1497 {
michael@0 1498 png_app_warning(png_ptr, "Can't write tRNS with an alpha channel");
michael@0 1499 }
michael@0 1500 }
michael@0 1501 #endif
michael@0 1502
michael@0 1503 #ifdef PNG_WRITE_bKGD_SUPPORTED
michael@0 1504 /* Write the background chunk */
michael@0 1505 void /* PRIVATE */
michael@0 1506 png_write_bKGD(png_structrp png_ptr, png_const_color_16p back, int color_type)
michael@0 1507 {
michael@0 1508 png_byte buf[6];
michael@0 1509
michael@0 1510 png_debug(1, "in png_write_bKGD");
michael@0 1511
michael@0 1512 if (color_type == PNG_COLOR_TYPE_PALETTE)
michael@0 1513 {
michael@0 1514 if (
michael@0 1515 #ifdef PNG_MNG_FEATURES_SUPPORTED
michael@0 1516 (png_ptr->num_palette ||
michael@0 1517 (!(png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE))) &&
michael@0 1518 #endif
michael@0 1519 back->index >= png_ptr->num_palette)
michael@0 1520 {
michael@0 1521 png_warning(png_ptr, "Invalid background palette index");
michael@0 1522 return;
michael@0 1523 }
michael@0 1524
michael@0 1525 buf[0] = back->index;
michael@0 1526 png_write_complete_chunk(png_ptr, png_bKGD, buf, (png_size_t)1);
michael@0 1527 }
michael@0 1528
michael@0 1529 else if (color_type & PNG_COLOR_MASK_COLOR)
michael@0 1530 {
michael@0 1531 png_save_uint_16(buf, back->red);
michael@0 1532 png_save_uint_16(buf + 2, back->green);
michael@0 1533 png_save_uint_16(buf + 4, back->blue);
michael@0 1534 #ifdef PNG_WRITE_16BIT_SUPPORTED
michael@0 1535 if (png_ptr->bit_depth == 8 && (buf[0] | buf[2] | buf[4]))
michael@0 1536 #else
michael@0 1537 if (buf[0] | buf[2] | buf[4])
michael@0 1538 #endif
michael@0 1539 {
michael@0 1540 png_warning(png_ptr,
michael@0 1541 "Ignoring attempt to write 16-bit bKGD chunk when bit_depth is 8");
michael@0 1542
michael@0 1543 return;
michael@0 1544 }
michael@0 1545
michael@0 1546 png_write_complete_chunk(png_ptr, png_bKGD, buf, (png_size_t)6);
michael@0 1547 }
michael@0 1548
michael@0 1549 else
michael@0 1550 {
michael@0 1551 if (back->gray >= (1 << png_ptr->bit_depth))
michael@0 1552 {
michael@0 1553 png_warning(png_ptr,
michael@0 1554 "Ignoring attempt to write bKGD chunk out-of-range for bit_depth");
michael@0 1555
michael@0 1556 return;
michael@0 1557 }
michael@0 1558
michael@0 1559 png_save_uint_16(buf, back->gray);
michael@0 1560 png_write_complete_chunk(png_ptr, png_bKGD, buf, (png_size_t)2);
michael@0 1561 }
michael@0 1562 }
michael@0 1563 #endif
michael@0 1564
michael@0 1565 #ifdef PNG_WRITE_hIST_SUPPORTED
michael@0 1566 /* Write the histogram */
michael@0 1567 void /* PRIVATE */
michael@0 1568 png_write_hIST(png_structrp png_ptr, png_const_uint_16p hist, int num_hist)
michael@0 1569 {
michael@0 1570 int i;
michael@0 1571 png_byte buf[3];
michael@0 1572
michael@0 1573 png_debug(1, "in png_write_hIST");
michael@0 1574
michael@0 1575 if (num_hist > (int)png_ptr->num_palette)
michael@0 1576 {
michael@0 1577 png_debug2(3, "num_hist = %d, num_palette = %d", num_hist,
michael@0 1578 png_ptr->num_palette);
michael@0 1579
michael@0 1580 png_warning(png_ptr, "Invalid number of histogram entries specified");
michael@0 1581 return;
michael@0 1582 }
michael@0 1583
michael@0 1584 png_write_chunk_header(png_ptr, png_hIST, (png_uint_32)(num_hist * 2));
michael@0 1585
michael@0 1586 for (i = 0; i < num_hist; i++)
michael@0 1587 {
michael@0 1588 png_save_uint_16(buf, hist[i]);
michael@0 1589 png_write_chunk_data(png_ptr, buf, (png_size_t)2);
michael@0 1590 }
michael@0 1591
michael@0 1592 png_write_chunk_end(png_ptr);
michael@0 1593 }
michael@0 1594 #endif
michael@0 1595
michael@0 1596 #ifdef PNG_WRITE_tEXt_SUPPORTED
michael@0 1597 /* Write a tEXt chunk */
michael@0 1598 void /* PRIVATE */
michael@0 1599 png_write_tEXt(png_structrp png_ptr, png_const_charp key, png_const_charp text,
michael@0 1600 png_size_t text_len)
michael@0 1601 {
michael@0 1602 png_uint_32 key_len;
michael@0 1603 png_byte new_key[80];
michael@0 1604
michael@0 1605 png_debug(1, "in png_write_tEXt");
michael@0 1606
michael@0 1607 key_len = png_check_keyword(png_ptr, key, new_key);
michael@0 1608
michael@0 1609 if (key_len == 0)
michael@0 1610 png_error(png_ptr, "tEXt: invalid keyword");
michael@0 1611
michael@0 1612 if (text == NULL || *text == '\0')
michael@0 1613 text_len = 0;
michael@0 1614
michael@0 1615 else
michael@0 1616 text_len = strlen(text);
michael@0 1617
michael@0 1618 if (text_len > PNG_UINT_31_MAX - (key_len+1))
michael@0 1619 png_error(png_ptr, "tEXt: text too long");
michael@0 1620
michael@0 1621 /* Make sure we include the 0 after the key */
michael@0 1622 png_write_chunk_header(png_ptr, png_tEXt,
michael@0 1623 (png_uint_32)/*checked above*/(key_len + text_len + 1));
michael@0 1624 /*
michael@0 1625 * We leave it to the application to meet PNG-1.0 requirements on the
michael@0 1626 * contents of the text. PNG-1.0 through PNG-1.2 discourage the use of
michael@0 1627 * any non-Latin-1 characters except for NEWLINE. ISO PNG will forbid them.
michael@0 1628 * The NUL character is forbidden by PNG-1.0 through PNG-1.2 and ISO PNG.
michael@0 1629 */
michael@0 1630 png_write_chunk_data(png_ptr, new_key, key_len + 1);
michael@0 1631
michael@0 1632 if (text_len)
michael@0 1633 png_write_chunk_data(png_ptr, (png_const_bytep)text, text_len);
michael@0 1634
michael@0 1635 png_write_chunk_end(png_ptr);
michael@0 1636 }
michael@0 1637 #endif
michael@0 1638
michael@0 1639 #ifdef PNG_WRITE_zTXt_SUPPORTED
michael@0 1640 /* Write a compressed text chunk */
michael@0 1641 void /* PRIVATE */
michael@0 1642 png_write_zTXt(png_structrp png_ptr, png_const_charp key, png_const_charp text,
michael@0 1643 png_size_t text_len, int compression)
michael@0 1644 {
michael@0 1645 png_uint_32 key_len;
michael@0 1646 png_byte new_key[81];
michael@0 1647 compression_state comp;
michael@0 1648
michael@0 1649 png_debug(1, "in png_write_zTXt");
michael@0 1650 PNG_UNUSED(text_len) /* Always use strlen */
michael@0 1651
michael@0 1652 if (compression == PNG_TEXT_COMPRESSION_NONE)
michael@0 1653 {
michael@0 1654 png_write_tEXt(png_ptr, key, text, 0);
michael@0 1655 return;
michael@0 1656 }
michael@0 1657
michael@0 1658 if (compression != PNG_TEXT_COMPRESSION_zTXt)
michael@0 1659 png_error(png_ptr, "zTXt: invalid compression type");
michael@0 1660
michael@0 1661 key_len = png_check_keyword(png_ptr, key, new_key);
michael@0 1662
michael@0 1663 if (key_len == 0)
michael@0 1664 png_error(png_ptr, "zTXt: invalid keyword");
michael@0 1665
michael@0 1666 /* Add the compression method and 1 for the keyword separator. */
michael@0 1667 new_key[++key_len] = PNG_COMPRESSION_TYPE_BASE;
michael@0 1668 ++key_len;
michael@0 1669
michael@0 1670 /* Compute the compressed data; do it now for the length */
michael@0 1671 png_text_compress_init(&comp, (png_const_bytep)text,
michael@0 1672 text == NULL ? 0 : strlen(text));
michael@0 1673
michael@0 1674 if (png_text_compress(png_ptr, png_zTXt, &comp, key_len) != Z_OK)
michael@0 1675 png_error(png_ptr, png_ptr->zstream.msg);
michael@0 1676
michael@0 1677 /* Write start of chunk */
michael@0 1678 png_write_chunk_header(png_ptr, png_zTXt, key_len + comp.output_len);
michael@0 1679
michael@0 1680 /* Write key */
michael@0 1681 png_write_chunk_data(png_ptr, new_key, key_len);
michael@0 1682
michael@0 1683 /* Write the compressed data */
michael@0 1684 png_write_compressed_data_out(png_ptr, &comp);
michael@0 1685
michael@0 1686 /* Close the chunk */
michael@0 1687 png_write_chunk_end(png_ptr);
michael@0 1688 }
michael@0 1689 #endif
michael@0 1690
michael@0 1691 #ifdef PNG_WRITE_iTXt_SUPPORTED
michael@0 1692 /* Write an iTXt chunk */
michael@0 1693 void /* PRIVATE */
michael@0 1694 png_write_iTXt(png_structrp png_ptr, int compression, png_const_charp key,
michael@0 1695 png_const_charp lang, png_const_charp lang_key, png_const_charp text)
michael@0 1696 {
michael@0 1697 png_uint_32 key_len, prefix_len;
michael@0 1698 png_size_t lang_len, lang_key_len;
michael@0 1699 png_byte new_key[82];
michael@0 1700 compression_state comp;
michael@0 1701
michael@0 1702 png_debug(1, "in png_write_iTXt");
michael@0 1703
michael@0 1704 key_len = png_check_keyword(png_ptr, key, new_key);
michael@0 1705
michael@0 1706 if (key_len == 0)
michael@0 1707 png_error(png_ptr, "iTXt: invalid keyword");
michael@0 1708
michael@0 1709 /* Set the compression flag */
michael@0 1710 switch (compression)
michael@0 1711 {
michael@0 1712 case PNG_ITXT_COMPRESSION_NONE:
michael@0 1713 case PNG_TEXT_COMPRESSION_NONE:
michael@0 1714 compression = new_key[++key_len] = 0; /* no compression */
michael@0 1715 break;
michael@0 1716
michael@0 1717 case PNG_TEXT_COMPRESSION_zTXt:
michael@0 1718 case PNG_ITXT_COMPRESSION_zTXt:
michael@0 1719 compression = new_key[++key_len] = 1; /* compressed */
michael@0 1720 break;
michael@0 1721
michael@0 1722 default:
michael@0 1723 png_error(png_ptr, "iTXt: invalid compression");
michael@0 1724 }
michael@0 1725
michael@0 1726 new_key[++key_len] = PNG_COMPRESSION_TYPE_BASE;
michael@0 1727 ++key_len; /* for the keywod separator */
michael@0 1728
michael@0 1729 /* We leave it to the application to meet PNG-1.0 requirements on the
michael@0 1730 * contents of the text. PNG-1.0 through PNG-1.2 discourage the use of
michael@0 1731 * any non-Latin-1 characters except for NEWLINE. ISO PNG, however,
michael@0 1732 * specifies that the text is UTF-8 and this really doesn't require any
michael@0 1733 * checking.
michael@0 1734 *
michael@0 1735 * The NUL character is forbidden by PNG-1.0 through PNG-1.2 and ISO PNG.
michael@0 1736 *
michael@0 1737 * TODO: validate the language tag correctly (see the spec.)
michael@0 1738 */
michael@0 1739 if (lang == NULL) lang = ""; /* empty language is valid */
michael@0 1740 lang_len = strlen(lang)+1;
michael@0 1741 if (lang_key == NULL) lang_key = ""; /* may be empty */
michael@0 1742 lang_key_len = strlen(lang_key)+1;
michael@0 1743 if (text == NULL) text = ""; /* may be empty */
michael@0 1744
michael@0 1745 prefix_len = key_len;
michael@0 1746 if (lang_len > PNG_UINT_31_MAX-prefix_len)
michael@0 1747 prefix_len = PNG_UINT_31_MAX;
michael@0 1748 else
michael@0 1749 prefix_len = (png_uint_32)(prefix_len + lang_len);
michael@0 1750
michael@0 1751 if (lang_key_len > PNG_UINT_31_MAX-prefix_len)
michael@0 1752 prefix_len = PNG_UINT_31_MAX;
michael@0 1753 else
michael@0 1754 prefix_len = (png_uint_32)(prefix_len + lang_key_len);
michael@0 1755
michael@0 1756 png_text_compress_init(&comp, (png_const_bytep)text, strlen(text));
michael@0 1757
michael@0 1758 if (compression)
michael@0 1759 {
michael@0 1760 if (png_text_compress(png_ptr, png_iTXt, &comp, prefix_len) != Z_OK)
michael@0 1761 png_error(png_ptr, png_ptr->zstream.msg);
michael@0 1762 }
michael@0 1763
michael@0 1764 else
michael@0 1765 {
michael@0 1766 if (comp.input_len > PNG_UINT_31_MAX-prefix_len)
michael@0 1767 png_error(png_ptr, "iTXt: uncompressed text too long");
michael@0 1768
michael@0 1769 /* So the string will fit in a chunk: */
michael@0 1770 comp.output_len = (png_uint_32)/*SAFE*/comp.input_len;
michael@0 1771 }
michael@0 1772
michael@0 1773 png_write_chunk_header(png_ptr, png_iTXt, comp.output_len + prefix_len);
michael@0 1774
michael@0 1775 png_write_chunk_data(png_ptr, new_key, key_len);
michael@0 1776
michael@0 1777 png_write_chunk_data(png_ptr, (png_const_bytep)lang, lang_len);
michael@0 1778
michael@0 1779 png_write_chunk_data(png_ptr, (png_const_bytep)lang_key, lang_key_len);
michael@0 1780
michael@0 1781 if (compression)
michael@0 1782 png_write_compressed_data_out(png_ptr, &comp);
michael@0 1783
michael@0 1784 else
michael@0 1785 png_write_chunk_data(png_ptr, (png_const_bytep)text, comp.input_len);
michael@0 1786
michael@0 1787 png_write_chunk_end(png_ptr);
michael@0 1788 }
michael@0 1789 #endif
michael@0 1790
michael@0 1791 #ifdef PNG_WRITE_oFFs_SUPPORTED
michael@0 1792 /* Write the oFFs chunk */
michael@0 1793 void /* PRIVATE */
michael@0 1794 png_write_oFFs(png_structrp png_ptr, png_int_32 x_offset, png_int_32 y_offset,
michael@0 1795 int unit_type)
michael@0 1796 {
michael@0 1797 png_byte buf[9];
michael@0 1798
michael@0 1799 png_debug(1, "in png_write_oFFs");
michael@0 1800
michael@0 1801 if (unit_type >= PNG_OFFSET_LAST)
michael@0 1802 png_warning(png_ptr, "Unrecognized unit type for oFFs chunk");
michael@0 1803
michael@0 1804 png_save_int_32(buf, x_offset);
michael@0 1805 png_save_int_32(buf + 4, y_offset);
michael@0 1806 buf[8] = (png_byte)unit_type;
michael@0 1807
michael@0 1808 png_write_complete_chunk(png_ptr, png_oFFs, buf, (png_size_t)9);
michael@0 1809 }
michael@0 1810 #endif
michael@0 1811 #ifdef PNG_WRITE_pCAL_SUPPORTED
michael@0 1812 /* Write the pCAL chunk (described in the PNG extensions document) */
michael@0 1813 void /* PRIVATE */
michael@0 1814 png_write_pCAL(png_structrp png_ptr, png_charp purpose, png_int_32 X0,
michael@0 1815 png_int_32 X1, int type, int nparams, png_const_charp units,
michael@0 1816 png_charpp params)
michael@0 1817 {
michael@0 1818 png_uint_32 purpose_len;
michael@0 1819 png_size_t units_len, total_len;
michael@0 1820 png_size_tp params_len;
michael@0 1821 png_byte buf[10];
michael@0 1822 png_byte new_purpose[80];
michael@0 1823 int i;
michael@0 1824
michael@0 1825 png_debug1(1, "in png_write_pCAL (%d parameters)", nparams);
michael@0 1826
michael@0 1827 if (type >= PNG_EQUATION_LAST)
michael@0 1828 png_error(png_ptr, "Unrecognized equation type for pCAL chunk");
michael@0 1829
michael@0 1830 purpose_len = png_check_keyword(png_ptr, purpose, new_purpose);
michael@0 1831
michael@0 1832 if (purpose_len == 0)
michael@0 1833 png_error(png_ptr, "pCAL: invalid keyword");
michael@0 1834
michael@0 1835 ++purpose_len; /* terminator */
michael@0 1836
michael@0 1837 png_debug1(3, "pCAL purpose length = %d", (int)purpose_len);
michael@0 1838 units_len = strlen(units) + (nparams == 0 ? 0 : 1);
michael@0 1839 png_debug1(3, "pCAL units length = %d", (int)units_len);
michael@0 1840 total_len = purpose_len + units_len + 10;
michael@0 1841
michael@0 1842 params_len = (png_size_tp)png_malloc(png_ptr,
michael@0 1843 (png_alloc_size_t)(nparams * (sizeof (png_size_t))));
michael@0 1844
michael@0 1845 /* Find the length of each parameter, making sure we don't count the
michael@0 1846 * null terminator for the last parameter.
michael@0 1847 */
michael@0 1848 for (i = 0; i < nparams; i++)
michael@0 1849 {
michael@0 1850 params_len[i] = strlen(params[i]) + (i == nparams - 1 ? 0 : 1);
michael@0 1851 png_debug2(3, "pCAL parameter %d length = %lu", i,
michael@0 1852 (unsigned long)params_len[i]);
michael@0 1853 total_len += params_len[i];
michael@0 1854 }
michael@0 1855
michael@0 1856 png_debug1(3, "pCAL total length = %d", (int)total_len);
michael@0 1857 png_write_chunk_header(png_ptr, png_pCAL, (png_uint_32)total_len);
michael@0 1858 png_write_chunk_data(png_ptr, new_purpose, purpose_len);
michael@0 1859 png_save_int_32(buf, X0);
michael@0 1860 png_save_int_32(buf + 4, X1);
michael@0 1861 buf[8] = (png_byte)type;
michael@0 1862 buf[9] = (png_byte)nparams;
michael@0 1863 png_write_chunk_data(png_ptr, buf, (png_size_t)10);
michael@0 1864 png_write_chunk_data(png_ptr, (png_const_bytep)units, (png_size_t)units_len);
michael@0 1865
michael@0 1866 for (i = 0; i < nparams; i++)
michael@0 1867 {
michael@0 1868 png_write_chunk_data(png_ptr, (png_const_bytep)params[i], params_len[i]);
michael@0 1869 }
michael@0 1870
michael@0 1871 png_free(png_ptr, params_len);
michael@0 1872 png_write_chunk_end(png_ptr);
michael@0 1873 }
michael@0 1874 #endif
michael@0 1875
michael@0 1876 #ifdef PNG_WRITE_sCAL_SUPPORTED
michael@0 1877 /* Write the sCAL chunk */
michael@0 1878 void /* PRIVATE */
michael@0 1879 png_write_sCAL_s(png_structrp png_ptr, int unit, png_const_charp width,
michael@0 1880 png_const_charp height)
michael@0 1881 {
michael@0 1882 png_byte buf[64];
michael@0 1883 png_size_t wlen, hlen, total_len;
michael@0 1884
michael@0 1885 png_debug(1, "in png_write_sCAL_s");
michael@0 1886
michael@0 1887 wlen = strlen(width);
michael@0 1888 hlen = strlen(height);
michael@0 1889 total_len = wlen + hlen + 2;
michael@0 1890
michael@0 1891 if (total_len > 64)
michael@0 1892 {
michael@0 1893 png_warning(png_ptr, "Can't write sCAL (buffer too small)");
michael@0 1894 return;
michael@0 1895 }
michael@0 1896
michael@0 1897 buf[0] = (png_byte)unit;
michael@0 1898 memcpy(buf + 1, width, wlen + 1); /* Append the '\0' here */
michael@0 1899 memcpy(buf + wlen + 2, height, hlen); /* Do NOT append the '\0' here */
michael@0 1900
michael@0 1901 png_debug1(3, "sCAL total length = %u", (unsigned int)total_len);
michael@0 1902 png_write_complete_chunk(png_ptr, png_sCAL, buf, total_len);
michael@0 1903 }
michael@0 1904 #endif
michael@0 1905
michael@0 1906 #ifdef PNG_WRITE_pHYs_SUPPORTED
michael@0 1907 /* Write the pHYs chunk */
michael@0 1908 void /* PRIVATE */
michael@0 1909 png_write_pHYs(png_structrp png_ptr, png_uint_32 x_pixels_per_unit,
michael@0 1910 png_uint_32 y_pixels_per_unit,
michael@0 1911 int unit_type)
michael@0 1912 {
michael@0 1913 png_byte buf[9];
michael@0 1914
michael@0 1915 png_debug(1, "in png_write_pHYs");
michael@0 1916
michael@0 1917 if (unit_type >= PNG_RESOLUTION_LAST)
michael@0 1918 png_warning(png_ptr, "Unrecognized unit type for pHYs chunk");
michael@0 1919
michael@0 1920 png_save_uint_32(buf, x_pixels_per_unit);
michael@0 1921 png_save_uint_32(buf + 4, y_pixels_per_unit);
michael@0 1922 buf[8] = (png_byte)unit_type;
michael@0 1923
michael@0 1924 png_write_complete_chunk(png_ptr, png_pHYs, buf, (png_size_t)9);
michael@0 1925 }
michael@0 1926 #endif
michael@0 1927
michael@0 1928 #ifdef PNG_WRITE_tIME_SUPPORTED
michael@0 1929 /* Write the tIME chunk. Use either png_convert_from_struct_tm()
michael@0 1930 * or png_convert_from_time_t(), or fill in the structure yourself.
michael@0 1931 */
michael@0 1932 void /* PRIVATE */
michael@0 1933 png_write_tIME(png_structrp png_ptr, png_const_timep mod_time)
michael@0 1934 {
michael@0 1935 png_byte buf[7];
michael@0 1936
michael@0 1937 png_debug(1, "in png_write_tIME");
michael@0 1938
michael@0 1939 if (mod_time->month > 12 || mod_time->month < 1 ||
michael@0 1940 mod_time->day > 31 || mod_time->day < 1 ||
michael@0 1941 mod_time->hour > 23 || mod_time->second > 60)
michael@0 1942 {
michael@0 1943 png_warning(png_ptr, "Invalid time specified for tIME chunk");
michael@0 1944 return;
michael@0 1945 }
michael@0 1946
michael@0 1947 png_save_uint_16(buf, mod_time->year);
michael@0 1948 buf[2] = mod_time->month;
michael@0 1949 buf[3] = mod_time->day;
michael@0 1950 buf[4] = mod_time->hour;
michael@0 1951 buf[5] = mod_time->minute;
michael@0 1952 buf[6] = mod_time->second;
michael@0 1953
michael@0 1954 png_write_complete_chunk(png_ptr, png_tIME, buf, (png_size_t)7);
michael@0 1955 }
michael@0 1956 #endif
michael@0 1957
michael@0 1958 #ifdef PNG_WRITE_APNG_SUPPORTED
michael@0 1959 void /* PRIVATE */
michael@0 1960 png_write_acTL(png_structp png_ptr,
michael@0 1961 png_uint_32 num_frames, png_uint_32 num_plays)
michael@0 1962 {
michael@0 1963 png_byte buf[8];
michael@0 1964
michael@0 1965 png_debug(1, "in png_write_acTL");
michael@0 1966
michael@0 1967 png_ptr->num_frames_to_write = num_frames;
michael@0 1968
michael@0 1969 if (png_ptr->apng_flags & PNG_FIRST_FRAME_HIDDEN)
michael@0 1970 num_frames--;
michael@0 1971
michael@0 1972 png_save_uint_32(buf, num_frames);
michael@0 1973 png_save_uint_32(buf + 4, num_plays);
michael@0 1974
michael@0 1975 png_write_complete_chunk(png_ptr, png_acTL, buf, (png_size_t)8);
michael@0 1976 }
michael@0 1977
michael@0 1978 void /* PRIVATE */
michael@0 1979 png_write_fcTL(png_structp png_ptr, png_uint_32 width, png_uint_32 height,
michael@0 1980 png_uint_32 x_offset, png_uint_32 y_offset,
michael@0 1981 png_uint_16 delay_num, png_uint_16 delay_den, png_byte dispose_op,
michael@0 1982 png_byte blend_op)
michael@0 1983 {
michael@0 1984 png_byte buf[26];
michael@0 1985
michael@0 1986 png_debug(1, "in png_write_fcTL");
michael@0 1987
michael@0 1988 if (png_ptr->num_frames_written == 0 && (x_offset != 0 || y_offset != 0))
michael@0 1989 png_error(png_ptr, "x and/or y offset for the first frame aren't 0");
michael@0 1990 if (png_ptr->num_frames_written == 0 &&
michael@0 1991 (width != png_ptr->first_frame_width ||
michael@0 1992 height != png_ptr->first_frame_height))
michael@0 1993 png_error(png_ptr, "width and/or height in the first frame's fcTL "
michael@0 1994 "don't match the ones in IHDR");
michael@0 1995
michael@0 1996 /* more error checking */
michael@0 1997 png_ensure_fcTL_is_valid(png_ptr, width, height, x_offset, y_offset,
michael@0 1998 delay_num, delay_den, dispose_op, blend_op);
michael@0 1999
michael@0 2000 png_save_uint_32(buf, png_ptr->next_seq_num);
michael@0 2001 png_save_uint_32(buf + 4, width);
michael@0 2002 png_save_uint_32(buf + 8, height);
michael@0 2003 png_save_uint_32(buf + 12, x_offset);
michael@0 2004 png_save_uint_32(buf + 16, y_offset);
michael@0 2005 png_save_uint_16(buf + 20, delay_num);
michael@0 2006 png_save_uint_16(buf + 22, delay_den);
michael@0 2007 buf[24] = dispose_op;
michael@0 2008 buf[25] = blend_op;
michael@0 2009
michael@0 2010 png_write_complete_chunk(png_ptr, png_fcTL, buf, (png_size_t)26);
michael@0 2011
michael@0 2012 png_ptr->next_seq_num++;
michael@0 2013 }
michael@0 2014
michael@0 2015 void /* PRIVATE */
michael@0 2016 png_write_fdAT(png_structp png_ptr,
michael@0 2017 png_const_bytep data, png_size_t length)
michael@0 2018 {
michael@0 2019 png_byte buf[4];
michael@0 2020
michael@0 2021 png_write_chunk_header(png_ptr, png_fdAT, (png_uint_32)(4 + length));
michael@0 2022
michael@0 2023 png_save_uint_32(buf, png_ptr->next_seq_num);
michael@0 2024 png_write_chunk_data(png_ptr, buf, 4);
michael@0 2025
michael@0 2026 png_write_chunk_data(png_ptr, data, length);
michael@0 2027
michael@0 2028 png_write_chunk_end(png_ptr);
michael@0 2029
michael@0 2030 png_ptr->next_seq_num++;
michael@0 2031 }
michael@0 2032 #endif /* PNG_WRITE_APNG_SUPPORTED */
michael@0 2033
michael@0 2034 /* Initializes the row writing capability of libpng */
michael@0 2035 void /* PRIVATE */
michael@0 2036 png_write_start_row(png_structrp png_ptr)
michael@0 2037 {
michael@0 2038 #ifdef PNG_WRITE_INTERLACING_SUPPORTED
michael@0 2039 /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */
michael@0 2040
michael@0 2041 /* Start of interlace block */
michael@0 2042 static PNG_CONST png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
michael@0 2043
michael@0 2044 /* Offset to next interlace block */
michael@0 2045 static PNG_CONST png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
michael@0 2046
michael@0 2047 /* Start of interlace block in the y direction */
michael@0 2048 static PNG_CONST png_byte png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1};
michael@0 2049
michael@0 2050 /* Offset to next interlace block in the y direction */
michael@0 2051 static PNG_CONST png_byte png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
michael@0 2052 #endif
michael@0 2053
michael@0 2054 png_alloc_size_t buf_size;
michael@0 2055 int usr_pixel_depth;
michael@0 2056
michael@0 2057 png_debug(1, "in png_write_start_row");
michael@0 2058
michael@0 2059 usr_pixel_depth = png_ptr->usr_channels * png_ptr->usr_bit_depth;
michael@0 2060 buf_size = PNG_ROWBYTES(usr_pixel_depth, png_ptr->width) + 1;
michael@0 2061
michael@0 2062 /* 1.5.6: added to allow checking in the row write code. */
michael@0 2063 png_ptr->transformed_pixel_depth = png_ptr->pixel_depth;
michael@0 2064 png_ptr->maximum_pixel_depth = (png_byte)usr_pixel_depth;
michael@0 2065
michael@0 2066 /* Set up row buffer */
michael@0 2067 png_ptr->row_buf = (png_bytep)png_malloc(png_ptr, buf_size);
michael@0 2068
michael@0 2069 png_ptr->row_buf[0] = PNG_FILTER_VALUE_NONE;
michael@0 2070
michael@0 2071 #ifdef PNG_WRITE_FILTER_SUPPORTED
michael@0 2072 /* Set up filtering buffer, if using this filter */
michael@0 2073 if (png_ptr->do_filter & PNG_FILTER_SUB)
michael@0 2074 {
michael@0 2075 png_ptr->sub_row = (png_bytep)png_malloc(png_ptr, png_ptr->rowbytes + 1);
michael@0 2076
michael@0 2077 png_ptr->sub_row[0] = PNG_FILTER_VALUE_SUB;
michael@0 2078 }
michael@0 2079
michael@0 2080 /* We only need to keep the previous row if we are using one of these. */
michael@0 2081 if (png_ptr->do_filter & (PNG_FILTER_AVG | PNG_FILTER_UP | PNG_FILTER_PAETH))
michael@0 2082 {
michael@0 2083 /* Set up previous row buffer */
michael@0 2084 png_ptr->prev_row = (png_bytep)png_calloc(png_ptr, buf_size);
michael@0 2085
michael@0 2086 if (png_ptr->do_filter & PNG_FILTER_UP)
michael@0 2087 {
michael@0 2088 png_ptr->up_row = (png_bytep)png_malloc(png_ptr,
michael@0 2089 png_ptr->rowbytes + 1);
michael@0 2090
michael@0 2091 png_ptr->up_row[0] = PNG_FILTER_VALUE_UP;
michael@0 2092 }
michael@0 2093
michael@0 2094 if (png_ptr->do_filter & PNG_FILTER_AVG)
michael@0 2095 {
michael@0 2096 png_ptr->avg_row = (png_bytep)png_malloc(png_ptr,
michael@0 2097 png_ptr->rowbytes + 1);
michael@0 2098
michael@0 2099 png_ptr->avg_row[0] = PNG_FILTER_VALUE_AVG;
michael@0 2100 }
michael@0 2101
michael@0 2102 if (png_ptr->do_filter & PNG_FILTER_PAETH)
michael@0 2103 {
michael@0 2104 png_ptr->paeth_row = (png_bytep)png_malloc(png_ptr,
michael@0 2105 png_ptr->rowbytes + 1);
michael@0 2106
michael@0 2107 png_ptr->paeth_row[0] = PNG_FILTER_VALUE_PAETH;
michael@0 2108 }
michael@0 2109 }
michael@0 2110 #endif /* PNG_WRITE_FILTER_SUPPORTED */
michael@0 2111
michael@0 2112 #ifdef PNG_WRITE_INTERLACING_SUPPORTED
michael@0 2113 /* If interlaced, we need to set up width and height of pass */
michael@0 2114 if (png_ptr->interlaced)
michael@0 2115 {
michael@0 2116 if (!(png_ptr->transformations & PNG_INTERLACE))
michael@0 2117 {
michael@0 2118 png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 -
michael@0 2119 png_pass_ystart[0]) / png_pass_yinc[0];
michael@0 2120
michael@0 2121 png_ptr->usr_width = (png_ptr->width + png_pass_inc[0] - 1 -
michael@0 2122 png_pass_start[0]) / png_pass_inc[0];
michael@0 2123 }
michael@0 2124
michael@0 2125 else
michael@0 2126 {
michael@0 2127 png_ptr->num_rows = png_ptr->height;
michael@0 2128 png_ptr->usr_width = png_ptr->width;
michael@0 2129 }
michael@0 2130 }
michael@0 2131
michael@0 2132 else
michael@0 2133 #endif
michael@0 2134 {
michael@0 2135 png_ptr->num_rows = png_ptr->height;
michael@0 2136 png_ptr->usr_width = png_ptr->width;
michael@0 2137 }
michael@0 2138 }
michael@0 2139
michael@0 2140 /* Internal use only. Called when finished processing a row of data. */
michael@0 2141 void /* PRIVATE */
michael@0 2142 png_write_finish_row(png_structrp png_ptr)
michael@0 2143 {
michael@0 2144 #ifdef PNG_WRITE_INTERLACING_SUPPORTED
michael@0 2145 /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */
michael@0 2146
michael@0 2147 /* Start of interlace block */
michael@0 2148 static PNG_CONST png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
michael@0 2149
michael@0 2150 /* Offset to next interlace block */
michael@0 2151 static PNG_CONST png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
michael@0 2152
michael@0 2153 /* Start of interlace block in the y direction */
michael@0 2154 static PNG_CONST png_byte png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1};
michael@0 2155
michael@0 2156 /* Offset to next interlace block in the y direction */
michael@0 2157 static PNG_CONST png_byte png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
michael@0 2158 #endif
michael@0 2159
michael@0 2160 png_debug(1, "in png_write_finish_row");
michael@0 2161
michael@0 2162 /* Next row */
michael@0 2163 png_ptr->row_number++;
michael@0 2164
michael@0 2165 /* See if we are done */
michael@0 2166 if (png_ptr->row_number < png_ptr->num_rows)
michael@0 2167 return;
michael@0 2168
michael@0 2169 #ifdef PNG_WRITE_INTERLACING_SUPPORTED
michael@0 2170 /* If interlaced, go to next pass */
michael@0 2171 if (png_ptr->interlaced)
michael@0 2172 {
michael@0 2173 png_ptr->row_number = 0;
michael@0 2174 if (png_ptr->transformations & PNG_INTERLACE)
michael@0 2175 {
michael@0 2176 png_ptr->pass++;
michael@0 2177 }
michael@0 2178
michael@0 2179 else
michael@0 2180 {
michael@0 2181 /* Loop until we find a non-zero width or height pass */
michael@0 2182 do
michael@0 2183 {
michael@0 2184 png_ptr->pass++;
michael@0 2185
michael@0 2186 if (png_ptr->pass >= 7)
michael@0 2187 break;
michael@0 2188
michael@0 2189 png_ptr->usr_width = (png_ptr->width +
michael@0 2190 png_pass_inc[png_ptr->pass] - 1 -
michael@0 2191 png_pass_start[png_ptr->pass]) /
michael@0 2192 png_pass_inc[png_ptr->pass];
michael@0 2193
michael@0 2194 png_ptr->num_rows = (png_ptr->height +
michael@0 2195 png_pass_yinc[png_ptr->pass] - 1 -
michael@0 2196 png_pass_ystart[png_ptr->pass]) /
michael@0 2197 png_pass_yinc[png_ptr->pass];
michael@0 2198
michael@0 2199 if (png_ptr->transformations & PNG_INTERLACE)
michael@0 2200 break;
michael@0 2201
michael@0 2202 } while (png_ptr->usr_width == 0 || png_ptr->num_rows == 0);
michael@0 2203
michael@0 2204 }
michael@0 2205
michael@0 2206 /* Reset the row above the image for the next pass */
michael@0 2207 if (png_ptr->pass < 7)
michael@0 2208 {
michael@0 2209 if (png_ptr->prev_row != NULL)
michael@0 2210 memset(png_ptr->prev_row, 0,
michael@0 2211 (png_size_t)(PNG_ROWBYTES(png_ptr->usr_channels*
michael@0 2212 png_ptr->usr_bit_depth, png_ptr->width)) + 1);
michael@0 2213
michael@0 2214 return;
michael@0 2215 }
michael@0 2216 }
michael@0 2217 #endif
michael@0 2218
michael@0 2219 /* If we get here, we've just written the last row, so we need
michael@0 2220 to flush the compressor */
michael@0 2221 png_compress_IDAT(png_ptr, NULL, 0, Z_FINISH);
michael@0 2222 }
michael@0 2223
michael@0 2224 #ifdef PNG_WRITE_INTERLACING_SUPPORTED
michael@0 2225 /* Pick out the correct pixels for the interlace pass.
michael@0 2226 * The basic idea here is to go through the row with a source
michael@0 2227 * pointer and a destination pointer (sp and dp), and copy the
michael@0 2228 * correct pixels for the pass. As the row gets compacted,
michael@0 2229 * sp will always be >= dp, so we should never overwrite anything.
michael@0 2230 * See the default: case for the easiest code to understand.
michael@0 2231 */
michael@0 2232 void /* PRIVATE */
michael@0 2233 png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass)
michael@0 2234 {
michael@0 2235 /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */
michael@0 2236
michael@0 2237 /* Start of interlace block */
michael@0 2238 static PNG_CONST png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
michael@0 2239
michael@0 2240 /* Offset to next interlace block */
michael@0 2241 static PNG_CONST png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
michael@0 2242
michael@0 2243 png_debug(1, "in png_do_write_interlace");
michael@0 2244
michael@0 2245 /* We don't have to do anything on the last pass (6) */
michael@0 2246 if (pass < 6)
michael@0 2247 {
michael@0 2248 /* Each pixel depth is handled separately */
michael@0 2249 switch (row_info->pixel_depth)
michael@0 2250 {
michael@0 2251 case 1:
michael@0 2252 {
michael@0 2253 png_bytep sp;
michael@0 2254 png_bytep dp;
michael@0 2255 int shift;
michael@0 2256 int d;
michael@0 2257 int value;
michael@0 2258 png_uint_32 i;
michael@0 2259 png_uint_32 row_width = row_info->width;
michael@0 2260
michael@0 2261 dp = row;
michael@0 2262 d = 0;
michael@0 2263 shift = 7;
michael@0 2264
michael@0 2265 for (i = png_pass_start[pass]; i < row_width;
michael@0 2266 i += png_pass_inc[pass])
michael@0 2267 {
michael@0 2268 sp = row + (png_size_t)(i >> 3);
michael@0 2269 value = (int)(*sp >> (7 - (int)(i & 0x07))) & 0x01;
michael@0 2270 d |= (value << shift);
michael@0 2271
michael@0 2272 if (shift == 0)
michael@0 2273 {
michael@0 2274 shift = 7;
michael@0 2275 *dp++ = (png_byte)d;
michael@0 2276 d = 0;
michael@0 2277 }
michael@0 2278
michael@0 2279 else
michael@0 2280 shift--;
michael@0 2281
michael@0 2282 }
michael@0 2283 if (shift != 7)
michael@0 2284 *dp = (png_byte)d;
michael@0 2285
michael@0 2286 break;
michael@0 2287 }
michael@0 2288
michael@0 2289 case 2:
michael@0 2290 {
michael@0 2291 png_bytep sp;
michael@0 2292 png_bytep dp;
michael@0 2293 int shift;
michael@0 2294 int d;
michael@0 2295 int value;
michael@0 2296 png_uint_32 i;
michael@0 2297 png_uint_32 row_width = row_info->width;
michael@0 2298
michael@0 2299 dp = row;
michael@0 2300 shift = 6;
michael@0 2301 d = 0;
michael@0 2302
michael@0 2303 for (i = png_pass_start[pass]; i < row_width;
michael@0 2304 i += png_pass_inc[pass])
michael@0 2305 {
michael@0 2306 sp = row + (png_size_t)(i >> 2);
michael@0 2307 value = (*sp >> ((3 - (int)(i & 0x03)) << 1)) & 0x03;
michael@0 2308 d |= (value << shift);
michael@0 2309
michael@0 2310 if (shift == 0)
michael@0 2311 {
michael@0 2312 shift = 6;
michael@0 2313 *dp++ = (png_byte)d;
michael@0 2314 d = 0;
michael@0 2315 }
michael@0 2316
michael@0 2317 else
michael@0 2318 shift -= 2;
michael@0 2319 }
michael@0 2320 if (shift != 6)
michael@0 2321 *dp = (png_byte)d;
michael@0 2322
michael@0 2323 break;
michael@0 2324 }
michael@0 2325
michael@0 2326 case 4:
michael@0 2327 {
michael@0 2328 png_bytep sp;
michael@0 2329 png_bytep dp;
michael@0 2330 int shift;
michael@0 2331 int d;
michael@0 2332 int value;
michael@0 2333 png_uint_32 i;
michael@0 2334 png_uint_32 row_width = row_info->width;
michael@0 2335
michael@0 2336 dp = row;
michael@0 2337 shift = 4;
michael@0 2338 d = 0;
michael@0 2339 for (i = png_pass_start[pass]; i < row_width;
michael@0 2340 i += png_pass_inc[pass])
michael@0 2341 {
michael@0 2342 sp = row + (png_size_t)(i >> 1);
michael@0 2343 value = (*sp >> ((1 - (int)(i & 0x01)) << 2)) & 0x0f;
michael@0 2344 d |= (value << shift);
michael@0 2345
michael@0 2346 if (shift == 0)
michael@0 2347 {
michael@0 2348 shift = 4;
michael@0 2349 *dp++ = (png_byte)d;
michael@0 2350 d = 0;
michael@0 2351 }
michael@0 2352
michael@0 2353 else
michael@0 2354 shift -= 4;
michael@0 2355 }
michael@0 2356 if (shift != 4)
michael@0 2357 *dp = (png_byte)d;
michael@0 2358
michael@0 2359 break;
michael@0 2360 }
michael@0 2361
michael@0 2362 default:
michael@0 2363 {
michael@0 2364 png_bytep sp;
michael@0 2365 png_bytep dp;
michael@0 2366 png_uint_32 i;
michael@0 2367 png_uint_32 row_width = row_info->width;
michael@0 2368 png_size_t pixel_bytes;
michael@0 2369
michael@0 2370 /* Start at the beginning */
michael@0 2371 dp = row;
michael@0 2372
michael@0 2373 /* Find out how many bytes each pixel takes up */
michael@0 2374 pixel_bytes = (row_info->pixel_depth >> 3);
michael@0 2375
michael@0 2376 /* Loop through the row, only looking at the pixels that matter */
michael@0 2377 for (i = png_pass_start[pass]; i < row_width;
michael@0 2378 i += png_pass_inc[pass])
michael@0 2379 {
michael@0 2380 /* Find out where the original pixel is */
michael@0 2381 sp = row + (png_size_t)i * pixel_bytes;
michael@0 2382
michael@0 2383 /* Move the pixel */
michael@0 2384 if (dp != sp)
michael@0 2385 memcpy(dp, sp, pixel_bytes);
michael@0 2386
michael@0 2387 /* Next pixel */
michael@0 2388 dp += pixel_bytes;
michael@0 2389 }
michael@0 2390 break;
michael@0 2391 }
michael@0 2392 }
michael@0 2393 /* Set new row width */
michael@0 2394 row_info->width = (row_info->width +
michael@0 2395 png_pass_inc[pass] - 1 -
michael@0 2396 png_pass_start[pass]) /
michael@0 2397 png_pass_inc[pass];
michael@0 2398
michael@0 2399 row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,
michael@0 2400 row_info->width);
michael@0 2401 }
michael@0 2402 }
michael@0 2403 #endif
michael@0 2404
michael@0 2405 /* This filters the row, chooses which filter to use, if it has not already
michael@0 2406 * been specified by the application, and then writes the row out with the
michael@0 2407 * chosen filter.
michael@0 2408 */
michael@0 2409 static void
michael@0 2410 png_write_filtered_row(png_structrp png_ptr, png_bytep filtered_row,
michael@0 2411 png_size_t row_bytes);
michael@0 2412
michael@0 2413 #define PNG_MAXSUM (((png_uint_32)(-1)) >> 1)
michael@0 2414 #define PNG_HISHIFT 10
michael@0 2415 #define PNG_LOMASK ((png_uint_32)0xffffL)
michael@0 2416 #define PNG_HIMASK ((png_uint_32)(~PNG_LOMASK >> PNG_HISHIFT))
michael@0 2417 void /* PRIVATE */
michael@0 2418 png_write_find_filter(png_structrp png_ptr, png_row_infop row_info)
michael@0 2419 {
michael@0 2420 png_bytep best_row;
michael@0 2421 #ifdef PNG_WRITE_FILTER_SUPPORTED
michael@0 2422 png_bytep prev_row, row_buf;
michael@0 2423 png_uint_32 mins, bpp;
michael@0 2424 png_byte filter_to_do = png_ptr->do_filter;
michael@0 2425 png_size_t row_bytes = row_info->rowbytes;
michael@0 2426 #ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
michael@0 2427 int num_p_filters = png_ptr->num_prev_filters;
michael@0 2428 #endif
michael@0 2429
michael@0 2430 png_debug(1, "in png_write_find_filter");
michael@0 2431
michael@0 2432 #ifndef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
michael@0 2433 if (png_ptr->row_number == 0 && filter_to_do == PNG_ALL_FILTERS)
michael@0 2434 {
michael@0 2435 /* These will never be selected so we need not test them. */
michael@0 2436 filter_to_do &= ~(PNG_FILTER_UP | PNG_FILTER_PAETH);
michael@0 2437 }
michael@0 2438 #endif
michael@0 2439
michael@0 2440 /* Find out how many bytes offset each pixel is */
michael@0 2441 bpp = (row_info->pixel_depth + 7) >> 3;
michael@0 2442
michael@0 2443 prev_row = png_ptr->prev_row;
michael@0 2444 #endif
michael@0 2445 best_row = png_ptr->row_buf;
michael@0 2446 #ifdef PNG_WRITE_FILTER_SUPPORTED
michael@0 2447 row_buf = best_row;
michael@0 2448 mins = PNG_MAXSUM;
michael@0 2449
michael@0 2450 /* The prediction method we use is to find which method provides the
michael@0 2451 * smallest value when summing the absolute values of the distances
michael@0 2452 * from zero, using anything >= 128 as negative numbers. This is known
michael@0 2453 * as the "minimum sum of absolute differences" heuristic. Other
michael@0 2454 * heuristics are the "weighted minimum sum of absolute differences"
michael@0 2455 * (experimental and can in theory improve compression), and the "zlib
michael@0 2456 * predictive" method (not implemented yet), which does test compressions
michael@0 2457 * of lines using different filter methods, and then chooses the
michael@0 2458 * (series of) filter(s) that give minimum compressed data size (VERY
michael@0 2459 * computationally expensive).
michael@0 2460 *
michael@0 2461 * GRR 980525: consider also
michael@0 2462 *
michael@0 2463 * (1) minimum sum of absolute differences from running average (i.e.,
michael@0 2464 * keep running sum of non-absolute differences & count of bytes)
michael@0 2465 * [track dispersion, too? restart average if dispersion too large?]
michael@0 2466 *
michael@0 2467 * (1b) minimum sum of absolute differences from sliding average, probably
michael@0 2468 * with window size <= deflate window (usually 32K)
michael@0 2469 *
michael@0 2470 * (2) minimum sum of squared differences from zero or running average
michael@0 2471 * (i.e., ~ root-mean-square approach)
michael@0 2472 */
michael@0 2473
michael@0 2474
michael@0 2475 /* We don't need to test the 'no filter' case if this is the only filter
michael@0 2476 * that has been chosen, as it doesn't actually do anything to the data.
michael@0 2477 */
michael@0 2478 if ((filter_to_do & PNG_FILTER_NONE) && filter_to_do != PNG_FILTER_NONE)
michael@0 2479 {
michael@0 2480 png_bytep rp;
michael@0 2481 png_uint_32 sum = 0;
michael@0 2482 png_size_t i;
michael@0 2483 int v;
michael@0 2484
michael@0 2485 for (i = 0, rp = row_buf + 1; i < row_bytes; i++, rp++)
michael@0 2486 {
michael@0 2487 v = *rp;
michael@0 2488 sum += (v < 128) ? v : 256 - v;
michael@0 2489 }
michael@0 2490
michael@0 2491 #ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
michael@0 2492 if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
michael@0 2493 {
michael@0 2494 png_uint_32 sumhi, sumlo;
michael@0 2495 int j;
michael@0 2496 sumlo = sum & PNG_LOMASK;
michael@0 2497 sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK; /* Gives us some footroom */
michael@0 2498
michael@0 2499 /* Reduce the sum if we match any of the previous rows */
michael@0 2500 for (j = 0; j < num_p_filters; j++)
michael@0 2501 {
michael@0 2502 if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_NONE)
michael@0 2503 {
michael@0 2504 sumlo = (sumlo * png_ptr->filter_weights[j]) >>
michael@0 2505 PNG_WEIGHT_SHIFT;
michael@0 2506
michael@0 2507 sumhi = (sumhi * png_ptr->filter_weights[j]) >>
michael@0 2508 PNG_WEIGHT_SHIFT;
michael@0 2509 }
michael@0 2510 }
michael@0 2511
michael@0 2512 /* Factor in the cost of this filter (this is here for completeness,
michael@0 2513 * but it makes no sense to have a "cost" for the NONE filter, as
michael@0 2514 * it has the minimum possible computational cost - none).
michael@0 2515 */
michael@0 2516 sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_NONE]) >>
michael@0 2517 PNG_COST_SHIFT;
michael@0 2518
michael@0 2519 sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_NONE]) >>
michael@0 2520 PNG_COST_SHIFT;
michael@0 2521
michael@0 2522 if (sumhi > PNG_HIMASK)
michael@0 2523 sum = PNG_MAXSUM;
michael@0 2524
michael@0 2525 else
michael@0 2526 sum = (sumhi << PNG_HISHIFT) + sumlo;
michael@0 2527 }
michael@0 2528 #endif
michael@0 2529 mins = sum;
michael@0 2530 }
michael@0 2531
michael@0 2532 /* Sub filter */
michael@0 2533 if (filter_to_do == PNG_FILTER_SUB)
michael@0 2534 /* It's the only filter so no testing is needed */
michael@0 2535 {
michael@0 2536 png_bytep rp, lp, dp;
michael@0 2537 png_size_t i;
michael@0 2538
michael@0 2539 for (i = 0, rp = row_buf + 1, dp = png_ptr->sub_row + 1; i < bpp;
michael@0 2540 i++, rp++, dp++)
michael@0 2541 {
michael@0 2542 *dp = *rp;
michael@0 2543 }
michael@0 2544
michael@0 2545 for (lp = row_buf + 1; i < row_bytes;
michael@0 2546 i++, rp++, lp++, dp++)
michael@0 2547 {
michael@0 2548 *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff);
michael@0 2549 }
michael@0 2550
michael@0 2551 best_row = png_ptr->sub_row;
michael@0 2552 }
michael@0 2553
michael@0 2554 else if (filter_to_do & PNG_FILTER_SUB)
michael@0 2555 {
michael@0 2556 png_bytep rp, dp, lp;
michael@0 2557 png_uint_32 sum = 0, lmins = mins;
michael@0 2558 png_size_t i;
michael@0 2559 int v;
michael@0 2560
michael@0 2561 #ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
michael@0 2562 /* We temporarily increase the "minimum sum" by the factor we
michael@0 2563 * would reduce the sum of this filter, so that we can do the
michael@0 2564 * early exit comparison without scaling the sum each time.
michael@0 2565 */
michael@0 2566 if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
michael@0 2567 {
michael@0 2568 int j;
michael@0 2569 png_uint_32 lmhi, lmlo;
michael@0 2570 lmlo = lmins & PNG_LOMASK;
michael@0 2571 lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;
michael@0 2572
michael@0 2573 for (j = 0; j < num_p_filters; j++)
michael@0 2574 {
michael@0 2575 if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_SUB)
michael@0 2576 {
michael@0 2577 lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
michael@0 2578 PNG_WEIGHT_SHIFT;
michael@0 2579
michael@0 2580 lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
michael@0 2581 PNG_WEIGHT_SHIFT;
michael@0 2582 }
michael@0 2583 }
michael@0 2584
michael@0 2585 lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >>
michael@0 2586 PNG_COST_SHIFT;
michael@0 2587
michael@0 2588 lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >>
michael@0 2589 PNG_COST_SHIFT;
michael@0 2590
michael@0 2591 if (lmhi > PNG_HIMASK)
michael@0 2592 lmins = PNG_MAXSUM;
michael@0 2593
michael@0 2594 else
michael@0 2595 lmins = (lmhi << PNG_HISHIFT) + lmlo;
michael@0 2596 }
michael@0 2597 #endif
michael@0 2598
michael@0 2599 for (i = 0, rp = row_buf + 1, dp = png_ptr->sub_row + 1; i < bpp;
michael@0 2600 i++, rp++, dp++)
michael@0 2601 {
michael@0 2602 v = *dp = *rp;
michael@0 2603
michael@0 2604 sum += (v < 128) ? v : 256 - v;
michael@0 2605 }
michael@0 2606
michael@0 2607 for (lp = row_buf + 1; i < row_bytes;
michael@0 2608 i++, rp++, lp++, dp++)
michael@0 2609 {
michael@0 2610 v = *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff);
michael@0 2611
michael@0 2612 sum += (v < 128) ? v : 256 - v;
michael@0 2613
michael@0 2614 if (sum > lmins) /* We are already worse, don't continue. */
michael@0 2615 break;
michael@0 2616 }
michael@0 2617
michael@0 2618 #ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
michael@0 2619 if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
michael@0 2620 {
michael@0 2621 int j;
michael@0 2622 png_uint_32 sumhi, sumlo;
michael@0 2623 sumlo = sum & PNG_LOMASK;
michael@0 2624 sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;
michael@0 2625
michael@0 2626 for (j = 0; j < num_p_filters; j++)
michael@0 2627 {
michael@0 2628 if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_SUB)
michael@0 2629 {
michael@0 2630 sumlo = (sumlo * png_ptr->inv_filter_weights[j]) >>
michael@0 2631 PNG_WEIGHT_SHIFT;
michael@0 2632
michael@0 2633 sumhi = (sumhi * png_ptr->inv_filter_weights[j]) >>
michael@0 2634 PNG_WEIGHT_SHIFT;
michael@0 2635 }
michael@0 2636 }
michael@0 2637
michael@0 2638 sumlo = (sumlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >>
michael@0 2639 PNG_COST_SHIFT;
michael@0 2640
michael@0 2641 sumhi = (sumhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >>
michael@0 2642 PNG_COST_SHIFT;
michael@0 2643
michael@0 2644 if (sumhi > PNG_HIMASK)
michael@0 2645 sum = PNG_MAXSUM;
michael@0 2646
michael@0 2647 else
michael@0 2648 sum = (sumhi << PNG_HISHIFT) + sumlo;
michael@0 2649 }
michael@0 2650 #endif
michael@0 2651
michael@0 2652 if (sum < mins)
michael@0 2653 {
michael@0 2654 mins = sum;
michael@0 2655 best_row = png_ptr->sub_row;
michael@0 2656 }
michael@0 2657 }
michael@0 2658
michael@0 2659 /* Up filter */
michael@0 2660 if (filter_to_do == PNG_FILTER_UP)
michael@0 2661 {
michael@0 2662 png_bytep rp, dp, pp;
michael@0 2663 png_size_t i;
michael@0 2664
michael@0 2665 for (i = 0, rp = row_buf + 1, dp = png_ptr->up_row + 1,
michael@0 2666 pp = prev_row + 1; i < row_bytes;
michael@0 2667 i++, rp++, pp++, dp++)
michael@0 2668 {
michael@0 2669 *dp = (png_byte)(((int)*rp - (int)*pp) & 0xff);
michael@0 2670 }
michael@0 2671
michael@0 2672 best_row = png_ptr->up_row;
michael@0 2673 }
michael@0 2674
michael@0 2675 else if (filter_to_do & PNG_FILTER_UP)
michael@0 2676 {
michael@0 2677 png_bytep rp, dp, pp;
michael@0 2678 png_uint_32 sum = 0, lmins = mins;
michael@0 2679 png_size_t i;
michael@0 2680 int v;
michael@0 2681
michael@0 2682
michael@0 2683 #ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
michael@0 2684 if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
michael@0 2685 {
michael@0 2686 int j;
michael@0 2687 png_uint_32 lmhi, lmlo;
michael@0 2688 lmlo = lmins & PNG_LOMASK;
michael@0 2689 lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;
michael@0 2690
michael@0 2691 for (j = 0; j < num_p_filters; j++)
michael@0 2692 {
michael@0 2693 if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_UP)
michael@0 2694 {
michael@0 2695 lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
michael@0 2696 PNG_WEIGHT_SHIFT;
michael@0 2697
michael@0 2698 lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
michael@0 2699 PNG_WEIGHT_SHIFT;
michael@0 2700 }
michael@0 2701 }
michael@0 2702
michael@0 2703 lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_UP]) >>
michael@0 2704 PNG_COST_SHIFT;
michael@0 2705
michael@0 2706 lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_UP]) >>
michael@0 2707 PNG_COST_SHIFT;
michael@0 2708
michael@0 2709 if (lmhi > PNG_HIMASK)
michael@0 2710 lmins = PNG_MAXSUM;
michael@0 2711
michael@0 2712 else
michael@0 2713 lmins = (lmhi << PNG_HISHIFT) + lmlo;
michael@0 2714 }
michael@0 2715 #endif
michael@0 2716
michael@0 2717 for (i = 0, rp = row_buf + 1, dp = png_ptr->up_row + 1,
michael@0 2718 pp = prev_row + 1; i < row_bytes; i++)
michael@0 2719 {
michael@0 2720 v = *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff);
michael@0 2721
michael@0 2722 sum += (v < 128) ? v : 256 - v;
michael@0 2723
michael@0 2724 if (sum > lmins) /* We are already worse, don't continue. */
michael@0 2725 break;
michael@0 2726 }
michael@0 2727
michael@0 2728 #ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
michael@0 2729 if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
michael@0 2730 {
michael@0 2731 int j;
michael@0 2732 png_uint_32 sumhi, sumlo;
michael@0 2733 sumlo = sum & PNG_LOMASK;
michael@0 2734 sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;
michael@0 2735
michael@0 2736 for (j = 0; j < num_p_filters; j++)
michael@0 2737 {
michael@0 2738 if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_UP)
michael@0 2739 {
michael@0 2740 sumlo = (sumlo * png_ptr->filter_weights[j]) >>
michael@0 2741 PNG_WEIGHT_SHIFT;
michael@0 2742
michael@0 2743 sumhi = (sumhi * png_ptr->filter_weights[j]) >>
michael@0 2744 PNG_WEIGHT_SHIFT;
michael@0 2745 }
michael@0 2746 }
michael@0 2747
michael@0 2748 sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_UP]) >>
michael@0 2749 PNG_COST_SHIFT;
michael@0 2750
michael@0 2751 sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_UP]) >>
michael@0 2752 PNG_COST_SHIFT;
michael@0 2753
michael@0 2754 if (sumhi > PNG_HIMASK)
michael@0 2755 sum = PNG_MAXSUM;
michael@0 2756
michael@0 2757 else
michael@0 2758 sum = (sumhi << PNG_HISHIFT) + sumlo;
michael@0 2759 }
michael@0 2760 #endif
michael@0 2761
michael@0 2762 if (sum < mins)
michael@0 2763 {
michael@0 2764 mins = sum;
michael@0 2765 best_row = png_ptr->up_row;
michael@0 2766 }
michael@0 2767 }
michael@0 2768
michael@0 2769 /* Avg filter */
michael@0 2770 if (filter_to_do == PNG_FILTER_AVG)
michael@0 2771 {
michael@0 2772 png_bytep rp, dp, pp, lp;
michael@0 2773 png_uint_32 i;
michael@0 2774
michael@0 2775 for (i = 0, rp = row_buf + 1, dp = png_ptr->avg_row + 1,
michael@0 2776 pp = prev_row + 1; i < bpp; i++)
michael@0 2777 {
michael@0 2778 *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff);
michael@0 2779 }
michael@0 2780
michael@0 2781 for (lp = row_buf + 1; i < row_bytes; i++)
michael@0 2782 {
michael@0 2783 *dp++ = (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2))
michael@0 2784 & 0xff);
michael@0 2785 }
michael@0 2786 best_row = png_ptr->avg_row;
michael@0 2787 }
michael@0 2788
michael@0 2789 else if (filter_to_do & PNG_FILTER_AVG)
michael@0 2790 {
michael@0 2791 png_bytep rp, dp, pp, lp;
michael@0 2792 png_uint_32 sum = 0, lmins = mins;
michael@0 2793 png_size_t i;
michael@0 2794 int v;
michael@0 2795
michael@0 2796 #ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
michael@0 2797 if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
michael@0 2798 {
michael@0 2799 int j;
michael@0 2800 png_uint_32 lmhi, lmlo;
michael@0 2801 lmlo = lmins & PNG_LOMASK;
michael@0 2802 lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;
michael@0 2803
michael@0 2804 for (j = 0; j < num_p_filters; j++)
michael@0 2805 {
michael@0 2806 if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_AVG)
michael@0 2807 {
michael@0 2808 lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
michael@0 2809 PNG_WEIGHT_SHIFT;
michael@0 2810
michael@0 2811 lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
michael@0 2812 PNG_WEIGHT_SHIFT;
michael@0 2813 }
michael@0 2814 }
michael@0 2815
michael@0 2816 lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_AVG]) >>
michael@0 2817 PNG_COST_SHIFT;
michael@0 2818
michael@0 2819 lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_AVG]) >>
michael@0 2820 PNG_COST_SHIFT;
michael@0 2821
michael@0 2822 if (lmhi > PNG_HIMASK)
michael@0 2823 lmins = PNG_MAXSUM;
michael@0 2824
michael@0 2825 else
michael@0 2826 lmins = (lmhi << PNG_HISHIFT) + lmlo;
michael@0 2827 }
michael@0 2828 #endif
michael@0 2829
michael@0 2830 for (i = 0, rp = row_buf + 1, dp = png_ptr->avg_row + 1,
michael@0 2831 pp = prev_row + 1; i < bpp; i++)
michael@0 2832 {
michael@0 2833 v = *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff);
michael@0 2834
michael@0 2835 sum += (v < 128) ? v : 256 - v;
michael@0 2836 }
michael@0 2837
michael@0 2838 for (lp = row_buf + 1; i < row_bytes; i++)
michael@0 2839 {
michael@0 2840 v = *dp++ =
michael@0 2841 (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2)) & 0xff);
michael@0 2842
michael@0 2843 sum += (v < 128) ? v : 256 - v;
michael@0 2844
michael@0 2845 if (sum > lmins) /* We are already worse, don't continue. */
michael@0 2846 break;
michael@0 2847 }
michael@0 2848
michael@0 2849 #ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
michael@0 2850 if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
michael@0 2851 {
michael@0 2852 int j;
michael@0 2853 png_uint_32 sumhi, sumlo;
michael@0 2854 sumlo = sum & PNG_LOMASK;
michael@0 2855 sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;
michael@0 2856
michael@0 2857 for (j = 0; j < num_p_filters; j++)
michael@0 2858 {
michael@0 2859 if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_NONE)
michael@0 2860 {
michael@0 2861 sumlo = (sumlo * png_ptr->filter_weights[j]) >>
michael@0 2862 PNG_WEIGHT_SHIFT;
michael@0 2863
michael@0 2864 sumhi = (sumhi * png_ptr->filter_weights[j]) >>
michael@0 2865 PNG_WEIGHT_SHIFT;
michael@0 2866 }
michael@0 2867 }
michael@0 2868
michael@0 2869 sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_AVG]) >>
michael@0 2870 PNG_COST_SHIFT;
michael@0 2871
michael@0 2872 sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_AVG]) >>
michael@0 2873 PNG_COST_SHIFT;
michael@0 2874
michael@0 2875 if (sumhi > PNG_HIMASK)
michael@0 2876 sum = PNG_MAXSUM;
michael@0 2877
michael@0 2878 else
michael@0 2879 sum = (sumhi << PNG_HISHIFT) + sumlo;
michael@0 2880 }
michael@0 2881 #endif
michael@0 2882
michael@0 2883 if (sum < mins)
michael@0 2884 {
michael@0 2885 mins = sum;
michael@0 2886 best_row = png_ptr->avg_row;
michael@0 2887 }
michael@0 2888 }
michael@0 2889
michael@0 2890 /* Paeth filter */
michael@0 2891 if (filter_to_do == PNG_FILTER_PAETH)
michael@0 2892 {
michael@0 2893 png_bytep rp, dp, pp, cp, lp;
michael@0 2894 png_size_t i;
michael@0 2895
michael@0 2896 for (i = 0, rp = row_buf + 1, dp = png_ptr->paeth_row + 1,
michael@0 2897 pp = prev_row + 1; i < bpp; i++)
michael@0 2898 {
michael@0 2899 *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff);
michael@0 2900 }
michael@0 2901
michael@0 2902 for (lp = row_buf + 1, cp = prev_row + 1; i < row_bytes; i++)
michael@0 2903 {
michael@0 2904 int a, b, c, pa, pb, pc, p;
michael@0 2905
michael@0 2906 b = *pp++;
michael@0 2907 c = *cp++;
michael@0 2908 a = *lp++;
michael@0 2909
michael@0 2910 p = b - c;
michael@0 2911 pc = a - c;
michael@0 2912
michael@0 2913 #ifdef PNG_USE_ABS
michael@0 2914 pa = abs(p);
michael@0 2915 pb = abs(pc);
michael@0 2916 pc = abs(p + pc);
michael@0 2917 #else
michael@0 2918 pa = p < 0 ? -p : p;
michael@0 2919 pb = pc < 0 ? -pc : pc;
michael@0 2920 pc = (p + pc) < 0 ? -(p + pc) : p + pc;
michael@0 2921 #endif
michael@0 2922
michael@0 2923 p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c;
michael@0 2924
michael@0 2925 *dp++ = (png_byte)(((int)*rp++ - p) & 0xff);
michael@0 2926 }
michael@0 2927 best_row = png_ptr->paeth_row;
michael@0 2928 }
michael@0 2929
michael@0 2930 else if (filter_to_do & PNG_FILTER_PAETH)
michael@0 2931 {
michael@0 2932 png_bytep rp, dp, pp, cp, lp;
michael@0 2933 png_uint_32 sum = 0, lmins = mins;
michael@0 2934 png_size_t i;
michael@0 2935 int v;
michael@0 2936
michael@0 2937 #ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
michael@0 2938 if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
michael@0 2939 {
michael@0 2940 int j;
michael@0 2941 png_uint_32 lmhi, lmlo;
michael@0 2942 lmlo = lmins & PNG_LOMASK;
michael@0 2943 lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;
michael@0 2944
michael@0 2945 for (j = 0; j < num_p_filters; j++)
michael@0 2946 {
michael@0 2947 if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_PAETH)
michael@0 2948 {
michael@0 2949 lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
michael@0 2950 PNG_WEIGHT_SHIFT;
michael@0 2951
michael@0 2952 lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
michael@0 2953 PNG_WEIGHT_SHIFT;
michael@0 2954 }
michael@0 2955 }
michael@0 2956
michael@0 2957 lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_PAETH]) >>
michael@0 2958 PNG_COST_SHIFT;
michael@0 2959
michael@0 2960 lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_PAETH]) >>
michael@0 2961 PNG_COST_SHIFT;
michael@0 2962
michael@0 2963 if (lmhi > PNG_HIMASK)
michael@0 2964 lmins = PNG_MAXSUM;
michael@0 2965
michael@0 2966 else
michael@0 2967 lmins = (lmhi << PNG_HISHIFT) + lmlo;
michael@0 2968 }
michael@0 2969 #endif
michael@0 2970
michael@0 2971 for (i = 0, rp = row_buf + 1, dp = png_ptr->paeth_row + 1,
michael@0 2972 pp = prev_row + 1; i < bpp; i++)
michael@0 2973 {
michael@0 2974 v = *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff);
michael@0 2975
michael@0 2976 sum += (v < 128) ? v : 256 - v;
michael@0 2977 }
michael@0 2978
michael@0 2979 for (lp = row_buf + 1, cp = prev_row + 1; i < row_bytes; i++)
michael@0 2980 {
michael@0 2981 int a, b, c, pa, pb, pc, p;
michael@0 2982
michael@0 2983 b = *pp++;
michael@0 2984 c = *cp++;
michael@0 2985 a = *lp++;
michael@0 2986
michael@0 2987 #ifndef PNG_SLOW_PAETH
michael@0 2988 p = b - c;
michael@0 2989 pc = a - c;
michael@0 2990 #ifdef PNG_USE_ABS
michael@0 2991 pa = abs(p);
michael@0 2992 pb = abs(pc);
michael@0 2993 pc = abs(p + pc);
michael@0 2994 #else
michael@0 2995 pa = p < 0 ? -p : p;
michael@0 2996 pb = pc < 0 ? -pc : pc;
michael@0 2997 pc = (p + pc) < 0 ? -(p + pc) : p + pc;
michael@0 2998 #endif
michael@0 2999 p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c;
michael@0 3000 #else /* PNG_SLOW_PAETH */
michael@0 3001 p = a + b - c;
michael@0 3002 pa = abs(p - a);
michael@0 3003 pb = abs(p - b);
michael@0 3004 pc = abs(p - c);
michael@0 3005
michael@0 3006 if (pa <= pb && pa <= pc)
michael@0 3007 p = a;
michael@0 3008
michael@0 3009 else if (pb <= pc)
michael@0 3010 p = b;
michael@0 3011
michael@0 3012 else
michael@0 3013 p = c;
michael@0 3014 #endif /* PNG_SLOW_PAETH */
michael@0 3015
michael@0 3016 v = *dp++ = (png_byte)(((int)*rp++ - p) & 0xff);
michael@0 3017
michael@0 3018 sum += (v < 128) ? v : 256 - v;
michael@0 3019
michael@0 3020 if (sum > lmins) /* We are already worse, don't continue. */
michael@0 3021 break;
michael@0 3022 }
michael@0 3023
michael@0 3024 #ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
michael@0 3025 if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
michael@0 3026 {
michael@0 3027 int j;
michael@0 3028 png_uint_32 sumhi, sumlo;
michael@0 3029 sumlo = sum & PNG_LOMASK;
michael@0 3030 sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;
michael@0 3031
michael@0 3032 for (j = 0; j < num_p_filters; j++)
michael@0 3033 {
michael@0 3034 if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_PAETH)
michael@0 3035 {
michael@0 3036 sumlo = (sumlo * png_ptr->filter_weights[j]) >>
michael@0 3037 PNG_WEIGHT_SHIFT;
michael@0 3038
michael@0 3039 sumhi = (sumhi * png_ptr->filter_weights[j]) >>
michael@0 3040 PNG_WEIGHT_SHIFT;
michael@0 3041 }
michael@0 3042 }
michael@0 3043
michael@0 3044 sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_PAETH]) >>
michael@0 3045 PNG_COST_SHIFT;
michael@0 3046
michael@0 3047 sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_PAETH]) >>
michael@0 3048 PNG_COST_SHIFT;
michael@0 3049
michael@0 3050 if (sumhi > PNG_HIMASK)
michael@0 3051 sum = PNG_MAXSUM;
michael@0 3052
michael@0 3053 else
michael@0 3054 sum = (sumhi << PNG_HISHIFT) + sumlo;
michael@0 3055 }
michael@0 3056 #endif
michael@0 3057
michael@0 3058 if (sum < mins)
michael@0 3059 {
michael@0 3060 best_row = png_ptr->paeth_row;
michael@0 3061 }
michael@0 3062 }
michael@0 3063 #endif /* PNG_WRITE_FILTER_SUPPORTED */
michael@0 3064
michael@0 3065 /* Do the actual writing of the filtered row data from the chosen filter. */
michael@0 3066 png_write_filtered_row(png_ptr, best_row, row_info->rowbytes+1);
michael@0 3067
michael@0 3068 #ifdef PNG_WRITE_FILTER_SUPPORTED
michael@0 3069 #ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
michael@0 3070 /* Save the type of filter we picked this time for future calculations */
michael@0 3071 if (png_ptr->num_prev_filters > 0)
michael@0 3072 {
michael@0 3073 int j;
michael@0 3074
michael@0 3075 for (j = 1; j < num_p_filters; j++)
michael@0 3076 {
michael@0 3077 png_ptr->prev_filters[j] = png_ptr->prev_filters[j - 1];
michael@0 3078 }
michael@0 3079
michael@0 3080 png_ptr->prev_filters[j] = best_row[0];
michael@0 3081 }
michael@0 3082 #endif
michael@0 3083 #endif /* PNG_WRITE_FILTER_SUPPORTED */
michael@0 3084 }
michael@0 3085
michael@0 3086
michael@0 3087 /* Do the actual writing of a previously filtered row. */
michael@0 3088 static void
michael@0 3089 png_write_filtered_row(png_structrp png_ptr, png_bytep filtered_row,
michael@0 3090 png_size_t full_row_length/*includes filter byte*/)
michael@0 3091 {
michael@0 3092 png_debug(1, "in png_write_filtered_row");
michael@0 3093
michael@0 3094 png_debug1(2, "filter = %d", filtered_row[0]);
michael@0 3095
michael@0 3096 png_compress_IDAT(png_ptr, filtered_row, full_row_length, Z_NO_FLUSH);
michael@0 3097
michael@0 3098 /* Swap the current and previous rows */
michael@0 3099 if (png_ptr->prev_row != NULL)
michael@0 3100 {
michael@0 3101 png_bytep tptr;
michael@0 3102
michael@0 3103 tptr = png_ptr->prev_row;
michael@0 3104 png_ptr->prev_row = png_ptr->row_buf;
michael@0 3105 png_ptr->row_buf = tptr;
michael@0 3106 }
michael@0 3107
michael@0 3108 /* Finish row - updates counters and flushes zlib if last row */
michael@0 3109 png_write_finish_row(png_ptr);
michael@0 3110
michael@0 3111 #ifdef PNG_WRITE_FLUSH_SUPPORTED
michael@0 3112 png_ptr->flush_rows++;
michael@0 3113
michael@0 3114 if (png_ptr->flush_dist > 0 &&
michael@0 3115 png_ptr->flush_rows >= png_ptr->flush_dist)
michael@0 3116 {
michael@0 3117 png_write_flush(png_ptr);
michael@0 3118 }
michael@0 3119 #endif
michael@0 3120 }
michael@0 3121
michael@0 3122 #ifdef PNG_WRITE_APNG_SUPPORTED
michael@0 3123 void /* PRIVATE */
michael@0 3124 png_write_reset(png_structp png_ptr)
michael@0 3125 {
michael@0 3126 png_ptr->row_number = 0;
michael@0 3127 png_ptr->pass = 0;
michael@0 3128 png_ptr->mode &= ~PNG_HAVE_IDAT;
michael@0 3129 }
michael@0 3130
michael@0 3131 void /* PRIVATE */
michael@0 3132 png_write_reinit(png_structp png_ptr, png_infop info_ptr,
michael@0 3133 png_uint_32 width, png_uint_32 height)
michael@0 3134 {
michael@0 3135 if (png_ptr->num_frames_written == 0 &&
michael@0 3136 (width != png_ptr->first_frame_width ||
michael@0 3137 height != png_ptr->first_frame_height))
michael@0 3138 png_error(png_ptr, "width and/or height in the first frame's fcTL "
michael@0 3139 "don't match the ones in IHDR");
michael@0 3140 if (width > png_ptr->first_frame_width ||
michael@0 3141 height > png_ptr->first_frame_height)
michael@0 3142 png_error(png_ptr, "width and/or height for a frame greater than"
michael@0 3143 "the ones in IHDR");
michael@0 3144
michael@0 3145 png_set_IHDR(png_ptr, info_ptr, width, height,
michael@0 3146 info_ptr->bit_depth, info_ptr->color_type,
michael@0 3147 info_ptr->interlace_type, info_ptr->compression_type,
michael@0 3148 info_ptr->filter_type);
michael@0 3149
michael@0 3150 png_ptr->width = width;
michael@0 3151 png_ptr->height = height;
michael@0 3152 png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth, width);
michael@0 3153 png_ptr->usr_width = png_ptr->width;
michael@0 3154 }
michael@0 3155 #endif /* PNG_WRITE_APNG_SUPPORTED */
michael@0 3156 #endif /* PNG_WRITE_SUPPORTED */

mercurial