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