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