2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13 % Read/Write Portable Network Graphics Image Format %
17 % Glenn Randers-Pehrson %
21 % Copyright 1999-2013 ImageMagick Studio LLC, a non-profit organization %
22 % dedicated to making software imaging solutions freely available. %
24 % You may not use this file except in compliance with the License. You may %
25 % obtain a copy of the License at %
27 % http://www.imagemagick.org/script/license.php %
29 % Unless required by applicable law or agreed to in writing, software %
30 % distributed under the License is distributed on an "AS IS" BASIS, %
31 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
32 % See the License for the specific language governing permissions and %
33 % limitations under the License. %
35 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
44 #include "MagickCore/studio.h"
45 #include "MagickCore/artifact.h"
46 #include "MagickCore/attribute.h"
47 #include "MagickCore/blob.h"
48 #include "MagickCore/blob-private.h"
49 #include "MagickCore/cache.h"
50 #include "MagickCore/channel.h"
51 #include "MagickCore/color.h"
52 #include "MagickCore/color-private.h"
53 #include "MagickCore/colormap.h"
54 #include "MagickCore/colorspace.h"
55 #include "MagickCore/colorspace-private.h"
56 #include "MagickCore/constitute.h"
57 #include "MagickCore/enhance.h"
58 #include "MagickCore/exception.h"
59 #include "MagickCore/exception-private.h"
60 #include "MagickCore/geometry.h"
61 #include "MagickCore/histogram.h"
62 #include "MagickCore/image.h"
63 #include "MagickCore/image-private.h"
64 #include "MagickCore/layer.h"
65 #include "MagickCore/list.h"
66 #include "MagickCore/log.h"
67 #include "MagickCore/MagickCore.h"
68 #include "MagickCore/memory_.h"
69 #include "MagickCore/module.h"
70 #include "MagickCore/monitor.h"
71 #include "MagickCore/monitor-private.h"
72 #include "MagickCore/option.h"
73 #include "MagickCore/pixel.h"
74 #include "MagickCore/pixel-accessor.h"
75 #include "MagickCore/profile.h"
76 #include "MagickCore/property.h"
77 #include "MagickCore/quantum-private.h"
78 #include "MagickCore/resource_.h"
79 #include "MagickCore/semaphore.h"
80 #include "MagickCore/quantum-private.h"
81 #include "MagickCore/static.h"
82 #include "MagickCore/statistic.h"
83 #include "MagickCore/string_.h"
84 #include "MagickCore/string-private.h"
85 #include "MagickCore/transform.h"
86 #include "MagickCore/utility.h"
87 #if defined(MAGICKCORE_PNG_DELEGATE)
89 /* Suppress libpng pedantic warnings that were added in
90 * libpng-1.2.41 and libpng-1.4.0. If you are working on
91 * migration to libpng-1.5, remove these defines and then
92 * fix any code that generates warnings.
94 /* #define PNG_DEPRECATED Use of this function is deprecated */
95 /* #define PNG_USE_RESULT The result of this function must be checked */
96 /* #define PNG_NORETURN This function does not return */
97 /* #define PNG_ALLOCATED The result of the function is new memory */
98 /* #define PNG_DEPSTRUCT Access to this struct member is deprecated */
100 /* PNG_PTR_NORETURN does not work on some platforms, in libpng-1.5.x */
101 #define PNG_PTR_NORETURN
106 /* ImageMagick differences */
107 #define first_scene scene
109 #if PNG_LIBPNG_VER > 10011
111 Optional declarations. Define or undefine them as you like.
113 /* #define PNG_DEBUG -- turning this on breaks VisualC compiling */
116 Features under construction. Define these to work on them.
118 #undef MNG_OBJECT_BUFFERS
119 #undef MNG_BASI_SUPPORTED
120 #define MNG_COALESCE_LAYERS /* In 5.4.4, this interfered with MMAP'ed files. */
121 #define MNG_INSERT_LAYERS /* Troublesome, but seem to work as of 5.4.4 */
122 #if defined(MAGICKCORE_JPEG_DELEGATE)
123 # define JNG_SUPPORTED /* Not finished as of 5.5.2. See "To do" comments. */
125 #if !defined(RGBColorMatchExact)
126 #define IsPNGColorEqual(color,target) \
127 (((color).red == (target).red) && \
128 ((color).green == (target).green) && \
129 ((color).blue == (target).blue))
132 /* Macros for left-bit-replication to ensure that pixels
133 * and PixelInfos all have the same image->depth, and for use
134 * in PNG8 quantization.
138 /* LBR01: Replicate top bit */
140 #define LBR01PacketRed(pixelpacket) \
141 (pixelpacket).red=(ScaleQuantumToChar((pixelpacket).red) < 0x10 ? \
144 #define LBR01PacketGreen(pixelpacket) \
145 (pixelpacket).green=(ScaleQuantumToChar((pixelpacket).green) < 0x10 ? \
148 #define LBR01PacketBlue(pixelpacket) \
149 (pixelpacket).blue=(ScaleQuantumToChar((pixelpacket).blue) < 0x10 ? \
152 #define LBR01PacketAlpha(pixelpacket) \
153 (pixelpacket).alpha=(ScaleQuantumToChar((pixelpacket).alpha) < 0x10 ? \
156 #define LBR01PacketRGB(pixelpacket) \
158 LBR01PacketRed((pixelpacket)); \
159 LBR01PacketGreen((pixelpacket)); \
160 LBR01PacketBlue((pixelpacket)); \
163 #define LBR01PacketRGBO(pixelpacket) \
165 LBR01PacketRGB((pixelpacket)); \
166 LBR01PacketAlpha((pixelpacket)); \
169 #define LBR01PixelRed(pixel) \
170 (SetPixelRed(image, \
171 ScaleQuantumToChar(GetPixelRed(image,(pixel))) < 0x10 ? \
172 0 : QuantumRange,(pixel)));
174 #define LBR01PixelGreen(pixel) \
175 (SetPixelGreen(image, \
176 ScaleQuantumToChar(GetPixelGreen(image,(pixel))) < 0x10 ? \
177 0 : QuantumRange,(pixel)));
179 #define LBR01PixelBlue(pixel) \
180 (SetPixelBlue(image, \
181 ScaleQuantumToChar(GetPixelBlue(image,(pixel))) < 0x10 ? \
182 0 : QuantumRange,(pixel)));
184 #define LBR01PixelAlpha(pixel) \
185 (SetPixelAlpha(image, \
186 ScaleQuantumToChar(GetPixelAlpha(image,(pixel))) < 0x10 ? \
187 0 : QuantumRange,(pixel)));
189 #define LBR01PixelRGB(pixel) \
191 LBR01PixelRed((pixel)); \
192 LBR01PixelGreen((pixel)); \
193 LBR01PixelBlue((pixel)); \
196 #define LBR01PixelRGBA(pixel) \
198 LBR01PixelRGB((pixel)); \
199 LBR01PixelAlpha((pixel)); \
202 /* LBR02: Replicate top 2 bits */
204 #define LBR02PacketRed(pixelpacket) \
206 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).red) & 0xc0; \
207 (pixelpacket).red=ScaleCharToQuantum( \
208 (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))); \
210 #define LBR02PacketGreen(pixelpacket) \
212 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).green) & 0xc0; \
213 (pixelpacket).green=ScaleCharToQuantum( \
214 (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))); \
216 #define LBR02PacketBlue(pixelpacket) \
218 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).blue) & 0xc0; \
219 (pixelpacket).blue=ScaleCharToQuantum( \
220 (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))); \
222 #define LBR02PacketAlpha(pixelpacket) \
224 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).alpha) & 0xc0; \
225 (pixelpacket).alpha=ScaleCharToQuantum( \
226 (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))); \
229 #define LBR02PacketRGB(pixelpacket) \
231 LBR02PacketRed((pixelpacket)); \
232 LBR02PacketGreen((pixelpacket)); \
233 LBR02PacketBlue((pixelpacket)); \
236 #define LBR02PacketRGBO(pixelpacket) \
238 LBR02PacketRGB((pixelpacket)); \
239 LBR02PacketAlpha((pixelpacket)); \
242 #define LBR02PixelRed(pixel) \
244 unsigned char lbr_bits=ScaleQuantumToChar(GetPixelRed(image,(pixel))) \
246 SetPixelRed(image, ScaleCharToQuantum( \
247 (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))), \
250 #define LBR02PixelGreen(pixel) \
252 unsigned char lbr_bits=ScaleQuantumToChar(GetPixelGreen(image,(pixel)))\
254 SetPixelGreen(image, ScaleCharToQuantum( \
255 (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))), \
258 #define LBR02PixelBlue(pixel) \
260 unsigned char lbr_bits= \
261 ScaleQuantumToChar(GetPixelBlue(image,(pixel))) & 0xc0; \
262 SetPixelBlue(image, ScaleCharToQuantum( \
263 (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))), \
266 #define LBR02PixelAlpha(pixel) \
268 unsigned char lbr_bits= \
269 ScaleQuantumToChar(GetPixelAlpha(image,(pixel))) & 0xc0; \
270 SetPixelAlpha(image, ScaleCharToQuantum( \
271 (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))), \
275 #define LBR02PixelRGB(pixel) \
277 LBR02PixelRed((pixel)); \
278 LBR02PixelGreen((pixel)); \
279 LBR02PixelBlue((pixel)); \
282 #define LBR02PixelRGBA(pixel) \
284 LBR02PixelRGB((pixel)); \
285 LBR02PixelAlpha((pixel)); \
288 /* LBR03: Replicate top 3 bits (only used with opaque pixels during
289 PNG8 quantization) */
291 #define LBR03PacketRed(pixelpacket) \
293 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).red) & 0xe0; \
294 (pixelpacket).red=ScaleCharToQuantum( \
295 (lbr_bits | (lbr_bits >> 3) | (lbr_bits >> 6))); \
297 #define LBR03PacketGreen(pixelpacket) \
299 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).green) & 0xe0; \
300 (pixelpacket).green=ScaleCharToQuantum( \
301 (lbr_bits | (lbr_bits >> 3) | (lbr_bits >> 6))); \
303 #define LBR03PacketBlue(pixelpacket) \
305 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).blue) & 0xe0; \
306 (pixelpacket).blue=ScaleCharToQuantum( \
307 (lbr_bits | (lbr_bits >> 3) | (lbr_bits >> 6))); \
310 #define LBR03PacketRGB(pixelpacket) \
312 LBR03PacketRed((pixelpacket)); \
313 LBR03PacketGreen((pixelpacket)); \
314 LBR03PacketBlue((pixelpacket)); \
317 #define LBR03PixelRed(pixel) \
319 unsigned char lbr_bits=ScaleQuantumToChar(GetPixelRed(image,(pixel))) \
321 SetPixelRed(image, ScaleCharToQuantum( \
322 (lbr_bits | (lbr_bits >> 3) | (lbr_bits >> 6))), (pixel)); \
324 #define LBR03Green(pixel) \
326 unsigned char lbr_bits=ScaleQuantumToChar(GetPixelGreen(image,(pixel)))\
328 SetPixelGreen(image, ScaleCharToQuantum( \
329 (lbr_bits | (lbr_bits >> 3) | (lbr_bits >> 6))), (pixel)); \
331 #define LBR03Blue(pixel) \
333 unsigned char lbr_bits=ScaleQuantumToChar(GetPixelBlue(image,(pixel))) \
335 SetPixelBlue(image, ScaleCharToQuantum( \
336 (lbr_bits | (lbr_bits >> 3) | (lbr_bits >> 6))), (pixel)); \
339 #define LBR03RGB(pixel) \
341 LBR03PixelRed((pixel)); \
342 LBR03Green((pixel)); \
343 LBR03Blue((pixel)); \
346 /* LBR04: Replicate top 4 bits */
348 #define LBR04PacketRed(pixelpacket) \
350 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).red) & 0xf0; \
351 (pixelpacket).red=ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))); \
353 #define LBR04PacketGreen(pixelpacket) \
355 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).green) & 0xf0; \
356 (pixelpacket).green=ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))); \
358 #define LBR04PacketBlue(pixelpacket) \
360 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).blue) & 0xf0; \
361 (pixelpacket).blue=ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))); \
363 #define LBR04PacketAlpha(pixelpacket) \
365 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).alpha) & 0xf0; \
366 (pixelpacket).alpha=ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))); \
369 #define LBR04PacketRGB(pixelpacket) \
371 LBR04PacketRed((pixelpacket)); \
372 LBR04PacketGreen((pixelpacket)); \
373 LBR04PacketBlue((pixelpacket)); \
376 #define LBR04PacketRGBO(pixelpacket) \
378 LBR04PacketRGB((pixelpacket)); \
379 LBR04PacketAlpha((pixelpacket)); \
382 #define LBR04PixelRed(pixel) \
384 unsigned char lbr_bits=ScaleQuantumToChar(GetPixelRed(image,(pixel))) \
387 ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))), (pixel)); \
389 #define LBR04PixelGreen(pixel) \
391 unsigned char lbr_bits=ScaleQuantumToChar(GetPixelGreen(image,(pixel)))\
393 SetPixelGreen(image,\
394 ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))), (pixel)); \
396 #define LBR04PixelBlue(pixel) \
398 unsigned char lbr_bits= \
399 ScaleQuantumToChar(GetPixelBlue(image,(pixel))) & 0xf0; \
401 ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))), (pixel)); \
403 #define LBR04PixelAlpha(pixel) \
405 unsigned char lbr_bits= \
406 ScaleQuantumToChar(GetPixelAlpha(image,(pixel))) & 0xf0; \
407 SetPixelAlpha(image,\
408 ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))), (pixel)); \
411 #define LBR04PixelRGB(pixel) \
413 LBR04PixelRed((pixel)); \
414 LBR04PixelGreen((pixel)); \
415 LBR04PixelBlue((pixel)); \
418 #define LBR04PixelRGBA(pixel) \
420 LBR04PixelRGB((pixel)); \
421 LBR04PixelAlpha((pixel)); \
425 #if MAGICKCORE_QUANTUM_DEPTH > 8
426 /* LBR08: Replicate top 8 bits */
428 #define LBR08PacketRed(pixelpacket) \
430 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).red); \
431 (pixelpacket).red=ScaleCharToQuantum((lbr_bits)); \
433 #define LBR08PacketGreen(pixelpacket) \
435 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).green); \
436 (pixelpacket).green=ScaleCharToQuantum((lbr_bits)); \
438 #define LBR08PacketBlue(pixelpacket) \
440 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).blue); \
441 (pixelpacket).blue=ScaleCharToQuantum((lbr_bits)); \
443 #define LBR08PacketAlpha(pixelpacket) \
445 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).alpha); \
446 (pixelpacket).alpha=ScaleCharToQuantum((lbr_bits)); \
449 #define LBR08PacketRGB(pixelpacket) \
451 LBR08PacketRed((pixelpacket)); \
452 LBR08PacketGreen((pixelpacket)); \
453 LBR08PacketBlue((pixelpacket)); \
456 #define LBR08PacketRGBO(pixelpacket) \
458 LBR08PacketRGB((pixelpacket)); \
459 LBR08PacketAlpha((pixelpacket)); \
462 #define LBR08PixelRed(pixel) \
464 unsigned char lbr_bits= \
465 ScaleQuantumToChar(GetPixelRed(image,(pixel))); \
467 ScaleCharToQuantum((lbr_bits)), (pixel)); \
469 #define LBR08PixelGreen(pixel) \
471 unsigned char lbr_bits= \
472 ScaleQuantumToChar(GetPixelGreen(image,(pixel))); \
473 SetPixelGreen(image,\
474 ScaleCharToQuantum((lbr_bits)), (pixel)); \
476 #define LBR08PixelBlue(pixel) \
478 unsigned char lbr_bits= \
479 ScaleQuantumToChar(GetPixelBlue(image,(pixel))); \
481 ScaleCharToQuantum((lbr_bits)), (pixel)); \
483 #define LBR08PixelAlpha(pixel) \
485 unsigned char lbr_bits= \
486 ScaleQuantumToChar(GetPixelAlpha(image,(pixel))); \
487 SetPixelAlpha(image,\
488 ScaleCharToQuantum((lbr_bits)), (pixel)); \
491 #define LBR08PixelRGB(pixel) \
493 LBR08PixelRed((pixel)); \
494 LBR08PixelGreen((pixel)); \
495 LBR08PixelBlue((pixel)); \
498 #define LBR08PixelRGBA(pixel) \
500 LBR08PixelRGB((pixel)); \
501 LBR08PixelAlpha((pixel)); \
503 #endif /* MAGICKCORE_QUANTUM_DEPTH > 8 */
506 #if MAGICKCORE_QUANTUM_DEPTH > 16
507 /* LBR16: Replicate top 16 bits */
509 #define LBR16PacketRed(pixelpacket) \
511 unsigned short lbr_bits=ScaleQuantumToShort((pixelpacket).red); \
512 (pixelpacket).red=ScaleShortToQuantum((lbr_bits)); \
514 #define LBR16PacketGreen(pixelpacket) \
516 unsigned short lbr_bits=ScaleQuantumToShort((pixelpacket).green); \
517 (pixelpacket).green=ScaleShortToQuantum((lbr_bits)); \
519 #define LBR16PacketBlue(pixelpacket) \
521 unsigned short lbr_bits=ScaleQuantumToShort((pixelpacket).blue); \
522 (pixelpacket).blue=ScaleShortToQuantum((lbr_bits)); \
524 #define LBR16PacketAlpha(pixelpacket) \
526 unsigned short lbr_bits=ScaleQuantumToShort((pixelpacket).alpha); \
527 (pixelpacket).alpha=ScaleShortToQuantum((lbr_bits)); \
530 #define LBR16PacketRGB(pixelpacket) \
532 LBR16PacketRed((pixelpacket)); \
533 LBR16PacketGreen((pixelpacket)); \
534 LBR16PacketBlue((pixelpacket)); \
537 #define LBR16PacketRGBO(pixelpacket) \
539 LBR16PacketRGB((pixelpacket)); \
540 LBR16PacketAlpha((pixelpacket)); \
543 #define LBR16PixelRed(pixel) \
545 unsigned short lbr_bits= \
546 ScaleQuantumToShort(GetPixelRed(image,(pixel))); \
548 ScaleShortToQuantum((lbr_bits)),(pixel)); \
550 #define LBR16PixelGreen(pixel) \
552 unsigned short lbr_bits= \
553 ScaleQuantumToShort(GetPixelGreen(image,(pixel))); \
554 SetPixelGreen(image,\
555 ScaleShortToQuantum((lbr_bits)),(pixel)); \
557 #define LBR16PixelBlue(pixel) \
559 unsigned short lbr_bits= \
560 ScaleQuantumToShort(GetPixelBlue(image,(pixel))); \
562 ScaleShortToQuantum((lbr_bits)),(pixel)); \
564 #define LBR16PixelAlpha(pixel) \
566 unsigned short lbr_bits= \
567 ScaleQuantumToShort(GetPixelAlpha(image,(pixel))); \
568 SetPixelAlpha(image,\
569 ScaleShortToQuantum((lbr_bits)),(pixel)); \
572 #define LBR16PixelRGB(pixel) \
574 LBR16PixelRed((pixel)); \
575 LBR16PixelGreen((pixel)); \
576 LBR16PixelBlue((pixel)); \
579 #define LBR16PixelRGBA(pixel) \
581 LBR16PixelRGB((pixel)); \
582 LBR16PixelAlpha((pixel)); \
584 #endif /* MAGICKCORE_QUANTUM_DEPTH > 16 */
587 Establish thread safety.
588 setjmp/longjmp is claimed to be safe on these platforms:
589 setjmp/longjmp is alleged to be unsafe on these platforms:
591 #ifndef SETJMP_IS_THREAD_SAFE
592 #define PNG_SETJMP_NOT_THREAD_SAFE
595 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
597 *ping_semaphore = (SemaphoreInfo *) NULL;
601 This temporary until I set up malloc'ed object attributes array.
602 Recompile with MNG_MAX_OBJECTS=65536L to avoid this limit but
605 #define MNG_MAX_OBJECTS 256
608 If this not defined, spec is interpreted strictly. If it is
609 defined, an attempt will be made to recover from some errors,
611 o global PLTE too short
616 Don't try to define PNG_MNG_FEATURES_SUPPORTED here. Make sure
617 it's defined in libpng/pngconf.h, version 1.0.9 or later. It won't work
618 with earlier versions of libpng. From libpng-1.0.3a to libpng-1.0.8,
619 PNG_READ|WRITE_EMPTY_PLTE were used but those have been deprecated in
620 libpng in favor of PNG_MNG_FEATURES_SUPPORTED, so we set them here.
621 PNG_MNG_FEATURES_SUPPORTED is disabled by default in libpng-1.0.9 and
622 will be enabled by default in libpng-1.2.0.
624 #ifdef PNG_MNG_FEATURES_SUPPORTED
625 # ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
626 # define PNG_READ_EMPTY_PLTE_SUPPORTED
628 # ifndef PNG_WRITE_EMPTY_PLTE_SUPPORTED
629 # define PNG_WRITE_EMPTY_PLTE_SUPPORTED
634 Maximum valid size_t in PNG/MNG chunks is (2^31)-1
635 This macro is only defined in libpng-1.0.3 and later.
636 Previously it was PNG_MAX_UINT but that was deprecated in libpng-1.2.6
638 #ifndef PNG_UINT_31_MAX
639 #define PNG_UINT_31_MAX (png_uint_32) 0x7fffffffL
643 Constant strings for known chunk types. If you need to add a chunk,
644 add a string holding the name here. To make the code more
645 portable, we use ASCII numbers like this, not characters.
648 static png_byte mng_MHDR[5]={ 77, 72, 68, 82, (png_byte) '\0'};
649 static png_byte mng_BACK[5]={ 66, 65, 67, 75, (png_byte) '\0'};
650 static png_byte mng_BASI[5]={ 66, 65, 83, 73, (png_byte) '\0'};
651 static png_byte mng_CLIP[5]={ 67, 76, 73, 80, (png_byte) '\0'};
652 static png_byte mng_CLON[5]={ 67, 76, 79, 78, (png_byte) '\0'};
653 static png_byte mng_DEFI[5]={ 68, 69, 70, 73, (png_byte) '\0'};
654 static png_byte mng_DHDR[5]={ 68, 72, 68, 82, (png_byte) '\0'};
655 static png_byte mng_DISC[5]={ 68, 73, 83, 67, (png_byte) '\0'};
656 static png_byte mng_ENDL[5]={ 69, 78, 68, 76, (png_byte) '\0'};
657 static png_byte mng_FRAM[5]={ 70, 82, 65, 77, (png_byte) '\0'};
658 static png_byte mng_IEND[5]={ 73, 69, 78, 68, (png_byte) '\0'};
659 static png_byte mng_IHDR[5]={ 73, 72, 68, 82, (png_byte) '\0'};
660 static png_byte mng_JHDR[5]={ 74, 72, 68, 82, (png_byte) '\0'};
661 static png_byte mng_LOOP[5]={ 76, 79, 79, 80, (png_byte) '\0'};
662 static png_byte mng_MAGN[5]={ 77, 65, 71, 78, (png_byte) '\0'};
663 static png_byte mng_MEND[5]={ 77, 69, 78, 68, (png_byte) '\0'};
664 static png_byte mng_MOVE[5]={ 77, 79, 86, 69, (png_byte) '\0'};
665 static png_byte mng_PAST[5]={ 80, 65, 83, 84, (png_byte) '\0'};
666 static png_byte mng_PLTE[5]={ 80, 76, 84, 69, (png_byte) '\0'};
667 static png_byte mng_SAVE[5]={ 83, 65, 86, 69, (png_byte) '\0'};
668 static png_byte mng_SEEK[5]={ 83, 69, 69, 75, (png_byte) '\0'};
669 static png_byte mng_SHOW[5]={ 83, 72, 79, 87, (png_byte) '\0'};
670 static png_byte mng_TERM[5]={ 84, 69, 82, 77, (png_byte) '\0'};
671 static png_byte mng_bKGD[5]={ 98, 75, 71, 68, (png_byte) '\0'};
672 static png_byte mng_cHRM[5]={ 99, 72, 82, 77, (png_byte) '\0'};
673 static png_byte mng_gAMA[5]={103, 65, 77, 65, (png_byte) '\0'};
674 static png_byte mng_iCCP[5]={105, 67, 67, 80, (png_byte) '\0'};
675 static png_byte mng_nEED[5]={110, 69, 69, 68, (png_byte) '\0'};
676 static png_byte mng_pHYg[5]={112, 72, 89, 103, (png_byte) '\0'};
677 static png_byte mng_vpAg[5]={118, 112, 65, 103, (png_byte) '\0'};
678 static png_byte mng_pHYs[5]={112, 72, 89, 115, (png_byte) '\0'};
679 static png_byte mng_sBIT[5]={115, 66, 73, 84, (png_byte) '\0'};
680 static png_byte mng_sRGB[5]={115, 82, 71, 66, (png_byte) '\0'};
681 static png_byte mng_tRNS[5]={116, 82, 78, 83, (png_byte) '\0'};
683 #if defined(JNG_SUPPORTED)
684 static png_byte mng_IDAT[5]={ 73, 68, 65, 84, (png_byte) '\0'};
685 static png_byte mng_JDAT[5]={ 74, 68, 65, 84, (png_byte) '\0'};
686 static png_byte mng_JDAA[5]={ 74, 68, 65, 65, (png_byte) '\0'};
687 static png_byte mng_JdAA[5]={ 74, 100, 65, 65, (png_byte) '\0'};
688 static png_byte mng_JSEP[5]={ 74, 83, 69, 80, (png_byte) '\0'};
689 static png_byte mng_oFFs[5]={111, 70, 70, 115, (png_byte) '\0'};
693 Other known chunks that are not yet supported by ImageMagick:
694 static png_byte mng_hIST[5]={104, 73, 83, 84, (png_byte) '\0'};
695 static png_byte mng_iCCP[5]={105, 67, 67, 80, (png_byte) '\0'};
696 static png_byte mng_iTXt[5]={105, 84, 88, 116, (png_byte) '\0'};
697 static png_byte mng_sPLT[5]={115, 80, 76, 84, (png_byte) '\0'};
698 static png_byte mng_sTER[5]={115, 84, 69, 82, (png_byte) '\0'};
699 static png_byte mng_tEXt[5]={116, 69, 88, 116, (png_byte) '\0'};
700 static png_byte mng_tIME[5]={116, 73, 77, 69, (png_byte) '\0'};
701 static png_byte mng_zTXt[5]={122, 84, 88, 116, (png_byte) '\0'};
704 typedef struct _MngBox
713 typedef struct _MngPair
720 #ifdef MNG_OBJECT_BUFFERS
721 typedef struct _MngBuffer
753 typedef struct _MngInfo
756 #ifdef MNG_OBJECT_BUFFERS
758 *ob[MNG_MAX_OBJECTS];
769 #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
770 bytes_in_read_buffer,
776 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
777 defined(PNG_MNG_FEATURES_SUPPORTED)
789 have_saved_bkgd_index,
790 have_write_global_chrm,
791 have_write_global_gama,
792 have_write_global_plte,
793 have_write_global_srgb,
807 x_off[MNG_MAX_OBJECTS],
808 y_off[MNG_MAX_OBJECTS];
814 object_clip[MNG_MAX_OBJECTS];
817 /* These flags could be combined into one byte */
818 exists[MNG_MAX_OBJECTS],
819 frozen[MNG_MAX_OBJECTS],
821 invisible[MNG_MAX_OBJECTS],
822 viewable[MNG_MAX_OBJECTS];
834 #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
852 global_x_pixels_per_unit,
853 global_y_pixels_per_unit,
863 global_phys_unit_type,
878 write_png_compression_level,
879 write_png_compression_strategy,
880 write_png_compression_filter,
887 #ifdef MNG_BASI_SUPPORTED
895 basi_compression_method,
897 basi_interlace_method,
920 /* Added at version 6.6.6-7 */
928 /* ping_exclude_iTXt, */
935 ping_exclude_zCCP, /* hex-encoded iCCP */
937 ping_preserve_colormap;
943 Forward declarations.
945 static MagickBooleanType
946 WritePNGImage(const ImageInfo *,Image *,ExceptionInfo *);
948 static MagickBooleanType
949 WriteMNGImage(const ImageInfo *,Image *,ExceptionInfo *);
951 #if defined(JNG_SUPPORTED)
952 static MagickBooleanType
953 WriteJNGImage(const ImageInfo *,Image *,ExceptionInfo *);
956 #if PNG_LIBPNG_VER > 10011
959 #if (MAGICKCORE_QUANTUM_DEPTH >= 16)
960 static MagickBooleanType
961 LosslessReduceDepthOK(Image *image,ExceptionInfo *exception)
963 /* Reduce bit depth if it can be reduced losslessly from 16+ to 8.
965 * This is true if the high byte and the next highest byte of
966 * each sample of the image, the colormap, and the background color
967 * are equal to each other. We check this by seeing if the samples
968 * are unchanged when we scale them down to 8 and back up to Quantum.
970 * We don't use the method GetImageDepth() because it doesn't check
971 * background and doesn't handle PseudoClass specially.
974 #define QuantumToCharToQuantumEqQuantum(quantum) \
975 ((ScaleCharToQuantum((unsigned char) ScaleQuantumToChar(quantum))) == quantum)
978 ok_to_reduce=MagickFalse;
980 if (image->depth >= 16)
987 QuantumToCharToQuantumEqQuantum(image->background_color.red) &&
988 QuantumToCharToQuantumEqQuantum(image->background_color.green) &&
989 QuantumToCharToQuantumEqQuantum(image->background_color.blue) ?
990 MagickTrue : MagickFalse;
992 if (ok_to_reduce != MagickFalse && image->storage_class == PseudoClass)
996 for (indx=0; indx < (ssize_t) image->colors; indx++)
999 QuantumToCharToQuantumEqQuantum(
1000 image->colormap[indx].red) &&
1001 QuantumToCharToQuantumEqQuantum(
1002 image->colormap[indx].green) &&
1003 QuantumToCharToQuantumEqQuantum(
1004 image->colormap[indx].blue)) ?
1005 MagickTrue : MagickFalse;
1007 if (ok_to_reduce == MagickFalse)
1012 if ((ok_to_reduce != MagickFalse) &&
1013 (image->storage_class != PseudoClass))
1021 for (y=0; y < (ssize_t) image->rows; y++)
1023 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1025 if (p == (const Quantum *) NULL)
1027 ok_to_reduce = MagickFalse;
1031 for (x=(ssize_t) image->columns-1; x >= 0; x--)
1034 QuantumToCharToQuantumEqQuantum(GetPixelRed(image,p)) &&
1035 QuantumToCharToQuantumEqQuantum(GetPixelGreen(image,p)) &&
1036 QuantumToCharToQuantumEqQuantum(GetPixelBlue(image,p)) ?
1037 MagickTrue : MagickFalse;
1039 if (ok_to_reduce == MagickFalse)
1042 p+=GetPixelChannels(image);
1049 if (ok_to_reduce != MagickFalse)
1051 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1052 " OK to reduce PNG bit depth to 8 without loss of info");
1056 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1057 " Not OK to reduce PNG bit depth to 8 without loss of info");
1061 return ok_to_reduce;
1063 #endif /* MAGICKCORE_QUANTUM_DEPTH >= 16 */
1065 static const char* PngColorTypeToString(const unsigned int color_type)
1068 *result = "Unknown";
1072 case PNG_COLOR_TYPE_GRAY:
1075 case PNG_COLOR_TYPE_GRAY_ALPHA:
1076 result = "Gray+Alpha";
1078 case PNG_COLOR_TYPE_PALETTE:
1081 case PNG_COLOR_TYPE_RGB:
1084 case PNG_COLOR_TYPE_RGB_ALPHA:
1085 result = "RGB+Alpha";
1093 Magick_RenderingIntent_to_PNG_RenderingIntent(const RenderingIntent intent)
1097 case PerceptualIntent:
1100 case RelativeIntent:
1103 case SaturationIntent:
1106 case AbsoluteIntent:
1114 static RenderingIntent
1115 Magick_RenderingIntent_from_PNG_RenderingIntent(const int ping_intent)
1117 switch (ping_intent)
1120 return PerceptualIntent;
1123 return RelativeIntent;
1126 return SaturationIntent;
1129 return AbsoluteIntent;
1132 return UndefinedIntent;
1137 Magick_RenderingIntentString_from_PNG_RenderingIntent(const int ping_intent)
1139 switch (ping_intent)
1142 return "Perceptual Intent";
1145 return "Relative Intent";
1148 return "Saturation Intent";
1151 return "Absolute Intent";
1154 return "Undefined Intent";
1158 static inline ssize_t MagickMax(const ssize_t x,const ssize_t y)
1167 Magick_ColorType_from_PNG_ColorType(const int ping_colortype)
1169 switch (ping_colortype)
1187 return "UndefinedColorType";
1192 static inline ssize_t MagickMin(const ssize_t x,const ssize_t y)
1199 #endif /* PNG_LIBPNG_VER > 10011 */
1200 #endif /* MAGICKCORE_PNG_DELEGATE */
1203 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1211 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1213 % IsMNG() returns MagickTrue if the image format type, identified by the
1214 % magick string, is MNG.
1216 % The format of the IsMNG method is:
1218 % MagickBooleanType IsMNG(const unsigned char *magick,const size_t length)
1220 % A description of each parameter follows:
1222 % o magick: compare image format pattern against these bytes.
1224 % o length: Specifies the length of the magick string.
1228 static MagickBooleanType IsMNG(const unsigned char *magick,const size_t length)
1231 return(MagickFalse);
1233 if (memcmp(magick,"\212MNG\r\n\032\n",8) == 0)
1236 return(MagickFalse);
1240 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1248 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1250 % IsJNG() returns MagickTrue if the image format type, identified by the
1251 % magick string, is JNG.
1253 % The format of the IsJNG method is:
1255 % MagickBooleanType IsJNG(const unsigned char *magick,const size_t length)
1257 % A description of each parameter follows:
1259 % o magick: compare image format pattern against these bytes.
1261 % o length: Specifies the length of the magick string.
1265 static MagickBooleanType IsJNG(const unsigned char *magick,const size_t length)
1268 return(MagickFalse);
1270 if (memcmp(magick,"\213JNG\r\n\032\n",8) == 0)
1273 return(MagickFalse);
1277 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1285 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1287 % IsPNG() returns MagickTrue if the image format type, identified by the
1288 % magick string, is PNG.
1290 % The format of the IsPNG method is:
1292 % MagickBooleanType IsPNG(const unsigned char *magick,const size_t length)
1294 % A description of each parameter follows:
1296 % o magick: compare image format pattern against these bytes.
1298 % o length: Specifies the length of the magick string.
1301 static MagickBooleanType IsPNG(const unsigned char *magick,const size_t length)
1304 return(MagickFalse);
1306 if (memcmp(magick,"\211PNG\r\n\032\n",8) == 0)
1309 return(MagickFalse);
1312 #if defined(MAGICKCORE_PNG_DELEGATE)
1313 #if defined(__cplusplus) || defined(c_plusplus)
1317 #if (PNG_LIBPNG_VER > 10011)
1318 static size_t WriteBlobMSBULong(Image *image,const size_t value)
1323 assert(image != (Image *) NULL);
1324 assert(image->signature == MagickSignature);
1325 buffer[0]=(unsigned char) (value >> 24);
1326 buffer[1]=(unsigned char) (value >> 16);
1327 buffer[2]=(unsigned char) (value >> 8);
1328 buffer[3]=(unsigned char) value;
1329 return((size_t) WriteBlob(image,4,buffer));
1332 static void PNGLong(png_bytep p,png_uint_32 value)
1334 *p++=(png_byte) ((value >> 24) & 0xff);
1335 *p++=(png_byte) ((value >> 16) & 0xff);
1336 *p++=(png_byte) ((value >> 8) & 0xff);
1337 *p++=(png_byte) (value & 0xff);
1340 #if defined(JNG_SUPPORTED)
1341 static void PNGsLong(png_bytep p,png_int_32 value)
1343 *p++=(png_byte) ((value >> 24) & 0xff);
1344 *p++=(png_byte) ((value >> 16) & 0xff);
1345 *p++=(png_byte) ((value >> 8) & 0xff);
1346 *p++=(png_byte) (value & 0xff);
1350 static void PNGShort(png_bytep p,png_uint_16 value)
1352 *p++=(png_byte) ((value >> 8) & 0xff);
1353 *p++=(png_byte) (value & 0xff);
1356 static void PNGType(png_bytep p,png_bytep type)
1358 (void) CopyMagickMemory(p,type,4*sizeof(png_byte));
1361 static void LogPNGChunk(MagickBooleanType logging, png_bytep type,
1364 if (logging != MagickFalse)
1365 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1366 " Writing %c%c%c%c chunk, length: %.20g",
1367 type[0],type[1],type[2],type[3],(double) length);
1369 #endif /* PNG_LIBPNG_VER > 10011 */
1371 #if defined(__cplusplus) || defined(c_plusplus)
1375 #if PNG_LIBPNG_VER > 10011
1377 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1381 % R e a d P N G I m a g e %
1385 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1387 % ReadPNGImage() reads a Portable Network Graphics (PNG) or
1388 % Multiple-image Network Graphics (MNG) image file and returns it. It
1389 % allocates the memory necessary for the new Image structure and returns a
1390 % pointer to the new image or set of images.
1392 % MNG support written by Glenn Randers-Pehrson, glennrp@image...
1394 % The format of the ReadPNGImage method is:
1396 % Image *ReadPNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
1398 % A description of each parameter follows:
1400 % o image_info: the image info.
1402 % o exception: return any errors or warnings in this structure.
1404 % To do, more or less in chronological order (as of version 5.5.2,
1405 % November 26, 2002 -- glennrp -- see also "To do" under WriteMNGImage):
1407 % Get 16-bit cheap transparency working.
1409 % (At this point, PNG decoding is supposed to be in full MNG-LC compliance)
1411 % Preserve all unknown and not-yet-handled known chunks found in input
1412 % PNG file and copy them into output PNG files according to the PNG
1415 % (At this point, PNG encoding should be in full MNG compliance)
1417 % Provide options for choice of background to use when the MNG BACK
1418 % chunk is not present or is not mandatory (i.e., leave transparent,
1419 % user specified, MNG BACK, PNG bKGD)
1421 % Implement LOOP/ENDL [done, but could do discretionary loops more
1422 % efficiently by linking in the duplicate frames.].
1424 % Decode and act on the MHDR simplicity profile (offer option to reject
1425 % files or attempt to process them anyway when the profile isn't LC or VLC).
1427 % Upgrade to full MNG without Delta-PNG.
1429 % o BACK [done a while ago except for background image ID]
1430 % o MOVE [done 15 May 1999]
1431 % o CLIP [done 15 May 1999]
1432 % o DISC [done 19 May 1999]
1433 % o SAVE [partially done 19 May 1999 (marks objects frozen)]
1434 % o SEEK [partially done 19 May 1999 (discard function only)]
1438 % o MNG-level tEXt/iTXt/zTXt
1443 % o iTXt (wait for libpng implementation).
1445 % Use the scene signature to discover when an identical scene is
1446 % being reused, and just point to the original image->exception instead
1447 % of storing another set of pixels. This not specific to MNG
1448 % but could be applied generally.
1450 % Upgrade to full MNG with Delta-PNG.
1452 % JNG tEXt/iTXt/zTXt
1454 % We will not attempt to read files containing the CgBI chunk.
1455 % They are really Xcode files meant for display on the iPhone.
1456 % These are not valid PNG files and it is impossible to recover
1457 % the original PNG from files that have been converted to Xcode-PNG,
1458 % since irretrievable loss of color data has occurred due to the
1459 % use of premultiplied alpha.
1462 #if defined(__cplusplus) || defined(c_plusplus)
1467 This the function that does the actual reading of data. It is
1468 the same as the one supplied in libpng, except that it receives the
1469 datastream from the ReadBlob() function instead of standard input.
1471 static void png_get_data(png_structp png_ptr,png_bytep data,png_size_t length)
1476 image=(Image *) png_get_io_ptr(png_ptr);
1482 check=(png_size_t) ReadBlob(image,(size_t) length,data);
1483 if (check != length)
1488 (void) FormatLocaleString(msg,MaxTextExtent,
1489 "Expected %.20g bytes; found %.20g bytes",(double) length,
1491 png_warning(png_ptr,msg);
1492 png_error(png_ptr,"Read Exception");
1497 #if !defined(PNG_READ_EMPTY_PLTE_SUPPORTED) && \
1498 !defined(PNG_MNG_FEATURES_SUPPORTED)
1499 /* We use mng_get_data() instead of png_get_data() if we have a libpng
1500 * older than libpng-1.0.3a, which was the first to allow the empty
1501 * PLTE, or a newer libpng in which PNG_MNG_FEATURES_SUPPORTED was
1502 * ifdef'ed out. Earlier versions would crash if the bKGD chunk was
1503 * encountered after an empty PLTE, so we have to look ahead for bKGD
1504 * chunks and remove them from the datastream that is passed to libpng,
1505 * and store their contents for later use.
1507 static void mng_get_data(png_structp png_ptr,png_bytep data,png_size_t length)
1522 mng_info=(MngInfo *) png_get_io_ptr(png_ptr);
1523 image=(Image *) mng_info->image;
1524 while (mng_info->bytes_in_read_buffer && length)
1526 data[i]=mng_info->read_buffer[i];
1527 mng_info->bytes_in_read_buffer--;
1533 check=(png_size_t) ReadBlob(image,(size_t) length,(char *) data);
1535 if (check != length)
1536 png_error(png_ptr,"Read Exception");
1540 if ((data[0] == 0) && (data[1] == 0) && (data[2] == 0) &&
1543 check=(png_size_t) ReadBlob(image,(size_t) length,
1544 (char *) mng_info->read_buffer);
1545 mng_info->read_buffer[4]=0;
1546 mng_info->bytes_in_read_buffer=4;
1547 if (memcmp(mng_info->read_buffer,mng_PLTE,4) == 0)
1548 mng_info->found_empty_plte=MagickTrue;
1549 if (memcmp(mng_info->read_buffer,mng_IEND,4) == 0)
1551 mng_info->found_empty_plte=MagickFalse;
1552 mng_info->have_saved_bkgd_index=MagickFalse;
1556 if ((data[0] == 0) && (data[1] == 0) && (data[2] == 0) &&
1559 check=(png_size_t) ReadBlob(image,(size_t) length,
1560 (char *) mng_info->read_buffer);
1561 mng_info->read_buffer[4]=0;
1562 mng_info->bytes_in_read_buffer=4;
1563 if (memcmp(mng_info->read_buffer,mng_bKGD,4) == 0)
1564 if (mng_info->found_empty_plte)
1567 Skip the bKGD data byte and CRC.
1570 ReadBlob(image,5,(char *) mng_info->read_buffer);
1571 check=(png_size_t) ReadBlob(image,(size_t) length,
1572 (char *) mng_info->read_buffer);
1573 mng_info->saved_bkgd_index=mng_info->read_buffer[0];
1574 mng_info->have_saved_bkgd_index=MagickTrue;
1575 mng_info->bytes_in_read_buffer=0;
1583 static void png_put_data(png_structp png_ptr,png_bytep data,png_size_t length)
1588 image=(Image *) png_get_io_ptr(png_ptr);
1594 check=(png_size_t) WriteBlob(image,(size_t) length,data);
1596 if (check != length)
1597 png_error(png_ptr,"WriteBlob Failed");
1601 static void png_flush_data(png_structp png_ptr)
1606 #ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
1607 static int PalettesAreEqual(Image *a,Image *b)
1612 if ((a == (Image *) NULL) || (b == (Image *) NULL))
1613 return((int) MagickFalse);
1615 if (a->storage_class != PseudoClass || b->storage_class != PseudoClass)
1616 return((int) MagickFalse);
1618 if (a->colors != b->colors)
1619 return((int) MagickFalse);
1621 for (i=0; i < (ssize_t) a->colors; i++)
1623 if ((a->colormap[i].red != b->colormap[i].red) ||
1624 (a->colormap[i].green != b->colormap[i].green) ||
1625 (a->colormap[i].blue != b->colormap[i].blue))
1626 return((int) MagickFalse);
1629 return((int) MagickTrue);
1633 static void MngInfoDiscardObject(MngInfo *mng_info,int i)
1635 if (i && (i < MNG_MAX_OBJECTS) && (mng_info != (MngInfo *) NULL) &&
1636 mng_info->exists[i] && !mng_info->frozen[i])
1638 #ifdef MNG_OBJECT_BUFFERS
1639 if (mng_info->ob[i] != (MngBuffer *) NULL)
1641 if (mng_info->ob[i]->reference_count > 0)
1642 mng_info->ob[i]->reference_count--;
1644 if (mng_info->ob[i]->reference_count == 0)
1646 if (mng_info->ob[i]->image != (Image *) NULL)
1647 mng_info->ob[i]->image=DestroyImage(mng_info->ob[i]->image);
1649 mng_info->ob[i]=DestroyString(mng_info->ob[i]);
1652 mng_info->ob[i]=(MngBuffer *) NULL;
1654 mng_info->exists[i]=MagickFalse;
1655 mng_info->invisible[i]=MagickFalse;
1656 mng_info->viewable[i]=MagickFalse;
1657 mng_info->frozen[i]=MagickFalse;
1658 mng_info->x_off[i]=0;
1659 mng_info->y_off[i]=0;
1660 mng_info->object_clip[i].left=0;
1661 mng_info->object_clip[i].right=(ssize_t) PNG_UINT_31_MAX;
1662 mng_info->object_clip[i].top=0;
1663 mng_info->object_clip[i].bottom=(ssize_t) PNG_UINT_31_MAX;
1667 static void MngInfoFreeStruct(MngInfo *mng_info,
1668 MagickBooleanType *have_mng_structure)
1670 if (*have_mng_structure != MagickFalse && (mng_info != (MngInfo *) NULL))
1675 for (i=1; i < MNG_MAX_OBJECTS; i++)
1676 MngInfoDiscardObject(mng_info,i);
1678 if (mng_info->global_plte != (png_colorp) NULL)
1679 mng_info->global_plte=(png_colorp)
1680 RelinquishMagickMemory(mng_info->global_plte);
1682 mng_info=(MngInfo *) RelinquishMagickMemory(mng_info);
1683 *have_mng_structure=MagickFalse;
1687 static MngBox mng_minimum_box(MngBox box1,MngBox box2)
1693 if (box.left < box2.left)
1696 if (box.top < box2.top)
1699 if (box.right > box2.right)
1700 box.right=box2.right;
1702 if (box.bottom > box2.bottom)
1703 box.bottom=box2.bottom;
1708 static MngBox mng_read_box(MngBox previous_box,char delta_type,unsigned char *p)
1714 Read clipping boundaries from DEFI, CLIP, FRAM, or PAST chunk.
1716 box.left=(ssize_t) ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]);
1717 box.right=(ssize_t) ((p[4] << 24) | (p[5] << 16) | (p[6] << 8) | p[7]);
1718 box.top=(ssize_t) ((p[8] << 24) | (p[9] << 16) | (p[10] << 8) | p[11]);
1719 box.bottom=(ssize_t) ((p[12] << 24) | (p[13] << 16) | (p[14] << 8) | p[15]);
1720 if (delta_type != 0)
1722 box.left+=previous_box.left;
1723 box.right+=previous_box.right;
1724 box.top+=previous_box.top;
1725 box.bottom+=previous_box.bottom;
1731 static MngPair mng_read_pair(MngPair previous_pair,int delta_type,
1737 Read two ssize_ts from CLON, MOVE or PAST chunk
1739 pair.a=(long) ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]);
1740 pair.b=(long) ((p[4] << 24) | (p[5] << 16) | (p[6] << 8) | p[7]);
1742 if (delta_type != 0)
1744 pair.a+=previous_pair.a;
1745 pair.b+=previous_pair.b;
1751 static long mng_get_long(unsigned char *p)
1753 return((long) ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]));
1756 typedef struct _PNGErrorInfo
1765 static void MagickPNGErrorHandler(png_struct *ping,png_const_charp message)
1776 error_info=(PNGErrorInfo *) png_get_error_ptr(ping);
1777 image=error_info->image;
1778 exception=error_info->exception;
1780 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1781 " libpng-%s error: %s", PNG_LIBPNG_VER_STRING,message);
1783 (void) ThrowMagickException(exception,GetMagickModule(),CoderError,message,
1784 "`%s'",image->filename);
1786 #if (PNG_LIBPNG_VER < 10500)
1787 /* A warning about deprecated use of jmpbuf here is unavoidable if you
1788 * are building with libpng-1.4.x and can be ignored.
1790 longjmp(ping->jmpbuf,1);
1792 png_longjmp(ping,1);
1796 static void MagickPNGWarningHandler(png_struct *ping,png_const_charp message)
1807 if (LocaleCompare(message, "Missing PLTE before tRNS") == 0)
1808 png_error(ping, message);
1810 error_info=(PNGErrorInfo *) png_get_error_ptr(ping);
1811 image=error_info->image;
1812 exception=error_info->exception;
1813 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1814 " libpng-%s warning: %s", PNG_LIBPNG_VER_STRING,message);
1816 (void) ThrowMagickException(exception,GetMagickModule(),CoderWarning,
1817 message,"`%s'",image->filename);
1820 #ifdef PNG_USER_MEM_SUPPORTED
1821 #if PNG_LIBPNG_VER >= 14000
1822 static png_voidp Magick_png_malloc(png_structp png_ptr,png_alloc_size_t size)
1824 static png_voidp Magick_png_malloc(png_structp png_ptr,png_size_t size)
1828 return((png_voidp) AcquireMagickMemory((size_t) size));
1832 Free a pointer. It is removed from the list at the same time.
1834 static png_free_ptr Magick_png_free(png_structp png_ptr,png_voidp ptr)
1837 ptr=RelinquishMagickMemory(ptr);
1838 return((png_free_ptr) NULL);
1842 #if defined(__cplusplus) || defined(c_plusplus)
1847 Magick_png_read_raw_profile(png_struct *ping,Image *image,
1848 const ImageInfo *image_info, png_textp text,int ii,ExceptionInfo *exception)
1853 register unsigned char
1867 unhex[103]={0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,
1868 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,
1869 0,0,0,0,0,0,0,0,0,1, 2,3,4,5,6,7,8,9,0,0,
1870 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,
1871 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,10,11,12,
1875 /* look for newline */
1879 /* look for length */
1880 while (*sp == '\0' || *sp == ' ' || *sp == '\n')
1883 length=(png_uint_32) StringToLong(sp);
1885 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1886 " length: %lu",(unsigned long) length);
1888 while (*sp != ' ' && *sp != '\n')
1891 /* allocate space */
1894 png_warning(ping,"invalid profile length");
1895 return(MagickFalse);
1898 profile=BlobToStringInfo((const void *) NULL,length);
1900 if (profile == (StringInfo *) NULL)
1902 png_warning(ping, "unable to copy profile");
1903 return(MagickFalse);
1906 /* copy profile, skipping white space and column 1 "=" signs */
1907 dp=GetStringInfoDatum(profile);
1910 for (i=0; i < (ssize_t) nibbles; i++)
1912 while (*sp < '0' || (*sp > '9' && *sp < 'a') || *sp > 'f')
1916 png_warning(ping, "ran out of profile data");
1917 profile=DestroyStringInfo(profile);
1918 return(MagickFalse);
1924 *dp=(unsigned char) (16*unhex[(int) *sp++]);
1927 (*dp++)+=unhex[(int) *sp++];
1930 We have already read "Raw profile type.
1932 (void) SetImageProfile(image,&text[ii].key[17],profile,exception);
1933 profile=DestroyStringInfo(profile);
1935 if (image_info->verbose)
1936 (void) printf(" Found a generic profile, type %s\n",&text[ii].key[17]);
1941 #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
1942 static int read_vpag_chunk_callback(png_struct *ping, png_unknown_chunkp chunk)
1948 /* The unknown chunk structure contains the chunk data:
1953 Note that libpng has already taken care of the CRC handling.
1956 LogMagickEvent(CoderEvent,GetMagickModule(),
1957 " read_vpag_chunk: found %c%c%c%c chunk",
1958 chunk->name[0],chunk->name[1],chunk->name[2],chunk->name[3]);
1960 if (chunk->name[0] != 118 || chunk->name[1] != 112 ||
1961 chunk->name[2] != 65 ||chunk-> name[3] != 103)
1962 return(0); /* Did not recognize */
1964 /* recognized vpAg */
1966 if (chunk->size != 9)
1967 return(-1); /* Error return */
1969 if (chunk->data[8] != 0)
1970 return(0); /* ImageMagick requires pixel units */
1972 image=(Image *) png_get_user_chunk_ptr(ping);
1974 image->page.width=(size_t) ((chunk->data[0] << 24) |
1975 (chunk->data[1] << 16) | (chunk->data[2] << 8) | chunk->data[3]);
1977 image->page.height=(size_t) ((chunk->data[4] << 24) |
1978 (chunk->data[5] << 16) | (chunk->data[6] << 8) | chunk->data[7]);
1980 /* Return one of the following: */
1981 /* return(-n); chunk had an error */
1982 /* return(0); did not recognize */
1983 /* return(n); success */
1991 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1995 % R e a d O n e P N G I m a g e %
1999 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2001 % ReadOnePNGImage() reads a Portable Network Graphics (PNG) image file
2002 % (minus the 8-byte signature) and returns it. It allocates the memory
2003 % necessary for the new Image structure and returns a pointer to the new
2006 % The format of the ReadOnePNGImage method is:
2008 % Image *ReadOnePNGImage(MngInfo *mng_info, const ImageInfo *image_info,
2009 % ExceptionInfo *exception)
2011 % A description of each parameter follows:
2013 % o mng_info: Specifies a pointer to a MngInfo structure.
2015 % o image_info: the image info.
2017 % o exception: return any errors or warnings in this structure.
2020 static Image *ReadOnePNGImage(MngInfo *mng_info,
2021 const ImageInfo *image_info, ExceptionInfo *exception)
2023 /* Read one PNG image */
2025 /* To do: Read the tIME chunk into the date:modify property */
2026 /* To do: Read the tEXt/Creation Time chunk into the date:create property */
2032 intent, /* "PNG Rendering intent", which is ICC intent + 1 */
2042 ping_interlace_method,
2043 ping_compression_method,
2057 ping_found_sRGB_cHRM,
2096 register unsigned char
2114 *volatile ping_pixels;
2116 #ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED
2117 png_byte unused_chunks[]=
2119 104, 73, 83, 84, (png_byte) '\0', /* hIST */
2120 105, 84, 88, 116, (png_byte) '\0', /* iTXt */
2121 112, 67, 65, 76, (png_byte) '\0', /* pCAL */
2122 115, 67, 65, 76, (png_byte) '\0', /* sCAL */
2123 115, 80, 76, 84, (png_byte) '\0', /* sPLT */
2124 116, 73, 77, 69, (png_byte) '\0', /* tIME */
2125 #ifdef PNG_APNG_SUPPORTED /* libpng was built with APNG patch; */
2126 /* ignore the APNG chunks */
2127 97, 99, 84, 76, (png_byte) '\0', /* acTL */
2128 102, 99, 84, 76, (png_byte) '\0', /* fcTL */
2129 102, 100, 65, 84, (png_byte) '\0', /* fdAT */
2134 logging=LogMagickEvent(CoderEvent,GetMagickModule(),
2135 " Enter ReadOnePNGImage()");
2137 #if (PNG_LIBPNG_VER < 10200)
2138 if (image_info->verbose)
2139 printf("Your PNG library (libpng-%s) is rather old.\n",
2140 PNG_LIBPNG_VER_STRING);
2143 #if (PNG_LIBPNG_VER >= 10400)
2144 # ifndef PNG_TRANSFORM_GRAY_TO_RGB /* Added at libpng-1.4.0beta67 */
2145 if (image_info->verbose)
2147 printf("Your PNG library (libpng-%s) is an old beta version.\n",
2148 PNG_LIBPNG_VER_STRING);
2149 printf("Please update it.\n");
2155 quantum_info = (QuantumInfo *) NULL;
2156 image=mng_info->image;
2158 if (logging != MagickFalse)
2160 (void)LogMagickEvent(CoderEvent,GetMagickModule(),
2161 " Before reading:");
2163 (void)LogMagickEvent(CoderEvent,GetMagickModule(),
2164 " image->alpha_trait=%d",(int) image->alpha_trait);
2166 (void)LogMagickEvent(CoderEvent,GetMagickModule(),
2167 " image->rendering_intent=%d",(int) image->rendering_intent);
2169 (void)LogMagickEvent(CoderEvent,GetMagickModule(),
2170 " image->colorspace=%d",(int) image->colorspace);
2172 (void)LogMagickEvent(CoderEvent,GetMagickModule(),
2173 " image->gamma=%f", image->gamma);
2175 intent=Magick_RenderingIntent_to_PNG_RenderingIntent(image->rendering_intent);
2177 /* Set to an out-of-range color unless tRNS chunk is present */
2178 transparent_color.red=65537;
2179 transparent_color.green=65537;
2180 transparent_color.blue=65537;
2181 transparent_color.alpha=65537;
2186 num_raw_profiles = 0;
2188 ping_found_cHRM = MagickFalse;
2189 ping_found_gAMA = MagickFalse;
2190 ping_found_iCCP = MagickFalse;
2191 ping_found_sRGB = MagickFalse;
2194 Allocate the PNG structures
2196 #ifdef PNG_USER_MEM_SUPPORTED
2197 error_info.image=image;
2198 error_info.exception=exception;
2199 ping=png_create_read_struct_2(PNG_LIBPNG_VER_STRING,&error_info,
2200 MagickPNGErrorHandler,MagickPNGWarningHandler, NULL,
2201 (png_malloc_ptr) Magick_png_malloc,(png_free_ptr) Magick_png_free);
2203 ping=png_create_read_struct(PNG_LIBPNG_VER_STRING,&error_info,
2204 MagickPNGErrorHandler,MagickPNGWarningHandler);
2206 if (ping == (png_struct *) NULL)
2207 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2209 ping_info=png_create_info_struct(ping);
2211 if (ping_info == (png_info *) NULL)
2213 png_destroy_read_struct(&ping,(png_info **) NULL,(png_info **) NULL);
2214 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2217 end_info=png_create_info_struct(ping);
2219 if (end_info == (png_info *) NULL)
2221 png_destroy_read_struct(&ping,&ping_info,(png_info **) NULL);
2222 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2225 ping_pixels=(unsigned char *) NULL;
2227 if (setjmp(png_jmpbuf(ping)))
2230 PNG image is corrupt.
2232 png_destroy_read_struct(&ping,&ping_info,&end_info);
2234 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
2235 UnlockSemaphoreInfo(ping_semaphore);
2238 if (ping_pixels != (unsigned char *) NULL)
2239 ping_pixels=(unsigned char *) RelinquishMagickMemory(ping_pixels);
2241 if (logging != MagickFalse)
2242 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2243 " exit ReadOnePNGImage() with error.");
2245 if (image != (Image *) NULL)
2247 InheritException(exception,exception);
2251 return(GetFirstImageInList(image));
2254 /* { For navigation to end of SETJMP-protected block. Within this
2255 * block, use png_error() instead of Throwing an Exception, to ensure
2256 * that libpng is able to clean up, and that the semaphore is unlocked.
2259 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
2260 LockSemaphoreInfo(ping_semaphore);
2264 Prepare PNG for reading.
2267 mng_info->image_found++;
2268 png_set_sig_bytes(ping,8);
2270 if (LocaleCompare(image_info->magick,"MNG") == 0)
2272 #if defined(PNG_MNG_FEATURES_SUPPORTED)
2273 (void) png_permit_mng_features(ping,PNG_ALL_MNG_FEATURES);
2274 png_set_read_fn(ping,image,png_get_data);
2276 #if defined(PNG_READ_EMPTY_PLTE_SUPPORTED)
2277 png_permit_empty_plte(ping,MagickTrue);
2278 png_set_read_fn(ping,image,png_get_data);
2280 mng_info->image=image;
2281 mng_info->bytes_in_read_buffer=0;
2282 mng_info->found_empty_plte=MagickFalse;
2283 mng_info->have_saved_bkgd_index=MagickFalse;
2284 png_set_read_fn(ping,mng_info,mng_get_data);
2290 png_set_read_fn(ping,image,png_get_data);
2292 #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
2293 /* Ignore unused chunks and all unknown chunks except for vpAg */
2294 #if PNG_LIBPNG_VER < 10700 /* Avoid libpng16 warning */
2295 png_set_keep_unknown_chunks(ping, 2, NULL, 0);
2297 png_set_keep_unknown_chunks(ping, 1, NULL, 0);
2299 png_set_keep_unknown_chunks(ping, 2, mng_vpAg, 1);
2300 png_set_keep_unknown_chunks(ping, 1, unused_chunks,
2301 (int)sizeof(unused_chunks)/5);
2302 /* Callback for other unknown chunks */
2303 png_set_read_user_chunk_fn(ping, image, read_vpag_chunk_callback);
2306 #ifdef PNG_SET_USER_LIMITS_SUPPORTED
2307 # if (PNG_LIBPNG_VER >= 10400)
2308 /* Limit the size of the chunk storage cache used for sPLT, text,
2309 * and unknown chunks.
2311 png_set_chunk_cache_max(ping, 32767);
2315 #ifdef PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED
2316 /* Disable new libpng-1.5.10 feature */
2317 png_set_check_for_invalid_index (ping, 0);
2320 #if (PNG_LIBPNG_VER < 10400)
2321 # if defined(PNG_USE_PNGGCCRD) && defined(PNG_ASSEMBLER_CODE_SUPPORTED) && \
2322 (PNG_LIBPNG_VER >= 10200) && (PNG_LIBPNG_VER < 10220) && defined(__i386__)
2323 /* Disable thread-unsafe features of pnggccrd */
2324 if (png_access_version_number() >= 10200)
2326 png_uint_32 mmx_disable_mask=0;
2327 png_uint_32 asm_flags;
2329 mmx_disable_mask |= ( PNG_ASM_FLAG_MMX_READ_COMBINE_ROW \
2330 | PNG_ASM_FLAG_MMX_READ_FILTER_SUB \
2331 | PNG_ASM_FLAG_MMX_READ_FILTER_AVG \
2332 | PNG_ASM_FLAG_MMX_READ_FILTER_PAETH );
2333 asm_flags=png_get_asm_flags(ping);
2334 png_set_asm_flags(ping, asm_flags & ~mmx_disable_mask);
2339 png_read_info(ping,ping_info);
2341 png_get_IHDR(ping,ping_info,&ping_width,&ping_height,
2342 &ping_bit_depth,&ping_color_type,
2343 &ping_interlace_method,&ping_compression_method,
2344 &ping_filter_method);
2346 ping_file_depth = ping_bit_depth;
2348 /* Save bit-depth and color-type in case we later want to write a PNG00 */
2353 (void) FormatLocaleString(msg,MaxTextExtent,"%d",(int) ping_color_type);
2354 (void) SetImageProperty(image,"png:IHDR.color-type-orig ",msg,exception);
2356 (void) FormatLocaleString(msg,MaxTextExtent,"%d",(int) ping_bit_depth);
2357 (void) SetImageProperty(image,"png:IHDR.bit-depth-orig ",msg,exception);
2360 (void) png_get_tRNS(ping, ping_info, &ping_trans_alpha, &ping_num_trans,
2363 (void) png_get_bKGD(ping, ping_info, &ping_background);
2365 if (ping_bit_depth < 8)
2367 png_set_packing(ping);
2371 image->depth=ping_bit_depth;
2372 image->depth=GetImageQuantumDepth(image,MagickFalse);
2373 image->interlace=ping_interlace_method != 0 ? PNGInterlace : NoInterlace;
2375 if (((int) ping_color_type == PNG_COLOR_TYPE_GRAY) ||
2376 ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA))
2378 image->rendering_intent=UndefinedIntent;
2379 intent=Magick_RenderingIntent_to_PNG_RenderingIntent(UndefinedIntent);
2381 (void) ResetMagickMemory(&image->chromaticity,0,
2382 sizeof(image->chromaticity));
2385 if (logging != MagickFalse)
2387 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2388 " PNG width: %.20g, height: %.20g",
2389 (double) ping_width, (double) ping_height);
2391 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2392 " PNG color_type: %d, bit_depth: %d",
2393 ping_color_type, ping_bit_depth);
2395 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2396 " PNG compression_method: %d",
2397 ping_compression_method);
2399 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2400 " PNG interlace_method: %d, filter_method: %d",
2401 ping_interlace_method,ping_filter_method);
2404 if (png_get_valid(ping,ping_info,PNG_INFO_gAMA))
2406 ping_found_gAMA=MagickTrue;
2407 if (logging != MagickFalse)
2408 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2409 " Found PNG gAMA chunk.");
2412 if (png_get_valid(ping,ping_info,PNG_INFO_cHRM))
2414 ping_found_cHRM=MagickTrue;
2415 if (logging != MagickFalse)
2416 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2417 " Found PNG cHRM chunk.");
2420 if (png_get_valid(ping,ping_info,PNG_INFO_iCCP))
2422 ping_found_iCCP=MagickTrue;
2423 if (logging != MagickFalse)
2424 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2425 " Found PNG iCCP chunk.");
2428 if (png_get_valid(ping,ping_info,PNG_INFO_sRGB))
2430 ping_found_sRGB=MagickTrue;
2431 if (logging != MagickFalse)
2432 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2433 " Found PNG sRGB chunk.");
2436 #ifdef PNG_READ_iCCP_SUPPORTED
2437 if (png_get_valid(ping,ping_info,PNG_INFO_iCCP))
2442 #if (PNG_LIBPNG_VER < 10500)
2456 (void) png_get_iCCP(ping,ping_info,&name,(int *) &compression,&info,
2459 if (profile_length != 0)
2464 if (logging != MagickFalse)
2465 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2466 " Reading PNG iCCP chunk.");
2467 profile=BlobToStringInfo(info,profile_length);
2468 if (profile == (StringInfo *) NULL)
2470 png_warning(ping, "ICC profile is NULL");
2471 profile=DestroyStringInfo(profile);
2475 (void) SetImageProfile(image,"icc",profile,exception);
2476 profile=DestroyStringInfo(profile);
2481 #if defined(PNG_READ_sRGB_SUPPORTED)
2483 if (mng_info->have_global_srgb)
2485 image->rendering_intent=Magick_RenderingIntent_from_PNG_RenderingIntent
2486 (mng_info->global_srgb_intent);
2489 if (png_get_sRGB(ping,ping_info,&intent))
2491 image->rendering_intent=Magick_RenderingIntent_from_PNG_RenderingIntent
2494 if (logging != MagickFalse)
2495 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2496 " Reading PNG sRGB chunk: rendering_intent: %d",intent);
2501 if (!png_get_gAMA(ping,ping_info,&file_gamma))
2502 if (mng_info->have_global_gama)
2503 png_set_gAMA(ping,ping_info,mng_info->global_gamma);
2505 if (png_get_gAMA(ping,ping_info,&file_gamma))
2507 image->gamma=(float) file_gamma;
2508 if (logging != MagickFalse)
2509 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2510 " Reading PNG gAMA chunk: gamma: %f",file_gamma);
2514 if (!png_get_valid(ping,ping_info,PNG_INFO_cHRM))
2516 if (mng_info->have_global_chrm != MagickFalse)
2518 (void) png_set_cHRM(ping,ping_info,
2519 mng_info->global_chrm.white_point.x,
2520 mng_info->global_chrm.white_point.y,
2521 mng_info->global_chrm.red_primary.x,
2522 mng_info->global_chrm.red_primary.y,
2523 mng_info->global_chrm.green_primary.x,
2524 mng_info->global_chrm.green_primary.y,
2525 mng_info->global_chrm.blue_primary.x,
2526 mng_info->global_chrm.blue_primary.y);
2530 if (png_get_valid(ping,ping_info,PNG_INFO_cHRM))
2532 (void) png_get_cHRM(ping,ping_info,
2533 &image->chromaticity.white_point.x,
2534 &image->chromaticity.white_point.y,
2535 &image->chromaticity.red_primary.x,
2536 &image->chromaticity.red_primary.y,
2537 &image->chromaticity.green_primary.x,
2538 &image->chromaticity.green_primary.y,
2539 &image->chromaticity.blue_primary.x,
2540 &image->chromaticity.blue_primary.y);
2542 if (image->chromaticity.red_primary.x>0.6399f &&
2543 image->chromaticity.red_primary.x<0.6401f &&
2544 image->chromaticity.red_primary.y>0.3299f &&
2545 image->chromaticity.red_primary.y<0.3301f &&
2546 image->chromaticity.green_primary.x>0.2999f &&
2547 image->chromaticity.green_primary.x<0.3001f &&
2548 image->chromaticity.green_primary.y>0.5999f &&
2549 image->chromaticity.green_primary.y<0.6001f &&
2550 image->chromaticity.blue_primary.x>0.1499f &&
2551 image->chromaticity.blue_primary.x<0.1501f &&
2552 image->chromaticity.blue_primary.y>0.0599f &&
2553 image->chromaticity.blue_primary.y<0.0601f &&
2554 image->chromaticity.white_point.x>0.3126f &&
2555 image->chromaticity.white_point.x<0.3128f &&
2556 image->chromaticity.white_point.y>0.3289f &&
2557 image->chromaticity.white_point.y<0.3291f)
2558 ping_found_sRGB_cHRM=MagickTrue;
2560 ping_found_cHRM=MagickTrue;
2563 if (image->rendering_intent != UndefinedIntent)
2565 if (ping_found_sRGB != MagickTrue &&
2566 (ping_found_gAMA != MagickTrue ||
2567 (image->gamma > .45 && image->gamma < .46)) &&
2568 (ping_found_cHRM != MagickTrue ||
2569 ping_found_sRGB_cHRM == MagickTrue) &&
2570 ping_found_iCCP != MagickTrue)
2572 png_set_sRGB(ping,ping_info,
2573 Magick_RenderingIntent_to_PNG_RenderingIntent
2574 (image->rendering_intent));
2575 if (ping_found_gAMA != MagickTrue)
2576 png_set_gAMA(ping,ping_info,1.000f/2.200f);
2577 file_gamma=1.000f/2.200f;
2578 ping_found_sRGB=MagickTrue;
2579 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2580 " Setting sRGB and gAMA as if in input");
2584 #if defined(PNG_oFFs_SUPPORTED)
2585 if (png_get_valid(ping,ping_info,PNG_INFO_oFFs))
2587 image->page.x=(ssize_t) png_get_x_offset_pixels(ping, ping_info);
2588 image->page.y=(ssize_t) png_get_y_offset_pixels(ping, ping_info);
2590 if (logging != MagickFalse)
2591 if (image->page.x || image->page.y)
2592 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2593 " Reading PNG oFFs chunk: x: %.20g, y: %.20g.",(double)
2594 image->page.x,(double) image->page.y);
2597 #if defined(PNG_pHYs_SUPPORTED)
2598 if (!png_get_valid(ping,ping_info,PNG_INFO_pHYs))
2600 if (mng_info->have_global_phys)
2602 png_set_pHYs(ping,ping_info,
2603 mng_info->global_x_pixels_per_unit,
2604 mng_info->global_y_pixels_per_unit,
2605 mng_info->global_phys_unit_type);
2609 if (png_get_valid(ping,ping_info,PNG_INFO_pHYs))
2612 Set image resolution.
2614 (void) png_get_pHYs(ping,ping_info,&x_resolution,&y_resolution,
2616 image->resolution.x=(double) x_resolution;
2617 image->resolution.y=(double) y_resolution;
2619 if (unit_type == PNG_RESOLUTION_METER)
2621 image->units=PixelsPerCentimeterResolution;
2622 image->resolution.x=(double) x_resolution/100.0;
2623 image->resolution.y=(double) y_resolution/100.0;
2626 if (logging != MagickFalse)
2627 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2628 " Reading PNG pHYs chunk: xres: %.20g, yres: %.20g, units: %d.",
2629 (double) x_resolution,(double) y_resolution,unit_type);
2633 if (png_get_valid(ping,ping_info,PNG_INFO_PLTE))
2638 (void) png_get_PLTE(ping,ping_info,&palette,&number_colors);
2640 if ((number_colors == 0) &&
2641 ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE))
2643 if (mng_info->global_plte_length)
2645 png_set_PLTE(ping,ping_info,mng_info->global_plte,
2646 (int) mng_info->global_plte_length);
2648 if (!png_get_valid(ping,ping_info,PNG_INFO_tRNS))
2650 if (mng_info->global_trns_length)
2653 "global tRNS has more entries than global PLTE");
2657 png_set_tRNS(ping,ping_info,mng_info->global_trns,
2658 (int) mng_info->global_trns_length,NULL);
2661 #ifdef PNG_READ_bKGD_SUPPORTED
2663 #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
2664 mng_info->have_saved_bkgd_index ||
2666 png_get_valid(ping,ping_info,PNG_INFO_bKGD))
2671 #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
2672 if (mng_info->have_saved_bkgd_index)
2673 background.index=mng_info->saved_bkgd_index;
2675 if (png_get_valid(ping, ping_info, PNG_INFO_bKGD))
2676 background.index=ping_background->index;
2678 background.red=(png_uint_16)
2679 mng_info->global_plte[background.index].red;
2681 background.green=(png_uint_16)
2682 mng_info->global_plte[background.index].green;
2684 background.blue=(png_uint_16)
2685 mng_info->global_plte[background.index].blue;
2687 background.gray=(png_uint_16)
2688 mng_info->global_plte[background.index].green;
2690 png_set_bKGD(ping,ping_info,&background);
2695 png_error(ping,"No global PLTE in file");
2699 #ifdef PNG_READ_bKGD_SUPPORTED
2700 if (mng_info->have_global_bkgd &&
2701 (!png_get_valid(ping,ping_info,PNG_INFO_bKGD)))
2702 image->background_color=mng_info->mng_global_bkgd;
2704 if (png_get_valid(ping,ping_info,PNG_INFO_bKGD))
2710 Set image background color.
2712 if (logging != MagickFalse)
2713 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2714 " Reading PNG bKGD chunk.");
2716 /* Scale background components to 16-bit, then scale
2719 if (logging != MagickFalse)
2720 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2721 " raw ping_background=(%d,%d,%d).",ping_background->red,
2722 ping_background->green,ping_background->blue);
2726 if (ping_file_depth == 1)
2729 else if (ping_file_depth == 2)
2732 else if (ping_file_depth == 4)
2735 if (ping_file_depth <= 8)
2738 ping_background->red *= bkgd_scale;
2739 ping_background->green *= bkgd_scale;
2740 ping_background->blue *= bkgd_scale;
2742 if (logging != MagickFalse)
2744 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2745 " bkgd_scale=%d.",bkgd_scale);
2747 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2748 " ping_background=(%d,%d,%d).",ping_background->red,
2749 ping_background->green,ping_background->blue);
2752 image->background_color.red=
2753 ScaleShortToQuantum(ping_background->red);
2755 image->background_color.green=
2756 ScaleShortToQuantum(ping_background->green);
2758 image->background_color.blue=
2759 ScaleShortToQuantum(ping_background->blue);
2761 image->background_color.alpha=OpaqueAlpha;
2763 if (logging != MagickFalse)
2764 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2765 " image->background_color=(%.20g,%.20g,%.20g).",
2766 (double) image->background_color.red,
2767 (double) image->background_color.green,
2768 (double) image->background_color.blue);
2770 #endif /* PNG_READ_bKGD_SUPPORTED */
2772 if (png_get_valid(ping,ping_info,PNG_INFO_tRNS))
2775 Image has a tRNS chunk.
2783 if (logging != MagickFalse)
2784 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2785 " Reading PNG tRNS chunk.");
2787 max_sample = (int) ((one << ping_file_depth) - 1);
2789 if ((ping_color_type == PNG_COLOR_TYPE_GRAY &&
2790 (int)ping_trans_color->gray > max_sample) ||
2791 (ping_color_type == PNG_COLOR_TYPE_RGB &&
2792 ((int)ping_trans_color->red > max_sample ||
2793 (int)ping_trans_color->green > max_sample ||
2794 (int)ping_trans_color->blue > max_sample)))
2796 if (logging != MagickFalse)
2797 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2798 " Ignoring PNG tRNS chunk with out-of-range sample.");
2799 png_free_data(ping, ping_info, PNG_FREE_TRNS, 0);
2800 png_set_invalid(ping,ping_info,PNG_INFO_tRNS);
2801 image->alpha_trait=UndefinedPixelTrait;
2808 scale_to_short = 65535L/((1UL << ping_file_depth)-1);
2810 /* Scale transparent_color to short */
2811 transparent_color.red= scale_to_short*ping_trans_color->red;
2812 transparent_color.green= scale_to_short*ping_trans_color->green;
2813 transparent_color.blue= scale_to_short*ping_trans_color->blue;
2814 transparent_color.alpha= scale_to_short*ping_trans_color->gray;
2816 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
2818 if (logging != MagickFalse)
2820 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2821 " Raw tRNS graylevel is %d.",ping_trans_color->gray);
2823 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2824 " scaled graylevel is %.20g.",transparent_color.alpha);
2826 transparent_color.red=transparent_color.alpha;
2827 transparent_color.green=transparent_color.alpha;
2828 transparent_color.blue=transparent_color.alpha;
2832 #if defined(PNG_READ_sBIT_SUPPORTED)
2833 if (mng_info->have_global_sbit)
2835 if (!png_get_valid(ping,ping_info,PNG_INFO_sBIT))
2836 png_set_sBIT(ping,ping_info,&mng_info->global_sbit);
2839 num_passes=png_set_interlace_handling(ping);
2841 png_read_update_info(ping,ping_info);
2843 ping_rowbytes=png_get_rowbytes(ping,ping_info);
2846 Initialize image structure.
2848 mng_info->image_box.left=0;
2849 mng_info->image_box.right=(ssize_t) ping_width;
2850 mng_info->image_box.top=0;
2851 mng_info->image_box.bottom=(ssize_t) ping_height;
2852 if (mng_info->mng_type == 0)
2854 mng_info->mng_width=ping_width;
2855 mng_info->mng_height=ping_height;
2856 mng_info->frame=mng_info->image_box;
2857 mng_info->clip=mng_info->image_box;
2862 image->page.y=mng_info->y_off[mng_info->object_id];
2865 image->compression=ZipCompression;
2866 image->columns=ping_width;
2867 image->rows=ping_height;
2869 if (((int) ping_color_type == PNG_COLOR_TYPE_GRAY) ||
2870 ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA))
2872 if ((!png_get_valid(ping,ping_info,PNG_INFO_gAMA) ||
2873 image->gamma == 1.0) && ping_found_sRGB != MagickTrue)
2875 /* Set image->gamma to 1.0, image->rendering_intent to Undefined,
2876 * image->colorspace to GRAY, and reset image->chromaticity.
2878 SetImageColorspace(image,GRAYColorspace,exception);
2882 (void)LogMagickEvent(CoderEvent,GetMagickModule(),
2883 " image->colorspace=%d",(int) image->colorspace);
2885 if (((int) ping_color_type == PNG_COLOR_TYPE_PALETTE) ||
2886 ((int) ping_bit_depth < 16 &&
2887 (int) ping_color_type == PNG_COLOR_TYPE_GRAY))
2892 image->storage_class=PseudoClass;
2894 image->colors=one << ping_file_depth;
2895 #if (MAGICKCORE_QUANTUM_DEPTH == 8)
2896 if (image->colors > 256)
2899 if (image->colors > 65536L)
2900 image->colors=65536L;
2902 if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
2907 (void) png_get_PLTE(ping,ping_info,&palette,&number_colors);
2908 image->colors=(size_t) number_colors;
2910 if (logging != MagickFalse)
2911 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2912 " Reading PNG PLTE chunk: number_colors: %d.",number_colors);
2916 if (image->storage_class == PseudoClass)
2919 Initialize image colormap.
2921 if (AcquireImageColormap(image,image->colors,exception) == MagickFalse)
2922 png_error(ping,"Memory allocation failed");
2924 if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
2929 (void) png_get_PLTE(ping,ping_info,&palette,&number_colors);
2931 for (i=0; i < (ssize_t) number_colors; i++)
2933 image->colormap[i].red=ScaleCharToQuantum(palette[i].red);
2934 image->colormap[i].green=ScaleCharToQuantum(palette[i].green);
2935 image->colormap[i].blue=ScaleCharToQuantum(palette[i].blue);
2938 for ( ; i < (ssize_t) image->colors; i++)
2940 image->colormap[i].red=0;
2941 image->colormap[i].green=0;
2942 image->colormap[i].blue=0;
2951 scale=(QuantumRange/((1UL << ping_file_depth)-1));
2956 for (i=0; i < (ssize_t) image->colors; i++)
2958 image->colormap[i].red=(Quantum) (i*scale);
2959 image->colormap[i].green=(Quantum) (i*scale);
2960 image->colormap[i].blue=(Quantum) (i*scale);
2965 /* Set some properties for reporting by "identify" */
2970 /* encode ping_width, ping_height, ping_file_depth, ping_color_type,
2971 ping_interlace_method in value */
2973 (void) FormatLocaleString(msg,MaxTextExtent,
2974 "%d, %d",(int) ping_width, (int) ping_height);
2975 (void) SetImageProperty(image,"png:IHDR.width,height ",msg,exception);
2977 (void) FormatLocaleString(msg,MaxTextExtent,"%d",(int) ping_file_depth);
2978 (void) SetImageProperty(image,"png:IHDR.bit_depth ",msg,exception);
2980 (void) FormatLocaleString(msg,MaxTextExtent,"%d (%s)",
2981 (int) ping_color_type,
2982 Magick_ColorType_from_PNG_ColorType((int)ping_color_type));
2983 (void) SetImageProperty(image,"png:IHDR.color_type ",msg,exception);
2985 if (ping_interlace_method == 0)
2987 (void) FormatLocaleString(msg,MaxTextExtent,"%d (Not interlaced)",
2988 (int) ping_interlace_method);
2990 else if (ping_interlace_method == 1)
2992 (void) FormatLocaleString(msg,MaxTextExtent,"%d (Adam7 method)",
2993 (int) ping_interlace_method);
2997 (void) FormatLocaleString(msg,MaxTextExtent,"%d (Unknown method)",
2998 (int) ping_interlace_method);
3000 (void) SetImageProperty(image,"png:IHDR.interlace_method",msg,exception);
3002 if (number_colors != 0)
3004 (void) FormatLocaleString(msg,MaxTextExtent,"%d",
3005 (int) number_colors);
3006 (void) SetImageProperty(image,"png:PLTE.number_colors ",msg,
3012 Read image scanlines.
3014 if (image->delay != 0)
3015 mng_info->scenes_found++;
3017 if ((mng_info->mng_type == 0 && (image->ping != MagickFalse)) || (
3018 (image_info->number_scenes != 0) && (mng_info->scenes_found > (ssize_t)
3019 (image_info->first_scene+image_info->number_scenes))))
3021 /* This happens later in non-ping decodes */
3022 if (png_get_valid(ping,ping_info,PNG_INFO_tRNS))
3023 image->storage_class=DirectClass;
3025 if (logging != MagickFalse)
3026 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3027 " Skipping PNG image data for scene %.20g",(double)
3028 mng_info->scenes_found-1);
3029 png_destroy_read_struct(&ping,&ping_info,&end_info);
3031 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
3032 UnlockSemaphoreInfo(ping_semaphore);
3035 if (logging != MagickFalse)
3036 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3037 " exit ReadOnePNGImage().");
3042 if (logging != MagickFalse)
3043 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3044 " Reading PNG IDAT chunk(s)");
3047 ping_pixels=(unsigned char *) AcquireQuantumMemory(image->rows,
3048 ping_rowbytes*sizeof(*ping_pixels));
3051 ping_pixels=(unsigned char *) AcquireQuantumMemory(ping_rowbytes,
3052 sizeof(*ping_pixels));
3054 if (ping_pixels == (unsigned char *) NULL)
3055 png_error(ping,"Memory allocation failed");
3057 if (logging != MagickFalse)
3058 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3059 " Converting PNG pixels to pixel packets");
3061 Convert PNG pixels to pixel packets.
3063 quantum_info=AcquireQuantumInfo(image_info,image);
3065 if (quantum_info == (QuantumInfo *) NULL)
3066 png_error(ping,"Failed to allocate quantum_info");
3068 (void) SetQuantumEndian(image,quantum_info,MSBEndian);
3073 found_transparent_pixel;
3075 found_transparent_pixel=MagickFalse;
3077 if (image->storage_class == DirectClass)
3079 for (pass=0; pass < num_passes; pass++)
3082 Convert image to DirectClass pixel packets.
3084 image->alpha_trait=(((int) ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA) ||
3085 ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) ||
3086 (png_get_valid(ping,ping_info,PNG_INFO_tRNS))) ?
3087 BlendPixelTrait : UndefinedPixelTrait;
3089 for (y=0; y < (ssize_t) image->rows; y++)
3092 row_offset=ping_rowbytes*y;
3097 png_read_row(ping,ping_pixels+row_offset,NULL);
3099 if (pass < num_passes-1)
3102 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
3104 if (q == (Quantum *) NULL)
3107 if ((int) ping_color_type == PNG_COLOR_TYPE_GRAY)
3108 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
3109 GrayQuantum,ping_pixels+row_offset,exception);
3111 else if ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
3112 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
3113 GrayAlphaQuantum,ping_pixels+row_offset,exception);
3115 else if ((int) ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA)
3116 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
3117 RGBAQuantum,ping_pixels+row_offset,exception);
3119 else if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
3120 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
3121 IndexQuantum,ping_pixels+row_offset,exception);
3123 else /* ping_color_type == PNG_COLOR_TYPE_RGB */
3124 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
3125 RGBQuantum,ping_pixels+row_offset,exception);
3127 if (found_transparent_pixel == MagickFalse)
3129 /* Is there a transparent pixel in the row? */
3130 if (y== 0 && logging != MagickFalse)
3131 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3132 " Looking for cheap transparent pixel");
3134 for (x=(ssize_t) image->columns-1; x >= 0; x--)
3136 if ((ping_color_type == PNG_COLOR_TYPE_RGBA ||
3137 ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) &&
3138 (GetPixelAlpha(image,q) != OpaqueAlpha))
3140 if (logging != MagickFalse)
3141 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3144 found_transparent_pixel = MagickTrue;
3147 if ((ping_color_type == PNG_COLOR_TYPE_RGB ||
3148 ping_color_type == PNG_COLOR_TYPE_GRAY) &&
3149 (ScaleQuantumToShort(GetPixelRed(image,q)) ==
3150 transparent_color.red &&
3151 ScaleQuantumToShort(GetPixelGreen(image,q)) ==
3152 transparent_color.green &&
3153 ScaleQuantumToShort(GetPixelBlue(image,q)) ==
3154 transparent_color.blue))
3156 if (logging != MagickFalse)
3157 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3159 found_transparent_pixel = MagickTrue;
3162 q+=GetPixelChannels(image);
3166 if ((image->previous == (Image *) NULL) && (num_passes == 1))
3168 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
3171 if (status == MagickFalse)
3174 if (SyncAuthenticPixels(image,exception) == MagickFalse)
3178 if ((image->previous == (Image *) NULL) && (num_passes != 1))
3180 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
3181 if (status == MagickFalse)
3187 else /* image->storage_class != DirectClass */
3189 for (pass=0; pass < num_passes; pass++)
3198 Convert grayscale image to PseudoClass pixel packets.
3200 if (logging != MagickFalse)
3201 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3202 " Converting grayscale pixels to pixel packets");
3204 image->alpha_trait=ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA ?
3205 BlendPixelTrait : UndefinedPixelTrait;
3207 quantum_scanline=(Quantum *) AcquireQuantumMemory(image->columns,
3208 (image->alpha_trait == BlendPixelTrait? 2 : 1)*
3209 sizeof(*quantum_scanline));
3211 if (quantum_scanline == (Quantum *) NULL)
3212 png_error(ping,"Memory allocation failed");
3214 for (y=0; y < (ssize_t) image->rows; y++)
3220 row_offset=ping_rowbytes*y;
3225 png_read_row(ping,ping_pixels+row_offset,NULL);
3227 if (pass < num_passes-1)
3230 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
3232 if (q == (Quantum *) NULL)
3235 p=ping_pixels+row_offset;
3238 switch (ping_bit_depth)
3243 if (ping_color_type == 4)
3244 for (x=(ssize_t) image->columns-1; x >= 0; x--)
3248 alpha=ScaleCharToQuantum((unsigned char)*p++);
3250 SetPixelAlpha(image,alpha,q);
3252 if (alpha != OpaqueAlpha)
3253 found_transparent_pixel = MagickTrue;
3255 q+=GetPixelChannels(image);
3259 for (x=(ssize_t) image->columns-1; x >= 0; x--)
3267 for (x=(ssize_t) image->columns-1; x >= 0; x--)
3269 #if (MAGICKCORE_QUANTUM_DEPTH == 16) || (MAGICKCORE_QUANTUM_DEPTH == 32)
3273 if (image->colors > 256)
3274 quantum=((*p++) << 8);
3280 *r=ScaleShortToQuantum(quantum);
3283 if (ping_color_type == 4)
3285 if (image->colors > 256)
3286 quantum=((*p++) << 8);
3292 alpha=ScaleShortToQuantum(quantum);
3293 SetPixelAlpha(image,alpha,q);
3295 if (alpha != OpaqueAlpha)
3296 found_transparent_pixel = MagickTrue;
3298 q+=GetPixelChannels(image);
3301 #else /* MAGICKCORE_QUANTUM_DEPTH == 8 */
3303 p++; /* strip low byte */
3305 if (ping_color_type == 4)
3307 SetPixelAlpha(image,*p++,q);
3309 if (GetPixelAlpha(image,q) != OpaqueAlpha)
3310 found_transparent_pixel = MagickTrue;
3313 q+=GetPixelChannels(image);
3326 Transfer image scanline.
3330 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
3332 if (q == (Quantum *) NULL)
3334 for (x=0; x < (ssize_t) image->columns; x++)
3336 SetPixelIndex(image,*r++,q);
3337 q+=GetPixelChannels(image);
3340 if (SyncAuthenticPixels(image,exception) == MagickFalse)
3343 if ((image->previous == (Image *) NULL) && (num_passes == 1))
3345 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
3348 if (status == MagickFalse)
3353 if ((image->previous == (Image *) NULL) && (num_passes != 1))
3355 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
3357 if (status == MagickFalse)
3361 quantum_scanline=(Quantum *) RelinquishMagickMemory(quantum_scanline);
3364 image->alpha_trait=found_transparent_pixel ? BlendPixelTrait :
3365 UndefinedPixelTrait;
3367 if (logging != MagickFalse)
3369 if (found_transparent_pixel != MagickFalse)
3370 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3371 " Found transparent pixel");
3374 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3375 " No transparent pixel was found");
3377 ping_color_type&=0x03;
3382 if (quantum_info != (QuantumInfo *) NULL)
3383 quantum_info=DestroyQuantumInfo(quantum_info);
3385 if (image->storage_class == PseudoClass)
3390 alpha_trait=image->alpha_trait;
3391 image->alpha_trait=UndefinedPixelTrait;
3392 (void) SyncImage(image,exception);
3393 image->alpha_trait=alpha_trait;
3396 png_read_end(ping,end_info);
3398 if (image_info->number_scenes != 0 && mng_info->scenes_found-1 <
3399 (ssize_t) image_info->first_scene && image->delay != 0)
3401 png_destroy_read_struct(&ping,&ping_info,&end_info);
3402 ping_pixels=(unsigned char *) RelinquishMagickMemory(ping_pixels);
3404 (void) SetImageBackgroundColor(image,exception);
3405 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
3406 UnlockSemaphoreInfo(ping_semaphore);
3408 if (logging != MagickFalse)
3409 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3410 " exit ReadOnePNGImage() early.");
3414 if (png_get_valid(ping,ping_info,PNG_INFO_tRNS))
3420 Image has a transparent background.
3422 storage_class=image->storage_class;
3423 image->alpha_trait=BlendPixelTrait;
3425 /* Balfour fix from imagemagick discourse server, 5 Feb 2010 */
3427 if (storage_class == PseudoClass)
3429 if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
3431 for (x=0; x < ping_num_trans; x++)
3433 image->colormap[x].alpha_trait=BlendPixelTrait;
3434 image->colormap[x].alpha =
3435 ScaleCharToQuantum((unsigned char)ping_trans_alpha[x]);
3439 else if (ping_color_type == PNG_COLOR_TYPE_GRAY)
3441 for (x=0; x < (int) image->colors; x++)
3443 if (ScaleQuantumToShort(image->colormap[x].red) ==
3444 transparent_color.alpha)
3446 image->colormap[x].alpha_trait=BlendPixelTrait;
3447 image->colormap[x].alpha = (Quantum) TransparentAlpha;
3451 (void) SyncImage(image,exception);
3454 #if 1 /* Should have already been done above, but glennrp problem P10
3459 for (y=0; y < (ssize_t) image->rows; y++)
3461 image->storage_class=storage_class;
3462 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
3464 if (q == (Quantum *) NULL)
3468 /* Caution: on a Q8 build, this does not distinguish between
3469 * 16-bit colors that differ only in the low byte
3471 for (x=(ssize_t) image->columns-1; x >= 0; x--)
3473 if (ScaleQuantumToShort(GetPixelRed(image,q)) ==
3474 transparent_color.red &&
3475 ScaleQuantumToShort(GetPixelGreen(image,q)) ==
3476 transparent_color.green &&
3477 ScaleQuantumToShort(GetPixelBlue(image,q)) ==
3478 transparent_color.blue)
3480 SetPixelAlpha(image,TransparentAlpha,q);
3483 #if 0 /* I have not found a case where this is needed. */
3486 SetPixelAlpha(image,q)=(Quantum) OpaqueAlpha;
3490 q+=GetPixelChannels(image);
3493 if (SyncAuthenticPixels(image,exception) == MagickFalse)
3499 image->storage_class=DirectClass;
3502 for (j = 0; j < 2; j++)
3505 status = png_get_text(ping,ping_info,&text,&num_text) != 0 ?
3506 MagickTrue : MagickFalse;
3508 status = png_get_text(ping,end_info,&text,&num_text) != 0 ?
3509 MagickTrue : MagickFalse;
3511 if (status != MagickFalse)
3512 for (i=0; i < (ssize_t) num_text; i++)
3514 /* Check for a profile */
3516 if (logging != MagickFalse)
3517 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3518 " Reading PNG text chunk");
3520 if (memcmp(text[i].key, "Raw profile type ",17) == 0)
3522 (void) Magick_png_read_raw_profile(ping,image,image_info,text,
3532 length=text[i].text_length;
3533 value=(char *) AcquireQuantumMemory(length+MaxTextExtent,
3535 if (value == (char *) NULL)
3537 png_error(ping,"Memory allocation failed");
3541 (void) ConcatenateMagickString(value,text[i].text,length+2);
3543 /* Don't save "density" or "units" property if we have a pHYs
3546 if (!png_get_valid(ping,ping_info,PNG_INFO_pHYs) ||
3547 (LocaleCompare(text[i].key,"density") != 0 &&
3548 LocaleCompare(text[i].key,"units") != 0))
3549 (void) SetImageProperty(image,text[i].key,value,exception);
3551 if (logging != MagickFalse)
3553 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3554 " length: %lu",(unsigned long) length);
3555 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3556 " Keyword: %s",text[i].key);
3559 value=DestroyString(value);
3562 num_text_total += num_text;
3565 #ifdef MNG_OBJECT_BUFFERS
3567 Store the object if necessary.
3569 if (object_id && !mng_info->frozen[object_id])
3571 if (mng_info->ob[object_id] == (MngBuffer *) NULL)
3574 create a new object buffer.
3576 mng_info->ob[object_id]=(MngBuffer *)
3577 AcquireMagickMemory(sizeof(MngBuffer));
3579 if (mng_info->ob[object_id] != (MngBuffer *) NULL)
3581 mng_info->ob[object_id]->image=(Image *) NULL;
3582 mng_info->ob[object_id]->reference_count=1;
3586 if ((mng_info->ob[object_id] == (MngBuffer *) NULL) ||
3587 mng_info->ob[object_id]->frozen)
3589 if (mng_info->ob[object_id] == (MngBuffer *) NULL)
3590 png_error(ping,"Memory allocation failed");
3592 if (mng_info->ob[object_id]->frozen)
3593 png_error(ping,"Cannot overwrite frozen MNG object buffer");
3599 if (mng_info->ob[object_id]->image != (Image *) NULL)
3600 mng_info->ob[object_id]->image=DestroyImage
3601 (mng_info->ob[object_id]->image);
3603 mng_info->ob[object_id]->image=CloneImage(image,0,0,MagickTrue,
3606 if (mng_info->ob[object_id]->image != (Image *) NULL)
3607 mng_info->ob[object_id]->image->file=(FILE *) NULL;
3610 png_error(ping, "Cloning image for object buffer failed");
3612 if (ping_width > 250000L || ping_height > 250000L)
3613 png_error(ping,"PNG Image dimensions are too large.");
3615 mng_info->ob[object_id]->width=ping_width;
3616 mng_info->ob[object_id]->height=ping_height;
3617 mng_info->ob[object_id]->color_type=ping_color_type;
3618 mng_info->ob[object_id]->sample_depth=ping_bit_depth;
3619 mng_info->ob[object_id]->interlace_method=ping_interlace_method;
3620 mng_info->ob[object_id]->compression_method=
3621 ping_compression_method;
3622 mng_info->ob[object_id]->filter_method=ping_filter_method;
3624 if (png_get_valid(ping,ping_info,PNG_INFO_PLTE))
3630 Copy the PLTE to the object buffer.
3632 png_get_PLTE(ping,ping_info,&plte,&number_colors);
3633 mng_info->ob[object_id]->plte_length=number_colors;
3635 for (i=0; i < number_colors; i++)
3637 mng_info->ob[object_id]->plte[i]=plte[i];
3642 mng_info->ob[object_id]->plte_length=0;
3647 /* Set image->alpha_trait to MagickTrue if the input colortype supports
3648 * alpha or if a valid tRNS chunk is present, no matter whether there
3649 * is actual transparency present.
3651 image->alpha_trait=(((int) ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA) ||
3652 ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) ||
3653 (png_get_valid(ping,ping_info,PNG_INFO_tRNS))) ?
3654 BlendPixelTrait : UndefinedPixelTrait;
3656 #if 0 /* I'm not sure what's wrong here but it does not work. */
3657 if (image->alpha_trait == BlendPixelTrait)
3659 if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
3660 (void) SetImageType(image,GrayscaleMatteType,exception);
3662 else if (ping_color_type == PNG_COLOR_TYPE_PALETTE)
3663 (void) SetImageType(image,PaletteMatteType,exception);
3666 (void) SetImageType(image,TrueColorMatteType,exception);
3671 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
3672 (void) SetImageType(image,GrayscaleType,exception);
3674 else if (ping_color_type == PNG_COLOR_TYPE_PALETTE)
3675 (void) SetImageType(image,PaletteType,exception);
3678 (void) SetImageType(image,TrueColorType,exception);
3682 /* Set more properties for identify to retrieve */
3687 if (num_text_total != 0)
3689 /* libpng doesn't tell us whether they were tEXt, zTXt, or iTXt */
3690 (void) FormatLocaleString(msg,MaxTextExtent,
3691 "%d tEXt/zTXt/iTXt chunks were found", num_text_total);
3692 (void) SetImageProperty(image,"png:text ",msg,
3696 if (num_raw_profiles != 0)
3698 (void) FormatLocaleString(msg,MaxTextExtent,
3699 "%d were found", num_raw_profiles);
3700 (void) SetImageProperty(image,"png:text-encoded profiles",msg,
3704 if (ping_found_cHRM != MagickFalse)
3706 (void) FormatLocaleString(msg,MaxTextExtent,"%s",
3707 "chunk was found (see Chromaticity, above)");
3708 (void) SetImageProperty(image,"png:cHRM ",msg,
3712 if (png_get_valid(ping,ping_info,PNG_INFO_bKGD))
3714 (void) FormatLocaleString(msg,MaxTextExtent,"%s",
3715 "chunk was found (see Background color, above)");
3716 (void) SetImageProperty(image,"png:bKGD ",msg,
3720 (void) FormatLocaleString(msg,MaxTextExtent,"%s",
3723 #if defined(PNG_iCCP_SUPPORTED)
3724 if (ping_found_iCCP != MagickFalse)
3725 (void) SetImageProperty(image,"png:iCCP ",msg,
3729 if (png_get_valid(ping,ping_info,PNG_INFO_tRNS))
3730 (void) SetImageProperty(image,"png:tRNS ",msg,
3733 #if defined(PNG_sRGB_SUPPORTED)
3734 if (ping_found_sRGB != MagickFalse)
3736 (void) FormatLocaleString(msg,MaxTextExtent,
3739 Magick_RenderingIntentString_from_PNG_RenderingIntent(intent));
3740 (void) SetImageProperty(image,"png:sRGB ",msg,
3745 if (ping_found_gAMA != MagickFalse)
3747 (void) FormatLocaleString(msg,MaxTextExtent,
3748 "gamma=%.8g (See Gamma, above)",
3750 (void) SetImageProperty(image,"png:gAMA ",msg,
3754 #if defined(PNG_pHYs_SUPPORTED)
3755 if (png_get_valid(ping,ping_info,PNG_INFO_pHYs))
3757 (void) FormatLocaleString(msg,MaxTextExtent,
3758 "x_res=%.10g, y_res=%.10g, units=%d",
3759 (double) x_resolution,(double) y_resolution, unit_type);
3760 (void) SetImageProperty(image,"png:pHYs ",msg,
3765 #if defined(PNG_oFFs_SUPPORTED)
3766 if (png_get_valid(ping,ping_info,PNG_INFO_oFFs))
3768 (void) FormatLocaleString(msg,MaxTextExtent,"x_off=%.20g, y_off=%.20g",
3769 (double) image->page.x,(double) image->page.y);
3770 (void) SetImageProperty(image,"png:oFFs ",msg,
3775 if ((image->page.width != 0 && image->page.width != image->columns) ||
3776 (image->page.height != 0 && image->page.height != image->rows))
3778 (void) FormatLocaleString(msg,MaxTextExtent,
3779 "width=%.20g, height=%.20g",
3780 (double) image->page.width,(double) image->page.height);
3781 (void) SetImageProperty(image,"png:vpAg ",msg,
3787 Relinquish resources.
3789 png_destroy_read_struct(&ping,&ping_info,&end_info);
3791 ping_pixels=(unsigned char *) RelinquishMagickMemory(ping_pixels);
3793 if (logging != MagickFalse)
3794 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3795 " exit ReadOnePNGImage()");
3797 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
3798 UnlockSemaphoreInfo(ping_semaphore);
3801 /* } for navigation to beginning of SETJMP-protected block, revert to
3802 * Throwing an Exception when an error occurs.
3807 /* end of reading one PNG image */
3810 static Image *ReadPNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
3825 magic_number[MaxTextExtent];
3833 assert(image_info != (const ImageInfo *) NULL);
3834 assert(image_info->signature == MagickSignature);
3836 if (image_info->debug != MagickFalse)
3837 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
3838 image_info->filename);
3840 assert(exception != (ExceptionInfo *) NULL);
3841 assert(exception->signature == MagickSignature);
3842 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter ReadPNGImage()");
3843 image=AcquireImage(image_info,exception);
3844 mng_info=(MngInfo *) NULL;
3845 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
3847 if (status == MagickFalse)
3848 ThrowReaderException(FileOpenError,"UnableToOpenFile");
3851 Verify PNG signature.
3853 count=ReadBlob(image,8,(unsigned char *) magic_number);
3855 if (count < 8 || memcmp(magic_number,"\211PNG\r\n\032\n",8) != 0)
3856 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
3859 Allocate a MngInfo structure.
3861 have_mng_structure=MagickFalse;
3862 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
3864 if (mng_info == (MngInfo *) NULL)
3865 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
3868 Initialize members of the MngInfo structure.
3870 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
3871 mng_info->image=image;
3872 have_mng_structure=MagickTrue;
3875 image=ReadOnePNGImage(mng_info,image_info,exception);
3876 MngInfoFreeStruct(mng_info,&have_mng_structure);
3878 if (image == (Image *) NULL)
3880 if (previous != (Image *) NULL)
3882 if (previous->signature != MagickSignature)
3883 ThrowReaderException(CorruptImageError,"CorruptImage");
3885 (void) CloseBlob(previous);
3886 (void) DestroyImageList(previous);
3889 if (logging != MagickFalse)
3890 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3891 "exit ReadPNGImage() with error");
3893 return((Image *) NULL);
3896 (void) CloseBlob(image);
3898 if ((image->columns == 0) || (image->rows == 0))
3900 if (logging != MagickFalse)
3901 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3902 "exit ReadPNGImage() with error.");
3904 ThrowReaderException(CorruptImageError,"CorruptImage");
3907 if ((IssRGBColorspace(image->colorspace) != MagickFalse) &&
3908 ((image->gamma < .45) || (image->gamma > .46)) &&
3909 !(image->chromaticity.red_primary.x>0.6399f &&
3910 image->chromaticity.red_primary.x<0.6401f &&
3911 image->chromaticity.red_primary.y>0.3299f &&
3912 image->chromaticity.red_primary.y<0.3301f &&
3913 image->chromaticity.green_primary.x>0.2999f &&
3914 image->chromaticity.green_primary.x<0.3001f &&
3915 image->chromaticity.green_primary.y>0.5999f &&
3916 image->chromaticity.green_primary.y<0.6001f &&
3917 image->chromaticity.blue_primary.x>0.1499f &&
3918 image->chromaticity.blue_primary.x<0.1501f &&
3919 image->chromaticity.blue_primary.y>0.0599f &&
3920 image->chromaticity.blue_primary.y<0.0601f &&
3921 image->chromaticity.white_point.x>0.3126f &&
3922 image->chromaticity.white_point.x<0.3128f &&
3923 image->chromaticity.white_point.y>0.3289f &&
3924 image->chromaticity.white_point.y<0.3291f))
3925 SetImageColorspace(image,RGBColorspace,exception);
3927 if (logging != MagickFalse)
3928 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3929 " page.w: %.20g, page.h: %.20g,page.x: %.20g, page.y: %.20g.",
3930 (double) image->page.width,(double) image->page.height,
3931 (double) image->page.x,(double) image->page.y);
3933 if (logging != MagickFalse)
3934 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit ReadPNGImage()");
3941 #if defined(JNG_SUPPORTED)
3943 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3947 % R e a d O n e J N G I m a g e %
3951 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3953 % ReadOneJNGImage() reads a JPEG Network Graphics (JNG) image file
3954 % (minus the 8-byte signature) and returns it. It allocates the memory
3955 % necessary for the new Image structure and returns a pointer to the new
3958 % JNG support written by Glenn Randers-Pehrson, glennrp@image...
3960 % The format of the ReadOneJNGImage method is:
3962 % Image *ReadOneJNGImage(MngInfo *mng_info, const ImageInfo *image_info,
3963 % ExceptionInfo *exception)
3965 % A description of each parameter follows:
3967 % o mng_info: Specifies a pointer to a MngInfo structure.
3969 % o image_info: the image info.
3971 % o exception: return any errors or warnings in this structure.
3974 static Image *ReadOneJNGImage(MngInfo *mng_info,
3975 const ImageInfo *image_info, ExceptionInfo *exception)
4002 jng_image_sample_depth,
4003 jng_image_compression_method,
4004 jng_image_interlace_method,
4005 jng_alpha_sample_depth,
4006 jng_alpha_compression_method,
4007 jng_alpha_filter_method,
4008 jng_alpha_interlace_method;
4010 register const Quantum
4020 register unsigned char
4031 jng_alpha_compression_method=0;
4032 jng_alpha_sample_depth=8;
4036 alpha_image=(Image *) NULL;
4037 color_image=(Image *) NULL;
4038 alpha_image_info=(ImageInfo *) NULL;
4039 color_image_info=(ImageInfo *) NULL;
4041 logging=LogMagickEvent(CoderEvent,GetMagickModule(),
4042 " Enter ReadOneJNGImage()");
4044 image=mng_info->image;
4046 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
4049 Allocate next image structure.
4051 if (logging != MagickFalse)
4052 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4053 " AcquireNextImage()");
4055 AcquireNextImage(image_info,image,exception);
4057 if (GetNextImageInList(image) == (Image *) NULL)
4058 return((Image *) NULL);
4060 image=SyncNextImageInList(image);
4062 mng_info->image=image;
4065 Signature bytes have already been read.
4068 read_JSEP=MagickFalse;
4069 reading_idat=MagickFalse;
4070 skip_to_iend=MagickFalse;
4074 type[MaxTextExtent];
4083 Read a new JNG chunk.
4085 status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
4086 2*GetBlobSize(image));
4088 if (status == MagickFalse)
4092 (void) ConcatenateMagickString(type,"errr",MaxTextExtent);
4093 length=ReadBlobMSBLong(image);
4094 count=(unsigned int) ReadBlob(image,4,(unsigned char *) type);
4096 if (logging != MagickFalse)
4097 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4098 " Reading JNG chunk type %c%c%c%c, length: %.20g",
4099 type[0],type[1],type[2],type[3],(double) length);
4101 if (length > PNG_UINT_31_MAX || count == 0)
4102 ThrowReaderException(CorruptImageError,"CorruptImage");
4105 chunk=(unsigned char *) NULL;
4109 chunk=(unsigned char *) AcquireQuantumMemory(length,sizeof(*chunk));
4111 if (chunk == (unsigned char *) NULL)
4112 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
4114 for (i=0; i < (ssize_t) length; i++)
4115 chunk[i]=(unsigned char) ReadBlobByte(image);
4120 (void) ReadBlobMSBLong(image); /* read crc word */
4125 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4130 if (memcmp(type,mng_JHDR,4) == 0)
4134 jng_width=(size_t) ((p[0] << 24) | (p[1] << 16) |
4135 (p[2] << 8) | p[3]);
4136 jng_height=(size_t) ((p[4] << 24) | (p[5] << 16) |
4137 (p[6] << 8) | p[7]);
4138 jng_color_type=p[8];
4139 jng_image_sample_depth=p[9];
4140 jng_image_compression_method=p[10];
4141 jng_image_interlace_method=p[11];
4143 image->interlace=jng_image_interlace_method != 0 ? PNGInterlace :
4146 jng_alpha_sample_depth=p[12];
4147 jng_alpha_compression_method=p[13];
4148 jng_alpha_filter_method=p[14];
4149 jng_alpha_interlace_method=p[15];
4151 if (logging != MagickFalse)
4153 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4154 " jng_width: %16lu",(unsigned long) jng_width);
4156 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4157 " jng_width: %16lu",(unsigned long) jng_height);
4159 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4160 " jng_color_type: %16d",jng_color_type);
4162 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4163 " jng_image_sample_depth: %3d",
4164 jng_image_sample_depth);
4166 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4167 " jng_image_compression_method:%3d",
4168 jng_image_compression_method);
4170 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4171 " jng_image_interlace_method: %3d",
4172 jng_image_interlace_method);
4174 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4175 " jng_alpha_sample_depth: %3d",
4176 jng_alpha_sample_depth);
4178 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4179 " jng_alpha_compression_method:%3d",
4180 jng_alpha_compression_method);
4182 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4183 " jng_alpha_filter_method: %3d",
4184 jng_alpha_filter_method);
4186 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4187 " jng_alpha_interlace_method: %3d",
4188 jng_alpha_interlace_method);
4193 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4199 if ((reading_idat == MagickFalse) && (read_JSEP == MagickFalse) &&
4200 ((memcmp(type,mng_JDAT,4) == 0) || (memcmp(type,mng_JdAA,4) == 0) ||
4201 (memcmp(type,mng_IDAT,4) == 0) || (memcmp(type,mng_JDAA,4) == 0)))
4204 o create color_image
4205 o open color_blob, attached to color_image
4206 o if (color type has alpha)
4207 open alpha_blob, attached to alpha_image
4210 color_image_info=(ImageInfo *)AcquireMagickMemory(sizeof(ImageInfo));
4212 if (color_image_info == (ImageInfo *) NULL)
4213 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
4215 GetImageInfo(color_image_info);
4216 color_image=AcquireImage(color_image_info,exception);
4218 if (color_image == (Image *) NULL)
4219 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
4221 if (logging != MagickFalse)
4222 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4223 " Creating color_blob.");
4225 (void) AcquireUniqueFilename(color_image->filename);
4226 status=OpenBlob(color_image_info,color_image,WriteBinaryBlobMode,
4229 if (status == MagickFalse)
4230 return((Image *) NULL);
4232 if ((image_info->ping == MagickFalse) && (jng_color_type >= 12))
4234 alpha_image_info=(ImageInfo *)
4235 AcquireMagickMemory(sizeof(ImageInfo));
4237 if (alpha_image_info == (ImageInfo *) NULL)
4238 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
4240 GetImageInfo(alpha_image_info);
4241 alpha_image=AcquireImage(alpha_image_info,exception);
4243 if (alpha_image == (Image *) NULL)
4245 alpha_image=DestroyImage(alpha_image);
4246 ThrowReaderException(ResourceLimitError,
4247 "MemoryAllocationFailed");
4250 if (logging != MagickFalse)
4251 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4252 " Creating alpha_blob.");
4254 (void) AcquireUniqueFilename(alpha_image->filename);
4255 status=OpenBlob(alpha_image_info,alpha_image,WriteBinaryBlobMode,
4258 if (status == MagickFalse)
4259 return((Image *) NULL);
4261 if (jng_alpha_compression_method == 0)
4266 if (logging != MagickFalse)
4267 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4268 " Writing IHDR chunk to alpha_blob.");
4270 (void) WriteBlob(alpha_image,8,(const unsigned char *)
4271 "\211PNG\r\n\032\n");
4273 (void) WriteBlobMSBULong(alpha_image,13L);
4274 PNGType(data,mng_IHDR);
4275 LogPNGChunk(logging,mng_IHDR,13L);
4276 PNGLong(data+4,jng_width);
4277 PNGLong(data+8,jng_height);
4278 data[12]=jng_alpha_sample_depth;
4279 data[13]=0; /* color_type gray */
4280 data[14]=0; /* compression method 0 */
4281 data[15]=0; /* filter_method 0 */
4282 data[16]=0; /* interlace_method 0 */
4283 (void) WriteBlob(alpha_image,17,data);
4284 (void) WriteBlobMSBULong(alpha_image,crc32(0,data,17));
4287 reading_idat=MagickTrue;
4290 if (memcmp(type,mng_JDAT,4) == 0)
4292 /* Copy chunk to color_image->blob */
4294 if (logging != MagickFalse)
4295 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4296 " Copying JDAT chunk data to color_blob.");
4298 (void) WriteBlob(color_image,length,chunk);
4301 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4306 if (memcmp(type,mng_IDAT,4) == 0)
4311 /* Copy IDAT header and chunk data to alpha_image->blob */
4313 if (image_info->ping == MagickFalse)
4315 if (logging != MagickFalse)
4316 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4317 " Copying IDAT chunk data to alpha_blob.");
4319 (void) WriteBlobMSBULong(alpha_image,(size_t) length);
4320 PNGType(data,mng_IDAT);
4321 LogPNGChunk(logging,mng_IDAT,length);
4322 (void) WriteBlob(alpha_image,4,data);
4323 (void) WriteBlob(alpha_image,length,chunk);
4324 (void) WriteBlobMSBULong(alpha_image,
4325 crc32(crc32(0,data,4),chunk,(uInt) length));
4329 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4334 if ((memcmp(type,mng_JDAA,4) == 0) || (memcmp(type,mng_JdAA,4) == 0))
4336 /* Copy chunk data to alpha_image->blob */
4338 if (image_info->ping == MagickFalse)
4340 if (logging != MagickFalse)
4341 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4342 " Copying JDAA chunk data to alpha_blob.");
4344 (void) WriteBlob(alpha_image,length,chunk);
4348 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4353 if (memcmp(type,mng_JSEP,4) == 0)
4355 read_JSEP=MagickTrue;
4358 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4363 if (memcmp(type,mng_bKGD,4) == 0)
4367 image->background_color.red=ScaleCharToQuantum(p[1]);
4368 image->background_color.green=image->background_color.red;
4369 image->background_color.blue=image->background_color.red;
4374 image->background_color.red=ScaleCharToQuantum(p[1]);
4375 image->background_color.green=ScaleCharToQuantum(p[3]);
4376 image->background_color.blue=ScaleCharToQuantum(p[5]);
4379 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4383 if (memcmp(type,mng_gAMA,4) == 0)
4386 image->gamma=((float) mng_get_long(p))*0.00001;
4388 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4392 if (memcmp(type,mng_cHRM,4) == 0)
4396 image->chromaticity.white_point.x=0.00001*mng_get_long(p);
4397 image->chromaticity.white_point.y=0.00001*mng_get_long(&p[4]);
4398 image->chromaticity.red_primary.x=0.00001*mng_get_long(&p[8]);
4399 image->chromaticity.red_primary.y=0.00001*mng_get_long(&p[12]);
4400 image->chromaticity.green_primary.x=0.00001*mng_get_long(&p[16]);
4401 image->chromaticity.green_primary.y=0.00001*mng_get_long(&p[20]);
4402 image->chromaticity.blue_primary.x=0.00001*mng_get_long(&p[24]);
4403 image->chromaticity.blue_primary.y=0.00001*mng_get_long(&p[28]);
4406 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4410 if (memcmp(type,mng_sRGB,4) == 0)
4414 image->rendering_intent=
4415 Magick_RenderingIntent_from_PNG_RenderingIntent(p[0]);
4416 image->gamma=1.000f/2.200f;
4417 image->chromaticity.red_primary.x=0.6400f;
4418 image->chromaticity.red_primary.y=0.3300f;
4419 image->chromaticity.green_primary.x=0.3000f;
4420 image->chromaticity.green_primary.y=0.6000f;
4421 image->chromaticity.blue_primary.x=0.1500f;
4422 image->chromaticity.blue_primary.y=0.0600f;
4423 image->chromaticity.white_point.x=0.3127f;
4424 image->chromaticity.white_point.y=0.3290f;
4427 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4431 if (memcmp(type,mng_oFFs,4) == 0)
4435 image->page.x=(ssize_t) mng_get_long(p);
4436 image->page.y=(ssize_t) mng_get_long(&p[4]);
4438 if ((int) p[8] != 0)
4440 image->page.x/=10000;
4441 image->page.y/=10000;
4446 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4451 if (memcmp(type,mng_pHYs,4) == 0)
4455 image->resolution.x=(double) mng_get_long(p);
4456 image->resolution.y=(double) mng_get_long(&p[4]);
4457 if ((int) p[8] == PNG_RESOLUTION_METER)
4459 image->units=PixelsPerCentimeterResolution;
4460 image->resolution.x=image->resolution.x/100.0f;
4461 image->resolution.y=image->resolution.y/100.0f;
4465 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4470 if (memcmp(type,mng_iCCP,4) == 0)
4474 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4481 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4483 if (memcmp(type,mng_IEND,4))
4493 Finish up reading image data:
4495 o read main image from color_blob.
4499 o if (color_type has alpha)
4500 if alpha_encoding is PNG
4501 read secondary image from alpha_blob via ReadPNG
4502 if alpha_encoding is JPEG
4503 read secondary image from alpha_blob via ReadJPEG
4507 o copy intensity of secondary image into
4508 alpha samples of main image.
4510 o destroy the secondary image.
4513 (void) CloseBlob(color_image);
4515 if (logging != MagickFalse)
4516 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4517 " Reading jng_image from color_blob.");
4519 (void) FormatLocaleString(color_image_info->filename,MaxTextExtent,"%s",
4520 color_image->filename);
4522 color_image_info->ping=MagickFalse; /* To do: avoid this */
4523 jng_image=ReadImage(color_image_info,exception);
4525 if (jng_image == (Image *) NULL)
4526 return((Image *) NULL);
4528 (void) RelinquishUniqueFileResource(color_image->filename);
4529 color_image=DestroyImage(color_image);
4530 color_image_info=DestroyImageInfo(color_image_info);
4532 if (jng_image == (Image *) NULL)
4533 return((Image *) NULL);
4535 if (logging != MagickFalse)
4536 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4537 " Copying jng_image pixels to main image.");
4539 image->rows=jng_height;
4540 image->columns=jng_width;
4542 for (y=0; y < (ssize_t) image->rows; y++)
4544 s=GetVirtualPixels(jng_image,0,y,image->columns,1,exception);
4545 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
4546 for (x=(ssize_t) image->columns; x != 0; x--)
4548 SetPixelRed(image,GetPixelRed(jng_image,s),q);
4549 SetPixelGreen(image,GetPixelGreen(jng_image,s),q);
4550 SetPixelBlue(image,GetPixelBlue(jng_image,s),q);
4551 q+=GetPixelChannels(image);
4552 s+=GetPixelChannels(jng_image);
4555 if (SyncAuthenticPixels(image,exception) == MagickFalse)
4559 jng_image=DestroyImage(jng_image);
4561 if (image_info->ping == MagickFalse)
4563 if (jng_color_type >= 12)
4565 if (jng_alpha_compression_method == 0)
4569 (void) WriteBlobMSBULong(alpha_image,0x00000000L);
4570 PNGType(data,mng_IEND);
4571 LogPNGChunk(logging,mng_IEND,0L);
4572 (void) WriteBlob(alpha_image,4,data);
4573 (void) WriteBlobMSBULong(alpha_image,crc32(0,data,4));
4576 (void) CloseBlob(alpha_image);
4578 if (logging != MagickFalse)
4579 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4580 " Reading alpha from alpha_blob.");
4582 (void) FormatLocaleString(alpha_image_info->filename,MaxTextExtent,
4583 "%s",alpha_image->filename);
4585 jng_image=ReadImage(alpha_image_info,exception);
4587 if (jng_image != (Image *) NULL)
4588 for (y=0; y < (ssize_t) image->rows; y++)
4590 s=GetVirtualPixels(jng_image,0,y,image->columns,1,
4592 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
4594 if (image->alpha_trait == BlendPixelTrait)
4595 for (x=(ssize_t) image->columns; x != 0; x--)
4597 SetPixelAlpha(image,GetPixelRed(jng_image,s),q);
4598 q+=GetPixelChannels(image);
4599 s+=GetPixelChannels(jng_image);
4603 for (x=(ssize_t) image->columns; x != 0; x--)
4605 SetPixelAlpha(image,GetPixelRed(jng_image,s),q);
4606 if (GetPixelAlpha(image,q) != OpaqueAlpha)
4607 image->alpha_trait=BlendPixelTrait;
4608 q+=GetPixelChannels(image);
4609 s+=GetPixelChannels(jng_image);
4612 if (SyncAuthenticPixels(image,exception) == MagickFalse)
4615 (void) RelinquishUniqueFileResource(alpha_image->filename);
4616 alpha_image=DestroyImage(alpha_image);
4617 alpha_image_info=DestroyImageInfo(alpha_image_info);
4618 if (jng_image != (Image *) NULL)
4619 jng_image=DestroyImage(jng_image);
4623 /* Read the JNG image. */
4625 if (mng_info->mng_type == 0)
4627 mng_info->mng_width=jng_width;
4628 mng_info->mng_height=jng_height;
4631 if (image->page.width == 0 && image->page.height == 0)
4633 image->page.width=jng_width;
4634 image->page.height=jng_height;
4637 if (image->page.x == 0 && image->page.y == 0)
4639 image->page.x=mng_info->x_off[mng_info->object_id];
4640 image->page.y=mng_info->y_off[mng_info->object_id];
4645 image->page.y=mng_info->y_off[mng_info->object_id];
4648 mng_info->image_found++;
4649 status=SetImageProgress(image,LoadImagesTag,2*TellBlob(image),
4650 2*GetBlobSize(image));
4652 if (logging != MagickFalse)
4653 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4654 " exit ReadOneJNGImage()");
4660 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4664 % R e a d J N G I m a g e %
4668 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4670 % ReadJNGImage() reads a JPEG Network Graphics (JNG) image file
4671 % (including the 8-byte signature) and returns it. It allocates the memory
4672 % necessary for the new Image structure and returns a pointer to the new
4675 % JNG support written by Glenn Randers-Pehrson, glennrp@image...
4677 % The format of the ReadJNGImage method is:
4679 % Image *ReadJNGImage(const ImageInfo *image_info, ExceptionInfo
4682 % A description of each parameter follows:
4684 % o image_info: the image info.
4686 % o exception: return any errors or warnings in this structure.
4690 static Image *ReadJNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
4705 magic_number[MaxTextExtent];
4713 assert(image_info != (const ImageInfo *) NULL);
4714 assert(image_info->signature == MagickSignature);
4715 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image_info->filename);
4716 assert(exception != (ExceptionInfo *) NULL);
4717 assert(exception->signature == MagickSignature);
4718 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter ReadJNGImage()");
4719 image=AcquireImage(image_info,exception);
4720 mng_info=(MngInfo *) NULL;
4721 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
4723 if (status == MagickFalse)
4724 return((Image *) NULL);
4726 if (LocaleCompare(image_info->magick,"JNG") != 0)
4727 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
4729 /* Verify JNG signature. */
4731 count=(size_t) ReadBlob(image,8,(unsigned char *) magic_number);
4733 if (count < 8 || memcmp(magic_number,"\213JNG\r\n\032\n",8) != 0)
4734 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
4736 /* Allocate a MngInfo structure. */
4738 have_mng_structure=MagickFalse;
4739 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(*mng_info));
4741 if (mng_info == (MngInfo *) NULL)
4742 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
4744 /* Initialize members of the MngInfo structure. */
4746 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
4747 have_mng_structure=MagickTrue;
4749 mng_info->image=image;
4751 image=ReadOneJNGImage(mng_info,image_info,exception);
4752 MngInfoFreeStruct(mng_info,&have_mng_structure);
4754 if (image == (Image *) NULL)
4756 if (IsImageObject(previous) != MagickFalse)
4758 (void) CloseBlob(previous);
4759 (void) DestroyImageList(previous);
4762 if (logging != MagickFalse)
4763 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4764 "exit ReadJNGImage() with error");
4766 return((Image *) NULL);
4768 (void) CloseBlob(image);
4770 if (image->columns == 0 || image->rows == 0)
4772 if (logging != MagickFalse)
4773 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4774 "exit ReadJNGImage() with error");
4776 ThrowReaderException(CorruptImageError,"CorruptImage");
4779 if (logging != MagickFalse)
4780 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit ReadJNGImage()");
4786 static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
4789 page_geometry[MaxTextExtent];
4822 #if defined(MNG_INSERT_LAYERS)
4824 mng_background_color;
4827 register unsigned char
4842 #if defined(MNG_INSERT_LAYERS)
4847 volatile unsigned int
4848 #ifdef MNG_OBJECT_BUFFERS
4849 mng_background_object=0,
4851 mng_type=0; /* 0: PNG or JNG; 1: MNG; 2: MNG-LC; 3: MNG-VLC */
4854 default_frame_timeout,
4856 #if defined(MNG_INSERT_LAYERS)
4862 /* These delays are all measured in image ticks_per_second,
4863 * not in MNG ticks_per_second
4866 default_frame_delay,
4870 #if defined(MNG_INSERT_LAYERS)
4879 previous_fb.bottom=0;
4881 previous_fb.right=0;
4883 default_fb.bottom=0;
4887 /* Open image file. */
4889 assert(image_info != (const ImageInfo *) NULL);
4890 assert(image_info->signature == MagickSignature);
4891 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image_info->filename);
4892 assert(exception != (ExceptionInfo *) NULL);
4893 assert(exception->signature == MagickSignature);
4894 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter ReadMNGImage()");
4895 image=AcquireImage(image_info,exception);
4896 mng_info=(MngInfo *) NULL;
4897 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
4899 if (status == MagickFalse)
4900 return((Image *) NULL);
4902 first_mng_object=MagickFalse;
4904 have_mng_structure=MagickFalse;
4906 /* Allocate a MngInfo structure. */
4908 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
4910 if (mng_info == (MngInfo *) NULL)
4911 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
4913 /* Initialize members of the MngInfo structure. */
4915 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
4916 mng_info->image=image;
4917 have_mng_structure=MagickTrue;
4919 if (LocaleCompare(image_info->magick,"MNG") == 0)
4922 magic_number[MaxTextExtent];
4924 /* Verify MNG signature. */
4925 count=(size_t) ReadBlob(image,8,(unsigned char *) magic_number);
4926 if (memcmp(magic_number,"\212MNG\r\n\032\n",8) != 0)
4927 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
4929 /* Initialize some nonzero members of the MngInfo structure. */
4930 for (i=0; i < MNG_MAX_OBJECTS; i++)
4932 mng_info->object_clip[i].right=(ssize_t) PNG_UINT_31_MAX;
4933 mng_info->object_clip[i].bottom=(ssize_t) PNG_UINT_31_MAX;
4935 mng_info->exists[0]=MagickTrue;
4938 first_mng_object=MagickTrue;
4940 #if defined(MNG_INSERT_LAYERS)
4941 insert_layers=MagickFalse; /* should be False when converting or mogrifying */
4943 default_frame_delay=0;
4944 default_frame_timeout=0;
4947 mng_info->ticks_per_second=1UL*image->ticks_per_second;
4949 skip_to_iend=MagickFalse;
4950 term_chunk_found=MagickFalse;
4951 mng_info->framing_mode=1;
4952 #if defined(MNG_INSERT_LAYERS)
4953 mandatory_back=MagickFalse;
4955 #if defined(MNG_INSERT_LAYERS)
4956 mng_background_color=image->background_color;
4958 default_fb=mng_info->frame;
4959 previous_fb=mng_info->frame;
4963 type[MaxTextExtent];
4965 if (LocaleCompare(image_info->magick,"MNG") == 0)
4974 (void) ConcatenateMagickString(type,"errr",MaxTextExtent);
4975 length=ReadBlobMSBLong(image);
4976 count=(size_t) ReadBlob(image,4,(unsigned char *) type);
4978 if (logging != MagickFalse)
4979 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4980 " Reading MNG chunk type %c%c%c%c, length: %.20g",
4981 type[0],type[1],type[2],type[3],(double) length);
4983 if (length > PNG_UINT_31_MAX)
4987 ThrowReaderException(CorruptImageError,"CorruptImage");
4990 chunk=(unsigned char *) NULL;
4994 chunk=(unsigned char *) AcquireQuantumMemory(length,sizeof(*chunk));
4996 if (chunk == (unsigned char *) NULL)
4997 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
4999 for (i=0; i < (ssize_t) length; i++)
5000 chunk[i]=(unsigned char) ReadBlobByte(image);
5005 (void) ReadBlobMSBLong(image); /* read crc word */
5007 #if !defined(JNG_SUPPORTED)
5008 if (memcmp(type,mng_JHDR,4) == 0)
5010 skip_to_iend=MagickTrue;
5012 if (mng_info->jhdr_warning == 0)
5013 (void) ThrowMagickException(exception,GetMagickModule(),
5014 CoderError,"JNGCompressNotSupported","`%s'",image->filename);
5016 mng_info->jhdr_warning++;
5019 if (memcmp(type,mng_DHDR,4) == 0)
5021 skip_to_iend=MagickTrue;
5023 if (mng_info->dhdr_warning == 0)
5024 (void) ThrowMagickException(exception,GetMagickModule(),
5025 CoderError,"DeltaPNGNotSupported","`%s'",image->filename);
5027 mng_info->dhdr_warning++;
5029 if (memcmp(type,mng_MEND,4) == 0)
5034 if (memcmp(type,mng_IEND,4) == 0)
5035 skip_to_iend=MagickFalse;
5038 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5040 if (logging != MagickFalse)
5041 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5047 if (memcmp(type,mng_MHDR,4) == 0)
5049 mng_info->mng_width=(size_t) ((p[0] << 24) | (p[1] << 16) |
5050 (p[2] << 8) | p[3]);
5052 mng_info->mng_height=(size_t) ((p[4] << 24) | (p[5] << 16) |
5053 (p[6] << 8) | p[7]);
5055 if (logging != MagickFalse)
5057 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5058 " MNG width: %.20g",(double) mng_info->mng_width);
5059 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5060 " MNG height: %.20g",(double) mng_info->mng_height);
5064 mng_info->ticks_per_second=(size_t) mng_get_long(p);
5066 if (mng_info->ticks_per_second == 0)
5067 default_frame_delay=0;
5070 default_frame_delay=1UL*image->ticks_per_second/
5071 mng_info->ticks_per_second;
5073 frame_delay=default_frame_delay;
5079 simplicity=(size_t) mng_get_long(p);
5082 mng_type=1; /* Full MNG */
5084 if ((simplicity != 0) && ((simplicity | 11) == 11))
5085 mng_type=2; /* LC */
5087 if ((simplicity != 0) && ((simplicity | 9) == 9))
5088 mng_type=3; /* VLC */
5090 #if defined(MNG_INSERT_LAYERS)
5092 insert_layers=MagickTrue;
5094 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
5096 /* Allocate next image structure. */
5097 AcquireNextImage(image_info,image,exception);
5099 if (GetNextImageInList(image) == (Image *) NULL)
5100 return((Image *) NULL);
5102 image=SyncNextImageInList(image);
5103 mng_info->image=image;
5106 if ((mng_info->mng_width > 65535L) ||
5107 (mng_info->mng_height > 65535L))
5108 ThrowReaderException(ImageError,"WidthOrHeightExceedsLimit");
5110 (void) FormatLocaleString(page_geometry,MaxTextExtent,
5111 "%.20gx%.20g+0+0",(double) mng_info->mng_width,(double)
5112 mng_info->mng_height);
5114 mng_info->frame.left=0;
5115 mng_info->frame.right=(ssize_t) mng_info->mng_width;
5116 mng_info->frame.top=0;
5117 mng_info->frame.bottom=(ssize_t) mng_info->mng_height;
5118 mng_info->clip=default_fb=previous_fb=mng_info->frame;
5120 for (i=0; i < MNG_MAX_OBJECTS; i++)
5121 mng_info->object_clip[i]=mng_info->frame;
5123 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5127 if (memcmp(type,mng_TERM,4) == 0)
5138 final_delay=(png_uint_32) mng_get_long(&p[2]);
5139 mng_iterations=(png_uint_32) mng_get_long(&p[6]);
5141 if (mng_iterations == PNG_UINT_31_MAX)
5144 image->iterations=mng_iterations;
5145 term_chunk_found=MagickTrue;
5148 if (logging != MagickFalse)
5150 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5151 " repeat=%d",repeat);
5153 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5154 " final_delay=%.20g",(double) final_delay);
5156 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5157 " image->iterations=%.20g",(double) image->iterations);
5160 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5163 if (memcmp(type,mng_DEFI,4) == 0)
5166 (void) ThrowMagickException(exception,GetMagickModule(),
5167 CoderError,"DEFI chunk found in MNG-VLC datastream","`%s'",
5170 object_id=(p[0] << 8) | p[1];
5172 if (mng_type == 2 && object_id != 0)
5173 (void) ThrowMagickException(exception,GetMagickModule(),
5174 CoderError,"Nonzero object_id in MNG-LC datastream","`%s'",
5177 if (object_id > MNG_MAX_OBJECTS)
5180 Instead of using a warning we should allocate a larger
5181 MngInfo structure and continue.
5183 (void) ThrowMagickException(exception,GetMagickModule(),
5184 CoderError,"object id too large","`%s'",image->filename);
5185 object_id=MNG_MAX_OBJECTS;
5188 if (mng_info->exists[object_id])
5189 if (mng_info->frozen[object_id])
5191 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5192 (void) ThrowMagickException(exception,
5193 GetMagickModule(),CoderError,
5194 "DEFI cannot redefine a frozen MNG object","`%s'",
5199 mng_info->exists[object_id]=MagickTrue;
5202 mng_info->invisible[object_id]=p[2];
5205 Extract object offset info.
5209 mng_info->x_off[object_id]=(ssize_t) ((p[4] << 24) |
5210 (p[5] << 16) | (p[6] << 8) | p[7]);
5212 mng_info->y_off[object_id]=(ssize_t) ((p[8] << 24) |
5213 (p[9] << 16) | (p[10] << 8) | p[11]);
5215 if (logging != MagickFalse)
5217 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5218 " x_off[%d]: %.20g",object_id,(double)
5219 mng_info->x_off[object_id]);
5221 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5222 " y_off[%d]: %.20g",object_id,(double)
5223 mng_info->y_off[object_id]);
5228 Extract object clipping info.
5231 mng_info->object_clip[object_id]=mng_read_box(mng_info->frame,0,
5234 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5237 if (memcmp(type,mng_bKGD,4) == 0)
5239 mng_info->have_global_bkgd=MagickFalse;
5243 mng_info->mng_global_bkgd.red=
5244 ScaleShortToQuantum((unsigned short) ((p[0] << 8) | p[1]));
5246 mng_info->mng_global_bkgd.green=
5247 ScaleShortToQuantum((unsigned short) ((p[2] << 8) | p[3]));
5249 mng_info->mng_global_bkgd.blue=
5250 ScaleShortToQuantum((unsigned short) ((p[4] << 8) | p[5]));
5252 mng_info->have_global_bkgd=MagickTrue;
5255 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5258 if (memcmp(type,mng_BACK,4) == 0)
5260 #if defined(MNG_INSERT_LAYERS)
5262 mandatory_back=p[6];
5267 if (mandatory_back && length > 5)
5269 mng_background_color.red=
5270 ScaleShortToQuantum((unsigned short) ((p[0] << 8) | p[1]));
5272 mng_background_color.green=
5273 ScaleShortToQuantum((unsigned short) ((p[2] << 8) | p[3]));
5275 mng_background_color.blue=
5276 ScaleShortToQuantum((unsigned short) ((p[4] << 8) | p[5]));
5278 mng_background_color.alpha=OpaqueAlpha;
5281 #ifdef MNG_OBJECT_BUFFERS
5283 mng_background_object=(p[7] << 8) | p[8];
5286 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5290 if (memcmp(type,mng_PLTE,4) == 0)
5292 /* Read global PLTE. */
5294 if (length && (length < 769))
5296 if (mng_info->global_plte == (png_colorp) NULL)
5297 mng_info->global_plte=(png_colorp) AcquireQuantumMemory(256,
5298 sizeof(*mng_info->global_plte));
5300 for (i=0; i < (ssize_t) (length/3); i++)
5302 mng_info->global_plte[i].red=p[3*i];
5303 mng_info->global_plte[i].green=p[3*i+1];
5304 mng_info->global_plte[i].blue=p[3*i+2];
5307 mng_info->global_plte_length=(unsigned int) (length/3);
5310 for ( ; i < 256; i++)
5312 mng_info->global_plte[i].red=i;
5313 mng_info->global_plte[i].green=i;
5314 mng_info->global_plte[i].blue=i;
5318 mng_info->global_plte_length=256;
5321 mng_info->global_plte_length=0;
5323 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5327 if (memcmp(type,mng_tRNS,4) == 0)
5329 /* read global tRNS */
5332 for (i=0; i < (ssize_t) length; i++)
5333 mng_info->global_trns[i]=p[i];
5336 for ( ; i < 256; i++)
5337 mng_info->global_trns[i]=255;
5339 mng_info->global_trns_length=(unsigned int) length;
5340 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5343 if (memcmp(type,mng_gAMA,4) == 0)
5350 igamma=mng_get_long(p);
5351 mng_info->global_gamma=((float) igamma)*0.00001;
5352 mng_info->have_global_gama=MagickTrue;
5356 mng_info->have_global_gama=MagickFalse;
5358 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5362 if (memcmp(type,mng_cHRM,4) == 0)
5364 /* Read global cHRM */
5368 mng_info->global_chrm.white_point.x=0.00001*mng_get_long(p);
5369 mng_info->global_chrm.white_point.y=0.00001*mng_get_long(&p[4]);
5370 mng_info->global_chrm.red_primary.x=0.00001*mng_get_long(&p[8]);
5371 mng_info->global_chrm.red_primary.y=0.00001*
5372 mng_get_long(&p[12]);
5373 mng_info->global_chrm.green_primary.x=0.00001*
5374 mng_get_long(&p[16]);
5375 mng_info->global_chrm.green_primary.y=0.00001*
5376 mng_get_long(&p[20]);
5377 mng_info->global_chrm.blue_primary.x=0.00001*
5378 mng_get_long(&p[24]);
5379 mng_info->global_chrm.blue_primary.y=0.00001*
5380 mng_get_long(&p[28]);
5381 mng_info->have_global_chrm=MagickTrue;
5384 mng_info->have_global_chrm=MagickFalse;
5386 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5390 if (memcmp(type,mng_sRGB,4) == 0)
5397 mng_info->global_srgb_intent=
5398 Magick_RenderingIntent_from_PNG_RenderingIntent(p[0]);
5399 mng_info->have_global_srgb=MagickTrue;
5402 mng_info->have_global_srgb=MagickFalse;
5404 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5408 if (memcmp(type,mng_iCCP,4) == 0)
5416 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5421 if (memcmp(type,mng_FRAM,4) == 0)
5424 (void) ThrowMagickException(exception,GetMagickModule(),
5425 CoderError,"FRAM chunk found in MNG-VLC datastream","`%s'",
5428 if ((mng_info->framing_mode == 2) || (mng_info->framing_mode == 4))
5429 image->delay=frame_delay;
5431 frame_delay=default_frame_delay;
5432 frame_timeout=default_frame_timeout;
5437 mng_info->framing_mode=p[0];
5439 if (logging != MagickFalse)
5440 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5441 " Framing_mode=%d",mng_info->framing_mode);
5445 /* Note the delay and frame clipping boundaries. */
5447 p++; /* framing mode */
5449 while (*p && ((p-chunk) < (ssize_t) length))
5450 p++; /* frame name */
5452 p++; /* frame name terminator */
5454 if ((p-chunk) < (ssize_t) (length-4))
5461 change_delay=(*p++);
5462 change_timeout=(*p++);
5463 change_clipping=(*p++);
5464 p++; /* change_sync */
5468 frame_delay=1UL*image->ticks_per_second*
5471 if (mng_info->ticks_per_second != 0)
5472 frame_delay/=mng_info->ticks_per_second;
5475 frame_delay=PNG_UINT_31_MAX;
5477 if (change_delay == 2)
5478 default_frame_delay=frame_delay;
5482 if (logging != MagickFalse)
5483 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5484 " Framing_delay=%.20g",(double) frame_delay);
5489 frame_timeout=1UL*image->ticks_per_second*
5492 if (mng_info->ticks_per_second != 0)
5493 frame_timeout/=mng_info->ticks_per_second;
5496 frame_timeout=PNG_UINT_31_MAX;
5498 if (change_delay == 2)
5499 default_frame_timeout=frame_timeout;
5503 if (logging != MagickFalse)
5504 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5505 " Framing_timeout=%.20g",(double) frame_timeout);
5508 if (change_clipping)
5510 fb=mng_read_box(previous_fb,(char) p[0],&p[1]);
5514 if (logging != MagickFalse)
5515 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5516 " Frame_clip: L=%.20g R=%.20g T=%.20g B=%.20g",
5517 (double) fb.left,(double) fb.right,(double) fb.top,
5518 (double) fb.bottom);
5520 if (change_clipping == 2)
5526 mng_info->clip=mng_minimum_box(fb,mng_info->frame);
5528 subframe_width=(size_t) (mng_info->clip.right
5529 -mng_info->clip.left);
5531 subframe_height=(size_t) (mng_info->clip.bottom
5532 -mng_info->clip.top);
5534 Insert a background layer behind the frame if framing_mode is 4.
5536 #if defined(MNG_INSERT_LAYERS)
5537 if (logging != MagickFalse)
5538 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5539 " subframe_width=%.20g, subframe_height=%.20g",(double)
5540 subframe_width,(double) subframe_height);
5542 if (insert_layers && (mng_info->framing_mode == 4) &&
5543 (subframe_width) && (subframe_height))
5545 /* Allocate next image structure. */
5546 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
5548 AcquireNextImage(image_info,image,exception);
5550 if (GetNextImageInList(image) == (Image *) NULL)
5552 image=DestroyImageList(image);
5553 MngInfoFreeStruct(mng_info,&have_mng_structure);
5554 return((Image *) NULL);
5557 image=SyncNextImageInList(image);
5560 mng_info->image=image;
5562 if (term_chunk_found)
5564 image->start_loop=MagickTrue;
5565 image->iterations=mng_iterations;
5566 term_chunk_found=MagickFalse;
5570 image->start_loop=MagickFalse;
5572 image->columns=subframe_width;
5573 image->rows=subframe_height;
5574 image->page.width=subframe_width;
5575 image->page.height=subframe_height;
5576 image->page.x=mng_info->clip.left;
5577 image->page.y=mng_info->clip.top;
5578 image->background_color=mng_background_color;
5579 image->alpha_trait=UndefinedPixelTrait;
5581 (void) SetImageBackgroundColor(image,exception);
5583 if (logging != MagickFalse)
5584 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5585 " Insert backgd layer, L=%.20g, R=%.20g T=%.20g, B=%.20g",
5586 (double) mng_info->clip.left,(double) mng_info->clip.right,
5587 (double) mng_info->clip.top,(double) mng_info->clip.bottom);
5590 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5593 if (memcmp(type,mng_CLIP,4) == 0)
5602 first_object=(p[0] << 8) | p[1];
5603 last_object=(p[2] << 8) | p[3];
5605 for (i=(int) first_object; i <= (int) last_object; i++)
5607 if (mng_info->exists[i] && !mng_info->frozen[i])
5612 box=mng_info->object_clip[i];
5613 mng_info->object_clip[i]=mng_read_box(box,(char) p[4],&p[5]);
5617 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5620 if (memcmp(type,mng_SAVE,4) == 0)
5622 for (i=1; i < MNG_MAX_OBJECTS; i++)
5623 if (mng_info->exists[i])
5625 mng_info->frozen[i]=MagickTrue;
5626 #ifdef MNG_OBJECT_BUFFERS
5627 if (mng_info->ob[i] != (MngBuffer *) NULL)
5628 mng_info->ob[i]->frozen=MagickTrue;
5633 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5638 if ((memcmp(type,mng_DISC,4) == 0) || (memcmp(type,mng_SEEK,4) == 0))
5640 /* Read DISC or SEEK. */
5642 if ((length == 0) || !memcmp(type,mng_SEEK,4))
5644 for (i=1; i < MNG_MAX_OBJECTS; i++)
5645 MngInfoDiscardObject(mng_info,i);
5653 for (j=0; j < (ssize_t) length; j+=2)
5655 i=p[j] << 8 | p[j+1];
5656 MngInfoDiscardObject(mng_info,i);
5661 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5666 if (memcmp(type,mng_MOVE,4) == 0)
5674 first_object=(p[0] << 8) | p[1];
5675 last_object=(p[2] << 8) | p[3];
5676 for (i=(ssize_t) first_object; i <= (ssize_t) last_object; i++)
5678 if (mng_info->exists[i] && !mng_info->frozen[i])
5686 old_pair.a=mng_info->x_off[i];
5687 old_pair.b=mng_info->y_off[i];
5688 new_pair=mng_read_pair(old_pair,(int) p[4],&p[5]);
5689 mng_info->x_off[i]=new_pair.a;
5690 mng_info->y_off[i]=new_pair.b;
5694 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5698 if (memcmp(type,mng_LOOP,4) == 0)
5700 ssize_t loop_iters=1;
5701 loop_level=chunk[0];
5702 mng_info->loop_active[loop_level]=1; /* mark loop active */
5704 /* Record starting point. */
5705 loop_iters=mng_get_long(&chunk[1]);
5707 if (logging != MagickFalse)
5708 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5709 " LOOP level %.20g has %.20g iterations ",(double) loop_level,
5710 (double) loop_iters);
5712 if (loop_iters == 0)
5713 skipping_loop=loop_level;
5717 mng_info->loop_jump[loop_level]=TellBlob(image);
5718 mng_info->loop_count[loop_level]=loop_iters;
5721 mng_info->loop_iteration[loop_level]=0;
5722 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5726 if (memcmp(type,mng_ENDL,4) == 0)
5728 loop_level=chunk[0];
5730 if (skipping_loop > 0)
5732 if (skipping_loop == loop_level)
5735 Found end of zero-iteration loop.
5738 mng_info->loop_active[loop_level]=0;
5744 if (mng_info->loop_active[loop_level] == 1)
5746 mng_info->loop_count[loop_level]--;
5747 mng_info->loop_iteration[loop_level]++;
5749 if (logging != MagickFalse)
5750 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5751 " ENDL: LOOP level %.20g has %.20g remaining iters ",
5752 (double) loop_level,(double)
5753 mng_info->loop_count[loop_level]);
5755 if (mng_info->loop_count[loop_level] != 0)
5757 offset=SeekBlob(image,mng_info->loop_jump[loop_level],
5761 ThrowReaderException(CorruptImageError,
5762 "ImproperImageHeader");
5773 mng_info->loop_active[loop_level]=0;
5775 for (i=0; i < loop_level; i++)
5776 if (mng_info->loop_active[i] == 1)
5777 last_level=(short) i;
5778 loop_level=last_level;
5783 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5787 if (memcmp(type,mng_CLON,4) == 0)
5789 if (mng_info->clon_warning == 0)
5790 (void) ThrowMagickException(exception,GetMagickModule(),
5791 CoderError,"CLON is not implemented yet","`%s'",
5794 mng_info->clon_warning++;
5797 if (memcmp(type,mng_MAGN,4) == 0)
5812 magn_first=(p[0] << 8) | p[1];
5818 magn_last=(p[2] << 8) | p[3];
5821 magn_last=magn_first;
5822 #ifndef MNG_OBJECT_BUFFERS
5823 if (magn_first || magn_last)
5824 if (mng_info->magn_warning == 0)
5826 (void) ThrowMagickException(exception,
5827 GetMagickModule(),CoderError,
5828 "MAGN is not implemented yet for nonzero objects",
5829 "`%s'",image->filename);
5831 mng_info->magn_warning++;
5841 magn_mx=(p[5] << 8) | p[6];
5850 magn_my=(p[7] << 8) | p[8];
5859 magn_ml=(p[9] << 8) | p[10];
5868 magn_mr=(p[11] << 8) | p[12];
5877 magn_mt=(p[13] << 8) | p[14];
5886 magn_mb=(p[15] << 8) | p[16];
5898 magn_methy=magn_methx;
5901 if (magn_methx > 5 || magn_methy > 5)
5902 if (mng_info->magn_warning == 0)
5904 (void) ThrowMagickException(exception,
5905 GetMagickModule(),CoderError,
5906 "Unknown MAGN method in MNG datastream","`%s'",
5909 mng_info->magn_warning++;
5911 #ifdef MNG_OBJECT_BUFFERS
5912 /* Magnify existing objects in the range magn_first to magn_last */
5914 if (magn_first == 0 || magn_last == 0)
5916 /* Save the magnification factors for object 0 */
5917 mng_info->magn_mb=magn_mb;
5918 mng_info->magn_ml=magn_ml;
5919 mng_info->magn_mr=magn_mr;
5920 mng_info->magn_mt=magn_mt;
5921 mng_info->magn_mx=magn_mx;
5922 mng_info->magn_my=magn_my;
5923 mng_info->magn_methx=magn_methx;
5924 mng_info->magn_methy=magn_methy;
5928 if (memcmp(type,mng_PAST,4) == 0)
5930 if (mng_info->past_warning == 0)
5931 (void) ThrowMagickException(exception,GetMagickModule(),
5932 CoderError,"PAST is not implemented yet","`%s'",
5935 mng_info->past_warning++;
5938 if (memcmp(type,mng_SHOW,4) == 0)
5940 if (mng_info->show_warning == 0)
5941 (void) ThrowMagickException(exception,GetMagickModule(),
5942 CoderError,"SHOW is not implemented yet","`%s'",
5945 mng_info->show_warning++;
5948 if (memcmp(type,mng_sBIT,4) == 0)
5951 mng_info->have_global_sbit=MagickFalse;
5955 mng_info->global_sbit.gray=p[0];
5956 mng_info->global_sbit.red=p[0];
5957 mng_info->global_sbit.green=p[1];
5958 mng_info->global_sbit.blue=p[2];
5959 mng_info->global_sbit.alpha=p[3];
5960 mng_info->have_global_sbit=MagickTrue;
5963 if (memcmp(type,mng_pHYs,4) == 0)
5967 mng_info->global_x_pixels_per_unit=
5968 (size_t) mng_get_long(p);
5969 mng_info->global_y_pixels_per_unit=
5970 (size_t) mng_get_long(&p[4]);
5971 mng_info->global_phys_unit_type=p[8];
5972 mng_info->have_global_phys=MagickTrue;
5976 mng_info->have_global_phys=MagickFalse;
5978 if (memcmp(type,mng_pHYg,4) == 0)
5980 if (mng_info->phyg_warning == 0)
5981 (void) ThrowMagickException(exception,GetMagickModule(),
5982 CoderError,"pHYg is not implemented.","`%s'",image->filename);
5984 mng_info->phyg_warning++;
5986 if (memcmp(type,mng_BASI,4) == 0)
5988 skip_to_iend=MagickTrue;
5990 if (mng_info->basi_warning == 0)
5991 (void) ThrowMagickException(exception,GetMagickModule(),
5992 CoderError,"BASI is not implemented yet","`%s'",
5995 mng_info->basi_warning++;
5996 #ifdef MNG_BASI_SUPPORTED
5997 basi_width=(size_t) ((p[0] << 24) | (p[1] << 16) |
5998 (p[2] << 8) | p[3]);
5999 basi_height=(size_t) ((p[4] << 24) | (p[5] << 16) |
6000 (p[6] << 8) | p[7]);
6001 basi_color_type=p[8];
6002 basi_compression_method=p[9];
6003 basi_filter_type=p[10];
6004 basi_interlace_method=p[11];
6006 basi_red=(p[12] << 8) & p[13];
6012 basi_green=(p[14] << 8) & p[15];
6018 basi_blue=(p[16] << 8) & p[17];
6024 basi_alpha=(p[18] << 8) & p[19];
6028 if (basi_sample_depth == 16)
6035 basi_viewable=p[20];
6041 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
6045 if (memcmp(type,mng_IHDR,4)
6046 #if defined(JNG_SUPPORTED)
6047 && memcmp(type,mng_JHDR,4)
6051 /* Not an IHDR or JHDR chunk */
6053 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
6058 if (logging != MagickFalse)
6059 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6060 " Processing %c%c%c%c chunk",type[0],type[1],type[2],type[3]);
6062 mng_info->exists[object_id]=MagickTrue;
6063 mng_info->viewable[object_id]=MagickTrue;
6065 if (mng_info->invisible[object_id])
6067 if (logging != MagickFalse)
6068 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6069 " Skipping invisible object");
6071 skip_to_iend=MagickTrue;
6072 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
6075 #if defined(MNG_INSERT_LAYERS)
6077 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
6079 image_width=(size_t) mng_get_long(p);
6080 image_height=(size_t) mng_get_long(&p[4]);
6082 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
6085 Insert a transparent background layer behind the entire animation
6086 if it is not full screen.
6088 #if defined(MNG_INSERT_LAYERS)
6089 if (insert_layers && mng_type && first_mng_object)
6091 if ((mng_info->clip.left > 0) || (mng_info->clip.top > 0) ||
6092 (image_width < mng_info->mng_width) ||
6093 (mng_info->clip.right < (ssize_t) mng_info->mng_width) ||
6094 (image_height < mng_info->mng_height) ||
6095 (mng_info->clip.bottom < (ssize_t) mng_info->mng_height))
6097 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
6100 Allocate next image structure.
6102 AcquireNextImage(image_info,image,exception);
6104 if (GetNextImageInList(image) == (Image *) NULL)
6106 image=DestroyImageList(image);
6107 MngInfoFreeStruct(mng_info,&have_mng_structure);
6108 return((Image *) NULL);
6111 image=SyncNextImageInList(image);
6113 mng_info->image=image;
6115 if (term_chunk_found)
6117 image->start_loop=MagickTrue;
6118 image->iterations=mng_iterations;
6119 term_chunk_found=MagickFalse;
6123 image->start_loop=MagickFalse;
6125 /* Make a background rectangle. */
6128 image->columns=mng_info->mng_width;
6129 image->rows=mng_info->mng_height;
6130 image->page.width=mng_info->mng_width;
6131 image->page.height=mng_info->mng_height;
6134 image->background_color=mng_background_color;
6135 (void) SetImageBackgroundColor(image,exception);
6136 if (logging != MagickFalse)
6137 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6138 " Inserted transparent background layer, W=%.20g, H=%.20g",
6139 (double) mng_info->mng_width,(double) mng_info->mng_height);
6143 Insert a background layer behind the upcoming image if
6144 framing_mode is 3, and we haven't already inserted one.
6146 if (insert_layers && (mng_info->framing_mode == 3) &&
6147 (subframe_width) && (subframe_height) && (simplicity == 0 ||
6148 (simplicity & 0x08)))
6150 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
6153 Allocate next image structure.
6155 AcquireNextImage(image_info,image,exception);
6157 if (GetNextImageInList(image) == (Image *) NULL)
6159 image=DestroyImageList(image);
6160 MngInfoFreeStruct(mng_info,&have_mng_structure);
6161 return((Image *) NULL);
6164 image=SyncNextImageInList(image);
6167 mng_info->image=image;
6169 if (term_chunk_found)
6171 image->start_loop=MagickTrue;
6172 image->iterations=mng_iterations;
6173 term_chunk_found=MagickFalse;
6177 image->start_loop=MagickFalse;
6180 image->columns=subframe_width;
6181 image->rows=subframe_height;
6182 image->page.width=subframe_width;
6183 image->page.height=subframe_height;
6184 image->page.x=mng_info->clip.left;
6185 image->page.y=mng_info->clip.top;
6186 image->background_color=mng_background_color;
6187 image->alpha_trait=UndefinedPixelTrait;
6188 (void) SetImageBackgroundColor(image,exception);
6190 if (logging != MagickFalse)
6191 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6192 " Insert background layer, L=%.20g, R=%.20g T=%.20g, B=%.20g",
6193 (double) mng_info->clip.left,(double) mng_info->clip.right,
6194 (double) mng_info->clip.top,(double) mng_info->clip.bottom);
6196 #endif /* MNG_INSERT_LAYERS */
6197 first_mng_object=MagickFalse;
6199 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
6202 Allocate next image structure.
6204 AcquireNextImage(image_info,image,exception);
6206 if (GetNextImageInList(image) == (Image *) NULL)
6208 image=DestroyImageList(image);
6209 MngInfoFreeStruct(mng_info,&have_mng_structure);
6210 return((Image *) NULL);
6213 image=SyncNextImageInList(image);
6215 mng_info->image=image;
6216 status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
6217 GetBlobSize(image));
6219 if (status == MagickFalse)
6222 if (term_chunk_found)
6224 image->start_loop=MagickTrue;
6225 term_chunk_found=MagickFalse;
6229 image->start_loop=MagickFalse;
6231 if (mng_info->framing_mode == 1 || mng_info->framing_mode == 3)
6233 image->delay=frame_delay;
6234 frame_delay=default_frame_delay;
6240 image->page.width=mng_info->mng_width;
6241 image->page.height=mng_info->mng_height;
6242 image->page.x=mng_info->x_off[object_id];
6243 image->page.y=mng_info->y_off[object_id];
6244 image->iterations=mng_iterations;
6247 Seek back to the beginning of the IHDR or JHDR chunk's length field.
6250 if (logging != MagickFalse)
6251 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6252 " Seeking back to beginning of %c%c%c%c chunk",type[0],type[1],
6255 offset=SeekBlob(image,-((ssize_t) length+12),SEEK_CUR);
6258 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
6262 mng_info->image=image;
6263 mng_info->mng_type=mng_type;
6264 mng_info->object_id=object_id;
6266 if (memcmp(type,mng_IHDR,4) == 0)
6267 image=ReadOnePNGImage(mng_info,image_info,exception);
6269 #if defined(JNG_SUPPORTED)
6271 image=ReadOneJNGImage(mng_info,image_info,exception);
6274 if (image == (Image *) NULL)
6276 if (IsImageObject(previous) != MagickFalse)
6278 (void) DestroyImageList(previous);
6279 (void) CloseBlob(previous);
6282 MngInfoFreeStruct(mng_info,&have_mng_structure);
6283 return((Image *) NULL);
6286 if (image->columns == 0 || image->rows == 0)
6288 (void) CloseBlob(image);
6289 image=DestroyImageList(image);
6290 MngInfoFreeStruct(mng_info,&have_mng_structure);
6291 return((Image *) NULL);
6294 mng_info->image=image;
6301 if (mng_info->magn_methx || mng_info->magn_methy)
6307 if (logging != MagickFalse)
6308 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6309 " Processing MNG MAGN chunk");
6311 if (mng_info->magn_methx == 1)
6313 magnified_width=mng_info->magn_ml;
6315 if (image->columns > 1)
6316 magnified_width += mng_info->magn_mr;
6318 if (image->columns > 2)
6319 magnified_width += (png_uint_32)
6320 ((image->columns-2)*(mng_info->magn_mx));
6325 magnified_width=(png_uint_32) image->columns;
6327 if (image->columns > 1)
6328 magnified_width += mng_info->magn_ml-1;
6330 if (image->columns > 2)
6331 magnified_width += mng_info->magn_mr-1;
6333 if (image->columns > 3)
6334 magnified_width += (png_uint_32)
6335 ((image->columns-3)*(mng_info->magn_mx-1));
6338 if (mng_info->magn_methy == 1)
6340 magnified_height=mng_info->magn_mt;
6342 if (image->rows > 1)
6343 magnified_height += mng_info->magn_mb;
6345 if (image->rows > 2)
6346 magnified_height += (png_uint_32)
6347 ((image->rows-2)*(mng_info->magn_my));
6352 magnified_height=(png_uint_32) image->rows;
6354 if (image->rows > 1)
6355 magnified_height += mng_info->magn_mt-1;
6357 if (image->rows > 2)
6358 magnified_height += mng_info->magn_mb-1;
6360 if (image->rows > 3)
6361 magnified_height += (png_uint_32)
6362 ((image->rows-3)*(mng_info->magn_my-1));
6365 if (magnified_height > image->rows ||
6366 magnified_width > image->columns)
6393 /* Allocate next image structure. */
6395 if (logging != MagickFalse)
6396 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6397 " Allocate magnified image");
6399 AcquireNextImage(image_info,image,exception);
6401 if (GetNextImageInList(image) == (Image *) NULL)
6403 image=DestroyImageList(image);
6404 MngInfoFreeStruct(mng_info,&have_mng_structure);
6405 return((Image *) NULL);
6408 large_image=SyncNextImageInList(image);
6410 large_image->columns=magnified_width;
6411 large_image->rows=magnified_height;
6413 magn_methx=mng_info->magn_methx;
6414 magn_methy=mng_info->magn_methy;
6416 #if (MAGICKCORE_QUANTUM_DEPTH > 16)
6417 #define QM unsigned short
6418 if (magn_methx != 1 || magn_methy != 1)
6421 Scale pixels to unsigned shorts to prevent
6422 overflow of intermediate values of interpolations
6424 for (y=0; y < (ssize_t) image->rows; y++)
6426 q=GetAuthenticPixels(image,0,y,image->columns,1,
6429 for (x=(ssize_t) image->columns-1; x >= 0; x--)
6431 SetPixelRed(image,ScaleQuantumToShort(
6432 GetPixelRed(image,q)),q);
6433 SetPixelGreen(image,ScaleQuantumToShort(
6434 GetPixelGreen(image,q)),q);
6435 SetPixelBlue(image,ScaleQuantumToShort(
6436 GetPixelBlue(image,q)),q);
6437 SetPixelAlpha(image,ScaleQuantumToShort(
6438 GetPixelAlpha(image,q)),q);
6439 q+=GetPixelChannels(image);
6442 if (SyncAuthenticPixels(image,exception) == MagickFalse)
6450 if (image->alpha_trait == BlendPixelTrait)
6451 (void) SetImageBackgroundColor(large_image,exception);
6455 large_image->background_color.alpha=OpaqueAlpha;
6456 (void) SetImageBackgroundColor(large_image,exception);
6458 if (magn_methx == 4)
6461 if (magn_methx == 5)
6464 if (magn_methy == 4)
6467 if (magn_methy == 5)
6471 /* magnify the rows into the right side of the large image */
6473 if (logging != MagickFalse)
6474 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6475 " Magnify the rows to %.20g",(double) large_image->rows);
6476 m=(ssize_t) mng_info->magn_mt;
6478 length=(size_t) image->columns*GetPixelChannels(image);
6479 next=(Quantum *) AcquireQuantumMemory(length,sizeof(*next));
6480 prev=(Quantum *) AcquireQuantumMemory(length,sizeof(*prev));
6482 if ((prev == (Quantum *) NULL) ||
6483 (next == (Quantum *) NULL))
6485 image=DestroyImageList(image);
6486 MngInfoFreeStruct(mng_info,&have_mng_structure);
6487 ThrowReaderException(ResourceLimitError,
6488 "MemoryAllocationFailed");
6491 n=GetAuthenticPixels(image,0,0,image->columns,1,exception);
6492 (void) CopyMagickMemory(next,n,length);
6494 for (y=0; y < (ssize_t) image->rows; y++)
6497 m=(ssize_t) mng_info->magn_mt;
6499 else if (magn_methy > 1 && y == (ssize_t) image->rows-2)
6500 m=(ssize_t) mng_info->magn_mb;
6502 else if (magn_methy <= 1 && y == (ssize_t) image->rows-1)
6503 m=(ssize_t) mng_info->magn_mb;
6505 else if (magn_methy > 1 && y == (ssize_t) image->rows-1)
6509 m=(ssize_t) mng_info->magn_my;
6515 if (y < (ssize_t) image->rows-1)
6517 n=GetAuthenticPixels(image,0,y+1,image->columns,1,
6519 (void) CopyMagickMemory(next,n,length);
6522 for (i=0; i < m; i++, yy++)
6527 assert(yy < (ssize_t) large_image->rows);
6530 q=GetAuthenticPixels(large_image,0,yy,large_image->columns,
6532 q+=(large_image->columns-image->columns)*
6533 GetPixelChannels(large_image);
6535 for (x=(ssize_t) image->columns-1; x >= 0; x--)
6537 /* To do: get color as function of indexes[x] */
6539 if (image->storage_class == PseudoClass)
6544 if (magn_methy <= 1)
6546 /* replicate previous */
6547 SetPixelRed(large_image,GetPixelRed(image,pixels),q);
6548 SetPixelGreen(large_image,GetPixelGreen(image,
6550 SetPixelBlue(large_image,GetPixelBlue(image,
6552 SetPixelAlpha(large_image,GetPixelAlpha(image,
6556 else if (magn_methy == 2 || magn_methy == 4)
6560 SetPixelRed(large_image,GetPixelRed(image,
6562 SetPixelGreen(large_image,GetPixelGreen(image,
6564 SetPixelBlue(large_image,GetPixelBlue(image,
6566 SetPixelAlpha(large_image,GetPixelAlpha(image,
6573 SetPixelRed(large_image,((QM) (((ssize_t)
6574 (2*i*(GetPixelRed(image,n)
6575 -GetPixelRed(image,pixels)+m))/
6577 +GetPixelRed(image,pixels)))),q);
6578 SetPixelGreen(large_image,((QM) (((ssize_t)
6579 (2*i*(GetPixelGreen(image,n)
6580 -GetPixelGreen(image,pixels)+m))/
6582 +GetPixelGreen(image,pixels)))),q);
6583 SetPixelBlue(large_image,((QM) (((ssize_t)
6584 (2*i*(GetPixelBlue(image,n)
6585 -GetPixelBlue(image,pixels)+m))/
6587 +GetPixelBlue(image,pixels)))),q);
6589 if (image->alpha_trait == BlendPixelTrait)
6590 SetPixelAlpha(large_image, ((QM) (((ssize_t)
6591 (2*i*(GetPixelAlpha(image,n)
6592 -GetPixelAlpha(image,pixels)+m))
6594 GetPixelAlpha(image,pixels)))),q);
6597 if (magn_methy == 4)
6599 /* Replicate nearest */
6600 if (i <= ((m+1) << 1))
6601 SetPixelAlpha(large_image,GetPixelAlpha(image,
6604 SetPixelAlpha(large_image,GetPixelAlpha(image,
6609 else /* if (magn_methy == 3 || magn_methy == 5) */
6611 /* Replicate nearest */
6612 if (i <= ((m+1) << 1))
6614 SetPixelRed(large_image,GetPixelRed(image,
6616 SetPixelGreen(large_image,GetPixelGreen(image,
6618 SetPixelBlue(large_image,GetPixelBlue(image,
6620 SetPixelAlpha(large_image,GetPixelAlpha(image,
6626 SetPixelRed(large_image,GetPixelRed(image,n),q);
6627 SetPixelGreen(large_image,GetPixelGreen(image,n),
6629 SetPixelBlue(large_image,GetPixelBlue(image,n),
6631 SetPixelAlpha(large_image,GetPixelAlpha(image,n),
6635 if (magn_methy == 5)
6637 SetPixelAlpha(large_image,(QM) (((ssize_t) (2*i*
6638 (GetPixelAlpha(image,n)
6639 -GetPixelAlpha(image,pixels))
6640 +m))/((ssize_t) (m*2))
6641 +GetPixelAlpha(image,pixels)),q);
6644 n+=GetPixelChannels(image);
6645 q+=GetPixelChannels(large_image);
6646 pixels+=GetPixelChannels(image);
6649 if (SyncAuthenticPixels(large_image,exception) == 0)
6655 prev=(Quantum *) RelinquishMagickMemory(prev);
6656 next=(Quantum *) RelinquishMagickMemory(next);
6658 length=image->columns;
6660 if (logging != MagickFalse)
6661 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6662 " Delete original image");
6664 DeleteImageFromList(&image);
6668 mng_info->image=image;
6670 /* magnify the columns */
6671 if (logging != MagickFalse)
6672 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6673 " Magnify the columns to %.20g",(double) image->columns);
6675 for (y=0; y < (ssize_t) image->rows; y++)
6680 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
6681 pixels=q+(image->columns-length)*GetPixelChannels(image);
6682 n=pixels+GetPixelChannels(image);
6684 for (x=(ssize_t) (image->columns-length);
6685 x < (ssize_t) image->columns; x++)
6687 /* To do: Rewrite using Get/Set***PixelChannel() */
6689 if (x == (ssize_t) (image->columns-length))
6690 m=(ssize_t) mng_info->magn_ml;
6692 else if (magn_methx > 1 && x == (ssize_t) image->columns-2)
6693 m=(ssize_t) mng_info->magn_mr;
6695 else if (magn_methx <= 1 && x == (ssize_t) image->columns-1)
6696 m=(ssize_t) mng_info->magn_mr;
6698 else if (magn_methx > 1 && x == (ssize_t) image->columns-1)
6702 m=(ssize_t) mng_info->magn_mx;
6704 for (i=0; i < m; i++)
6706 if (magn_methx <= 1)
6708 /* replicate previous */
6709 SetPixelRed(image,GetPixelRed(image,pixels),q);
6710 SetPixelGreen(image,GetPixelGreen(image,pixels),q);
6711 SetPixelBlue(image,GetPixelBlue(image,pixels),q);
6712 SetPixelAlpha(image,GetPixelAlpha(image,pixels),q);
6715 else if (magn_methx == 2 || magn_methx == 4)
6719 SetPixelRed(image,GetPixelRed(image,pixels),q);
6720 SetPixelGreen(image,GetPixelGreen(image,pixels),q);
6721 SetPixelBlue(image,GetPixelBlue(image,pixels),q);
6722 SetPixelAlpha(image,GetPixelAlpha(image,pixels),q);
6725 /* To do: Rewrite using Get/Set***PixelChannel() */
6729 SetPixelRed(image,(QM) ((2*i*(
6730 GetPixelRed(image,n)
6731 -GetPixelRed(image,pixels))+m)
6733 GetPixelRed(image,pixels)),q);
6735 SetPixelGreen(image,(QM) ((2*i*(
6736 GetPixelGreen(image,n)
6737 -GetPixelGreen(image,pixels))+m)
6739 GetPixelGreen(image,pixels)),q);
6741 SetPixelBlue(image,(QM) ((2*i*(
6742 GetPixelBlue(image,n)
6743 -GetPixelBlue(image,pixels))+m)
6745 GetPixelBlue(image,pixels)),q);
6746 if (image->alpha_trait == BlendPixelTrait)
6747 SetPixelAlpha(image,(QM) ((2*i*(
6748 GetPixelAlpha(image,n)
6749 -GetPixelAlpha(image,pixels))+m)
6751 GetPixelAlpha(image,pixels)),q);
6754 if (magn_methx == 4)
6756 /* Replicate nearest */
6757 if (i <= ((m+1) << 1))
6759 SetPixelAlpha(image,
6760 GetPixelAlpha(image,pixels)+0,q);
6764 SetPixelAlpha(image,
6765 GetPixelAlpha(image,n)+0,q);
6770 else /* if (magn_methx == 3 || magn_methx == 5) */
6772 /* Replicate nearest */
6773 if (i <= ((m+1) << 1))
6775 SetPixelRed(image,GetPixelRed(image,pixels),q);
6776 SetPixelGreen(image,GetPixelGreen(image,pixels),q);
6777 SetPixelBlue(image,GetPixelBlue(image,pixels),q);
6778 SetPixelAlpha(image,GetPixelAlpha(image,pixels),q);
6783 SetPixelRed(image,GetPixelRed(image,n),q);
6784 SetPixelGreen(image,GetPixelGreen(image,n),q);
6785 SetPixelBlue(image,GetPixelBlue(image,n),q);
6786 SetPixelAlpha(image,GetPixelAlpha(image,n),q);
6789 if (magn_methx == 5)
6792 SetPixelAlpha(image,
6793 (QM) ((2*i*( GetPixelAlpha(image,n)
6794 -GetPixelAlpha(image,pixels))+m)/
6796 +GetPixelAlpha(image,pixels)),q);
6799 q+=GetPixelChannels(image);
6801 n+=GetPixelChannels(image);
6802 p+=GetPixelChannels(image);
6805 if (SyncAuthenticPixels(image,exception) == MagickFalse)
6808 #if (MAGICKCORE_QUANTUM_DEPTH > 16)
6809 if (magn_methx != 1 || magn_methy != 1)
6812 Rescale pixels to Quantum
6814 for (y=0; y < (ssize_t) image->rows; y++)
6816 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
6818 for (x=(ssize_t) image->columns-1; x >= 0; x--)
6820 SetPixelRed(image,ScaleShortToQuantum(
6821 GetPixelRed(image,q)),q);
6822 SetPixelGreen(image,ScaleShortToQuantum(
6823 GetPixelGreen(image,q)),q);
6824 SetPixelBlue(image,ScaleShortToQuantum(
6825 GetPixelBlue(image,q)),q);
6826 SetPixelAlpha(image,ScaleShortToQuantum(
6827 GetPixelAlpha(image,q)),q);
6828 q+=GetPixelChannels(image);
6831 if (SyncAuthenticPixels(image,exception) == MagickFalse)
6836 if (logging != MagickFalse)
6837 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6838 " Finished MAGN processing");
6843 Crop_box is with respect to the upper left corner of the MNG.
6845 crop_box.left=mng_info->image_box.left+mng_info->x_off[object_id];
6846 crop_box.right=mng_info->image_box.right+mng_info->x_off[object_id];
6847 crop_box.top=mng_info->image_box.top+mng_info->y_off[object_id];
6848 crop_box.bottom=mng_info->image_box.bottom+mng_info->y_off[object_id];
6849 crop_box=mng_minimum_box(crop_box,mng_info->clip);
6850 crop_box=mng_minimum_box(crop_box,mng_info->frame);
6851 crop_box=mng_minimum_box(crop_box,mng_info->object_clip[object_id]);
6852 if ((crop_box.left != (mng_info->image_box.left
6853 +mng_info->x_off[object_id])) ||
6854 (crop_box.right != (mng_info->image_box.right
6855 +mng_info->x_off[object_id])) ||
6856 (crop_box.top != (mng_info->image_box.top
6857 +mng_info->y_off[object_id])) ||
6858 (crop_box.bottom != (mng_info->image_box.bottom
6859 +mng_info->y_off[object_id])))
6861 if (logging != MagickFalse)
6862 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6863 " Crop the PNG image");
6865 if ((crop_box.left < crop_box.right) &&
6866 (crop_box.top < crop_box.bottom))
6875 Crop_info is with respect to the upper left corner of
6878 crop_info.x=(crop_box.left-mng_info->x_off[object_id]);
6879 crop_info.y=(crop_box.top-mng_info->y_off[object_id]);
6880 crop_info.width=(size_t) (crop_box.right-crop_box.left);
6881 crop_info.height=(size_t) (crop_box.bottom-crop_box.top);
6882 image->page.width=image->columns;
6883 image->page.height=image->rows;
6886 im=CropImage(image,&crop_info,exception);
6888 if (im != (Image *) NULL)
6890 image->columns=im->columns;
6891 image->rows=im->rows;
6892 im=DestroyImage(im);
6893 image->page.width=image->columns;
6894 image->page.height=image->rows;
6895 image->page.x=crop_box.left;
6896 image->page.y=crop_box.top;
6903 No pixels in crop area. The MNG spec still requires
6904 a layer, though, so make a single transparent pixel in
6905 the top left corner.
6910 (void) SetImageBackgroundColor(image,exception);
6911 image->page.width=1;
6912 image->page.height=1;
6917 #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
6918 image=mng_info->image;
6922 #if (MAGICKCORE_QUANTUM_DEPTH > 16)
6923 /* PNG does not handle depths greater than 16 so reduce it even
6926 if (image->depth > 16)
6930 #if (MAGICKCORE_QUANTUM_DEPTH > 8)
6931 if (image->depth > 8)
6933 /* To do: fill low byte properly */
6937 if (LosslessReduceDepthOK(image,exception) != MagickFalse)
6941 if (image_info->number_scenes != 0)
6943 if (mng_info->scenes_found >
6944 (ssize_t) (image_info->first_scene+image_info->number_scenes))
6948 if (logging != MagickFalse)
6949 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6950 " Finished reading image datastream.");
6952 } while (LocaleCompare(image_info->magick,"MNG") == 0);
6954 (void) CloseBlob(image);
6956 if (logging != MagickFalse)
6957 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6958 " Finished reading all image datastreams.");
6960 #if defined(MNG_INSERT_LAYERS)
6961 if (insert_layers && !mng_info->image_found && (mng_info->mng_width) &&
6962 (mng_info->mng_height))
6965 Insert a background layer if nothing else was found.
6967 if (logging != MagickFalse)
6968 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6969 " No images found. Inserting a background layer.");
6971 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
6974 Allocate next image structure.
6976 AcquireNextImage(image_info,image,exception);
6977 if (GetNextImageInList(image) == (Image *) NULL)
6979 image=DestroyImageList(image);
6980 MngInfoFreeStruct(mng_info,&have_mng_structure);
6982 if (logging != MagickFalse)
6983 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6984 " Allocation failed, returning NULL.");
6986 return((Image *) NULL);
6988 image=SyncNextImageInList(image);
6990 image->columns=mng_info->mng_width;
6991 image->rows=mng_info->mng_height;
6992 image->page.width=mng_info->mng_width;
6993 image->page.height=mng_info->mng_height;
6996 image->background_color=mng_background_color;
6997 image->alpha_trait=UndefinedPixelTrait;
6999 if (image_info->ping == MagickFalse)
7000 (void) SetImageBackgroundColor(image,exception);
7002 mng_info->image_found++;
7005 image->iterations=mng_iterations;
7007 if (mng_iterations == 1)
7008 image->start_loop=MagickTrue;
7010 while (GetPreviousImageInList(image) != (Image *) NULL)
7013 if (image_count > 10*mng_info->image_found)
7015 if (logging != MagickFalse)
7016 (void) LogMagickEvent(CoderEvent,GetMagickModule()," No beginning");
7018 (void) ThrowMagickException(exception,GetMagickModule(),
7019 CoderError,"Linked list is corrupted, beginning of list not found",
7020 "`%s'",image_info->filename);
7022 return((Image *) NULL);
7025 image=GetPreviousImageInList(image);
7027 if (GetNextImageInList(image) == (Image *) NULL)
7029 if (logging != MagickFalse)
7030 (void) LogMagickEvent(CoderEvent,GetMagickModule()," Corrupt list");
7032 (void) ThrowMagickException(exception,GetMagickModule(),
7033 CoderError,"Linked list is corrupted; next_image is NULL","`%s'",
7034 image_info->filename);
7038 if (mng_info->ticks_per_second && mng_info->image_found > 1 &&
7039 GetNextImageInList(image) ==
7042 if (logging != MagickFalse)
7043 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7044 " First image null");
7046 (void) ThrowMagickException(exception,GetMagickModule(),
7047 CoderError,"image->next for first image is NULL but shouldn't be.",
7048 "`%s'",image_info->filename);
7051 if (mng_info->image_found == 0)
7053 if (logging != MagickFalse)
7054 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7055 " No visible images found.");
7057 (void) ThrowMagickException(exception,GetMagickModule(),
7058 CoderError,"No visible images in file","`%s'",image_info->filename);
7060 if (image != (Image *) NULL)
7061 image=DestroyImageList(image);
7063 MngInfoFreeStruct(mng_info,&have_mng_structure);
7064 return((Image *) NULL);
7067 if (mng_info->ticks_per_second)
7068 final_delay=1UL*MagickMax(image->ticks_per_second,1L)*
7069 final_delay/mng_info->ticks_per_second;
7072 image->start_loop=MagickTrue;
7074 /* Find final nonzero image delay */
7075 final_image_delay=0;
7077 while (GetNextImageInList(image) != (Image *) NULL)
7080 final_image_delay=image->delay;
7082 image=GetNextImageInList(image);
7085 if (final_delay < final_image_delay)
7086 final_delay=final_image_delay;
7088 image->delay=final_delay;
7090 if (logging != MagickFalse)
7091 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7092 " image->delay=%.20g, final_delay=%.20g",(double) image->delay,
7093 (double) final_delay);
7095 if (logging != MagickFalse)
7101 image=GetFirstImageInList(image);
7103 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7104 " Before coalesce:");
7106 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7107 " scene 0 delay=%.20g",(double) image->delay);
7109 while (GetNextImageInList(image) != (Image *) NULL)
7111 image=GetNextImageInList(image);
7112 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7113 " scene %.20g delay=%.20g",(double) scene++,(double) image->delay);
7117 image=GetFirstImageInList(image);
7118 #ifdef MNG_COALESCE_LAYERS
7128 if (logging != MagickFalse)
7129 (void) LogMagickEvent(CoderEvent,GetMagickModule()," Coalesce Images");
7132 next_image=CoalesceImages(image,exception);
7134 if (next_image == (Image *) NULL)
7135 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
7137 image=DestroyImageList(image);
7140 for (next=image; next != (Image *) NULL; next=next_image)
7142 next->page.width=mng_info->mng_width;
7143 next->page.height=mng_info->mng_height;
7146 next->scene=scene++;
7147 next_image=GetNextImageInList(next);
7149 if (next_image == (Image *) NULL)
7152 if (next->delay == 0)
7155 next_image->previous=GetPreviousImageInList(next);
7156 if (GetPreviousImageInList(next) == (Image *) NULL)
7159 next->previous->next=next_image;
7160 next=DestroyImage(next);
7166 while (GetNextImageInList(image) != (Image *) NULL)
7167 image=GetNextImageInList(image);
7169 image->dispose=BackgroundDispose;
7171 if (logging != MagickFalse)
7177 image=GetFirstImageInList(image);
7179 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7180 " After coalesce:");
7182 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7183 " scene 0 delay=%.20g dispose=%.20g",(double) image->delay,
7184 (double) image->dispose);
7186 while (GetNextImageInList(image) != (Image *) NULL)
7188 image=GetNextImageInList(image);
7190 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7191 " scene %.20g delay=%.20g dispose=%.20g",(double) scene++,
7192 (double) image->delay,(double) image->dispose);
7196 image=GetFirstImageInList(image);
7197 MngInfoFreeStruct(mng_info,&have_mng_structure);
7198 have_mng_structure=MagickFalse;
7200 if (logging != MagickFalse)
7201 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit ReadMNGImage()");
7203 return(GetFirstImageInList(image));
7205 #else /* PNG_LIBPNG_VER > 10011 */
7206 static Image *ReadPNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
7208 printf("Your PNG library is too old: You have libpng-%s\n",
7209 PNG_LIBPNG_VER_STRING);
7211 (void) ThrowMagickException(exception,GetMagickModule(),CoderError,
7212 "PNG library is too old","`%s'",image_info->filename);
7214 return(Image *) NULL;
7217 static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
7219 return(ReadPNGImage(image_info,exception));
7221 #endif /* PNG_LIBPNG_VER > 10011 */
7225 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7229 % R e g i s t e r P N G I m a g e %
7233 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7235 % RegisterPNGImage() adds properties for the PNG image format to
7236 % the list of supported formats. The properties include the image format
7237 % tag, a method to read and/or write the format, whether the format
7238 % supports the saving of more than one frame to the same file or blob,
7239 % whether the format supports native in-memory I/O, and a brief
7240 % description of the format.
7242 % The format of the RegisterPNGImage method is:
7244 % size_t RegisterPNGImage(void)
7247 ModuleExport size_t RegisterPNGImage(void)
7250 version[MaxTextExtent];
7258 "See http://www.libpng.org/ for details about the PNG format."
7263 "See http://www.libpng.org/pub/mng/ for details about the JNG\n"
7269 "See http://www.libpng.org/pub/mng/ for details about the MNG\n"
7275 #if defined(PNG_LIBPNG_VER_STRING)
7276 (void) ConcatenateMagickString(version,"libpng ",MaxTextExtent);
7277 (void) ConcatenateMagickString(version,PNG_LIBPNG_VER_STRING,MaxTextExtent);
7279 if (LocaleCompare(PNG_LIBPNG_VER_STRING,png_get_header_ver(NULL)) != 0)
7281 (void) ConcatenateMagickString(version,",",MaxTextExtent);
7282 (void) ConcatenateMagickString(version,png_get_libpng_ver(NULL),
7287 entry=SetMagickInfo("MNG");
7288 entry->seekable_stream=MagickTrue; /* To do: eliminate this. */
7290 #if defined(MAGICKCORE_PNG_DELEGATE)
7291 entry->decoder=(DecodeImageHandler *) ReadMNGImage;
7292 entry->encoder=(EncodeImageHandler *) WriteMNGImage;
7295 entry->magick=(IsImageFormatHandler *) IsMNG;
7296 entry->description=ConstantString("Multiple-image Network Graphics");
7298 if (*version != '\0')
7299 entry->version=ConstantString(version);
7301 entry->module=ConstantString("PNG");
7302 entry->note=ConstantString(MNGNote);
7303 (void) RegisterMagickInfo(entry);
7305 entry=SetMagickInfo("PNG");
7307 #if defined(MAGICKCORE_PNG_DELEGATE)
7308 entry->decoder=(DecodeImageHandler *) ReadPNGImage;
7309 entry->encoder=(EncodeImageHandler *) WritePNGImage;
7312 entry->magick=(IsImageFormatHandler *) IsPNG;
7313 entry->adjoin=MagickFalse;
7314 entry->description=ConstantString("Portable Network Graphics");
7315 entry->module=ConstantString("PNG");
7317 if (*version != '\0')
7318 entry->version=ConstantString(version);
7320 entry->note=ConstantString(PNGNote);
7321 (void) RegisterMagickInfo(entry);
7323 entry=SetMagickInfo("PNG8");
7325 #if defined(MAGICKCORE_PNG_DELEGATE)
7326 entry->decoder=(DecodeImageHandler *) ReadPNGImage;
7327 entry->encoder=(EncodeImageHandler *) WritePNGImage;
7330 entry->magick=(IsImageFormatHandler *) IsPNG;
7331 entry->adjoin=MagickFalse;
7332 entry->description=ConstantString(
7333 "8-bit indexed with optional binary transparency");
7334 entry->module=ConstantString("PNG");
7335 (void) RegisterMagickInfo(entry);
7337 entry=SetMagickInfo("PNG24");
7340 #if defined(ZLIB_VERSION)
7341 (void) ConcatenateMagickString(version,"zlib ",MaxTextExtent);
7342 (void) ConcatenateMagickString(version,ZLIB_VERSION,MaxTextExtent);
7344 if (LocaleCompare(ZLIB_VERSION,zlib_version) != 0)
7346 (void) ConcatenateMagickString(version,",",MaxTextExtent);
7347 (void) ConcatenateMagickString(version,zlib_version,MaxTextExtent);
7351 if (*version != '\0')
7352 entry->version=ConstantString(version);
7354 #if defined(MAGICKCORE_PNG_DELEGATE)
7355 entry->decoder=(DecodeImageHandler *) ReadPNGImage;
7356 entry->encoder=(EncodeImageHandler *) WritePNGImage;
7359 entry->magick=(IsImageFormatHandler *) IsPNG;
7360 entry->adjoin=MagickFalse;
7361 entry->description=ConstantString("opaque or binary transparent 24-bit RGB");
7362 entry->module=ConstantString("PNG");
7363 (void) RegisterMagickInfo(entry);
7365 entry=SetMagickInfo("PNG32");
7367 #if defined(MAGICKCORE_PNG_DELEGATE)
7368 entry->decoder=(DecodeImageHandler *) ReadPNGImage;
7369 entry->encoder=(EncodeImageHandler *) WritePNGImage;
7372 entry->magick=(IsImageFormatHandler *) IsPNG;
7373 entry->adjoin=MagickFalse;
7374 entry->description=ConstantString("opaque or transparent 32-bit RGBA");
7375 entry->module=ConstantString("PNG");
7376 (void) RegisterMagickInfo(entry);
7378 entry=SetMagickInfo("PNG48");
7380 #if defined(MAGICKCORE_PNG_DELEGATE)
7381 entry->decoder=(DecodeImageHandler *) ReadPNGImage;
7382 entry->encoder=(EncodeImageHandler *) WritePNGImage;
7385 entry->magick=(IsImageFormatHandler *) IsPNG;
7386 entry->adjoin=MagickFalse;
7387 entry->description=ConstantString("opaque or binary transparent 48-bit RGB");
7388 entry->module=ConstantString("PNG");
7389 (void) RegisterMagickInfo(entry);
7391 entry=SetMagickInfo("PNG64");
7393 #if defined(MAGICKCORE_PNG_DELEGATE)
7394 entry->decoder=(DecodeImageHandler *) ReadPNGImage;
7395 entry->encoder=(EncodeImageHandler *) WritePNGImage;
7398 entry->magick=(IsImageFormatHandler *) IsPNG;
7399 entry->adjoin=MagickFalse;
7400 entry->description=ConstantString("opaque or transparent 64-bit RGBA");
7401 entry->module=ConstantString("PNG");
7402 (void) RegisterMagickInfo(entry);
7404 entry=SetMagickInfo("PNG00");
7406 #if defined(MAGICKCORE_PNG_DELEGATE)
7407 entry->decoder=(DecodeImageHandler *) ReadPNGImage;
7408 entry->encoder=(EncodeImageHandler *) WritePNGImage;
7411 entry->magick=(IsImageFormatHandler *) IsPNG;
7412 entry->adjoin=MagickFalse;
7413 entry->description=ConstantString(
7414 "PNG inheriting bit-depth and color-type from original");
7415 entry->module=ConstantString("PNG");
7416 (void) RegisterMagickInfo(entry);
7418 entry=SetMagickInfo("JNG");
7420 #if defined(JNG_SUPPORTED)
7421 #if defined(MAGICKCORE_PNG_DELEGATE)
7422 entry->decoder=(DecodeImageHandler *) ReadJNGImage;
7423 entry->encoder=(EncodeImageHandler *) WriteJNGImage;
7427 entry->magick=(IsImageFormatHandler *) IsJNG;
7428 entry->adjoin=MagickFalse;
7429 entry->description=ConstantString("JPEG Network Graphics");
7430 entry->module=ConstantString("PNG");
7431 entry->note=ConstantString(JNGNote);
7432 (void) RegisterMagickInfo(entry);
7434 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
7435 ping_semaphore=AllocateSemaphoreInfo();
7438 return(MagickImageCoderSignature);
7442 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7446 % U n r e g i s t e r P N G I m a g e %
7450 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7452 % UnregisterPNGImage() removes format registrations made by the
7453 % PNG module from the list of supported formats.
7455 % The format of the UnregisterPNGImage method is:
7457 % UnregisterPNGImage(void)
7460 ModuleExport void UnregisterPNGImage(void)
7462 (void) UnregisterMagickInfo("MNG");
7463 (void) UnregisterMagickInfo("PNG");
7464 (void) UnregisterMagickInfo("PNG8");
7465 (void) UnregisterMagickInfo("PNG24");
7466 (void) UnregisterMagickInfo("PNG32");
7467 (void) UnregisterMagickInfo("PNG48");
7468 (void) UnregisterMagickInfo("PNG64");
7469 (void) UnregisterMagickInfo("PNG00");
7470 (void) UnregisterMagickInfo("JNG");
7472 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
7473 if (ping_semaphore != (SemaphoreInfo *) NULL)
7474 DestroySemaphoreInfo(&ping_semaphore);
7478 #if defined(MAGICKCORE_PNG_DELEGATE)
7479 #if PNG_LIBPNG_VER > 10011
7481 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7485 % W r i t e M N G I m a g e %
7489 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7491 % WriteMNGImage() writes an image in the Portable Network Graphics
7492 % Group's "Multiple-image Network Graphics" encoded image format.
7494 % MNG support written by Glenn Randers-Pehrson, glennrp@image...
7496 % The format of the WriteMNGImage method is:
7498 % MagickBooleanType WriteMNGImage(const ImageInfo *image_info,
7499 % Image *image,ExceptionInfo *exception)
7501 % A description of each parameter follows.
7503 % o image_info: the image info.
7505 % o image: The image.
7507 % o exception: return any errors or warnings in this structure.
7509 % To do (as of version 5.5.2, November 26, 2002 -- glennrp -- see also
7510 % "To do" under ReadPNGImage):
7512 % Preserve all unknown and not-yet-handled known chunks found in input
7513 % PNG file and copy them into output PNG files according to the PNG
7516 % Write the iCCP chunk at MNG level when (icc profile length > 0)
7518 % Improve selection of color type (use indexed-colour or indexed-colour
7519 % with tRNS when 256 or fewer unique RGBA values are present).
7521 % Figure out what to do with "dispose=<restore-to-previous>" (dispose == 3)
7522 % This will be complicated if we limit ourselves to generating MNG-LC
7523 % files. For now we ignore disposal method 3 and simply overlay the next
7526 % Check for identical PLTE's or PLTE/tRNS combinations and use a
7527 % global MNG PLTE or PLTE/tRNS combination when appropriate.
7528 % [mostly done 15 June 1999 but still need to take care of tRNS]
7530 % Check for identical sRGB and replace with a global sRGB (and remove
7531 % gAMA/cHRM if sRGB is found; check for identical gAMA/cHRM and
7532 % replace with global gAMA/cHRM (or with sRGB if appropriate; replace
7533 % local gAMA/cHRM with local sRGB if appropriate).
7535 % Check for identical sBIT chunks and write global ones.
7537 % Provide option to skip writing the signature tEXt chunks.
7539 % Use signatures to detect identical objects and reuse the first
7540 % instance of such objects instead of writing duplicate objects.
7542 % Use a smaller-than-32k value of compression window size when
7545 % Encode JNG datastreams. Mostly done as of 5.5.2; need to write
7546 % ancillary text chunks and save profiles.
7548 % Provide an option to force LC files (to ensure exact framing rate)
7551 % Provide an option to force VLC files instead of LC, even when offsets
7552 % are present. This will involve expanding the embedded images with a
7553 % transparent region at the top and/or left.
7557 Magick_png_write_raw_profile(const ImageInfo *image_info,png_struct *ping,
7558 png_info *ping_info, unsigned char *profile_type, unsigned char
7559 *profile_description, unsigned char *profile_data, png_uint_32 length)
7578 hex[16]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
7580 if (LocaleNCompare((char *) profile_type+1, "ng-chunk-",9) == 0)
7583 if (image_info->verbose)
7585 (void) printf("writing raw profile: type=%s, length=%.20g\n",
7586 (char *) profile_type, (double) length);
7589 #if PNG_LIBPNG_VER >= 14000
7590 text=(png_textp) png_malloc(ping,(png_alloc_size_t) sizeof(png_text));
7592 text=(png_textp) png_malloc(ping,(png_size_t) sizeof(png_text));
7594 description_length=(png_uint_32) strlen((const char *) profile_description);
7595 allocated_length=(png_uint_32) (length*2 + (length >> 5) + 20
7596 + description_length);
7597 #if PNG_LIBPNG_VER >= 14000
7598 text[0].text=(png_charp) png_malloc(ping,
7599 (png_alloc_size_t) allocated_length);
7600 text[0].key=(png_charp) png_malloc(ping, (png_alloc_size_t) 80);
7602 text[0].text=(png_charp) png_malloc(ping, (png_size_t) allocated_length);
7603 text[0].key=(png_charp) png_malloc(ping, (png_size_t) 80);
7605 text[0].key[0]='\0';
7606 (void) ConcatenateMagickString(text[0].key,
7607 "Raw profile type ",MaxTextExtent);
7608 (void) ConcatenateMagickString(text[0].key,(const char *) profile_type,62);
7612 (void) CopyMagickString(dp,(const char *) profile_description,
7614 dp+=description_length;
7616 (void) FormatLocaleString(dp,allocated_length-
7617 (png_size_t) (dp-text[0].text),"%8lu ",(unsigned long) length);
7620 for (i=0; i < (ssize_t) length; i++)
7624 *(dp++)=(char) hex[((*sp >> 4) & 0x0f)];
7625 *(dp++)=(char) hex[((*sp++ ) & 0x0f)];
7630 text[0].text_length=(png_size_t) (dp-text[0].text);
7631 text[0].compression=image_info->compression == NoCompression ||
7632 (image_info->compression == UndefinedCompression &&
7633 text[0].text_length < 128) ? -1 : 0;
7635 if (text[0].text_length <= allocated_length)
7636 png_set_text(ping,ping_info,text,1);
7638 png_free(ping,text[0].text);
7639 png_free(ping,text[0].key);
7640 png_free(ping,text);
7643 static MagickBooleanType Magick_png_write_chunk_from_profile(Image *image,
7644 const char *string, MagickBooleanType logging)
7657 ResetImageProfileIterator(image);
7659 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
7661 profile=GetImageProfile(image,name);
7663 if (profile != (const StringInfo *) NULL)
7668 if (LocaleNCompare(name,string,11) == 0)
7670 if (logging != MagickFalse)
7671 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7672 " Found %s profile",name);
7674 ping_profile=CloneStringInfo(profile);
7675 data=GetStringInfoDatum(ping_profile),
7676 length=(png_uint_32) GetStringInfoLength(ping_profile);
7681 (void) WriteBlobMSBULong(image,length-5); /* data length */
7682 (void) WriteBlob(image,length-1,data+1);
7683 (void) WriteBlobMSBULong(image,crc32(0,data+1,(uInt) length-1));
7684 ping_profile=DestroyStringInfo(ping_profile);
7688 name=GetNextImageProfile(image);
7695 /* Write one PNG image */
7696 static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
7697 const ImageInfo *IMimage_info,Image *IMimage,ExceptionInfo *exception)
7721 ping_trans_alpha[256];
7749 ping_have_cheap_transparency,
7760 /* ping_exclude_EXIF, */
7763 /* ping_exclude_iTXt, */
7768 /* ping_exclude_tRNS, */
7770 ping_exclude_zCCP, /* hex-encoded iCCP */
7773 ping_preserve_colormap,
7774 ping_need_colortype_warning,
7792 *volatile ping_pixels;
7798 ping_interlace_method,
7799 ping_compression_method,
7816 number_semitransparent,
7818 ping_pHYs_unit_type;
7821 ping_pHYs_x_resolution,
7822 ping_pHYs_y_resolution;
7824 logging=LogMagickEvent(CoderEvent,GetMagickModule(),
7825 " Enter WriteOnePNGImage()");
7827 image = CloneImage(IMimage,0,0,MagickFalse,exception);
7828 image_info=(ImageInfo *) CloneImageInfo(IMimage_info);
7829 if (image_info == (ImageInfo *) NULL)
7830 ThrowWriterException(ResourceLimitError, "MemoryAllocationFailed");
7832 /* Initialize some stuff */
7835 ping_interlace_method=0,
7836 ping_compression_method=0,
7837 ping_filter_method=0,
7840 ping_background.red = 0;
7841 ping_background.green = 0;
7842 ping_background.blue = 0;
7843 ping_background.gray = 0;
7844 ping_background.index = 0;
7846 ping_trans_color.red=0;
7847 ping_trans_color.green=0;
7848 ping_trans_color.blue=0;
7849 ping_trans_color.gray=0;
7851 ping_pHYs_unit_type = 0;
7852 ping_pHYs_x_resolution = 0;
7853 ping_pHYs_y_resolution = 0;
7855 ping_have_blob=MagickFalse;
7856 ping_have_color=MagickTrue;
7857 ping_have_non_bw=MagickTrue;
7858 ping_have_PLTE=MagickFalse;
7859 ping_have_bKGD=MagickFalse;
7860 ping_have_pHYs=MagickFalse;
7861 ping_have_tRNS=MagickFalse;
7863 ping_exclude_bKGD=mng_info->ping_exclude_bKGD;
7864 ping_exclude_cHRM=mng_info->ping_exclude_cHRM;
7865 ping_exclude_date=mng_info->ping_exclude_date;
7866 /* ping_exclude_EXIF=mng_info->ping_exclude_EXIF; */
7867 ping_exclude_gAMA=mng_info->ping_exclude_gAMA;
7868 ping_exclude_iCCP=mng_info->ping_exclude_iCCP;
7869 /* ping_exclude_iTXt=mng_info->ping_exclude_iTXt; */
7870 ping_exclude_oFFs=mng_info->ping_exclude_oFFs;
7871 ping_exclude_pHYs=mng_info->ping_exclude_pHYs;
7872 ping_exclude_sRGB=mng_info->ping_exclude_sRGB;
7873 ping_exclude_tEXt=mng_info->ping_exclude_tEXt;
7874 /* ping_exclude_tRNS=mng_info->ping_exclude_tRNS; */
7875 ping_exclude_vpAg=mng_info->ping_exclude_vpAg;
7876 ping_exclude_zCCP=mng_info->ping_exclude_zCCP; /* hex-encoded iCCP in zTXt */
7877 ping_exclude_zTXt=mng_info->ping_exclude_zTXt;
7879 ping_preserve_colormap = mng_info->ping_preserve_colormap;
7880 ping_need_colortype_warning = MagickFalse;
7882 /* Recognize the ICC sRGB profile and convert it to the sRGB chunk,
7883 * i.e., eliminate the ICC profile and set image->rendering_intent.
7884 * Note that this will not involve any changes to the actual pixels
7885 * but merely passes information to applications that read the resulting
7888 if (ping_exclude_sRGB == MagickFalse)
7896 ResetImageProfileIterator(image);
7897 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
7899 profile=GetImageProfile(image,name);
7901 if (profile != (StringInfo *) NULL)
7903 if ((LocaleCompare(name,"ICC") == 0) ||
7904 (LocaleCompare(name,"ICM") == 0))
7909 /* 0: not a known sRGB profile
7910 * 1: HP-Microsoft sRGB v2
7911 * 2: ICC sRGB v4 perceptual
7912 * 3: ICC sRGB v2 perceptual no black-compensation
7915 check_crc[4] = {0, 0xf29e526dUL, 0xbbef7812UL, 0x427ebb21UL},
7916 check_len[4] = {0, 3144, 60960, 3052};
7925 length=(png_uint_32) GetStringInfoLength(profile);
7927 for (icheck=3; icheck > 0; icheck--)
7929 if (length == check_len[icheck])
7931 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7932 " Got a %lu-byte ICC profile (potentially sRGB)",
7933 (unsigned long) length);
7935 data=GetStringInfoDatum(profile);
7936 profile_crc=crc32(0,data,length);
7938 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7939 " with crc=%8x",(unsigned int) profile_crc);
7941 if (profile_crc == check_crc[icheck])
7943 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7945 if (image->rendering_intent==UndefinedIntent)
7946 image->rendering_intent=PerceptualIntent;
7952 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7953 " Got a %lu-byte ICC profile",
7954 (unsigned long) length);
7957 name=GetNextImageProfile(image);
7962 number_semitransparent = 0;
7963 number_transparent = 0;
7965 if (logging != MagickFalse)
7967 if (image->storage_class == UndefinedClass)
7968 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7969 " storage_class=UndefinedClass");
7970 if (image->storage_class == DirectClass)
7971 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7972 " storage_class=DirectClass");
7973 if (image->storage_class == PseudoClass)
7974 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7975 " storage_class=PseudoClass");
7978 if (image->storage_class == PseudoClass &&
7979 (mng_info->write_png8 || mng_info->write_png24 || mng_info->write_png32 ||
7980 mng_info->write_png48 || mng_info->write_png64 ||
7981 (mng_info->write_png_colortype != 1 &&
7982 mng_info->write_png_colortype != 5)))
7984 (void) SyncImage(image,exception);
7985 image->storage_class = DirectClass;
7988 if (ping_preserve_colormap == MagickFalse)
7990 if (image->storage_class != PseudoClass && image->colormap != NULL)
7992 /* Free the bogus colormap; it can cause trouble later */
7993 if (logging != MagickFalse)
7994 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7995 " Freeing bogus colormap");
7996 (void) RelinquishMagickMemory(image->colormap);
7997 image->colormap=NULL;
8001 if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
8002 (void) TransformImageColorspace(image,sRGBColorspace,exception);
8005 Sometimes we get PseudoClass images whose RGB values don't match
8006 the colors in the colormap. This code syncs the RGB values.
8008 if (image->depth <= 8 && image->taint && image->storage_class == PseudoClass)
8009 (void) SyncImage(image,exception);
8011 #if (MAGICKCORE_QUANTUM_DEPTH == 8)
8012 if (image->depth > 8)
8014 if (logging != MagickFalse)
8015 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8016 " Reducing PNG bit depth to 8 since this is a Q8 build.");
8022 /* Respect the -depth option */
8023 if (image->depth < MAGICKCORE_QUANTUM_DEPTH)
8028 if (image->depth > 8)
8030 #if MAGICKCORE_QUANTUM_DEPTH > 16
8031 /* Scale to 16-bit */
8032 LBR16PacketRGBO(image->background_color);
8034 for (y=0; y < (ssize_t) image->rows; y++)
8036 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8038 if (r == (Quantum *) NULL)
8041 for (x=0; x < (ssize_t) image->columns; x++)
8044 r+=GetPixelChannels(image);
8047 if (SyncAuthenticPixels(image,exception) == MagickFalse)
8051 if (image->storage_class == PseudoClass && image->colormap != NULL)
8053 for (i=0; i < (ssize_t) image->colors; i++)
8055 LBR16PacketRGBO(image->colormap[i]);
8058 #endif /* MAGICKCORE_QUANTUM_DEPTH > 16 */
8061 else if (image->depth > 4)
8063 #if MAGICKCORE_QUANTUM_DEPTH > 8
8064 /* Scale to 8-bit */
8065 LBR08PacketRGBO(image->background_color);
8067 for (y=0; y < (ssize_t) image->rows; y++)
8069 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8071 if (r == (Quantum *) NULL)
8074 for (x=0; x < (ssize_t) image->columns; x++)
8077 r+=GetPixelChannels(image);
8080 if (SyncAuthenticPixels(image,exception) == MagickFalse)
8084 if (image->storage_class == PseudoClass && image->colormap != NULL)
8086 for (i=0; i < (ssize_t) image->colors; i++)
8088 LBR08PacketRGBO(image->colormap[i]);
8091 #endif /* MAGICKCORE_QUANTUM_DEPTH > 8 */
8094 if (image->depth > 2)
8096 /* Scale to 4-bit */
8097 LBR04PacketRGBO(image->background_color);
8099 for (y=0; y < (ssize_t) image->rows; y++)
8101 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8103 if (r == (Quantum *) NULL)
8106 for (x=0; x < (ssize_t) image->columns; x++)
8109 r+=GetPixelChannels(image);
8112 if (SyncAuthenticPixels(image,exception) == MagickFalse)
8116 if (image->storage_class == PseudoClass && image->colormap != NULL)
8118 for (i=0; i < (ssize_t) image->colors; i++)
8120 LBR04PacketRGBO(image->colormap[i]);
8125 else if (image->depth > 1)
8127 /* Scale to 2-bit */
8128 LBR02PacketRGBO(image->background_color);
8130 for (y=0; y < (ssize_t) image->rows; y++)
8132 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8134 if (r == (Quantum *) NULL)
8137 for (x=0; x < (ssize_t) image->columns; x++)
8140 r+=GetPixelChannels(image);
8143 if (SyncAuthenticPixels(image,exception) == MagickFalse)
8147 if (image->storage_class == PseudoClass && image->colormap != NULL)
8149 for (i=0; i < (ssize_t) image->colors; i++)
8151 LBR02PacketRGBO(image->colormap[i]);
8157 /* Scale to 1-bit */
8158 LBR01PacketRGBO(image->background_color);
8160 for (y=0; y < (ssize_t) image->rows; y++)
8162 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8164 if (r == (Quantum *) NULL)
8167 for (x=0; x < (ssize_t) image->columns; x++)
8170 r+=GetPixelChannels(image);
8173 if (SyncAuthenticPixels(image,exception) == MagickFalse)
8177 if (image->storage_class == PseudoClass && image->colormap != NULL)
8179 for (i=0; i < (ssize_t) image->colors; i++)
8181 LBR01PacketRGBO(image->colormap[i]);
8187 /* To do: set to next higher multiple of 8 */
8188 if (image->depth < 8)
8191 #if (MAGICKCORE_QUANTUM_DEPTH > 16)
8192 /* PNG does not handle depths greater than 16 so reduce it even
8195 if (image->depth > 8)
8199 #if (MAGICKCORE_QUANTUM_DEPTH > 8)
8200 if (image->depth > 8)
8202 /* To do: fill low byte properly */
8206 if (image->depth == 16 && mng_info->write_png_depth != 16)
8207 if (mng_info->write_png8 || LosslessReduceDepthOK(image,exception) != MagickFalse)
8211 if (image->storage_class != PseudoClass && mng_info->write_png_colortype &&
8212 (mng_info->write_png_colortype > 4 || (mng_info->write_png_depth >= 8 &&
8213 mng_info->write_png_colortype < 4 &&
8214 image->alpha_trait != BlendPixelTrait)))
8216 /* Avoid the expensive BUILD_PALETTE operation if we're sure that we
8217 * are not going to need the result.
8219 image_colors = (int) image->colors;
8220 number_opaque = (int) image->colors;
8221 if (mng_info->write_png_colortype == 1 ||
8222 mng_info->write_png_colortype == 5)
8223 ping_have_color=MagickFalse;
8225 ping_have_color=MagickTrue;
8226 ping_have_non_bw=MagickFalse;
8228 if (image->alpha_trait == BlendPixelTrait)
8230 number_transparent = 2;
8231 number_semitransparent = 1;
8236 number_transparent = 0;
8237 number_semitransparent = 0;
8245 * Normally we run this just once, but in the case of writing PNG8
8246 * we reduce the transparency to binary and run again, then if there
8247 * are still too many colors we reduce to a simple 4-4-4-1, then 3-3-3-1
8248 * RGBA palette and run again, and then to a simple 3-3-2-1 RGBA
8249 * palette. Then (To do) we take care of a final reduction that is only
8250 * needed if there are still 256 colors present and one of them has both
8251 * transparent and opaque instances.
8254 tried_332 = MagickFalse;
8255 tried_333 = MagickFalse;
8256 tried_444 = MagickFalse;
8261 * Sometimes we get DirectClass images that have 256 colors or fewer.
8262 * This code will build a colormap.
8264 * Also, sometimes we get PseudoClass images with an out-of-date
8265 * colormap. This code will replace the colormap with a new one.
8266 * Sometimes we get PseudoClass images that have more than 256 colors.
8267 * This code will delete the colormap and change the image to
8270 * If image->alpha_trait is MagickFalse, we ignore the alpha channel
8271 * even though it sometimes contains left-over non-opaque values.
8273 * Also we gather some information (number of opaque, transparent,
8274 * and semitransparent pixels, and whether the image has any non-gray
8275 * pixels or only black-and-white pixels) that we might need later.
8277 * Even if the user wants to force GrayAlpha or RGBA (colortype 4 or 6)
8278 * we need to check for bogus non-opaque values, at least.
8286 semitransparent[260],
8289 register const Quantum
8296 if (logging != MagickFalse)
8297 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8298 " Enter BUILD_PALETTE:");
8300 if (logging != MagickFalse)
8302 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8303 " image->columns=%.20g",(double) image->columns);
8304 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8305 " image->rows=%.20g",(double) image->rows);
8306 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8307 " image->alpha_trait=%.20g",(double) image->alpha_trait);
8308 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8309 " image->depth=%.20g",(double) image->depth);
8311 if (image->storage_class == PseudoClass && image->colormap != NULL)
8313 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8314 " Original colormap:");
8315 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8316 " i (red,green,blue,alpha)");
8318 for (i=0; i < 256; i++)
8320 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8321 " %d (%d,%d,%d,%d)",
8323 (int) image->colormap[i].red,
8324 (int) image->colormap[i].green,
8325 (int) image->colormap[i].blue,
8326 (int) image->colormap[i].alpha);
8329 for (i=image->colors - 10; i < (ssize_t) image->colors; i++)
8333 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8334 " %d (%d,%d,%d,%d)",
8336 (int) image->colormap[i].red,
8337 (int) image->colormap[i].green,
8338 (int) image->colormap[i].blue,
8339 (int) image->colormap[i].alpha);
8344 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8345 " image->colors=%d",(int) image->colors);
8347 if (image->colors == 0)
8348 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8349 " (zero means unknown)");
8351 if (ping_preserve_colormap == MagickFalse)
8352 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8353 " Regenerate the colormap");
8358 number_semitransparent = 0;
8359 number_transparent = 0;
8361 for (y=0; y < (ssize_t) image->rows; y++)
8363 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8365 if (q == (Quantum *) NULL)
8368 for (x=0; x < (ssize_t) image->columns; x++)
8370 if (image->alpha_trait != BlendPixelTrait ||
8371 GetPixelAlpha(image,q) == OpaqueAlpha)
8373 if (number_opaque < 259)
8375 if (number_opaque == 0)
8377 GetPixelInfoPixel(image, q, opaque);
8378 opaque[0].alpha=OpaqueAlpha;
8382 for (i=0; i< (ssize_t) number_opaque; i++)
8384 if (IsPixelEquivalent(image,q, opaque+i))
8388 if (i == (ssize_t) number_opaque && number_opaque < 259)
8391 GetPixelInfoPixel(image, q, opaque+i);
8392 opaque[i].alpha=OpaqueAlpha;
8396 else if (GetPixelAlpha(image,q) == TransparentAlpha)
8398 if (number_transparent < 259)
8400 if (number_transparent == 0)
8402 GetPixelInfoPixel(image, q, transparent);
8403 ping_trans_color.red=(unsigned short)
8404 GetPixelRed(image,q);
8405 ping_trans_color.green=(unsigned short)
8406 GetPixelGreen(image,q);
8407 ping_trans_color.blue=(unsigned short)
8408 GetPixelBlue(image,q);
8409 ping_trans_color.gray=(unsigned short)
8410 GetPixelGray(image,q);
8411 number_transparent = 1;
8414 for (i=0; i< (ssize_t) number_transparent; i++)
8416 if (IsPixelEquivalent(image,q, transparent+i))
8420 if (i == (ssize_t) number_transparent &&
8421 number_transparent < 259)
8423 number_transparent++;
8424 GetPixelInfoPixel(image,q,transparent+i);
8430 if (number_semitransparent < 259)
8432 if (number_semitransparent == 0)
8434 GetPixelInfoPixel(image,q,semitransparent);
8435 number_semitransparent = 1;
8438 for (i=0; i< (ssize_t) number_semitransparent; i++)
8440 if (IsPixelEquivalent(image,q, semitransparent+i)
8441 && GetPixelAlpha(image,q) ==
8442 semitransparent[i].alpha)
8446 if (i == (ssize_t) number_semitransparent &&
8447 number_semitransparent < 259)
8449 number_semitransparent++;
8450 GetPixelInfoPixel(image, q, semitransparent+i);
8454 q+=GetPixelChannels(image);
8458 if (mng_info->write_png8 == MagickFalse &&
8459 ping_exclude_bKGD == MagickFalse)
8461 /* Add the background color to the palette, if it
8462 * isn't already there.
8464 if (logging != MagickFalse)
8466 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8467 " Check colormap for background (%d,%d,%d)",
8468 (int) image->background_color.red,
8469 (int) image->background_color.green,
8470 (int) image->background_color.blue);
8472 for (i=0; i<number_opaque; i++)
8474 if (opaque[i].red == image->background_color.red &&
8475 opaque[i].green == image->background_color.green &&
8476 opaque[i].blue == image->background_color.blue)
8479 if (number_opaque < 259 && i == number_opaque)
8481 opaque[i] = image->background_color;
8482 ping_background.index = i;
8484 if (logging != MagickFalse)
8486 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8487 " background_color index is %d",(int) i);
8491 else if (logging != MagickFalse)
8492 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8493 " No room in the colormap to add background color");
8496 image_colors=number_opaque+number_transparent+number_semitransparent;
8498 if (mng_info->write_png8 != MagickFalse && image_colors > 256)
8500 /* No room for the background color; remove it. */
8505 if (logging != MagickFalse)
8507 if (image_colors > 256)
8508 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8509 " image has more than 256 colors");
8512 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8513 " image has %d colors",image_colors);
8516 if (ping_preserve_colormap != MagickFalse)
8519 if (mng_info->write_png_colortype != 7) /* We won't need this info */
8521 ping_have_color=MagickFalse;
8522 ping_have_non_bw=MagickFalse;
8524 if ((IssRGBCompatibleColorspace(image->colorspace) == MagickFalse) ||
8525 (IssRGBColorspace(image->colorspace) != MagickFalse))
8527 ping_have_color=MagickTrue;
8528 ping_have_non_bw=MagickTrue;
8531 if(image_colors > 256)
8533 for (y=0; y < (ssize_t) image->rows; y++)
8535 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8537 if (q == (Quantum *) NULL)
8541 for (x=0; x < (ssize_t) image->columns; x++)
8543 if (GetPixelRed(image,s) != GetPixelGreen(image,s) ||
8544 GetPixelRed(image,s) != GetPixelBlue(image,s))
8546 ping_have_color=MagickTrue;
8547 ping_have_non_bw=MagickTrue;
8550 s+=GetPixelChannels(image);
8553 if (ping_have_color != MagickFalse)
8556 /* Worst case is black-and-white; we are looking at every
8560 if (ping_have_non_bw == MagickFalse)
8563 for (x=0; x < (ssize_t) image->columns; x++)
8565 if (GetPixelRed(image,s) != 0 &&
8566 GetPixelRed(image,s) != QuantumRange)
8568 ping_have_non_bw=MagickTrue;
8571 s+=GetPixelChannels(image);
8578 if (image_colors < 257)
8584 * Initialize image colormap.
8587 if (logging != MagickFalse)
8588 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8589 " Sort the new colormap");
8591 /* Sort palette, transparent first */;
8595 for (i=0; i<number_transparent; i++)
8596 colormap[n++] = transparent[i];
8598 for (i=0; i<number_semitransparent; i++)
8599 colormap[n++] = semitransparent[i];
8601 for (i=0; i<number_opaque; i++)
8602 colormap[n++] = opaque[i];
8604 ping_background.index +=
8605 (number_transparent + number_semitransparent);
8607 /* image_colors < 257; search the colormap instead of the pixels
8608 * to get ping_have_color and ping_have_non_bw
8612 if (ping_have_color == MagickFalse)
8614 if (colormap[i].red != colormap[i].green ||
8615 colormap[i].red != colormap[i].blue)
8617 ping_have_color=MagickTrue;
8618 ping_have_non_bw=MagickTrue;
8623 if (ping_have_non_bw == MagickFalse)
8625 if (colormap[i].red != 0 && colormap[i].red != QuantumRange)
8626 ping_have_non_bw=MagickTrue;
8630 if ((mng_info->ping_exclude_tRNS == MagickFalse ||
8631 (number_transparent == 0 && number_semitransparent == 0)) &&
8632 (((mng_info->write_png_colortype-1) ==
8633 PNG_COLOR_TYPE_PALETTE) ||
8634 (mng_info->write_png_colortype == 0)))
8636 if (logging != MagickFalse)
8638 if (n != (ssize_t) image_colors)
8639 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8640 " image_colors (%d) and n (%d) don't match",
8643 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8644 " AcquireImageColormap");
8647 image->colors = image_colors;
8649 if (AcquireImageColormap(image,image_colors,exception) ==
8651 ThrowWriterException(ResourceLimitError,
8652 "MemoryAllocationFailed");
8654 for (i=0; i< (ssize_t) image_colors; i++)
8655 image->colormap[i] = colormap[i];
8657 if (logging != MagickFalse)
8659 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8660 " image->colors=%d (%d)",
8661 (int) image->colors, image_colors);
8663 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8664 " Update the pixel indexes");
8667 /* Sync the pixel indices with the new colormap */
8669 for (y=0; y < (ssize_t) image->rows; y++)
8671 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8673 if (q == (Quantum *) NULL)
8676 for (x=0; x < (ssize_t) image->columns; x++)
8678 for (i=0; i< (ssize_t) image_colors; i++)
8680 if ((image->alpha_trait != BlendPixelTrait ||
8681 image->colormap[i].alpha == GetPixelAlpha(image,q)) &&
8682 image->colormap[i].red == GetPixelRed(image,q) &&
8683 image->colormap[i].green == GetPixelGreen(image,q) &&
8684 image->colormap[i].blue == GetPixelBlue(image,q))
8686 SetPixelIndex(image,i,q);
8690 q+=GetPixelChannels(image);
8693 if (SyncAuthenticPixels(image,exception) == MagickFalse)
8699 if (logging != MagickFalse)
8701 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8702 " image->colors=%d", (int) image->colors);
8704 if (image->colormap != NULL)
8706 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8707 " i (red,green,blue,alpha)");
8709 for (i=0; i < (ssize_t) image->colors; i++)
8711 if (i < 300 || i >= (ssize_t) image->colors - 10)
8713 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8714 " %d (%d,%d,%d,%d)",
8716 (int) image->colormap[i].red,
8717 (int) image->colormap[i].green,
8718 (int) image->colormap[i].blue,
8719 (int) image->colormap[i].alpha);
8724 if (number_transparent < 257)
8725 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8726 " number_transparent = %d",
8727 number_transparent);
8730 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8731 " number_transparent > 256");
8733 if (number_opaque < 257)
8734 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8735 " number_opaque = %d",
8739 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8740 " number_opaque > 256");
8742 if (number_semitransparent < 257)
8743 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8744 " number_semitransparent = %d",
8745 number_semitransparent);
8748 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8749 " number_semitransparent > 256");
8751 if (ping_have_non_bw == MagickFalse)
8752 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8753 " All pixels and the background are black or white");
8755 else if (ping_have_color == MagickFalse)
8756 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8757 " All pixels and the background are gray");
8760 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8761 " At least one pixel or the background is non-gray");
8763 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8764 " Exit BUILD_PALETTE:");
8767 if (mng_info->write_png8 == MagickFalse)
8770 /* Make any reductions necessary for the PNG8 format */
8771 if (image_colors <= 256 &&
8772 image_colors != 0 && image->colormap != NULL &&
8773 number_semitransparent == 0 &&
8774 number_transparent <= 1)
8777 /* PNG8 can't have semitransparent colors so we threshold the
8778 * opacity to 0 or OpaqueOpacity, and PNG8 can only have one
8779 * transparent color so if more than one is transparent we merge
8780 * them into image->background_color.
8782 if (number_semitransparent != 0 || number_transparent > 1)
8784 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8785 " Thresholding the alpha channel to binary");
8787 for (y=0; y < (ssize_t) image->rows; y++)
8789 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8791 if (r == (Quantum *) NULL)
8794 for (x=0; x < (ssize_t) image->columns; x++)
8796 if (GetPixelAlpha(image,r) < OpaqueAlpha/2)
8798 SetPixelInfoPixel(image,&image->background_color,r);
8799 SetPixelAlpha(image,TransparentAlpha,r);
8802 SetPixelAlpha(image,OpaqueAlpha,r);
8803 r+=GetPixelChannels(image);
8806 if (SyncAuthenticPixels(image,exception) == MagickFalse)
8809 if (image_colors != 0 && image_colors <= 256 &&
8810 image->colormap != NULL)
8811 for (i=0; i<image_colors; i++)
8812 image->colormap[i].alpha =
8813 (image->colormap[i].alpha > TransparentAlpha/2 ?
8814 TransparentAlpha : OpaqueAlpha);
8819 /* PNG8 can't have more than 256 colors so we quantize the pixels and
8820 * background color to the 4-4-4-1, 3-3-3-1 or 3-3-2-1 palette. If the
8821 * image is mostly gray, the 4-4-4-1 palette is likely to end up with 256
8824 if (tried_444 == MagickFalse && (image_colors == 0 || image_colors > 256))
8826 if (logging != MagickFalse)
8827 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8828 " Quantizing the background color to 4-4-4");
8830 tried_444 = MagickTrue;
8832 LBR04PacketRGB(image->background_color);
8834 if (logging != MagickFalse)
8835 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8836 " Quantizing the pixel colors to 4-4-4");
8838 if (image->colormap == NULL)
8840 for (y=0; y < (ssize_t) image->rows; y++)
8842 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8844 if (r == (Quantum *) NULL)
8847 for (x=0; x < (ssize_t) image->columns; x++)
8849 if (GetPixelAlpha(image,r) == OpaqueAlpha)
8851 r+=GetPixelChannels(image);
8854 if (SyncAuthenticPixels(image,exception) == MagickFalse)
8859 else /* Should not reach this; colormap already exists and
8862 if (logging != MagickFalse)
8863 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8864 " Quantizing the colormap to 4-4-4");
8866 for (i=0; i<image_colors; i++)
8868 LBR04PacketRGB(image->colormap[i]);
8874 if (tried_333 == MagickFalse && (image_colors == 0 || image_colors > 256))
8876 if (logging != MagickFalse)
8877 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8878 " Quantizing the background color to 3-3-3");
8880 tried_333 = MagickTrue;
8882 LBR03PacketRGB(image->background_color);
8884 if (logging != MagickFalse)
8885 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8886 " Quantizing the pixel colors to 3-3-3-1");
8888 if (image->colormap == NULL)
8890 for (y=0; y < (ssize_t) image->rows; y++)
8892 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8894 if (r == (Quantum *) NULL)
8897 for (x=0; x < (ssize_t) image->columns; x++)
8899 if (GetPixelAlpha(image,r) == OpaqueAlpha)
8901 r+=GetPixelChannels(image);
8904 if (SyncAuthenticPixels(image,exception) == MagickFalse)
8909 else /* Should not reach this; colormap already exists and
8912 if (logging != MagickFalse)
8913 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8914 " Quantizing the colormap to 3-3-3-1");
8915 for (i=0; i<image_colors; i++)
8917 LBR03PacketRGB(image->colormap[i]);
8923 if (tried_332 == MagickFalse && (image_colors == 0 || image_colors > 256))
8925 if (logging != MagickFalse)
8926 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8927 " Quantizing the background color to 3-3-2");
8929 tried_332 = MagickTrue;
8931 /* Red and green were already done so we only quantize the blue
8935 LBR02PacketBlue(image->background_color);
8937 if (logging != MagickFalse)
8938 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8939 " Quantizing the pixel colors to 3-3-2-1");
8941 if (image->colormap == NULL)
8943 for (y=0; y < (ssize_t) image->rows; y++)
8945 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8947 if (r == (Quantum *) NULL)
8950 for (x=0; x < (ssize_t) image->columns; x++)
8952 if (GetPixelAlpha(image,r) == OpaqueAlpha)
8954 r+=GetPixelChannels(image);
8957 if (SyncAuthenticPixels(image,exception) == MagickFalse)
8962 else /* Should not reach this; colormap already exists and
8965 if (logging != MagickFalse)
8966 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8967 " Quantizing the colormap to 3-3-2-1");
8968 for (i=0; i<image_colors; i++)
8970 LBR02PacketBlue(image->colormap[i]);
8977 if (image_colors == 0 || image_colors > 256)
8979 /* Take care of special case with 256 colors + 1 transparent
8980 * color. We don't need to quantize to 2-3-2-1; we only need to
8981 * eliminate one color, so we'll merge the two darkest red
8982 * colors (0x49, 0, 0) -> (0x24, 0, 0).
8984 if (ScaleQuantumToChar(image->background_color.red) == 0x49 &&
8985 ScaleQuantumToChar(image->background_color.green) == 0x00 &&
8986 ScaleQuantumToChar(image->background_color.blue) == 0x00)
8988 image->background_color.red=ScaleCharToQuantum(0x24);
8991 if (image->colormap == NULL)
8993 for (y=0; y < (ssize_t) image->rows; y++)
8995 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8997 if (r == (Quantum *) NULL)
9000 for (x=0; x < (ssize_t) image->columns; x++)
9002 if (ScaleQuantumToChar(GetPixelRed(image,r)) == 0x49 &&
9003 ScaleQuantumToChar(GetPixelGreen(image,r)) == 0x00 &&
9004 ScaleQuantumToChar(GetPixelBlue(image,r)) == 0x00 &&
9005 GetPixelAlpha(image,r) == OpaqueAlpha)
9007 SetPixelRed(image,ScaleCharToQuantum(0x24),r);
9009 r+=GetPixelChannels(image);
9012 if (SyncAuthenticPixels(image,exception) == MagickFalse)
9020 for (i=0; i<image_colors; i++)
9022 if (ScaleQuantumToChar(image->colormap[i].red) == 0x49 &&
9023 ScaleQuantumToChar(image->colormap[i].green) == 0x00 &&
9024 ScaleQuantumToChar(image->colormap[i].blue) == 0x00)
9026 image->colormap[i].red=ScaleCharToQuantum(0x24);
9033 /* END OF BUILD_PALETTE */
9035 /* If we are excluding the tRNS chunk and there is transparency,
9036 * then we must write a Gray-Alpha (color-type 4) or RGBA (color-type 6)
9039 if (mng_info->ping_exclude_tRNS != MagickFalse &&
9040 (number_transparent != 0 || number_semitransparent != 0))
9042 unsigned int colortype=mng_info->write_png_colortype;
9044 if (ping_have_color == MagickFalse)
9045 mng_info->write_png_colortype = 5;
9048 mng_info->write_png_colortype = 7;
9050 if (colortype != 0 &&
9051 mng_info->write_png_colortype != colortype)
9052 ping_need_colortype_warning=MagickTrue;
9056 /* See if cheap transparency is possible. It is only possible
9057 * when there is a single transparent color, no semitransparent
9058 * color, and no opaque color that has the same RGB components
9059 * as the transparent color. We only need this information if
9060 * we are writing a PNG with colortype 0 or 2, and we have not
9061 * excluded the tRNS chunk.
9063 if (number_transparent == 1 &&
9064 mng_info->write_png_colortype < 4)
9066 ping_have_cheap_transparency = MagickTrue;
9068 if (number_semitransparent != 0)
9069 ping_have_cheap_transparency = MagickFalse;
9071 else if (image_colors == 0 || image_colors > 256 ||
9072 image->colormap == NULL)
9074 register const Quantum
9077 for (y=0; y < (ssize_t) image->rows; y++)
9079 q=GetVirtualPixels(image,0,y,image->columns,1, exception);
9081 if (q == (Quantum *) NULL)
9084 for (x=0; x < (ssize_t) image->columns; x++)
9086 if (GetPixelAlpha(image,q) != TransparentAlpha &&
9087 (unsigned short) GetPixelRed(image,q) ==
9088 ping_trans_color.red &&
9089 (unsigned short) GetPixelGreen(image,q) ==
9090 ping_trans_color.green &&
9091 (unsigned short) GetPixelBlue(image,q) ==
9092 ping_trans_color.blue)
9094 ping_have_cheap_transparency = MagickFalse;
9098 q+=GetPixelChannels(image);
9101 if (ping_have_cheap_transparency == MagickFalse)
9107 /* Assuming that image->colormap[0] is the one transparent color
9108 * and that all others are opaque.
9110 if (image_colors > 1)
9111 for (i=1; i<image_colors; i++)
9112 if (image->colormap[i].red == image->colormap[0].red &&
9113 image->colormap[i].green == image->colormap[0].green &&
9114 image->colormap[i].blue == image->colormap[0].blue)
9116 ping_have_cheap_transparency = MagickFalse;
9121 if (logging != MagickFalse)
9123 if (ping_have_cheap_transparency == MagickFalse)
9124 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9125 " Cheap transparency is not possible.");
9128 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9129 " Cheap transparency is possible.");
9133 ping_have_cheap_transparency = MagickFalse;
9135 image_depth=image->depth;
9137 quantum_info = (QuantumInfo *) NULL;
9139 image_colors=(int) image->colors;
9140 image_matte=image->alpha_trait == BlendPixelTrait ? MagickTrue : MagickFalse;
9142 mng_info->IsPalette=image->storage_class == PseudoClass &&
9143 image_colors <= 256 && image->colormap != NULL;
9145 if ((mng_info->write_png_colortype == 4 || mng_info->write_png8) &&
9146 (image->colors == 0 || image->colormap == NULL))
9148 image_info=DestroyImageInfo(image_info);
9149 image=DestroyImage(image);
9150 (void) ThrowMagickException(exception,GetMagickModule(),CoderError,
9151 "Cannot write PNG8 or color-type 3; colormap is NULL",
9152 "`%s'",IMimage->filename);
9153 return(MagickFalse);
9157 Allocate the PNG structures
9159 #ifdef PNG_USER_MEM_SUPPORTED
9160 error_info.image=image;
9161 error_info.exception=exception;
9162 ping=png_create_write_struct_2(PNG_LIBPNG_VER_STRING,&error_info,
9163 MagickPNGErrorHandler,MagickPNGWarningHandler,(void *) NULL,
9164 (png_malloc_ptr) Magick_png_malloc,(png_free_ptr) Magick_png_free);
9167 ping=png_create_write_struct(PNG_LIBPNG_VER_STRING,&error_info,
9168 MagickPNGErrorHandler,MagickPNGWarningHandler);
9171 if (ping == (png_struct *) NULL)
9172 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
9174 ping_info=png_create_info_struct(ping);
9176 if (ping_info == (png_info *) NULL)
9178 png_destroy_write_struct(&ping,(png_info **) NULL);
9179 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
9182 png_set_write_fn(ping,image,png_put_data,png_flush_data);
9183 ping_pixels=(unsigned char *) NULL;
9185 if (setjmp(png_jmpbuf(ping)))
9191 if (image_info->verbose)
9192 (void) printf("PNG write has failed.\n");
9194 png_destroy_write_struct(&ping,&ping_info);
9195 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
9196 UnlockSemaphoreInfo(ping_semaphore);
9199 if (ping_pixels != (unsigned char *) NULL)
9200 ping_pixels=(unsigned char *) RelinquishMagickMemory(ping_pixels);
9202 if (quantum_info != (QuantumInfo *) NULL)
9203 quantum_info=DestroyQuantumInfo(quantum_info);
9205 if (ping_have_blob != MagickFalse)
9206 (void) CloseBlob(image);
9207 image_info=DestroyImageInfo(image_info);
9208 image=DestroyImage(image);
9209 return(MagickFalse);
9212 /* { For navigation to end of SETJMP-protected block. Within this
9213 * block, use png_error() instead of Throwing an Exception, to ensure
9214 * that libpng is able to clean up, and that the semaphore is unlocked.
9217 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
9218 LockSemaphoreInfo(ping_semaphore);
9222 Prepare PNG for writing.
9225 #if defined(PNG_MNG_FEATURES_SUPPORTED)
9226 if (mng_info->write_mng)
9228 (void) png_permit_mng_features(ping,PNG_ALL_MNG_FEATURES);
9229 # ifdef PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED
9230 /* Disable new libpng-1.5.10 feature when writing a MNG because
9231 * zero-length PLTE is OK
9233 png_set_check_for_invalid_index (ping, 0);
9238 # ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
9239 if (mng_info->write_mng)
9240 png_permit_empty_plte(ping,MagickTrue);
9247 ping_width=(png_uint_32) image->columns;
9248 ping_height=(png_uint_32) image->rows;
9250 if (mng_info->write_png8 || mng_info->write_png24 || mng_info->write_png32)
9253 if (mng_info->write_png48 || mng_info->write_png64)
9256 if (mng_info->write_png_depth != 0)
9257 image_depth=mng_info->write_png_depth;
9259 /* Adjust requested depth to next higher valid depth if necessary */
9260 if (image_depth > 8)
9263 if ((image_depth > 4) && (image_depth < 8))
9266 if (image_depth == 3)
9269 if (logging != MagickFalse)
9271 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9272 " width=%.20g",(double) ping_width);
9273 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9274 " height=%.20g",(double) ping_height);
9275 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9276 " image_matte=%.20g",(double) image->alpha_trait);
9277 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9278 " image->depth=%.20g",(double) image->depth);
9279 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9280 " Tentative ping_bit_depth=%.20g",(double) image_depth);
9283 save_image_depth=image_depth;
9284 ping_bit_depth=(png_byte) save_image_depth;
9287 #if defined(PNG_pHYs_SUPPORTED)
9288 if (ping_exclude_pHYs == MagickFalse)
9290 if ((image->resolution.x != 0) && (image->resolution.y != 0) &&
9291 (!mng_info->write_mng || !mng_info->equal_physs))
9293 if (logging != MagickFalse)
9294 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9295 " Setting up pHYs chunk");
9297 if (image->units == PixelsPerInchResolution)
9299 ping_pHYs_unit_type=PNG_RESOLUTION_METER;
9300 ping_pHYs_x_resolution=
9301 (png_uint_32) ((100.0*image->resolution.x+0.5)/2.54);
9302 ping_pHYs_y_resolution=
9303 (png_uint_32) ((100.0*image->resolution.y+0.5)/2.54);
9306 else if (image->units == PixelsPerCentimeterResolution)
9308 ping_pHYs_unit_type=PNG_RESOLUTION_METER;
9309 ping_pHYs_x_resolution=(png_uint_32) (100.0*image->resolution.x+0.5);
9310 ping_pHYs_y_resolution=(png_uint_32) (100.0*image->resolution.y+0.5);
9315 ping_pHYs_unit_type=PNG_RESOLUTION_UNKNOWN;
9316 ping_pHYs_x_resolution=(png_uint_32) image->resolution.x;
9317 ping_pHYs_y_resolution=(png_uint_32) image->resolution.y;
9320 if (logging != MagickFalse)
9321 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9322 " Set up PNG pHYs chunk: xres: %.20g, yres: %.20g, units: %d.",
9323 (double) ping_pHYs_x_resolution,(double) ping_pHYs_y_resolution,
9324 (int) ping_pHYs_unit_type);
9325 ping_have_pHYs = MagickTrue;
9330 if (ping_exclude_bKGD == MagickFalse)
9332 if ((!mng_info->adjoin || !mng_info->equal_backgrounds))
9338 if (ping_bit_depth == 8)
9341 if (ping_bit_depth == 4)
9344 if (ping_bit_depth == 2)
9347 if (ping_bit_depth == 1)
9350 ping_background.red=(png_uint_16)
9351 (ScaleQuantumToShort(image->background_color.red) & mask);
9353 ping_background.green=(png_uint_16)
9354 (ScaleQuantumToShort(image->background_color.green) & mask);
9356 ping_background.blue=(png_uint_16)
9357 (ScaleQuantumToShort(image->background_color.blue) & mask);
9359 ping_background.gray=(png_uint_16) ping_background.green;
9362 if (logging != MagickFalse)
9364 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9365 " Setting up bKGD chunk (1)");
9366 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9367 " background_color index is %d",
9368 (int) ping_background.index);
9370 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9371 " ping_bit_depth=%d",ping_bit_depth);
9374 ping_have_bKGD = MagickTrue;
9378 Select the color type.
9383 if (mng_info->IsPalette && mng_info->write_png8)
9386 /* To do: make this a function cause it's used twice, except
9387 for reducing the sample depth from 8. */
9389 number_colors=image_colors;
9391 ping_have_tRNS=MagickFalse;
9396 ping_color_type=(png_byte) PNG_COLOR_TYPE_PALETTE;
9398 if (logging != MagickFalse)
9399 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9400 " Setting up PLTE chunk with %d colors (%d)",
9401 number_colors, image_colors);
9403 for (i=0; i < (ssize_t) number_colors; i++)
9405 palette[i].red=ScaleQuantumToChar(image->colormap[i].red);
9406 palette[i].green=ScaleQuantumToChar(image->colormap[i].green);
9407 palette[i].blue=ScaleQuantumToChar(image->colormap[i].blue);
9408 if (logging != MagickFalse)
9409 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9410 #if MAGICKCORE_QUANTUM_DEPTH == 8
9411 " %3ld (%3d,%3d,%3d)",
9413 " %5ld (%5d,%5d,%5d)",
9415 (long) i,palette[i].red,palette[i].green,palette[i].blue);
9419 ping_have_PLTE=MagickTrue;
9420 image_depth=ping_bit_depth;
9423 if (matte != MagickFalse)
9426 Identify which colormap entry is transparent.
9428 assert(number_colors <= 256);
9429 assert(image->colormap != NULL);
9431 for (i=0; i < (ssize_t) number_transparent; i++)
9432 ping_trans_alpha[i]=0;
9435 ping_num_trans=(unsigned short) (number_transparent +
9436 number_semitransparent);
9438 if (ping_num_trans == 0)
9439 ping_have_tRNS=MagickFalse;
9442 ping_have_tRNS=MagickTrue;
9445 if (ping_exclude_bKGD == MagickFalse)
9448 * Identify which colormap entry is the background color.
9451 for (i=0; i < (ssize_t) MagickMax(1L*number_colors-1L,1L); i++)
9452 if (IsPNGColorEqual(ping_background,image->colormap[i]))
9455 ping_background.index=(png_byte) i;
9457 if (logging != MagickFalse)
9459 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9460 " background_color index is %d",
9461 (int) ping_background.index);
9464 } /* end of write_png8 */
9466 else if (mng_info->write_png_colortype == 1)
9468 image_matte=MagickFalse;
9469 ping_color_type=(png_byte) PNG_COLOR_TYPE_GRAY;
9472 else if (mng_info->write_png24 || mng_info->write_png48 ||
9473 mng_info->write_png_colortype == 3)
9475 image_matte=MagickFalse;
9476 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB;
9479 else if (mng_info->write_png32 || mng_info->write_png64 ||
9480 mng_info->write_png_colortype == 7)
9482 image_matte=MagickTrue;
9483 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB_ALPHA;
9486 else /* mng_info->write_pngNN not specified */
9488 image_depth=ping_bit_depth;
9490 if (mng_info->write_png_colortype != 0)
9492 ping_color_type=(png_byte) mng_info->write_png_colortype-1;
9494 if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA ||
9495 ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA)
9496 image_matte=MagickTrue;
9499 image_matte=MagickFalse;
9501 if (logging != MagickFalse)
9502 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9503 " PNG colortype %d was specified:",(int) ping_color_type);
9506 else /* write_png_colortype not specified */
9508 if (logging != MagickFalse)
9509 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9510 " Selecting PNG colortype:");
9512 ping_color_type=(png_byte) ((matte != MagickFalse)?
9513 PNG_COLOR_TYPE_RGB_ALPHA:PNG_COLOR_TYPE_RGB);
9515 if (image_info->type == TrueColorType)
9517 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB;
9518 image_matte=MagickFalse;
9521 if (image_info->type == TrueColorMatteType)
9523 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB_ALPHA;
9524 image_matte=MagickTrue;
9527 if (image_info->type == PaletteType ||
9528 image_info->type == PaletteMatteType)
9529 ping_color_type=(png_byte) PNG_COLOR_TYPE_PALETTE;
9531 if (mng_info->write_png_colortype == 0 &&
9532 (image_info->type == UndefinedType ||
9533 image_info->type == OptimizeType))
9535 if (ping_have_color == MagickFalse)
9537 if (image_matte == MagickFalse)
9539 ping_color_type=(png_byte) PNG_COLOR_TYPE_GRAY;
9540 image_matte=MagickFalse;
9545 ping_color_type=(png_byte) PNG_COLOR_TYPE_GRAY_ALPHA;
9546 image_matte=MagickTrue;
9551 if (image_matte == MagickFalse)
9553 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB;
9554 image_matte=MagickFalse;
9559 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGBA;
9560 image_matte=MagickTrue;
9567 if (logging != MagickFalse)
9568 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9569 " Selected PNG colortype=%d",ping_color_type);
9571 if (ping_bit_depth < 8)
9573 if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA ||
9574 ping_color_type == PNG_COLOR_TYPE_RGB ||
9575 ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA)
9579 old_bit_depth=ping_bit_depth;
9581 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
9583 if (image->alpha_trait != BlendPixelTrait && ping_have_non_bw == MagickFalse)
9587 if (ping_color_type == PNG_COLOR_TYPE_PALETTE)
9592 if (image->colors == 0)
9595 png_error(ping,"image has 0 colors");
9598 while ((int) (one << ping_bit_depth) < (ssize_t) image_colors)
9599 ping_bit_depth <<= 1;
9602 if (logging != MagickFalse)
9604 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9605 " Number of colors: %.20g",(double) image_colors);
9607 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9608 " Tentative PNG bit depth: %d",ping_bit_depth);
9611 if (ping_bit_depth < (int) mng_info->write_png_depth)
9612 ping_bit_depth = mng_info->write_png_depth;
9615 image_depth=ping_bit_depth;
9617 if (logging != MagickFalse)
9619 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9620 " Tentative PNG color type: %s (%.20g)",
9621 PngColorTypeToString(ping_color_type),
9622 (double) ping_color_type);
9624 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9625 " image_info->type: %.20g",(double) image_info->type);
9627 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9628 " image_depth: %.20g",(double) image_depth);
9630 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9632 " image->depth: %.20g",(double) image->depth);
9634 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9635 " ping_bit_depth: %.20g",(double) ping_bit_depth);
9638 if (matte != MagickFalse)
9640 if (mng_info->IsPalette)
9642 if (mng_info->write_png_colortype == 0)
9644 ping_color_type=PNG_COLOR_TYPE_GRAY_ALPHA;
9646 if (ping_have_color != MagickFalse)
9647 ping_color_type=PNG_COLOR_TYPE_RGBA;
9651 * Determine if there is any transparent color.
9653 if (number_transparent + number_semitransparent == 0)
9656 No transparent pixels are present. Change 4 or 6 to 0 or 2.
9659 image_matte=MagickFalse;
9661 if (mng_info->write_png_colortype == 0)
9662 ping_color_type&=0x03;
9672 if (ping_bit_depth == 8)
9675 if (ping_bit_depth == 4)
9678 if (ping_bit_depth == 2)
9681 if (ping_bit_depth == 1)
9684 ping_trans_color.red=(png_uint_16)
9685 (ScaleQuantumToShort(image->colormap[0].red) & mask);
9687 ping_trans_color.green=(png_uint_16)
9688 (ScaleQuantumToShort(image->colormap[0].green) & mask);
9690 ping_trans_color.blue=(png_uint_16)
9691 (ScaleQuantumToShort(image->colormap[0].blue) & mask);
9693 ping_trans_color.gray=(png_uint_16)
9694 (ScaleQuantumToShort(GetPixelInfoIntensity(
9695 image->colormap)) & mask);
9697 ping_trans_color.index=(png_byte) 0;
9699 ping_have_tRNS=MagickTrue;
9702 if (ping_have_tRNS != MagickFalse)
9705 * Determine if there is one and only one transparent color
9706 * and if so if it is fully transparent.
9708 if (ping_have_cheap_transparency == MagickFalse)
9709 ping_have_tRNS=MagickFalse;
9712 if (ping_have_tRNS != MagickFalse)
9714 if (mng_info->write_png_colortype == 0)
9715 ping_color_type &= 0x03; /* changes 4 or 6 to 0 or 2 */
9717 if (image_depth == 8)
9719 ping_trans_color.red&=0xff;
9720 ping_trans_color.green&=0xff;
9721 ping_trans_color.blue&=0xff;
9722 ping_trans_color.gray&=0xff;
9728 if (image_depth == 8)
9730 ping_trans_color.red&=0xff;
9731 ping_trans_color.green&=0xff;
9732 ping_trans_color.blue&=0xff;
9733 ping_trans_color.gray&=0xff;
9740 if (ping_have_tRNS != MagickFalse)
9741 image_matte=MagickFalse;
9743 if ((mng_info->IsPalette) &&
9744 mng_info->write_png_colortype-1 != PNG_COLOR_TYPE_PALETTE &&
9745 ping_have_color == MagickFalse &&
9746 (image_matte == MagickFalse || image_depth >= 8))
9750 if (image_matte != MagickFalse)
9751 ping_color_type=PNG_COLOR_TYPE_GRAY_ALPHA;
9753 else if (mng_info->write_png_colortype-1 != PNG_COLOR_TYPE_GRAY_ALPHA)
9755 ping_color_type=PNG_COLOR_TYPE_GRAY;
9757 if (save_image_depth == 16 && image_depth == 8)
9759 if (logging != MagickFalse)
9761 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9762 " Scaling ping_trans_color (0)");
9764 ping_trans_color.gray*=0x0101;
9768 if (image_depth > MAGICKCORE_QUANTUM_DEPTH)
9769 image_depth=MAGICKCORE_QUANTUM_DEPTH;
9771 if ((image_colors == 0) ||
9772 ((ssize_t) (image_colors-1) > (ssize_t) MaxColormapSize))
9773 image_colors=(int) (one << image_depth);
9775 if (image_depth > 8)
9781 if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
9783 if(!mng_info->write_png_depth)
9787 while ((int) (one << ping_bit_depth)
9788 < (ssize_t) image_colors)
9789 ping_bit_depth <<= 1;
9793 else if (ping_color_type ==
9794 PNG_COLOR_TYPE_GRAY && image_colors < 17 &&
9795 mng_info->IsPalette)
9797 /* Check if grayscale is reducible */
9800 depth_4_ok=MagickTrue,
9801 depth_2_ok=MagickTrue,
9802 depth_1_ok=MagickTrue;
9804 for (i=0; i < (ssize_t) image_colors; i++)
9809 intensity=ScaleQuantumToChar(image->colormap[i].red);
9811 if ((intensity & 0x0f) != ((intensity & 0xf0) >> 4))
9812 depth_4_ok=depth_2_ok=depth_1_ok=MagickFalse;
9813 else if ((intensity & 0x03) != ((intensity & 0x0c) >> 2))
9814 depth_2_ok=depth_1_ok=MagickFalse;
9815 else if ((intensity & 0x01) != ((intensity & 0x02) >> 1))
9816 depth_1_ok=MagickFalse;
9819 if (depth_1_ok && mng_info->write_png_depth <= 1)
9822 else if (depth_2_ok && mng_info->write_png_depth <= 2)
9825 else if (depth_4_ok && mng_info->write_png_depth <= 4)
9830 image_depth=ping_bit_depth;
9835 if (mng_info->IsPalette)
9837 number_colors=image_colors;
9839 if (image_depth <= 8)
9844 ping_color_type=(png_byte) PNG_COLOR_TYPE_PALETTE;
9846 if (!(mng_info->have_write_global_plte && matte == MagickFalse))
9848 for (i=0; i < (ssize_t) number_colors; i++)
9850 palette[i].red=ScaleQuantumToChar(image->colormap[i].red);
9851 palette[i].green=ScaleQuantumToChar(image->colormap[i].green);
9852 palette[i].blue=ScaleQuantumToChar(image->colormap[i].blue);
9855 if (logging != MagickFalse)
9856 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9857 " Setting up PLTE chunk with %d colors",
9860 ping_have_PLTE=MagickTrue;
9863 /* color_type is PNG_COLOR_TYPE_PALETTE */
9864 if (mng_info->write_png_depth == 0)
9872 while ((one << ping_bit_depth) < (size_t) number_colors)
9873 ping_bit_depth <<= 1;
9878 if (matte != MagickFalse)
9881 * Set up trans_colors array.
9883 assert(number_colors <= 256);
9885 ping_num_trans=(unsigned short) (number_transparent +
9886 number_semitransparent);
9888 if (ping_num_trans == 0)
9889 ping_have_tRNS=MagickFalse;
9893 if (logging != MagickFalse)
9895 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9896 " Scaling ping_trans_color (1)");
9898 ping_have_tRNS=MagickTrue;
9900 for (i=0; i < ping_num_trans; i++)
9902 ping_trans_alpha[i]= (png_byte)
9903 ScaleQuantumToChar(image->colormap[i].alpha);
9913 if (image_depth < 8)
9916 if ((save_image_depth == 16) && (image_depth == 8))
9918 if (logging != MagickFalse)
9920 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9921 " Scaling ping_trans_color from (%d,%d,%d)",
9922 (int) ping_trans_color.red,
9923 (int) ping_trans_color.green,
9924 (int) ping_trans_color.blue);
9927 ping_trans_color.red*=0x0101;
9928 ping_trans_color.green*=0x0101;
9929 ping_trans_color.blue*=0x0101;
9930 ping_trans_color.gray*=0x0101;
9932 if (logging != MagickFalse)
9934 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9936 (int) ping_trans_color.red,
9937 (int) ping_trans_color.green,
9938 (int) ping_trans_color.blue);
9943 if (ping_bit_depth < (ssize_t) mng_info->write_png_depth)
9944 ping_bit_depth = (ssize_t) mng_info->write_png_depth;
9947 Adjust background and transparency samples in sub-8-bit grayscale files.
9949 if (ping_bit_depth < 8 && ping_color_type ==
9950 PNG_COLOR_TYPE_GRAY)
9958 maxval=(png_uint_16) ((one << ping_bit_depth)-1);
9960 if (ping_exclude_bKGD == MagickFalse)
9963 ping_background.gray=(png_uint_16) ((maxval/65535.)*
9964 (ScaleQuantumToShort(((GetPixelInfoIntensity(
9965 &image->background_color))) +.5)));
9967 if (logging != MagickFalse)
9968 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9969 " Setting up bKGD chunk (2)");
9970 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9971 " background_color index is %d",
9972 (int) ping_background.index);
9974 ping_have_bKGD = MagickTrue;
9977 if (logging != MagickFalse)
9978 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9979 " Scaling ping_trans_color.gray from %d",
9980 (int)ping_trans_color.gray);
9982 ping_trans_color.gray=(png_uint_16) ((maxval/255.)*(
9983 ping_trans_color.gray)+.5);
9985 if (logging != MagickFalse)
9986 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9987 " to %d", (int)ping_trans_color.gray);
9990 if (ping_exclude_bKGD == MagickFalse)
9992 if (mng_info->IsPalette && (int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
9995 Identify which colormap entry is the background color.
9998 number_colors=image_colors;
10000 for (i=0; i < (ssize_t) MagickMax(1L*number_colors,1L); i++)
10001 if (IsPNGColorEqual(image->background_color,image->colormap[i]))
10004 ping_background.index=(png_byte) i;
10006 if (logging != MagickFalse)
10008 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10009 " Setting up bKGD chunk with index=%d",(int) i);
10012 if (i < (ssize_t) number_colors)
10014 ping_have_bKGD = MagickTrue;
10016 if (logging != MagickFalse)
10018 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10019 " background =(%d,%d,%d)",
10020 (int) ping_background.red,
10021 (int) ping_background.green,
10022 (int) ping_background.blue);
10026 else /* Can't happen */
10028 if (logging != MagickFalse)
10029 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10030 " No room in PLTE to add bKGD color");
10031 ping_have_bKGD = MagickFalse;
10036 if (logging != MagickFalse)
10037 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10038 " PNG color type: %s (%d)", PngColorTypeToString(ping_color_type),
10041 Initialize compression level and filtering.
10043 if (logging != MagickFalse)
10045 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10046 " Setting up deflate compression");
10048 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10049 " Compression buffer size: 32768");
10052 png_set_compression_buffer_size(ping,32768L);
10054 if (logging != MagickFalse)
10055 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10056 " Compression mem level: 9");
10058 png_set_compression_mem_level(ping, 9);
10060 /* Untangle the "-quality" setting:
10062 Undefined is 0; the default is used.
10067 0: Use Z_HUFFMAN_ONLY strategy with the
10068 zlib default compression level
10070 1-9: the zlib compression level
10074 0-4: the PNG filter method
10076 5: libpng adaptive filtering if compression level > 5
10077 libpng filter type "none" if compression level <= 5
10078 or if image is grayscale or palette
10080 6: libpng adaptive filtering
10082 7: "LOCO" filtering (intrapixel differing) if writing
10083 a MNG, othewise "none". Did not work in IM-6.7.0-9
10084 and earlier because of a missing "else".
10086 8: Z_RLE strategy, all filters
10087 Unused prior to IM-6.7.0-10, was same as 6
10089 9: Z_RLE strategy, no PNG filters
10090 Unused prior to IM-6.7.0-10, was same as 6
10092 Note that using the -quality option, not all combinations of
10093 PNG filter type, zlib compression level, and zlib compression
10094 strategy are possible. This will be addressed soon in a
10095 release that accomodates "-define png:compression-strategy", etc.
10099 quality=image->quality == UndefinedCompressionQuality ? 75UL :
10104 if (mng_info->write_png_compression_strategy == 0)
10105 mng_info->write_png_compression_strategy = Z_HUFFMAN_ONLY+1;
10108 else if (mng_info->write_png_compression_level == 0)
10113 level=(int) MagickMin((ssize_t) quality/10,9);
10115 mng_info->write_png_compression_level = level+1;
10118 if (mng_info->write_png_compression_strategy == 0)
10120 if ((quality %10) == 8 || (quality %10) == 9)
10121 #ifdef Z_RLE /* Z_RLE was added to zlib-1.2.0 */
10122 mng_info->write_png_compression_strategy=Z_RLE+1;
10124 mng_info->write_png_compression_strategy = Z_DEFAULT_STRATEGY+1;
10128 if (mng_info->write_png_compression_filter == 0)
10129 mng_info->write_png_compression_filter=((int) quality % 10) + 1;
10131 if (logging != MagickFalse)
10133 if (mng_info->write_png_compression_level)
10134 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10135 " Compression level: %d",
10136 (int) mng_info->write_png_compression_level-1);
10138 if (mng_info->write_png_compression_strategy)
10139 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10140 " Compression strategy: %d",
10141 (int) mng_info->write_png_compression_strategy-1);
10143 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10144 " Setting up filtering");
10146 if (mng_info->write_png_compression_filter == 6)
10147 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10148 " Base filter method: ADAPTIVE");
10149 else if (mng_info->write_png_compression_filter == 0 ||
10150 mng_info->write_png_compression_filter == 1)
10151 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10152 " Base filter method: NONE");
10154 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10155 " Base filter method: %d",
10156 (int) mng_info->write_png_compression_filter-1);
10159 if (mng_info->write_png_compression_level != 0)
10160 png_set_compression_level(ping,mng_info->write_png_compression_level-1);
10162 if (mng_info->write_png_compression_filter == 6)
10164 if (((int) ping_color_type == PNG_COLOR_TYPE_GRAY) ||
10165 ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE) ||
10167 png_set_filter(ping,PNG_FILTER_TYPE_BASE,PNG_NO_FILTERS);
10169 png_set_filter(ping,PNG_FILTER_TYPE_BASE,PNG_ALL_FILTERS);
10171 else if (mng_info->write_png_compression_filter == 7 ||
10172 mng_info->write_png_compression_filter == 10)
10173 png_set_filter(ping,PNG_FILTER_TYPE_BASE,PNG_ALL_FILTERS);
10175 else if (mng_info->write_png_compression_filter == 8)
10177 #if defined(PNG_MNG_FEATURES_SUPPORTED) && defined(PNG_INTRAPIXEL_DIFFERENCING)
10178 if (mng_info->write_mng)
10180 if (((int) ping_color_type == PNG_COLOR_TYPE_RGB) ||
10181 ((int) ping_color_type == PNG_COLOR_TYPE_RGBA))
10182 ping_filter_method=PNG_INTRAPIXEL_DIFFERENCING;
10185 png_set_filter(ping,PNG_FILTER_TYPE_BASE,PNG_NO_FILTERS);
10188 else if (mng_info->write_png_compression_filter == 9)
10189 png_set_filter(ping,PNG_FILTER_TYPE_BASE,PNG_NO_FILTERS);
10191 else if (mng_info->write_png_compression_filter != 0)
10192 png_set_filter(ping,PNG_FILTER_TYPE_BASE,
10193 mng_info->write_png_compression_filter-1);
10195 if (mng_info->write_png_compression_strategy != 0)
10196 png_set_compression_strategy(ping,
10197 mng_info->write_png_compression_strategy-1);
10199 ping_interlace_method=image_info->interlace != NoInterlace;
10201 if (mng_info->write_mng)
10202 png_set_sig_bytes(ping,8);
10204 /* Bail out if cannot meet defined png:bit-depth or png:color-type */
10206 if (mng_info->write_png_colortype != 0)
10208 if (mng_info->write_png_colortype-1 == PNG_COLOR_TYPE_GRAY)
10209 if (ping_have_color != MagickFalse)
10211 ping_color_type = PNG_COLOR_TYPE_RGB;
10213 if (ping_bit_depth < 8)
10217 if (mng_info->write_png_colortype-1 == PNG_COLOR_TYPE_GRAY_ALPHA)
10218 if (ping_have_color != MagickFalse)
10219 ping_color_type = PNG_COLOR_TYPE_RGB_ALPHA;
10222 if (ping_need_colortype_warning != MagickFalse ||
10223 ((mng_info->write_png_depth &&
10224 (int) mng_info->write_png_depth != ping_bit_depth) ||
10225 (mng_info->write_png_colortype &&
10226 ((int) mng_info->write_png_colortype-1 != ping_color_type &&
10227 mng_info->write_png_colortype != 7 &&
10228 !(mng_info->write_png_colortype == 5 && ping_color_type == 0)))))
10230 if (logging != MagickFalse)
10232 if (ping_need_colortype_warning != MagickFalse)
10234 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10235 " Image has transparency but tRNS chunk was excluded");
10238 if (mng_info->write_png_depth)
10240 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10241 " Defined png:bit-depth=%u, Computed depth=%u",
10242 mng_info->write_png_depth,
10246 if (mng_info->write_png_colortype)
10248 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10249 " Defined png:color-type=%u, Computed color type=%u",
10250 mng_info->write_png_colortype-1,
10256 "Cannot write image with defined png:bit-depth or png:color-type.");
10259 if (image_matte != MagickFalse && image->alpha_trait != BlendPixelTrait)
10261 /* Add an opaque matte channel */
10262 image->alpha_trait = BlendPixelTrait;
10263 (void) SetImageAlpha(image,OpaqueAlpha,exception);
10265 if (logging != MagickFalse)
10266 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10267 " Added an opaque matte channel");
10270 if (number_transparent != 0 || number_semitransparent != 0)
10272 if (ping_color_type < 4)
10274 ping_have_tRNS=MagickTrue;
10275 if (logging != MagickFalse)
10276 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10277 " Setting ping_have_tRNS=MagickTrue.");
10281 if (logging != MagickFalse)
10282 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10283 " Writing PNG header chunks");
10285 png_set_IHDR(ping,ping_info,ping_width,ping_height,
10286 ping_bit_depth,ping_color_type,
10287 ping_interlace_method,ping_compression_method,
10288 ping_filter_method);
10290 if (ping_color_type == 3 && ping_have_PLTE != MagickFalse)
10292 png_set_PLTE(ping,ping_info,palette,number_colors);
10294 if (logging != MagickFalse)
10296 for (i=0; i< (ssize_t) number_colors; i++)
10298 if (i < ping_num_trans)
10299 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10300 " PLTE[%d] = (%d,%d,%d), tRNS[%d] = (%d)",
10302 (int) palette[i].red,
10303 (int) palette[i].green,
10304 (int) palette[i].blue,
10306 (int) ping_trans_alpha[i]);
10308 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10309 " PLTE[%d] = (%d,%d,%d)",
10311 (int) palette[i].red,
10312 (int) palette[i].green,
10313 (int) palette[i].blue);
10318 /* Only write the iCCP chunk if we are not writing the sRGB chunk. */
10319 if (ping_exclude_sRGB != MagickFalse ||
10320 (!png_get_valid(ping,ping_info,PNG_INFO_sRGB)))
10322 if ((ping_exclude_tEXt == MagickFalse ||
10323 ping_exclude_zTXt == MagickFalse) &&
10324 (ping_exclude_iCCP == MagickFalse || ping_exclude_zCCP == MagickFalse))
10326 ResetImageProfileIterator(image);
10327 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
10329 profile=GetImageProfile(image,name);
10331 if (profile != (StringInfo *) NULL)
10333 #ifdef PNG_WRITE_iCCP_SUPPORTED
10334 if ((LocaleCompare(name,"ICC") == 0) ||
10335 (LocaleCompare(name,"ICM") == 0))
10338 if (ping_exclude_iCCP == MagickFalse)
10340 png_set_iCCP(ping,ping_info,(png_charp) name,0,
10341 #if (PNG_LIBPNG_VER < 10500)
10342 (png_charp) GetStringInfoDatum(profile),
10344 (png_const_bytep) GetStringInfoDatum(profile),
10346 (png_uint_32) GetStringInfoLength(profile));
10352 if (ping_exclude_zCCP == MagickFalse)
10354 Magick_png_write_raw_profile(image_info,ping,ping_info,
10355 (unsigned char *) name,(unsigned char *) name,
10356 GetStringInfoDatum(profile),
10357 (png_uint_32) GetStringInfoLength(profile));
10361 if (logging != MagickFalse)
10362 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10363 " Setting up text chunk with %s profile",name);
10365 name=GetNextImageProfile(image);
10370 #if defined(PNG_WRITE_sRGB_SUPPORTED)
10371 if ((mng_info->have_write_global_srgb == 0) &&
10372 (png_get_valid(ping,ping_info,PNG_INFO_sRGB)))
10374 if (ping_exclude_sRGB == MagickFalse)
10377 Note image rendering intent.
10379 if (logging != MagickFalse)
10380 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10381 " Setting up sRGB chunk");
10383 (void) png_set_sRGB(ping,ping_info,(
10384 Magick_RenderingIntent_to_PNG_RenderingIntent(
10385 image->rendering_intent)));
10389 if ((!mng_info->write_mng) || (!png_get_valid(ping,ping_info,PNG_INFO_sRGB)))
10392 if (ping_exclude_gAMA == MagickFalse &&
10393 (ping_exclude_sRGB == MagickFalse ||
10394 (image->gamma < .45 || image->gamma > .46)))
10396 if ((mng_info->have_write_global_gama == 0) && (image->gamma != 0.0))
10400 To do: check for cHRM+gAMA == sRGB, and write sRGB instead.
10402 if (logging != MagickFalse)
10403 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10404 " Setting up gAMA chunk");
10406 png_set_gAMA(ping,ping_info,image->gamma);
10410 if (ping_exclude_cHRM == MagickFalse)
10412 if ((mng_info->have_write_global_chrm == 0) &&
10413 (image->chromaticity.red_primary.x != 0.0))
10416 Note image chromaticity.
10417 To do: check for cHRM+gAMA == sRGB, and write sRGB instead.
10425 wp=image->chromaticity.white_point;
10426 rp=image->chromaticity.red_primary;
10427 gp=image->chromaticity.green_primary;
10428 bp=image->chromaticity.blue_primary;
10430 if (logging != MagickFalse)
10431 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10432 " Setting up cHRM chunk");
10434 png_set_cHRM(ping,ping_info,wp.x,wp.y,rp.x,rp.y,gp.x,gp.y,
10440 if (ping_exclude_bKGD == MagickFalse)
10442 if (ping_have_bKGD != MagickFalse)
10444 png_set_bKGD(ping,ping_info,&ping_background);
10447 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10448 " Setting up bKGD chunk");
10449 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10450 " background color = (%d,%d,%d)",
10451 (int) ping_background.red,
10452 (int) ping_background.green,
10453 (int) ping_background.blue);
10454 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10455 " index = %d, gray=%d",
10456 (int) ping_background.index,
10457 (int) ping_background.gray);
10462 if (ping_exclude_pHYs == MagickFalse)
10464 if (ping_have_pHYs != MagickFalse)
10466 png_set_pHYs(ping,ping_info,
10467 ping_pHYs_x_resolution,
10468 ping_pHYs_y_resolution,
10469 ping_pHYs_unit_type);
10473 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10474 " Setting up pHYs chunk");
10475 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10476 " x_resolution=%lu",
10477 (unsigned long) ping_pHYs_x_resolution);
10478 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10479 " y_resolution=%lu",
10480 (unsigned long) ping_pHYs_y_resolution);
10481 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10483 (unsigned long) ping_pHYs_unit_type);
10488 #if defined(PNG_oFFs_SUPPORTED)
10489 if (ping_exclude_oFFs == MagickFalse)
10491 if (image->page.x || image->page.y)
10493 png_set_oFFs(ping,ping_info,(png_int_32) image->page.x,
10494 (png_int_32) image->page.y, 0);
10496 if (logging != MagickFalse)
10497 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10498 " Setting up oFFs chunk with x=%d, y=%d, units=0",
10499 (int) image->page.x, (int) image->page.y);
10504 if (mng_info->need_blob != MagickFalse)
10506 if (OpenBlob(image_info,image,WriteBinaryBlobMode,exception) ==
10508 png_error(ping,"WriteBlob Failed");
10510 ping_have_blob=MagickTrue;
10513 png_write_info_before_PLTE(ping, ping_info);
10515 if (ping_have_tRNS != MagickFalse && ping_color_type < 4)
10517 if (logging != MagickFalse)
10519 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10520 " Calling png_set_tRNS with num_trans=%d",ping_num_trans);
10523 if (ping_color_type == 3)
10524 (void) png_set_tRNS(ping, ping_info,
10531 (void) png_set_tRNS(ping, ping_info,
10534 &ping_trans_color);
10536 if (logging != MagickFalse)
10538 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10539 " tRNS color =(%d,%d,%d)",
10540 (int) ping_trans_color.red,
10541 (int) ping_trans_color.green,
10542 (int) ping_trans_color.blue);
10547 /* write any png-chunk-b profiles */
10548 (void) Magick_png_write_chunk_from_profile(image,"PNG-chunk-b",logging);
10550 png_write_info(ping,ping_info);
10552 /* write any PNG-chunk-m profiles */
10553 (void) Magick_png_write_chunk_from_profile(image,"PNG-chunk-m",logging);
10555 if (ping_exclude_vpAg == MagickFalse)
10557 if ((image->page.width != 0 && image->page.width != image->columns) ||
10558 (image->page.height != 0 && image->page.height != image->rows))
10563 (void) WriteBlobMSBULong(image,9L); /* data length=8 */
10564 PNGType(chunk,mng_vpAg);
10565 LogPNGChunk(logging,mng_vpAg,9L);
10566 PNGLong(chunk+4,(png_uint_32) image->page.width);
10567 PNGLong(chunk+8,(png_uint_32) image->page.height);
10568 chunk[12]=0; /* unit = pixels */
10569 (void) WriteBlob(image,13,chunk);
10570 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
10574 #if (PNG_LIBPNG_VER == 10206)
10575 /* avoid libpng-1.2.6 bug by setting PNG_HAVE_IDAT flag */
10576 #define PNG_HAVE_IDAT 0x04
10577 ping->mode |= PNG_HAVE_IDAT;
10578 #undef PNG_HAVE_IDAT
10581 png_set_packing(ping);
10585 rowbytes=image->columns;
10586 if (image_depth > 8)
10588 switch (ping_color_type)
10590 case PNG_COLOR_TYPE_RGB:
10594 case PNG_COLOR_TYPE_GRAY_ALPHA:
10598 case PNG_COLOR_TYPE_RGBA:
10606 if (logging != MagickFalse)
10608 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10609 " Writing PNG image data");
10611 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10612 " Allocating %.20g bytes of memory for pixels",(double) rowbytes);
10614 ping_pixels=(unsigned char *) AcquireQuantumMemory(rowbytes,
10615 sizeof(*ping_pixels));
10617 if (ping_pixels == (unsigned char *) NULL)
10618 png_error(ping,"Allocation of memory for pixels failed");
10621 Initialize image scanlines.
10623 quantum_info=AcquireQuantumInfo(image_info,image);
10624 if (quantum_info == (QuantumInfo *) NULL)
10625 png_error(ping,"Memory allocation for quantum_info failed");
10626 quantum_info->format=UndefinedQuantumFormat;
10627 quantum_info->depth=image_depth;
10628 (void) SetQuantumEndian(image,quantum_info,MSBEndian);
10629 num_passes=png_set_interlace_handling(ping);
10631 if ((!mng_info->write_png8 && !mng_info->write_png24 &&
10632 !mng_info->write_png48 && !mng_info->write_png64 &&
10633 !mng_info->write_png32) &&
10634 (mng_info->IsPalette ||
10635 (image_info->type == BilevelType)) &&
10636 image_matte == MagickFalse &&
10637 ping_have_non_bw == MagickFalse)
10639 /* Palette, Bilevel, or Opaque Monochrome */
10640 register const Quantum
10643 quantum_info->depth=8;
10644 for (pass=0; pass < num_passes; pass++)
10647 Convert PseudoClass image to a PNG monochrome image.
10649 for (y=0; y < (ssize_t) image->rows; y++)
10651 if (logging != MagickFalse && y == 0)
10652 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10653 " Writing row of pixels (0)");
10655 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
10657 if (p == (const Quantum *) NULL)
10660 if (mng_info->IsPalette)
10662 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10663 quantum_info,GrayQuantum,ping_pixels,exception);
10664 if (mng_info->write_png_colortype-1 == PNG_COLOR_TYPE_PALETTE &&
10665 mng_info->write_png_depth &&
10666 mng_info->write_png_depth != old_bit_depth)
10668 /* Undo pixel scaling */
10669 for (i=0; i < (ssize_t) image->columns; i++)
10670 *(ping_pixels+i)=(unsigned char) (*(ping_pixels+i)
10671 >> (8-old_bit_depth));
10677 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10678 quantum_info,RedQuantum,ping_pixels,exception);
10681 if (mng_info->write_png_colortype-1 != PNG_COLOR_TYPE_PALETTE)
10682 for (i=0; i < (ssize_t) image->columns; i++)
10683 *(ping_pixels+i)=(unsigned char) ((*(ping_pixels+i) > 127) ?
10686 if (logging != MagickFalse && y == 0)
10687 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10688 " Writing row of pixels (1)");
10690 png_write_row(ping,ping_pixels);
10692 if (image->previous == (Image *) NULL)
10694 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
10695 if (status == MagickFalse)
10701 else /* Not Palette, Bilevel, or Opaque Monochrome */
10703 if ((!mng_info->write_png8 && !mng_info->write_png24 &&
10704 !mng_info->write_png48 && !mng_info->write_png64 &&
10705 !mng_info->write_png32) && (image_matte != MagickFalse ||
10706 (ping_bit_depth >= MAGICKCORE_QUANTUM_DEPTH)) &&
10707 (mng_info->IsPalette) && ping_have_color == MagickFalse)
10709 register const Quantum
10712 for (pass=0; pass < num_passes; pass++)
10715 for (y=0; y < (ssize_t) image->rows; y++)
10717 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
10719 if (p == (const Quantum *) NULL)
10722 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
10724 if (mng_info->IsPalette)
10725 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10726 quantum_info,GrayQuantum,ping_pixels,exception);
10729 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10730 quantum_info,RedQuantum,ping_pixels,exception);
10732 if (logging != MagickFalse && y == 0)
10733 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10734 " Writing GRAY PNG pixels (2)");
10737 else /* PNG_COLOR_TYPE_GRAY_ALPHA */
10739 if (logging != MagickFalse && y == 0)
10740 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10741 " Writing GRAY_ALPHA PNG pixels (2)");
10743 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10744 quantum_info,GrayAlphaQuantum,ping_pixels,exception);
10747 if (logging != MagickFalse && y == 0)
10748 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10749 " Writing row of pixels (2)");
10751 png_write_row(ping,ping_pixels);
10754 if (image->previous == (Image *) NULL)
10756 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
10757 if (status == MagickFalse)
10765 register const Quantum
10768 for (pass=0; pass < num_passes; pass++)
10770 if ((image_depth > 8) ||
10771 mng_info->write_png24 ||
10772 mng_info->write_png32 ||
10773 mng_info->write_png48 ||
10774 mng_info->write_png64 ||
10775 (!mng_info->write_png8 && !mng_info->IsPalette))
10777 for (y=0; y < (ssize_t) image->rows; y++)
10779 p=GetVirtualPixels(image,0,y,image->columns,1, exception);
10781 if (p == (const Quantum *) NULL)
10784 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
10786 if (image->storage_class == DirectClass)
10787 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10788 quantum_info,RedQuantum,ping_pixels,exception);
10791 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10792 quantum_info,GrayQuantum,ping_pixels,exception);
10795 else if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
10797 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10798 quantum_info,GrayAlphaQuantum,ping_pixels,
10801 if (logging != MagickFalse && y == 0)
10802 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10803 " Writing GRAY_ALPHA PNG pixels (3)");
10806 else if (image_matte != MagickFalse)
10807 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10808 quantum_info,RGBAQuantum,ping_pixels,exception);
10811 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10812 quantum_info,RGBQuantum,ping_pixels,exception);
10814 if (logging != MagickFalse && y == 0)
10815 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10816 " Writing row of pixels (3)");
10818 png_write_row(ping,ping_pixels);
10823 /* not ((image_depth > 8) ||
10824 mng_info->write_png24 || mng_info->write_png32 ||
10825 mng_info->write_png48 || mng_info->write_png64 ||
10826 (!mng_info->write_png8 && !mng_info->IsPalette))
10829 if ((ping_color_type != PNG_COLOR_TYPE_GRAY) &&
10830 (ping_color_type != PNG_COLOR_TYPE_GRAY_ALPHA))
10832 if (logging != MagickFalse)
10833 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10834 " pass %d, Image Is not GRAY or GRAY_ALPHA",pass);
10836 quantum_info->depth=8;
10840 for (y=0; y < (ssize_t) image->rows; y++)
10842 if (logging != MagickFalse && y == 0)
10843 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10844 " pass %d, Image Is RGB, 16-bit GRAY, or GRAY_ALPHA",pass);
10846 p=GetVirtualPixels(image,0,y,image->columns,1, exception);
10848 if (p == (const Quantum *) NULL)
10851 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
10853 quantum_info->depth=image->depth;
10855 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10856 quantum_info,GrayQuantum,ping_pixels,exception);
10859 else if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
10861 if (logging != MagickFalse && y == 0)
10862 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10863 " Writing GRAY_ALPHA PNG pixels (4)");
10865 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10866 quantum_info,GrayAlphaQuantum,ping_pixels,
10872 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10873 quantum_info,IndexQuantum,ping_pixels,exception);
10875 if (logging != MagickFalse && y <= 2)
10877 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10878 " Writing row of non-gray pixels (4)");
10880 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10881 " ping_pixels[0]=%d,ping_pixels[1]=%d",
10882 (int)ping_pixels[0],(int)ping_pixels[1]);
10885 png_write_row(ping,ping_pixels);
10889 if (image->previous == (Image *) NULL)
10891 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
10892 if (status == MagickFalse)
10899 if (quantum_info != (QuantumInfo *) NULL)
10900 quantum_info=DestroyQuantumInfo(quantum_info);
10902 if (logging != MagickFalse)
10904 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10905 " Wrote PNG image data");
10907 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10908 " Width: %.20g",(double) ping_width);
10910 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10911 " Height: %.20g",(double) ping_height);
10913 if (mng_info->write_png_depth)
10915 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10916 " Defined png:bit-depth: %d",mng_info->write_png_depth);
10919 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10920 " PNG bit-depth written: %d",ping_bit_depth);
10922 if (mng_info->write_png_colortype)
10924 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10925 " Defined png:color-type: %d",mng_info->write_png_colortype-1);
10928 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10929 " PNG color-type written: %d",ping_color_type);
10931 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10932 " PNG Interlace method: %d",ping_interlace_method);
10935 Generate text chunks after IDAT.
10937 if (ping_exclude_tEXt == MagickFalse || ping_exclude_zTXt == MagickFalse)
10939 ResetImagePropertyIterator(image);
10940 property=GetNextImageProperty(image);
10941 while (property != (const char *) NULL)
10946 value=GetImageProperty(image,property,exception);
10948 /* Don't write any "png:" properties; those are just for "identify" */
10949 if (LocaleNCompare(property,"png:",4) != 0 &&
10951 /* Suppress density and units if we wrote a pHYs chunk */
10952 (ping_exclude_pHYs != MagickFalse ||
10953 LocaleCompare(property,"density") != 0 ||
10954 LocaleCompare(property,"units") != 0) &&
10956 /* Suppress the IM-generated Date:create and Date:modify */
10957 (ping_exclude_date == MagickFalse ||
10958 LocaleNCompare(property, "Date:",5) != 0))
10960 if (value != (const char *) NULL)
10963 #if PNG_LIBPNG_VER >= 14000
10964 text=(png_textp) png_malloc(ping,
10965 (png_alloc_size_t) sizeof(png_text));
10967 text=(png_textp) png_malloc(ping,(png_size_t) sizeof(png_text));
10969 text[0].key=(char *) property;
10970 text[0].text=(char *) value;
10971 text[0].text_length=strlen(value);
10973 if (ping_exclude_tEXt != MagickFalse)
10974 text[0].compression=PNG_TEXT_COMPRESSION_zTXt;
10976 else if (ping_exclude_zTXt != MagickFalse)
10977 text[0].compression=PNG_TEXT_COMPRESSION_NONE;
10981 text[0].compression=image_info->compression == NoCompression ||
10982 (image_info->compression == UndefinedCompression &&
10983 text[0].text_length < 128) ? PNG_TEXT_COMPRESSION_NONE :
10984 PNG_TEXT_COMPRESSION_zTXt ;
10987 if (logging != MagickFalse)
10989 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10990 " Setting up text chunk");
10992 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10993 " keyword: '%s'",text[0].key);
10996 png_set_text(ping,ping_info,text,1);
10997 png_free(ping,text);
11000 property=GetNextImageProperty(image);
11004 /* write any PNG-chunk-e profiles */
11005 (void) Magick_png_write_chunk_from_profile(image,"PNG-chunk-e",logging);
11007 if (logging != MagickFalse)
11008 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11009 " Writing PNG end info");
11011 png_write_end(ping,ping_info);
11013 if (mng_info->need_fram && (int) image->dispose == BackgroundDispose)
11015 if (mng_info->page.x || mng_info->page.y ||
11016 (ping_width != mng_info->page.width) ||
11017 (ping_height != mng_info->page.height))
11023 Write FRAM 4 with clipping boundaries followed by FRAM 1.
11025 (void) WriteBlobMSBULong(image,27L); /* data length=27 */
11026 PNGType(chunk,mng_FRAM);
11027 LogPNGChunk(logging,mng_FRAM,27L);
11029 chunk[5]=0; /* frame name separator (no name) */
11030 chunk[6]=1; /* flag for changing delay, for next frame only */
11031 chunk[7]=0; /* flag for changing frame timeout */
11032 chunk[8]=1; /* flag for changing frame clipping for next frame */
11033 chunk[9]=0; /* flag for changing frame sync_id */
11034 PNGLong(chunk+10,(png_uint_32) (0L)); /* temporary 0 delay */
11035 chunk[14]=0; /* clipping boundaries delta type */
11036 PNGLong(chunk+15,(png_uint_32) (mng_info->page.x)); /* left cb */
11038 (png_uint_32) (mng_info->page.x + ping_width));
11039 PNGLong(chunk+23,(png_uint_32) (mng_info->page.y)); /* top cb */
11041 (png_uint_32) (mng_info->page.y + ping_height));
11042 (void) WriteBlob(image,31,chunk);
11043 (void) WriteBlobMSBULong(image,crc32(0,chunk,31));
11044 mng_info->old_framing_mode=4;
11045 mng_info->framing_mode=1;
11049 mng_info->framing_mode=3;
11051 if (mng_info->write_mng && !mng_info->need_fram &&
11052 ((int) image->dispose == 3))
11053 png_error(ping, "Cannot convert GIF with disposal method 3 to MNG-LC");
11056 Free PNG resources.
11059 png_destroy_write_struct(&ping,&ping_info);
11061 ping_pixels=(unsigned char *) RelinquishMagickMemory(ping_pixels);
11063 if (ping_have_blob != MagickFalse)
11064 (void) CloseBlob(image);
11066 image_info=DestroyImageInfo(image_info);
11067 image=DestroyImage(image);
11069 /* Store bit depth actually written */
11070 s[0]=(char) ping_bit_depth;
11073 (void) SetImageProperty(IMimage,"png:bit-depth-written",s,exception);
11075 if (logging != MagickFalse)
11076 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11077 " exit WriteOnePNGImage()");
11079 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
11080 UnlockSemaphoreInfo(ping_semaphore);
11083 /* } for navigation to beginning of SETJMP-protected block. Revert to
11084 * Throwing an Exception when an error occurs.
11087 return(MagickTrue);
11088 /* End write one PNG image */
11093 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11097 % W r i t e P N G I m a g e %
11101 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11103 % WritePNGImage() writes a Portable Network Graphics (PNG) or
11104 % Multiple-image Network Graphics (MNG) image file.
11106 % MNG support written by Glenn Randers-Pehrson, glennrp@image...
11108 % The format of the WritePNGImage method is:
11110 % MagickBooleanType WritePNGImage(const ImageInfo *image_info,
11111 % Image *image,ExceptionInfo *exception)
11113 % A description of each parameter follows:
11115 % o image_info: the image info.
11117 % o image: The image.
11119 % o exception: return any errors or warnings in this structure.
11121 % Returns MagickTrue on success, MagickFalse on failure.
11123 % Communicating with the PNG encoder:
11125 % While the datastream written is always in PNG format and normally would
11126 % be given the "png" file extension, this method also writes the following
11127 % pseudo-formats which are subsets of png:
11129 % o PNG8: An 8-bit indexed PNG datastream is written. If the image has
11130 % a depth greater than 8, the depth is reduced. If transparency
11131 % is present, the tRNS chunk must only have values 0 and 255
11132 % (i.e., transparency is binary: fully opaque or fully
11133 % transparent). If other values are present they will be
11134 % 50%-thresholded to binary transparency. If more than 256
11135 % colors are present, they will be quantized to the 4-4-4-1,
11136 % 3-3-3-1, or 3-3-2-1 palette. The underlying RGB color
11137 % of any resulting fully-transparent pixels is changed to
11138 % the image's background color.
11140 % If you want better quantization or dithering of the colors
11141 % or alpha than that, you need to do it before calling the
11142 % PNG encoder. The pixels contain 8-bit indices even if
11143 % they could be represented with 1, 2, or 4 bits. Grayscale
11144 % images will be written as indexed PNG files even though the
11145 % PNG grayscale type might be slightly more efficient. Please
11146 % note that writing to the PNG8 format may result in loss
11147 % of color and alpha data.
11149 % o PNG24: An 8-bit per sample RGB PNG datastream is written. The tRNS
11150 % chunk can be present to convey binary transparency by naming
11151 % one of the colors as transparent. The only loss incurred
11152 % is reduction of sample depth to 8. If the image has more
11153 % than one transparent color, has semitransparent pixels, or
11154 % has an opaque pixel with the same RGB components as the
11155 % transparent color, an image is not written.
11157 % o PNG32: An 8-bit per sample RGBA PNG is written. Partial
11158 % transparency is permitted, i.e., the alpha sample for
11159 % each pixel can have any value from 0 to 255. The alpha
11160 % channel is present even if the image is fully opaque.
11161 % The only loss in data is the reduction of the sample depth
11164 % o PNG48: A 16-bit per sample RGB PNG datastream is written. The tRNS
11165 % chunk can be present to convey binary transparency by naming
11166 % one of the colors as transparent. If the image has more
11167 % than one transparent color, has semitransparent pixels, or
11168 % has an opaque pixel with the same RGB components as the
11169 % transparent color, an image is not written.
11171 % o PNG64: A 16-bit per sample RGBA PNG is written. Partial
11172 % transparency is permitted, i.e., the alpha sample for
11173 % each pixel can have any value from 0 to 65535. The alpha
11174 % channel is present even if the image is fully opaque.
11176 % o PNG00: A PNG that inherits its colortype and bit-depth from the input
11177 % image, if the input was a PNG, is written. If these values
11178 % cannot be found, then "PNG00" falls back to the regular "PNG"
11181 % o -define: For more precise control of the PNG output, you can use the
11182 % Image options "png:bit-depth" and "png:color-type". These
11183 % can be set from the commandline with "-define" and also
11184 % from the application programming interfaces. The options
11185 % are case-independent and are converted to lowercase before
11186 % being passed to this encoder.
11188 % png:color-type can be 0, 2, 3, 4, or 6.
11190 % When png:color-type is 0 (Grayscale), png:bit-depth can
11191 % be 1, 2, 4, 8, or 16.
11193 % When png:color-type is 2 (RGB), png:bit-depth can
11196 % When png:color-type is 3 (Indexed), png:bit-depth can
11197 % be 1, 2, 4, or 8. This refers to the number of bits
11198 % used to store the index. The color samples always have
11199 % bit-depth 8 in indexed PNG files.
11201 % When png:color-type is 4 (Gray-Matte) or 6 (RGB-Matte),
11202 % png:bit-depth can be 8 or 16.
11204 % If the image cannot be written without loss with the
11205 % requested bit-depth and color-type, a PNG file will not
11206 % be written, a warning will be issued, and the encoder will
11207 % return MagickFalse.
11209 % Since image encoders should not be responsible for the "heavy lifting",
11210 % the user should make sure that ImageMagick has already reduced the
11211 % image depth and number of colors and limit transparency to binary
11212 % transparency prior to attempting to write the image with depth, color,
11213 % or transparency limitations.
11215 % Note that another definition, "png:bit-depth-written" exists, but it
11216 % is not intended for external use. It is only used internally by the
11217 % PNG encoder to inform the JNG encoder of the depth of the alpha channel.
11219 % It is possible to request that the PNG encoder write previously-formatted
11220 % ancillary chunks in the output PNG file, using the "-profile" commandline
11221 % option as shown below or by setting the profile via a programming
11224 % -profile PNG-chunk-x:<file>
11226 % where x is a location flag and <file> is a file containing the chunk
11227 % name in the first 4 bytes, then a colon (":"), followed by the chunk data.
11228 % This encoder will compute the chunk length and CRC, so those must not
11229 % be included in the file.
11231 % "x" can be "b" (before PLTE), "m" (middle, i.e., between PLTE and IDAT),
11232 % or "e" (end, i.e., after IDAT). If you want to write multiple chunks
11233 % of the same type, then add a short unique string after the "x" to prevent
11234 % subsequent profiles from overwriting the preceding ones, e.g.,
11236 % -profile PNG-chunk-b01:file01 -profile PNG-chunk-b02:file02
11238 % As of version 6.6.6 the following optimizations are always done:
11240 % o 32-bit depth is reduced to 16.
11241 % o 16-bit depth is reduced to 8 if all pixels contain samples whose
11242 % high byte and low byte are identical.
11243 % o Palette is sorted to remove unused entries and to put a
11244 % transparent color first, if BUILD_PNG_PALETTE is defined.
11245 % o Opaque matte channel is removed when writing an indexed PNG.
11246 % o Grayscale images are reduced to 1, 2, or 4 bit depth if
11247 % this can be done without loss and a larger bit depth N was not
11248 % requested via the "-define png:bit-depth=N" option.
11249 % o If matte channel is present but only one transparent color is
11250 % present, RGB+tRNS is written instead of RGBA
11251 % o Opaque matte channel is removed (or added, if color-type 4 or 6
11252 % was requested when converting an opaque image).
11254 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11256 static MagickBooleanType WritePNGImage(const ImageInfo *image_info,
11257 Image *image,ExceptionInfo *exception)
11262 have_mng_structure,
11278 assert(image_info != (const ImageInfo *) NULL);
11279 assert(image_info->signature == MagickSignature);
11280 assert(image != (Image *) NULL);
11281 assert(image->signature == MagickSignature);
11282 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
11283 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter WritePNGImage()");
11285 Allocate a MngInfo structure.
11287 have_mng_structure=MagickFalse;
11288 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
11290 if (mng_info == (MngInfo *) NULL)
11291 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
11294 Initialize members of the MngInfo structure.
11296 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
11297 mng_info->image=image;
11298 mng_info->equal_backgrounds=MagickTrue;
11299 have_mng_structure=MagickTrue;
11301 /* See if user has requested a specific PNG subformat */
11303 mng_info->write_png8=LocaleCompare(image_info->magick,"PNG8") == 0;
11304 mng_info->write_png24=LocaleCompare(image_info->magick,"PNG24") == 0;
11305 mng_info->write_png32=LocaleCompare(image_info->magick,"PNG32") == 0;
11306 mng_info->write_png48=LocaleCompare(image_info->magick,"PNG48") == 0;
11307 mng_info->write_png64=LocaleCompare(image_info->magick,"PNG64") == 0;
11309 value=GetImageOption(image_info,"png:format");
11311 if (value != (char *) NULL)
11313 mng_info->write_png8 = MagickFalse;
11314 mng_info->write_png24 = MagickFalse;
11315 mng_info->write_png32 = MagickFalse;
11316 mng_info->write_png48 = MagickFalse;
11317 mng_info->write_png64 = MagickFalse;
11319 if (LocaleCompare(value,"png8") == 0)
11320 mng_info->write_png8 = MagickTrue;
11322 else if (LocaleCompare(value,"png24") == 0)
11323 mng_info->write_png24 = MagickTrue;
11325 else if (LocaleCompare(value,"png32") == 0)
11326 mng_info->write_png32 = MagickTrue;
11328 else if (LocaleCompare(value,"png48") == 0)
11329 mng_info->write_png48 = MagickTrue;
11331 else if (LocaleCompare(value,"png64") == 0)
11332 mng_info->write_png64 = MagickTrue;
11335 if (LocaleCompare(value,"png00") == 0)
11337 /* Retrieve png:IHDR.bit-depth-orig and png:IHDR.color-type-orig
11338 Note that whitespace at the end of the property names must match
11339 that in the corresponding SetImageProperty() calls.
11341 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11342 " Format=%s",value);
11344 value=GetImageProperty(image,"png:IHDR.bit-depth-orig ",exception);
11346 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11347 " png00 inherited bit depth=%s",value);
11349 if (value != (char *) NULL)
11351 if (LocaleCompare(value,"1") == 0)
11352 mng_info->write_png_depth = 1;
11354 else if (LocaleCompare(value,"1") == 0)
11355 mng_info->write_png_depth = 2;
11357 else if (LocaleCompare(value,"2") == 0)
11358 mng_info->write_png_depth = 4;
11360 else if (LocaleCompare(value,"8") == 0)
11361 mng_info->write_png_depth = 8;
11363 else if (LocaleCompare(value,"16") == 0)
11364 mng_info->write_png_depth = 16;
11367 value=GetImageProperty(image,"png:IHDR.color-type-orig ",exception);
11369 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11370 " png00 inherited color type=%s",value);
11372 if (value != (char *) NULL)
11374 if (LocaleCompare(value,"0") == 0)
11375 mng_info->write_png_colortype = 1;
11377 else if (LocaleCompare(value,"2") == 0)
11378 mng_info->write_png_colortype = 3;
11380 else if (LocaleCompare(value,"3") == 0)
11381 mng_info->write_png_colortype = 4;
11383 else if (LocaleCompare(value,"4") == 0)
11384 mng_info->write_png_colortype = 5;
11386 else if (LocaleCompare(value,"6") == 0)
11387 mng_info->write_png_colortype = 7;
11391 if (mng_info->write_png8)
11393 mng_info->write_png_colortype = /* 3 */ 4;
11394 mng_info->write_png_depth = 8;
11398 if (mng_info->write_png24)
11400 mng_info->write_png_colortype = /* 2 */ 3;
11401 mng_info->write_png_depth = 8;
11404 if (image->alpha_trait == BlendPixelTrait)
11405 (void) SetImageType(image,TrueColorMatteType,exception);
11408 (void) SetImageType(image,TrueColorType,exception);
11410 (void) SyncImage(image,exception);
11413 if (mng_info->write_png32)
11415 mng_info->write_png_colortype = /* 6 */ 7;
11416 mng_info->write_png_depth = 8;
11419 if (image->alpha_trait == BlendPixelTrait)
11420 (void) SetImageType(image,TrueColorMatteType,exception);
11423 (void) SetImageType(image,TrueColorType,exception);
11425 (void) SyncImage(image,exception);
11428 if (mng_info->write_png48)
11430 mng_info->write_png_colortype = /* 2 */ 3;
11431 mng_info->write_png_depth = 16;
11434 if (image->alpha_trait == BlendPixelTrait)
11435 (void) SetImageType(image,TrueColorMatteType,exception);
11438 (void) SetImageType(image,TrueColorType,exception);
11440 (void) SyncImage(image,exception);
11443 if (mng_info->write_png64)
11445 mng_info->write_png_colortype = /* 6 */ 7;
11446 mng_info->write_png_depth = 16;
11449 if (image->alpha_trait == BlendPixelTrait)
11450 (void) SetImageType(image,TrueColorMatteType,exception);
11453 (void) SetImageType(image,TrueColorType,exception);
11455 (void) SyncImage(image,exception);
11458 value=GetImageOption(image_info,"png:bit-depth");
11460 if (value != (char *) NULL)
11462 if (LocaleCompare(value,"1") == 0)
11463 mng_info->write_png_depth = 1;
11465 else if (LocaleCompare(value,"2") == 0)
11466 mng_info->write_png_depth = 2;
11468 else if (LocaleCompare(value,"4") == 0)
11469 mng_info->write_png_depth = 4;
11471 else if (LocaleCompare(value,"8") == 0)
11472 mng_info->write_png_depth = 8;
11474 else if (LocaleCompare(value,"16") == 0)
11475 mng_info->write_png_depth = 16;
11478 (void) ThrowMagickException(exception,
11479 GetMagickModule(),CoderWarning,
11480 "ignoring invalid defined png:bit-depth",
11483 if (logging != MagickFalse)
11484 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11485 " png:bit-depth=%d was defined.\n",mng_info->write_png_depth);
11488 value=GetImageOption(image_info,"png:color-type");
11490 if (value != (char *) NULL)
11492 /* We must store colortype+1 because 0 is a valid colortype */
11493 if (LocaleCompare(value,"0") == 0)
11494 mng_info->write_png_colortype = 1;
11496 else if (LocaleCompare(value,"1") == 0)
11497 mng_info->write_png_colortype = 2;
11499 else if (LocaleCompare(value,"2") == 0)
11500 mng_info->write_png_colortype = 3;
11502 else if (LocaleCompare(value,"3") == 0)
11503 mng_info->write_png_colortype = 4;
11505 else if (LocaleCompare(value,"4") == 0)
11506 mng_info->write_png_colortype = 5;
11508 else if (LocaleCompare(value,"6") == 0)
11509 mng_info->write_png_colortype = 7;
11512 (void) ThrowMagickException(exception,
11513 GetMagickModule(),CoderWarning,
11514 "ignoring invalid defined png:color-type",
11517 if (logging != MagickFalse)
11518 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11519 " png:color-type=%d was defined.\n",mng_info->write_png_colortype-1);
11522 /* Check for chunks to be excluded:
11524 * The default is to not exclude any known chunks except for any
11525 * listed in the "unused_chunks" array, above.
11527 * Chunks can be listed for exclusion via a "png:exclude-chunk"
11528 * define (in the image properties or in the image artifacts)
11529 * or via a mng_info member. For convenience, in addition
11530 * to or instead of a comma-separated list of chunks, the
11531 * "exclude-chunk" string can be simply "all" or "none".
11533 * The exclude-chunk define takes priority over the mng_info.
11535 * A "png:include-chunk" define takes priority over both the
11536 * mng_info and the "png:exclude-chunk" define. Like the
11537 * "exclude-chunk" string, it can define "all" or "none" as
11538 * well as a comma-separated list. Chunks that are unknown to
11539 * ImageMagick are always excluded, regardless of their "copy-safe"
11540 * status according to the PNG specification, and even if they
11541 * appear in the "include-chunk" list. Such defines appearing among
11542 * the image options take priority over those found among the image
11545 * Finally, all chunks listed in the "unused_chunks" array are
11546 * automatically excluded, regardless of the other instructions
11549 * if you exclude sRGB but not gAMA (recommended), then sRGB chunk
11550 * will not be written and the gAMA chunk will only be written if it
11551 * is not between .45 and .46, or approximately (1.0/2.2).
11553 * If you exclude tRNS and the image has transparency, the colortype
11554 * is forced to be 4 or 6 (GRAY_ALPHA or RGB_ALPHA).
11556 * The -strip option causes StripImage() to set the png:include-chunk
11557 * artifact to "none,trns,gama".
11560 mng_info->ping_exclude_bKGD=MagickFalse;
11561 mng_info->ping_exclude_cHRM=MagickFalse;
11562 mng_info->ping_exclude_date=MagickFalse;
11563 mng_info->ping_exclude_EXIF=MagickFalse; /* hex-encoded EXIF in zTXt */
11564 mng_info->ping_exclude_gAMA=MagickFalse;
11565 mng_info->ping_exclude_iCCP=MagickFalse;
11566 /* mng_info->ping_exclude_iTXt=MagickFalse; */
11567 mng_info->ping_exclude_oFFs=MagickFalse;
11568 mng_info->ping_exclude_pHYs=MagickFalse;
11569 mng_info->ping_exclude_sRGB=MagickFalse;
11570 mng_info->ping_exclude_tEXt=MagickFalse;
11571 mng_info->ping_exclude_tRNS=MagickFalse;
11572 mng_info->ping_exclude_vpAg=MagickFalse;
11573 mng_info->ping_exclude_zCCP=MagickFalse; /* hex-encoded iCCP in zTXt */
11574 mng_info->ping_exclude_zTXt=MagickFalse;
11576 mng_info->ping_preserve_colormap=MagickFalse;
11578 value=GetImageArtifact(image,"png:preserve-colormap");
11580 value=GetImageOption(image_info,"png:preserve-colormap");
11582 mng_info->ping_preserve_colormap=MagickTrue;
11584 /* Thes compression-level, compression-strategy, and compression-filter
11585 * defines take precedence over values from the -quality option.
11587 value=GetImageArtifact(image,"png:compression-level");
11589 value=GetImageOption(image_info,"png:compression-level");
11592 /* We have to add 1 to everything because 0 is a valid input,
11593 * and we want to use 0 (the default) to mean undefined.
11595 if (LocaleCompare(value,"0") == 0)
11596 mng_info->write_png_compression_level = 1;
11598 else if (LocaleCompare(value,"1") == 0)
11599 mng_info->write_png_compression_level = 2;
11601 else if (LocaleCompare(value,"2") == 0)
11602 mng_info->write_png_compression_level = 3;
11604 else if (LocaleCompare(value,"3") == 0)
11605 mng_info->write_png_compression_level = 4;
11607 else if (LocaleCompare(value,"4") == 0)
11608 mng_info->write_png_compression_level = 5;
11610 else if (LocaleCompare(value,"5") == 0)
11611 mng_info->write_png_compression_level = 6;
11613 else if (LocaleCompare(value,"6") == 0)
11614 mng_info->write_png_compression_level = 7;
11616 else if (LocaleCompare(value,"7") == 0)
11617 mng_info->write_png_compression_level = 8;
11619 else if (LocaleCompare(value,"8") == 0)
11620 mng_info->write_png_compression_level = 9;
11622 else if (LocaleCompare(value,"9") == 0)
11623 mng_info->write_png_compression_level = 10;
11626 (void) ThrowMagickException(exception,
11627 GetMagickModule(),CoderWarning,
11628 "ignoring invalid defined png:compression-level",
11632 value=GetImageArtifact(image,"png:compression-strategy");
11634 value=GetImageOption(image_info,"png:compression-strategy");
11638 if (LocaleCompare(value,"0") == 0)
11639 mng_info->write_png_compression_strategy = Z_DEFAULT_STRATEGY+1;
11641 else if (LocaleCompare(value,"1") == 0)
11642 mng_info->write_png_compression_strategy = Z_FILTERED+1;
11644 else if (LocaleCompare(value,"2") == 0)
11645 mng_info->write_png_compression_strategy = Z_HUFFMAN_ONLY+1;
11647 else if (LocaleCompare(value,"3") == 0)
11648 #ifdef Z_RLE /* Z_RLE was added to zlib-1.2.0 */
11649 mng_info->write_png_compression_strategy = Z_RLE+1;
11651 mng_info->write_png_compression_strategy = Z_DEFAULT_STRATEGY+1;
11654 else if (LocaleCompare(value,"4") == 0)
11655 #ifdef Z_FIXED /* Z_FIXED was added to zlib-1.2.2.2 */
11656 mng_info->write_png_compression_strategy = Z_FIXED+1;
11658 mng_info->write_png_compression_strategy = Z_DEFAULT_STRATEGY+1;
11662 (void) ThrowMagickException(exception,
11663 GetMagickModule(),CoderWarning,
11664 "ignoring invalid defined png:compression-strategy",
11668 value=GetImageArtifact(image,"png:compression-filter");
11670 value=GetImageOption(image_info,"png:compression-filter");
11674 /* To do: combinations of filters allowed by libpng
11675 * masks 0x08 through 0xf8
11677 * Implement this as a comma-separated list of 0,1,2,3,4,5
11678 * where 5 is a special case meaning PNG_ALL_FILTERS.
11681 if (LocaleCompare(value,"0") == 0)
11682 mng_info->write_png_compression_filter = 1;
11684 else if (LocaleCompare(value,"1") == 0)
11685 mng_info->write_png_compression_filter = 2;
11687 else if (LocaleCompare(value,"2") == 0)
11688 mng_info->write_png_compression_filter = 3;
11690 else if (LocaleCompare(value,"3") == 0)
11691 mng_info->write_png_compression_filter = 4;
11693 else if (LocaleCompare(value,"4") == 0)
11694 mng_info->write_png_compression_filter = 5;
11696 else if (LocaleCompare(value,"5") == 0)
11697 mng_info->write_png_compression_filter = 6;
11700 (void) ThrowMagickException(exception,
11701 GetMagickModule(),CoderWarning,
11702 "ignoring invalid defined png:compression-filter",
11706 excluding=MagickFalse;
11708 for (source=0; source<1; source++)
11712 value=GetImageArtifact(image,"png:exclude-chunk");
11715 value=GetImageArtifact(image,"png:exclude-chunks");
11719 value=GetImageOption(image_info,"png:exclude-chunk");
11722 value=GetImageOption(image_info,"png:exclude-chunks");
11731 excluding=MagickTrue;
11733 if (logging != MagickFalse)
11736 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11737 " png:exclude-chunk=%s found in image artifacts.\n", value);
11739 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11740 " png:exclude-chunk=%s found in image properties.\n", value);
11743 last=strlen(value);
11745 for (i=0; i<(int) last; i+=5)
11748 if (LocaleNCompare(value+i,"all",3) == 0)
11750 mng_info->ping_exclude_bKGD=MagickTrue;
11751 mng_info->ping_exclude_cHRM=MagickTrue;
11752 mng_info->ping_exclude_date=MagickTrue;
11753 mng_info->ping_exclude_EXIF=MagickTrue;
11754 mng_info->ping_exclude_gAMA=MagickTrue;
11755 mng_info->ping_exclude_iCCP=MagickTrue;
11756 /* mng_info->ping_exclude_iTXt=MagickTrue; */
11757 mng_info->ping_exclude_oFFs=MagickTrue;
11758 mng_info->ping_exclude_pHYs=MagickTrue;
11759 mng_info->ping_exclude_sRGB=MagickTrue;
11760 mng_info->ping_exclude_tEXt=MagickTrue;
11761 mng_info->ping_exclude_tRNS=MagickTrue;
11762 mng_info->ping_exclude_vpAg=MagickTrue;
11763 mng_info->ping_exclude_zCCP=MagickTrue;
11764 mng_info->ping_exclude_zTXt=MagickTrue;
11768 if (LocaleNCompare(value+i,"none",4) == 0)
11770 mng_info->ping_exclude_bKGD=MagickFalse;
11771 mng_info->ping_exclude_cHRM=MagickFalse;
11772 mng_info->ping_exclude_date=MagickFalse;
11773 mng_info->ping_exclude_EXIF=MagickFalse;
11774 mng_info->ping_exclude_gAMA=MagickFalse;
11775 mng_info->ping_exclude_iCCP=MagickFalse;
11776 /* mng_info->ping_exclude_iTXt=MagickFalse; */
11777 mng_info->ping_exclude_oFFs=MagickFalse;
11778 mng_info->ping_exclude_pHYs=MagickFalse;
11779 mng_info->ping_exclude_sRGB=MagickFalse;
11780 mng_info->ping_exclude_tEXt=MagickFalse;
11781 mng_info->ping_exclude_tRNS=MagickFalse;
11782 mng_info->ping_exclude_vpAg=MagickFalse;
11783 mng_info->ping_exclude_zCCP=MagickFalse;
11784 mng_info->ping_exclude_zTXt=MagickFalse;
11787 if (LocaleNCompare(value+i,"bkgd",4) == 0)
11788 mng_info->ping_exclude_bKGD=MagickTrue;
11790 if (LocaleNCompare(value+i,"chrm",4) == 0)
11791 mng_info->ping_exclude_cHRM=MagickTrue;
11793 if (LocaleNCompare(value+i,"date",4) == 0)
11794 mng_info->ping_exclude_date=MagickTrue;
11796 if (LocaleNCompare(value+i,"exif",4) == 0)
11797 mng_info->ping_exclude_EXIF=MagickTrue;
11799 if (LocaleNCompare(value+i,"gama",4) == 0)
11800 mng_info->ping_exclude_gAMA=MagickTrue;
11802 if (LocaleNCompare(value+i,"iccp",4) == 0)
11803 mng_info->ping_exclude_iCCP=MagickTrue;
11806 if (LocaleNCompare(value+i,"itxt",4) == 0)
11807 mng_info->ping_exclude_iTXt=MagickTrue;
11810 if (LocaleNCompare(value+i,"gama",4) == 0)
11811 mng_info->ping_exclude_gAMA=MagickTrue;
11813 if (LocaleNCompare(value+i,"offs",4) == 0)
11814 mng_info->ping_exclude_oFFs=MagickTrue;
11816 if (LocaleNCompare(value+i,"phys",4) == 0)
11817 mng_info->ping_exclude_pHYs=MagickTrue;
11819 if (LocaleNCompare(value+i,"srgb",4) == 0)
11820 mng_info->ping_exclude_sRGB=MagickTrue;
11822 if (LocaleNCompare(value+i,"text",4) == 0)
11823 mng_info->ping_exclude_tEXt=MagickTrue;
11825 if (LocaleNCompare(value+i,"trns",4) == 0)
11826 mng_info->ping_exclude_tRNS=MagickTrue;
11828 if (LocaleNCompare(value+i,"vpag",4) == 0)
11829 mng_info->ping_exclude_vpAg=MagickTrue;
11831 if (LocaleNCompare(value+i,"zccp",4) == 0)
11832 mng_info->ping_exclude_zCCP=MagickTrue;
11834 if (LocaleNCompare(value+i,"ztxt",4) == 0)
11835 mng_info->ping_exclude_zTXt=MagickTrue;
11841 for (source=0; source<1; source++)
11845 value=GetImageArtifact(image,"png:include-chunk");
11848 value=GetImageArtifact(image,"png:include-chunks");
11852 value=GetImageOption(image_info,"png:include-chunk");
11855 value=GetImageOption(image_info,"png:include-chunks");
11863 excluding=MagickTrue;
11865 if (logging != MagickFalse)
11868 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11869 " png:include-chunk=%s found in image artifacts.\n", value);
11871 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11872 " png:include-chunk=%s found in image properties.\n", value);
11875 last=strlen(value);
11877 for (i=0; i<(int) last; i+=5)
11879 if (LocaleNCompare(value+i,"all",3) == 0)
11881 mng_info->ping_exclude_bKGD=MagickFalse;
11882 mng_info->ping_exclude_cHRM=MagickFalse;
11883 mng_info->ping_exclude_date=MagickFalse;
11884 mng_info->ping_exclude_EXIF=MagickFalse;
11885 mng_info->ping_exclude_gAMA=MagickFalse;
11886 mng_info->ping_exclude_iCCP=MagickFalse;
11887 /* mng_info->ping_exclude_iTXt=MagickFalse; */
11888 mng_info->ping_exclude_oFFs=MagickFalse;
11889 mng_info->ping_exclude_pHYs=MagickFalse;
11890 mng_info->ping_exclude_sRGB=MagickFalse;
11891 mng_info->ping_exclude_tEXt=MagickFalse;
11892 mng_info->ping_exclude_tRNS=MagickFalse;
11893 mng_info->ping_exclude_vpAg=MagickFalse;
11894 mng_info->ping_exclude_zCCP=MagickFalse;
11895 mng_info->ping_exclude_zTXt=MagickFalse;
11899 if (LocaleNCompare(value+i,"none",4) == 0)
11901 mng_info->ping_exclude_bKGD=MagickTrue;
11902 mng_info->ping_exclude_cHRM=MagickTrue;
11903 mng_info->ping_exclude_date=MagickTrue;
11904 mng_info->ping_exclude_EXIF=MagickTrue;
11905 mng_info->ping_exclude_gAMA=MagickTrue;
11906 mng_info->ping_exclude_iCCP=MagickTrue;
11907 /* mng_info->ping_exclude_iTXt=MagickTrue; */
11908 mng_info->ping_exclude_oFFs=MagickTrue;
11909 mng_info->ping_exclude_pHYs=MagickTrue;
11910 mng_info->ping_exclude_sRGB=MagickTrue;
11911 mng_info->ping_exclude_tEXt=MagickTrue;
11912 mng_info->ping_exclude_tRNS=MagickTrue;
11913 mng_info->ping_exclude_vpAg=MagickTrue;
11914 mng_info->ping_exclude_zCCP=MagickTrue;
11915 mng_info->ping_exclude_zTXt=MagickTrue;
11918 if (LocaleNCompare(value+i,"bkgd",4) == 0)
11919 mng_info->ping_exclude_bKGD=MagickFalse;
11921 if (LocaleNCompare(value+i,"chrm",4) == 0)
11922 mng_info->ping_exclude_cHRM=MagickFalse;
11924 if (LocaleNCompare(value+i,"date",4) == 0)
11925 mng_info->ping_exclude_date=MagickFalse;
11927 if (LocaleNCompare(value+i,"exif",4) == 0)
11928 mng_info->ping_exclude_EXIF=MagickFalse;
11930 if (LocaleNCompare(value+i,"gama",4) == 0)
11931 mng_info->ping_exclude_gAMA=MagickFalse;
11933 if (LocaleNCompare(value+i,"iccp",4) == 0)
11934 mng_info->ping_exclude_iCCP=MagickFalse;
11937 if (LocaleNCompare(value+i,"itxt",4) == 0)
11938 mng_info->ping_exclude_iTXt=MagickFalse;
11941 if (LocaleNCompare(value+i,"gama",4) == 0)
11942 mng_info->ping_exclude_gAMA=MagickFalse;
11944 if (LocaleNCompare(value+i,"offs",4) == 0)
11945 mng_info->ping_exclude_oFFs=MagickFalse;
11947 if (LocaleNCompare(value+i,"phys",4) == 0)
11948 mng_info->ping_exclude_pHYs=MagickFalse;
11950 if (LocaleNCompare(value+i,"srgb",4) == 0)
11951 mng_info->ping_exclude_sRGB=MagickFalse;
11953 if (LocaleNCompare(value+i,"text",4) == 0)
11954 mng_info->ping_exclude_tEXt=MagickFalse;
11956 if (LocaleNCompare(value+i,"trns",4) == 0)
11957 mng_info->ping_exclude_tRNS=MagickFalse;
11959 if (LocaleNCompare(value+i,"vpag",4) == 0)
11960 mng_info->ping_exclude_vpAg=MagickFalse;
11962 if (LocaleNCompare(value+i,"zccp",4) == 0)
11963 mng_info->ping_exclude_zCCP=MagickFalse;
11965 if (LocaleNCompare(value+i,"ztxt",4) == 0)
11966 mng_info->ping_exclude_zTXt=MagickFalse;
11972 if (excluding != MagickFalse && logging != MagickFalse)
11974 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11975 " Chunks to be excluded from the output png:");
11976 if (mng_info->ping_exclude_bKGD != MagickFalse)
11977 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11979 if (mng_info->ping_exclude_cHRM != MagickFalse)
11980 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11982 if (mng_info->ping_exclude_date != MagickFalse)
11983 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11985 if (mng_info->ping_exclude_EXIF != MagickFalse)
11986 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11988 if (mng_info->ping_exclude_gAMA != MagickFalse)
11989 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11991 if (mng_info->ping_exclude_iCCP != MagickFalse)
11992 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11995 if (mng_info->ping_exclude_iTXt != MagickFalse)
11996 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11999 if (mng_info->ping_exclude_oFFs != MagickFalse)
12000 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12002 if (mng_info->ping_exclude_pHYs != MagickFalse)
12003 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12005 if (mng_info->ping_exclude_sRGB != MagickFalse)
12006 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12008 if (mng_info->ping_exclude_tEXt != MagickFalse)
12009 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12011 if (mng_info->ping_exclude_tRNS != MagickFalse)
12012 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12014 if (mng_info->ping_exclude_vpAg != MagickFalse)
12015 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12017 if (mng_info->ping_exclude_zCCP != MagickFalse)
12018 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12020 if (mng_info->ping_exclude_zTXt != MagickFalse)
12021 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12025 mng_info->need_blob = MagickTrue;
12027 status=WriteOnePNGImage(mng_info,image_info,image,exception);
12029 MngInfoFreeStruct(mng_info,&have_mng_structure);
12031 if (logging != MagickFalse)
12032 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit WritePNGImage()");
12037 #if defined(JNG_SUPPORTED)
12039 /* Write one JNG image */
12040 static MagickBooleanType WriteOneJNGImage(MngInfo *mng_info,
12041 const ImageInfo *image_info,Image *image,ExceptionInfo *exception)
12062 jng_alpha_compression_method,
12063 jng_alpha_sample_depth,
12071 logging=LogMagickEvent(CoderEvent,GetMagickModule(),
12072 " Enter WriteOneJNGImage()");
12074 blob=(unsigned char *) NULL;
12075 jpeg_image=(Image *) NULL;
12076 jpeg_image_info=(ImageInfo *) NULL;
12079 transparent=image_info->type==GrayscaleMatteType ||
12080 image_info->type==TrueColorMatteType || image->alpha_trait == BlendPixelTrait;
12082 jng_quality=image_info->quality == 0UL ? 75UL : image_info->quality%1000;
12084 jng_alpha_compression_method=image->compression==JPEGCompression? 8 : 0;
12086 jng_alpha_quality=image_info->quality == 0UL ? 75UL :
12087 image_info->quality;
12089 if (jng_alpha_quality >= 1000)
12090 jng_alpha_quality /= 1000;
12096 /* Create JPEG blob, image, and image_info */
12097 if (logging != MagickFalse)
12098 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12099 " Creating jpeg_image_info for alpha.");
12101 jpeg_image_info=(ImageInfo *) CloneImageInfo(image_info);
12103 if (jpeg_image_info == (ImageInfo *) NULL)
12104 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
12106 if (logging != MagickFalse)
12107 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12108 " Creating jpeg_image.");
12110 jpeg_image=SeparateImage(image,AlphaChannel,exception);
12111 if (jpeg_image == (Image *) NULL)
12112 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
12113 (void) CopyMagickString(jpeg_image->magick,"JPEG",MaxTextExtent);
12114 jpeg_image->alpha_trait=UndefinedPixelTrait;
12115 jpeg_image->quality=jng_alpha_quality;
12116 jpeg_image_info->type=GrayscaleType;
12117 (void) SetImageType(jpeg_image,GrayscaleType,exception);
12118 (void) AcquireUniqueFilename(jpeg_image->filename);
12119 (void) FormatLocaleString(jpeg_image_info->filename,MaxTextExtent,
12120 "%s",jpeg_image->filename);
12124 jng_alpha_compression_method=0;
12126 jng_alpha_sample_depth=0;
12129 /* To do: check bit depth of PNG alpha channel */
12131 /* Check if image is grayscale. */
12132 if (image_info->type != TrueColorMatteType && image_info->type !=
12133 TrueColorType && IsImageGray(image,exception))
12136 if (logging != MagickFalse)
12138 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12139 " JNG Quality = %d",(int) jng_quality);
12140 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12141 " JNG Color Type = %d",jng_color_type);
12144 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12145 " JNG Alpha Compression = %d",jng_alpha_compression_method);
12146 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12147 " JNG Alpha Depth = %d",jng_alpha_sample_depth);
12148 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12149 " JNG Alpha Quality = %d",(int) jng_alpha_quality);
12155 if (jng_alpha_compression_method==0)
12160 /* Encode alpha as a grayscale PNG blob */
12161 status=OpenBlob(jpeg_image_info,jpeg_image,WriteBinaryBlobMode,
12163 if (logging != MagickFalse)
12164 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12165 " Creating PNG blob.");
12168 (void) CopyMagickString(jpeg_image_info->magick,"PNG",MaxTextExtent);
12169 (void) CopyMagickString(jpeg_image->magick,"PNG",MaxTextExtent);
12170 jpeg_image_info->interlace=NoInterlace;
12172 /* Exclude all ancillary chunks */
12173 (void) SetImageArtifact(jpeg_image,"png:exclude-chunks","all");
12175 blob=ImageToBlob(jpeg_image_info,jpeg_image,&length,
12178 /* Retrieve sample depth used */
12179 value=GetImageProperty(jpeg_image,"png:bit-depth-written",exception);
12180 if (value != (char *) NULL)
12181 jng_alpha_sample_depth= (unsigned int) value[0];
12185 /* Encode alpha as a grayscale JPEG blob */
12187 status=OpenBlob(jpeg_image_info,jpeg_image,WriteBinaryBlobMode,
12190 (void) CopyMagickString(jpeg_image_info->magick,"JPEG",MaxTextExtent);
12191 (void) CopyMagickString(jpeg_image->magick,"JPEG",MaxTextExtent);
12192 jpeg_image_info->interlace=NoInterlace;
12193 if (logging != MagickFalse)
12194 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12195 " Creating blob.");
12196 blob=ImageToBlob(jpeg_image_info,jpeg_image,&length,
12198 jng_alpha_sample_depth=8;
12200 if (logging != MagickFalse)
12201 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12202 " Successfully read jpeg_image into a blob, length=%.20g.",
12206 /* Destroy JPEG image and image_info */
12207 jpeg_image=DestroyImage(jpeg_image);
12208 (void) RelinquishUniqueFileResource(jpeg_image_info->filename);
12209 jpeg_image_info=DestroyImageInfo(jpeg_image_info);
12212 /* Write JHDR chunk */
12213 (void) WriteBlobMSBULong(image,16L); /* chunk data length=16 */
12214 PNGType(chunk,mng_JHDR);
12215 LogPNGChunk(logging,mng_JHDR,16L);
12216 PNGLong(chunk+4,(png_uint_32) image->columns);
12217 PNGLong(chunk+8,(png_uint_32) image->rows);
12218 chunk[12]=jng_color_type;
12219 chunk[13]=8; /* sample depth */
12220 chunk[14]=8; /*jng_image_compression_method */
12221 chunk[15]=(unsigned char) (image_info->interlace == NoInterlace ? 0 : 8);
12222 chunk[16]=jng_alpha_sample_depth;
12223 chunk[17]=jng_alpha_compression_method;
12224 chunk[18]=0; /*jng_alpha_filter_method */
12225 chunk[19]=0; /*jng_alpha_interlace_method */
12226 (void) WriteBlob(image,20,chunk);
12227 (void) WriteBlobMSBULong(image,crc32(0,chunk,20));
12228 if (logging != MagickFalse)
12230 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12231 " JNG width:%15lu",(unsigned long) image->columns);
12233 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12234 " JNG height:%14lu",(unsigned long) image->rows);
12236 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12237 " JNG color type:%10d",jng_color_type);
12239 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12240 " JNG sample depth:%8d",8);
12242 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12243 " JNG compression:%9d",8);
12245 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12246 " JNG interlace:%11d",0);
12248 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12249 " JNG alpha depth:%9d",jng_alpha_sample_depth);
12251 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12252 " JNG alpha compression:%3d",jng_alpha_compression_method);
12254 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12255 " JNG alpha filter:%8d",0);
12257 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12258 " JNG alpha interlace:%5d",0);
12261 /* Write any JNG-chunk-b profiles */
12262 (void) Magick_png_write_chunk_from_profile(image,"JNG-chunk-b",logging);
12265 Write leading ancillary chunks
12271 Write JNG bKGD chunk
12282 if (jng_color_type == 8 || jng_color_type == 12)
12286 (void) WriteBlobMSBULong(image,(size_t) (num_bytes-4L));
12287 PNGType(chunk,mng_bKGD);
12288 LogPNGChunk(logging,mng_bKGD,(size_t) (num_bytes-4L));
12289 red=ScaleQuantumToChar(image->background_color.red);
12290 green=ScaleQuantumToChar(image->background_color.green);
12291 blue=ScaleQuantumToChar(image->background_color.blue);
12298 (void) WriteBlob(image,(size_t) num_bytes,chunk);
12299 (void) WriteBlobMSBULong(image,crc32(0,chunk,(uInt) num_bytes));
12302 if ((image->colorspace == sRGBColorspace || image->rendering_intent))
12305 Write JNG sRGB chunk
12307 (void) WriteBlobMSBULong(image,1L);
12308 PNGType(chunk,mng_sRGB);
12309 LogPNGChunk(logging,mng_sRGB,1L);
12311 if (image->rendering_intent != UndefinedIntent)
12312 chunk[4]=(unsigned char)
12313 Magick_RenderingIntent_to_PNG_RenderingIntent(
12314 (image->rendering_intent));
12317 chunk[4]=(unsigned char)
12318 Magick_RenderingIntent_to_PNG_RenderingIntent(
12319 (PerceptualIntent));
12321 (void) WriteBlob(image,5,chunk);
12322 (void) WriteBlobMSBULong(image,crc32(0,chunk,5));
12326 if (image->gamma != 0.0)
12329 Write JNG gAMA chunk
12331 (void) WriteBlobMSBULong(image,4L);
12332 PNGType(chunk,mng_gAMA);
12333 LogPNGChunk(logging,mng_gAMA,4L);
12334 PNGLong(chunk+4,(png_uint_32) (100000*image->gamma+0.5));
12335 (void) WriteBlob(image,8,chunk);
12336 (void) WriteBlobMSBULong(image,crc32(0,chunk,8));
12339 if ((mng_info->equal_chrms == MagickFalse) &&
12340 (image->chromaticity.red_primary.x != 0.0))
12346 Write JNG cHRM chunk
12348 (void) WriteBlobMSBULong(image,32L);
12349 PNGType(chunk,mng_cHRM);
12350 LogPNGChunk(logging,mng_cHRM,32L);
12351 primary=image->chromaticity.white_point;
12352 PNGLong(chunk+4,(png_uint_32) (100000*primary.x+0.5));
12353 PNGLong(chunk+8,(png_uint_32) (100000*primary.y+0.5));
12354 primary=image->chromaticity.red_primary;
12355 PNGLong(chunk+12,(png_uint_32) (100000*primary.x+0.5));
12356 PNGLong(chunk+16,(png_uint_32) (100000*primary.y+0.5));
12357 primary=image->chromaticity.green_primary;
12358 PNGLong(chunk+20,(png_uint_32) (100000*primary.x+0.5));
12359 PNGLong(chunk+24,(png_uint_32) (100000*primary.y+0.5));
12360 primary=image->chromaticity.blue_primary;
12361 PNGLong(chunk+28,(png_uint_32) (100000*primary.x+0.5));
12362 PNGLong(chunk+32,(png_uint_32) (100000*primary.y+0.5));
12363 (void) WriteBlob(image,36,chunk);
12364 (void) WriteBlobMSBULong(image,crc32(0,chunk,36));
12368 if (image->resolution.x && image->resolution.y && !mng_info->equal_physs)
12371 Write JNG pHYs chunk
12373 (void) WriteBlobMSBULong(image,9L);
12374 PNGType(chunk,mng_pHYs);
12375 LogPNGChunk(logging,mng_pHYs,9L);
12376 if (image->units == PixelsPerInchResolution)
12378 PNGLong(chunk+4,(png_uint_32)
12379 (image->resolution.x*100.0/2.54+0.5));
12381 PNGLong(chunk+8,(png_uint_32)
12382 (image->resolution.y*100.0/2.54+0.5));
12389 if (image->units == PixelsPerCentimeterResolution)
12391 PNGLong(chunk+4,(png_uint_32)
12392 (image->resolution.x*100.0+0.5));
12394 PNGLong(chunk+8,(png_uint_32)
12395 (image->resolution.y*100.0+0.5));
12402 PNGLong(chunk+4,(png_uint_32) (image->resolution.x+0.5));
12403 PNGLong(chunk+8,(png_uint_32) (image->resolution.y+0.5));
12407 (void) WriteBlob(image,13,chunk);
12408 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
12411 if (mng_info->write_mng == 0 && (image->page.x || image->page.y))
12414 Write JNG oFFs chunk
12416 (void) WriteBlobMSBULong(image,9L);
12417 PNGType(chunk,mng_oFFs);
12418 LogPNGChunk(logging,mng_oFFs,9L);
12419 PNGsLong(chunk+4,(ssize_t) (image->page.x));
12420 PNGsLong(chunk+8,(ssize_t) (image->page.y));
12422 (void) WriteBlob(image,13,chunk);
12423 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
12425 if (mng_info->write_mng == 0 && (image->page.width || image->page.height))
12427 (void) WriteBlobMSBULong(image,9L); /* data length=8 */
12428 PNGType(chunk,mng_vpAg);
12429 LogPNGChunk(logging,mng_vpAg,9L);
12430 PNGLong(chunk+4,(png_uint_32) image->page.width);
12431 PNGLong(chunk+8,(png_uint_32) image->page.height);
12432 chunk[12]=0; /* unit = pixels */
12433 (void) WriteBlob(image,13,chunk);
12434 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
12440 if (jng_alpha_compression_method==0)
12448 /* Write IDAT chunk header */
12449 if (logging != MagickFalse)
12450 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12451 " Write IDAT chunks from blob, length=%.20g.",(double)
12454 /* Copy IDAT chunks */
12457 for (i=8; i<(ssize_t) length; i+=len+12)
12459 len=(*p<<24)|((*(p+1))<<16)|((*(p+2))<<8)|(*(p+3));
12462 if (*(p)==73 && *(p+1)==68 && *(p+2)==65 && *(p+3)==84) /* IDAT */
12464 /* Found an IDAT chunk. */
12465 (void) WriteBlobMSBULong(image,(size_t) len);
12466 LogPNGChunk(logging,mng_IDAT,(size_t) len);
12467 (void) WriteBlob(image,(size_t) len+4,p);
12468 (void) WriteBlobMSBULong(image,
12469 crc32(0,p,(uInt) len+4));
12474 if (logging != MagickFalse)
12475 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12476 " Skipping %c%c%c%c chunk, length=%.20g.",
12477 *(p),*(p+1),*(p+2),*(p+3),(double) len);
12484 /* Write JDAA chunk header */
12485 if (logging != MagickFalse)
12486 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12487 " Write JDAA chunk, length=%.20g.",(double) length);
12488 (void) WriteBlobMSBULong(image,(size_t) length);
12489 PNGType(chunk,mng_JDAA);
12490 LogPNGChunk(logging,mng_JDAA,length);
12491 /* Write JDAT chunk(s) data */
12492 (void) WriteBlob(image,4,chunk);
12493 (void) WriteBlob(image,length,blob);
12494 (void) WriteBlobMSBULong(image,crc32(crc32(0,chunk,4),blob,
12497 blob=(unsigned char *) RelinquishMagickMemory(blob);
12500 /* Encode image as a JPEG blob */
12501 if (logging != MagickFalse)
12502 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12503 " Creating jpeg_image_info.");
12504 jpeg_image_info=(ImageInfo *) CloneImageInfo(image_info);
12505 if (jpeg_image_info == (ImageInfo *) NULL)
12506 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
12508 if (logging != MagickFalse)
12509 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12510 " Creating jpeg_image.");
12512 jpeg_image=CloneImage(image,0,0,MagickTrue,exception);
12513 if (jpeg_image == (Image *) NULL)
12514 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
12515 (void) CopyMagickString(jpeg_image->magick,"JPEG",MaxTextExtent);
12517 (void) AcquireUniqueFilename(jpeg_image->filename);
12518 (void) FormatLocaleString(jpeg_image_info->filename,MaxTextExtent,"%s",
12519 jpeg_image->filename);
12521 status=OpenBlob(jpeg_image_info,jpeg_image,WriteBinaryBlobMode,
12524 if (logging != MagickFalse)
12525 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12526 " Created jpeg_image, %.20g x %.20g.",(double) jpeg_image->columns,
12527 (double) jpeg_image->rows);
12529 if (jng_color_type == 8 || jng_color_type == 12)
12530 jpeg_image_info->type=GrayscaleType;
12532 jpeg_image_info->quality=jng_quality;
12533 jpeg_image->quality=jng_quality;
12534 (void) CopyMagickString(jpeg_image_info->magick,"JPEG",MaxTextExtent);
12535 (void) CopyMagickString(jpeg_image->magick,"JPEG",MaxTextExtent);
12537 if (logging != MagickFalse)
12538 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12539 " Creating blob.");
12541 blob=ImageToBlob(jpeg_image_info,jpeg_image,&length,exception);
12543 if (logging != MagickFalse)
12545 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12546 " Successfully read jpeg_image into a blob, length=%.20g.",
12549 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12550 " Write JDAT chunk, length=%.20g.",(double) length);
12553 /* Write JDAT chunk(s) */
12554 (void) WriteBlobMSBULong(image,(size_t) length);
12555 PNGType(chunk,mng_JDAT);
12556 LogPNGChunk(logging,mng_JDAT,length);
12557 (void) WriteBlob(image,4,chunk);
12558 (void) WriteBlob(image,length,blob);
12559 (void) WriteBlobMSBULong(image,crc32(crc32(0,chunk,4),blob,(uInt) length));
12561 jpeg_image=DestroyImage(jpeg_image);
12562 (void) RelinquishUniqueFileResource(jpeg_image_info->filename);
12563 jpeg_image_info=DestroyImageInfo(jpeg_image_info);
12564 blob=(unsigned char *) RelinquishMagickMemory(blob);
12566 /* Write any JNG-chunk-e profiles */
12567 (void) Magick_png_write_chunk_from_profile(image,"JNG-chunk-e",logging);
12569 /* Write IEND chunk */
12570 (void) WriteBlobMSBULong(image,0L);
12571 PNGType(chunk,mng_IEND);
12572 LogPNGChunk(logging,mng_IEND,0);
12573 (void) WriteBlob(image,4,chunk);
12574 (void) WriteBlobMSBULong(image,crc32(0,chunk,4));
12576 if (logging != MagickFalse)
12577 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12578 " exit WriteOneJNGImage()");
12585 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12589 % W r i t e J N G I m a g e %
12593 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12595 % WriteJNGImage() writes a JPEG Network Graphics (JNG) image file.
12597 % JNG support written by Glenn Randers-Pehrson, glennrp@image...
12599 % The format of the WriteJNGImage method is:
12601 % MagickBooleanType WriteJNGImage(const ImageInfo *image_info,
12602 % Image *image,ExceptionInfo *exception)
12604 % A description of each parameter follows:
12606 % o image_info: the image info.
12608 % o image: The image.
12610 % o exception: return any errors or warnings in this structure.
12612 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12614 static MagickBooleanType WriteJNGImage(const ImageInfo *image_info,Image *image,
12615 ExceptionInfo *exception)
12618 have_mng_structure,
12628 assert(image_info != (const ImageInfo *) NULL);
12629 assert(image_info->signature == MagickSignature);
12630 assert(image != (Image *) NULL);
12631 assert(image->signature == MagickSignature);
12632 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
12633 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter WriteJNGImage()");
12634 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
12635 if (status == MagickFalse)
12639 Allocate a MngInfo structure.
12641 have_mng_structure=MagickFalse;
12642 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
12643 if (mng_info == (MngInfo *) NULL)
12644 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
12646 Initialize members of the MngInfo structure.
12648 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
12649 mng_info->image=image;
12650 have_mng_structure=MagickTrue;
12652 (void) WriteBlob(image,8,(const unsigned char *) "\213JNG\r\n\032\n");
12654 status=WriteOneJNGImage(mng_info,image_info,image,exception);
12655 (void) CloseBlob(image);
12657 (void) CatchImageException(image);
12658 MngInfoFreeStruct(mng_info,&have_mng_structure);
12659 if (logging != MagickFalse)
12660 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit WriteJNGImage()");
12665 static MagickBooleanType WriteMNGImage(const ImageInfo *image_info,Image *image,
12666 ExceptionInfo *exception)
12675 have_mng_structure,
12678 volatile MagickBooleanType
12690 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
12691 defined(PNG_MNG_FEATURES_SUPPORTED)
12694 all_images_are_gray,
12704 volatile unsigned int
12715 #if (PNG_LIBPNG_VER < 10200)
12716 if (image_info->verbose)
12717 printf("Your PNG library (libpng-%s) is rather old.\n",
12718 PNG_LIBPNG_VER_STRING);
12724 assert(image_info != (const ImageInfo *) NULL);
12725 assert(image_info->signature == MagickSignature);
12726 assert(image != (Image *) NULL);
12727 assert(image->signature == MagickSignature);
12728 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
12729 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter WriteMNGImage()");
12730 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
12731 if (status == MagickFalse)
12735 Allocate a MngInfo structure.
12737 have_mng_structure=MagickFalse;
12738 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
12739 if (mng_info == (MngInfo *) NULL)
12740 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
12742 Initialize members of the MngInfo structure.
12744 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
12745 mng_info->image=image;
12746 have_mng_structure=MagickTrue;
12747 write_mng=LocaleCompare(image_info->magick,"MNG") == 0;
12750 * See if user has requested a specific PNG subformat to be used
12751 * for all of the PNGs in the MNG being written, e.g.,
12753 * convert *.png png8:animation.mng
12755 * To do: check -define png:bit_depth and png:color_type as well,
12756 * or perhaps use mng:bit_depth and mng:color_type instead for
12760 mng_info->write_png8=LocaleCompare(image_info->magick,"PNG8") == 0;
12761 mng_info->write_png24=LocaleCompare(image_info->magick,"PNG24") == 0;
12762 mng_info->write_png32=LocaleCompare(image_info->magick,"PNG32") == 0;
12764 write_jng=MagickFalse;
12765 if (image_info->compression == JPEGCompression)
12766 write_jng=MagickTrue;
12768 mng_info->adjoin=image_info->adjoin &&
12769 (GetNextImageInList(image) != (Image *) NULL) && write_mng;
12771 if (logging != MagickFalse)
12773 /* Log some info about the input */
12777 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12778 " Checking input image(s)");
12780 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12781 " Image_info depth: %.20g",(double) image_info->depth);
12783 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12784 " Type: %d",image_info->type);
12787 for (p=image; p != (Image *) NULL; p=GetNextImageInList(p))
12789 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12790 " Scene: %.20g",(double) scene++);
12792 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12793 " Image depth: %.20g",(double) p->depth);
12795 if (p->alpha_trait == BlendPixelTrait)
12796 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12800 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12803 if (p->storage_class == PseudoClass)
12804 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12805 " Storage class: PseudoClass");
12808 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12809 " Storage class: DirectClass");
12812 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12813 " Number of colors: %.20g",(double) p->colors);
12816 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12817 " Number of colors: unspecified");
12819 if (mng_info->adjoin == MagickFalse)
12824 use_global_plte=MagickFalse;
12825 all_images_are_gray=MagickFalse;
12826 #ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
12827 need_local_plte=MagickTrue;
12829 need_defi=MagickFalse;
12830 need_matte=MagickFalse;
12831 mng_info->framing_mode=1;
12832 mng_info->old_framing_mode=1;
12835 if (image_info->page != (char *) NULL)
12838 Determine image bounding box.
12840 SetGeometry(image,&mng_info->page);
12841 (void) ParseMetaGeometry(image_info->page,&mng_info->page.x,
12842 &mng_info->page.y,&mng_info->page.width,&mng_info->page.height);
12854 mng_info->page=image->page;
12855 need_geom=MagickTrue;
12856 if (mng_info->page.width || mng_info->page.height)
12857 need_geom=MagickFalse;
12859 Check all the scenes.
12861 initial_delay=image->delay;
12862 need_iterations=MagickFalse;
12863 mng_info->equal_chrms=image->chromaticity.red_primary.x != 0.0;
12864 mng_info->equal_physs=MagickTrue,
12865 mng_info->equal_gammas=MagickTrue;
12866 mng_info->equal_srgbs=MagickTrue;
12867 mng_info->equal_backgrounds=MagickTrue;
12869 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
12870 defined(PNG_MNG_FEATURES_SUPPORTED)
12871 all_images_are_gray=MagickTrue;
12872 mng_info->equal_palettes=MagickFalse;
12873 need_local_plte=MagickFalse;
12875 for (next_image=image; next_image != (Image *) NULL; )
12879 if ((next_image->columns+next_image->page.x) > mng_info->page.width)
12880 mng_info->page.width=next_image->columns+next_image->page.x;
12882 if ((next_image->rows+next_image->page.y) > mng_info->page.height)
12883 mng_info->page.height=next_image->rows+next_image->page.y;
12886 if (next_image->page.x || next_image->page.y)
12887 need_defi=MagickTrue;
12889 if (next_image->alpha_trait == BlendPixelTrait)
12890 need_matte=MagickTrue;
12892 if ((int) next_image->dispose >= BackgroundDispose)
12893 if ((next_image->alpha_trait == BlendPixelTrait) ||
12894 next_image->page.x || next_image->page.y ||
12895 ((next_image->columns < mng_info->page.width) &&
12896 (next_image->rows < mng_info->page.height)))
12897 mng_info->need_fram=MagickTrue;
12899 if (next_image->iterations)
12900 need_iterations=MagickTrue;
12902 final_delay=next_image->delay;
12904 if (final_delay != initial_delay || final_delay > 1UL*
12905 next_image->ticks_per_second)
12906 mng_info->need_fram=1;
12908 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
12909 defined(PNG_MNG_FEATURES_SUPPORTED)
12911 check for global palette possibility.
12913 if (image->alpha_trait == BlendPixelTrait)
12914 need_local_plte=MagickTrue;
12916 if (need_local_plte == 0)
12918 if (IsImageGray(image,exception) == MagickFalse)
12919 all_images_are_gray=MagickFalse;
12920 mng_info->equal_palettes=PalettesAreEqual(image,next_image);
12921 if (use_global_plte == 0)
12922 use_global_plte=mng_info->equal_palettes;
12923 need_local_plte=!mng_info->equal_palettes;
12926 if (GetNextImageInList(next_image) != (Image *) NULL)
12928 if (next_image->background_color.red !=
12929 next_image->next->background_color.red ||
12930 next_image->background_color.green !=
12931 next_image->next->background_color.green ||
12932 next_image->background_color.blue !=
12933 next_image->next->background_color.blue)
12934 mng_info->equal_backgrounds=MagickFalse;
12936 if (next_image->gamma != next_image->next->gamma)
12937 mng_info->equal_gammas=MagickFalse;
12939 if (next_image->rendering_intent !=
12940 next_image->next->rendering_intent)
12941 mng_info->equal_srgbs=MagickFalse;
12943 if ((next_image->units != next_image->next->units) ||
12944 (next_image->resolution.x != next_image->next->resolution.x) ||
12945 (next_image->resolution.y != next_image->next->resolution.y))
12946 mng_info->equal_physs=MagickFalse;
12948 if (mng_info->equal_chrms)
12950 if (next_image->chromaticity.red_primary.x !=
12951 next_image->next->chromaticity.red_primary.x ||
12952 next_image->chromaticity.red_primary.y !=
12953 next_image->next->chromaticity.red_primary.y ||
12954 next_image->chromaticity.green_primary.x !=
12955 next_image->next->chromaticity.green_primary.x ||
12956 next_image->chromaticity.green_primary.y !=
12957 next_image->next->chromaticity.green_primary.y ||
12958 next_image->chromaticity.blue_primary.x !=
12959 next_image->next->chromaticity.blue_primary.x ||
12960 next_image->chromaticity.blue_primary.y !=
12961 next_image->next->chromaticity.blue_primary.y ||
12962 next_image->chromaticity.white_point.x !=
12963 next_image->next->chromaticity.white_point.x ||
12964 next_image->chromaticity.white_point.y !=
12965 next_image->next->chromaticity.white_point.y)
12966 mng_info->equal_chrms=MagickFalse;
12970 next_image=GetNextImageInList(next_image);
12972 if (image_count < 2)
12974 mng_info->equal_backgrounds=MagickFalse;
12975 mng_info->equal_chrms=MagickFalse;
12976 mng_info->equal_gammas=MagickFalse;
12977 mng_info->equal_srgbs=MagickFalse;
12978 mng_info->equal_physs=MagickFalse;
12979 use_global_plte=MagickFalse;
12980 #ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
12981 need_local_plte=MagickTrue;
12983 need_iterations=MagickFalse;
12986 if (mng_info->need_fram == MagickFalse)
12989 Only certain framing rates 100/n are exactly representable without
12990 the FRAM chunk but we'll allow some slop in VLC files
12992 if (final_delay == 0)
12994 if (need_iterations != MagickFalse)
12997 It's probably a GIF with loop; don't run it *too* fast.
12999 if (mng_info->adjoin)
13002 (void) ThrowMagickException(exception,GetMagickModule(),
13004 "input has zero delay between all frames; assuming",
13009 mng_info->ticks_per_second=0;
13011 if (final_delay != 0)
13012 mng_info->ticks_per_second=(png_uint_32)
13013 (image->ticks_per_second/final_delay);
13014 if (final_delay > 50)
13015 mng_info->ticks_per_second=2;
13017 if (final_delay > 75)
13018 mng_info->ticks_per_second=1;
13020 if (final_delay > 125)
13021 mng_info->need_fram=MagickTrue;
13023 if (need_defi && final_delay > 2 && (final_delay != 4) &&
13024 (final_delay != 5) && (final_delay != 10) && (final_delay != 20) &&
13025 (final_delay != 25) && (final_delay != 50) && (final_delay !=
13026 1UL*image->ticks_per_second))
13027 mng_info->need_fram=MagickTrue; /* make it exact; cannot be VLC */
13030 if (mng_info->need_fram != MagickFalse)
13031 mng_info->ticks_per_second=1UL*image->ticks_per_second;
13033 If pseudocolor, we should also check to see if all the
13034 palettes are identical and write a global PLTE if they are.
13038 Write the MNG version 1.0 signature and MHDR chunk.
13040 (void) WriteBlob(image,8,(const unsigned char *) "\212MNG\r\n\032\n");
13041 (void) WriteBlobMSBULong(image,28L); /* chunk data length=28 */
13042 PNGType(chunk,mng_MHDR);
13043 LogPNGChunk(logging,mng_MHDR,28L);
13044 PNGLong(chunk+4,(png_uint_32) mng_info->page.width);
13045 PNGLong(chunk+8,(png_uint_32) mng_info->page.height);
13046 PNGLong(chunk+12,mng_info->ticks_per_second);
13047 PNGLong(chunk+16,0L); /* layer count=unknown */
13048 PNGLong(chunk+20,0L); /* frame count=unknown */
13049 PNGLong(chunk+24,0L); /* play time=unknown */
13054 if (need_defi || mng_info->need_fram || use_global_plte)
13055 PNGLong(chunk+28,27L); /* simplicity=LC+JNG */
13058 PNGLong(chunk+28,25L); /* simplicity=VLC+JNG */
13063 if (need_defi || mng_info->need_fram || use_global_plte)
13064 PNGLong(chunk+28,19L); /* simplicity=LC+JNG, no transparency */
13067 PNGLong(chunk+28,17L); /* simplicity=VLC+JNG, no transparency */
13075 if (need_defi || mng_info->need_fram || use_global_plte)
13076 PNGLong(chunk+28,11L); /* simplicity=LC */
13079 PNGLong(chunk+28,9L); /* simplicity=VLC */
13084 if (need_defi || mng_info->need_fram || use_global_plte)
13085 PNGLong(chunk+28,3L); /* simplicity=LC, no transparency */
13088 PNGLong(chunk+28,1L); /* simplicity=VLC, no transparency */
13091 (void) WriteBlob(image,32,chunk);
13092 (void) WriteBlobMSBULong(image,crc32(0,chunk,32));
13093 option=GetImageOption(image_info,"mng:need-cacheoff");
13094 if (option != (const char *) NULL)
13100 Write "nEED CACHEOFF" to turn playback caching off for streaming MNG.
13102 PNGType(chunk,mng_nEED);
13103 length=CopyMagickString((char *) chunk+4,"CACHEOFF",20);
13104 (void) WriteBlobMSBULong(image,(size_t) length);
13105 LogPNGChunk(logging,mng_nEED,(size_t) length);
13107 (void) WriteBlob(image,length,chunk);
13108 (void) WriteBlobMSBULong(image,crc32(0,chunk,(uInt) length));
13110 if ((GetPreviousImageInList(image) == (Image *) NULL) &&
13111 (GetNextImageInList(image) != (Image *) NULL) &&
13112 (image->iterations != 1))
13115 Write MNG TERM chunk
13117 (void) WriteBlobMSBULong(image,10L); /* data length=10 */
13118 PNGType(chunk,mng_TERM);
13119 LogPNGChunk(logging,mng_TERM,10L);
13120 chunk[4]=3; /* repeat animation */
13121 chunk[5]=0; /* show last frame when done */
13122 PNGLong(chunk+6,(png_uint_32) (mng_info->ticks_per_second*
13123 final_delay/MagickMax(image->ticks_per_second,1)));
13125 if (image->iterations == 0)
13126 PNGLong(chunk+10,PNG_UINT_31_MAX);
13129 PNGLong(chunk+10,(png_uint_32) image->iterations);
13131 if (logging != MagickFalse)
13133 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
13134 " TERM delay: %.20g",(double) (mng_info->ticks_per_second*
13135 final_delay/MagickMax(image->ticks_per_second,1)));
13137 if (image->iterations == 0)
13138 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
13139 " TERM iterations: %.20g",(double) PNG_UINT_31_MAX);
13142 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
13143 " Image iterations: %.20g",(double) image->iterations);
13145 (void) WriteBlob(image,14,chunk);
13146 (void) WriteBlobMSBULong(image,crc32(0,chunk,14));
13149 To do: check for cHRM+gAMA == sRGB, and write sRGB instead.
13151 if ((image->colorspace == sRGBColorspace || image->rendering_intent) &&
13152 mng_info->equal_srgbs)
13155 Write MNG sRGB chunk
13157 (void) WriteBlobMSBULong(image,1L);
13158 PNGType(chunk,mng_sRGB);
13159 LogPNGChunk(logging,mng_sRGB,1L);
13161 if (image->rendering_intent != UndefinedIntent)
13162 chunk[4]=(unsigned char)
13163 Magick_RenderingIntent_to_PNG_RenderingIntent(
13164 (image->rendering_intent));
13167 chunk[4]=(unsigned char)
13168 Magick_RenderingIntent_to_PNG_RenderingIntent(
13169 (PerceptualIntent));
13171 (void) WriteBlob(image,5,chunk);
13172 (void) WriteBlobMSBULong(image,crc32(0,chunk,5));
13173 mng_info->have_write_global_srgb=MagickTrue;
13178 if (image->gamma && mng_info->equal_gammas)
13181 Write MNG gAMA chunk
13183 (void) WriteBlobMSBULong(image,4L);
13184 PNGType(chunk,mng_gAMA);
13185 LogPNGChunk(logging,mng_gAMA,4L);
13186 PNGLong(chunk+4,(png_uint_32) (100000*image->gamma+0.5));
13187 (void) WriteBlob(image,8,chunk);
13188 (void) WriteBlobMSBULong(image,crc32(0,chunk,8));
13189 mng_info->have_write_global_gama=MagickTrue;
13191 if (mng_info->equal_chrms)
13197 Write MNG cHRM chunk
13199 (void) WriteBlobMSBULong(image,32L);
13200 PNGType(chunk,mng_cHRM);
13201 LogPNGChunk(logging,mng_cHRM,32L);
13202 primary=image->chromaticity.white_point;
13203 PNGLong(chunk+4,(png_uint_32) (100000*primary.x+0.5));
13204 PNGLong(chunk+8,(png_uint_32) (100000*primary.y+0.5));
13205 primary=image->chromaticity.red_primary;
13206 PNGLong(chunk+12,(png_uint_32) (100000*primary.x+0.5));
13207 PNGLong(chunk+16,(png_uint_32) (100000*primary.y+0.5));
13208 primary=image->chromaticity.green_primary;
13209 PNGLong(chunk+20,(png_uint_32) (100000*primary.x+0.5));
13210 PNGLong(chunk+24,(png_uint_32) (100000*primary.y+0.5));
13211 primary=image->chromaticity.blue_primary;
13212 PNGLong(chunk+28,(png_uint_32) (100000*primary.x+0.5));
13213 PNGLong(chunk+32,(png_uint_32) (100000*primary.y+0.5));
13214 (void) WriteBlob(image,36,chunk);
13215 (void) WriteBlobMSBULong(image,crc32(0,chunk,36));
13216 mng_info->have_write_global_chrm=MagickTrue;
13219 if (image->resolution.x && image->resolution.y && mng_info->equal_physs)
13222 Write MNG pHYs chunk
13224 (void) WriteBlobMSBULong(image,9L);
13225 PNGType(chunk,mng_pHYs);
13226 LogPNGChunk(logging,mng_pHYs,9L);
13228 if (image->units == PixelsPerInchResolution)
13230 PNGLong(chunk+4,(png_uint_32)
13231 (image->resolution.x*100.0/2.54+0.5));
13233 PNGLong(chunk+8,(png_uint_32)
13234 (image->resolution.y*100.0/2.54+0.5));
13241 if (image->units == PixelsPerCentimeterResolution)
13243 PNGLong(chunk+4,(png_uint_32)
13244 (image->resolution.x*100.0+0.5));
13246 PNGLong(chunk+8,(png_uint_32)
13247 (image->resolution.y*100.0+0.5));
13254 PNGLong(chunk+4,(png_uint_32) (image->resolution.x+0.5));
13255 PNGLong(chunk+8,(png_uint_32) (image->resolution.y+0.5));
13259 (void) WriteBlob(image,13,chunk);
13260 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
13263 Write MNG BACK chunk and global bKGD chunk, if the image is transparent
13264 or does not cover the entire frame.
13266 if (write_mng && ((image->alpha_trait == BlendPixelTrait) ||
13267 image->page.x > 0 || image->page.y > 0 || (image->page.width &&
13268 (image->page.width+image->page.x < mng_info->page.width))
13269 || (image->page.height && (image->page.height+image->page.y
13270 < mng_info->page.height))))
13272 (void) WriteBlobMSBULong(image,6L);
13273 PNGType(chunk,mng_BACK);
13274 LogPNGChunk(logging,mng_BACK,6L);
13275 red=ScaleQuantumToShort(image->background_color.red);
13276 green=ScaleQuantumToShort(image->background_color.green);
13277 blue=ScaleQuantumToShort(image->background_color.blue);
13278 PNGShort(chunk+4,red);
13279 PNGShort(chunk+6,green);
13280 PNGShort(chunk+8,blue);
13281 (void) WriteBlob(image,10,chunk);
13282 (void) WriteBlobMSBULong(image,crc32(0,chunk,10));
13283 if (mng_info->equal_backgrounds)
13285 (void) WriteBlobMSBULong(image,6L);
13286 PNGType(chunk,mng_bKGD);
13287 LogPNGChunk(logging,mng_bKGD,6L);
13288 (void) WriteBlob(image,10,chunk);
13289 (void) WriteBlobMSBULong(image,crc32(0,chunk,10));
13293 #ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
13294 if ((need_local_plte == MagickFalse) &&
13295 (image->storage_class == PseudoClass) &&
13296 (all_images_are_gray == MagickFalse))
13302 Write MNG PLTE chunk
13304 data_length=3*image->colors;
13305 (void) WriteBlobMSBULong(image,data_length);
13306 PNGType(chunk,mng_PLTE);
13307 LogPNGChunk(logging,mng_PLTE,data_length);
13309 for (i=0; i < (ssize_t) image->colors; i++)
13311 chunk[4+i*3]=(unsigned char) (ScaleQuantumToChar(
13312 image->colormap[i].red) & 0xff);
13313 chunk[5+i*3]=(unsigned char) (ScaleQuantumToChar(
13314 image->colormap[i].green) & 0xff);
13315 chunk[6+i*3]=(unsigned char) (ScaleQuantumToChar(
13316 image->colormap[i].blue) & 0xff);
13319 (void) WriteBlob(image,data_length+4,chunk);
13320 (void) WriteBlobMSBULong(image,crc32(0,chunk,(uInt) (data_length+4)));
13321 mng_info->have_write_global_plte=MagickTrue;
13327 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
13328 defined(PNG_MNG_FEATURES_SUPPORTED)
13329 mng_info->equal_palettes=MagickFalse;
13333 if (mng_info->adjoin)
13335 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
13336 defined(PNG_MNG_FEATURES_SUPPORTED)
13338 If we aren't using a global palette for the entire MNG, check to
13339 see if we can use one for two or more consecutive images.
13341 if (need_local_plte && use_global_plte && !all_images_are_gray)
13343 if (mng_info->IsPalette)
13346 When equal_palettes is true, this image has the same palette
13347 as the previous PseudoClass image
13349 mng_info->have_write_global_plte=mng_info->equal_palettes;
13350 mng_info->equal_palettes=PalettesAreEqual(image,image->next);
13351 if (mng_info->equal_palettes && !mng_info->have_write_global_plte)
13354 Write MNG PLTE chunk
13359 data_length=3*image->colors;
13360 (void) WriteBlobMSBULong(image,data_length);
13361 PNGType(chunk,mng_PLTE);
13362 LogPNGChunk(logging,mng_PLTE,data_length);
13364 for (i=0; i < (ssize_t) image->colors; i++)
13366 chunk[4+i*3]=ScaleQuantumToChar(image->colormap[i].red);
13367 chunk[5+i*3]=ScaleQuantumToChar(image->colormap[i].green);
13368 chunk[6+i*3]=ScaleQuantumToChar(image->colormap[i].blue);
13371 (void) WriteBlob(image,data_length+4,chunk);
13372 (void) WriteBlobMSBULong(image,crc32(0,chunk,
13373 (uInt) (data_length+4)));
13374 mng_info->have_write_global_plte=MagickTrue;
13378 mng_info->have_write_global_plte=MagickFalse;
13389 previous_x=mng_info->page.x;
13390 previous_y=mng_info->page.y;
13397 mng_info->page=image->page;
13398 if ((mng_info->page.x != previous_x) ||
13399 (mng_info->page.y != previous_y))
13401 (void) WriteBlobMSBULong(image,12L); /* data length=12 */
13402 PNGType(chunk,mng_DEFI);
13403 LogPNGChunk(logging,mng_DEFI,12L);
13404 chunk[4]=0; /* object 0 MSB */
13405 chunk[5]=0; /* object 0 LSB */
13406 chunk[6]=0; /* visible */
13407 chunk[7]=0; /* abstract */
13408 PNGLong(chunk+8,(png_uint_32) mng_info->page.x);
13409 PNGLong(chunk+12,(png_uint_32) mng_info->page.y);
13410 (void) WriteBlob(image,16,chunk);
13411 (void) WriteBlobMSBULong(image,crc32(0,chunk,16));
13416 mng_info->write_mng=write_mng;
13418 if ((int) image->dispose >= 3)
13419 mng_info->framing_mode=3;
13421 if (mng_info->need_fram && mng_info->adjoin &&
13422 ((image->delay != mng_info->delay) ||
13423 (mng_info->framing_mode != mng_info->old_framing_mode)))
13425 if (image->delay == mng_info->delay)
13428 Write a MNG FRAM chunk with the new framing mode.
13430 (void) WriteBlobMSBULong(image,1L); /* data length=1 */
13431 PNGType(chunk,mng_FRAM);
13432 LogPNGChunk(logging,mng_FRAM,1L);
13433 chunk[4]=(unsigned char) mng_info->framing_mode;
13434 (void) WriteBlob(image,5,chunk);
13435 (void) WriteBlobMSBULong(image,crc32(0,chunk,5));
13440 Write a MNG FRAM chunk with the delay.
13442 (void) WriteBlobMSBULong(image,10L); /* data length=10 */
13443 PNGType(chunk,mng_FRAM);
13444 LogPNGChunk(logging,mng_FRAM,10L);
13445 chunk[4]=(unsigned char) mng_info->framing_mode;
13446 chunk[5]=0; /* frame name separator (no name) */
13447 chunk[6]=2; /* flag for changing default delay */
13448 chunk[7]=0; /* flag for changing frame timeout */
13449 chunk[8]=0; /* flag for changing frame clipping */
13450 chunk[9]=0; /* flag for changing frame sync_id */
13451 PNGLong(chunk+10,(png_uint_32)
13452 ((mng_info->ticks_per_second*
13453 image->delay)/MagickMax(image->ticks_per_second,1)));
13454 (void) WriteBlob(image,14,chunk);
13455 (void) WriteBlobMSBULong(image,crc32(0,chunk,14));
13456 mng_info->delay=(png_uint_32) image->delay;
13458 mng_info->old_framing_mode=mng_info->framing_mode;
13461 #if defined(JNG_SUPPORTED)
13462 if (image_info->compression == JPEGCompression)
13467 if (logging != MagickFalse)
13468 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
13469 " Writing JNG object.");
13470 /* To do: specify the desired alpha compression method. */
13471 write_info=CloneImageInfo(image_info);
13472 write_info->compression=UndefinedCompression;
13473 status=WriteOneJNGImage(mng_info,write_info,image,exception);
13474 write_info=DestroyImageInfo(write_info);
13479 if (logging != MagickFalse)
13480 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
13481 " Writing PNG object.");
13483 mng_info->need_blob = MagickFalse;
13484 mng_info->ping_preserve_colormap = MagickFalse;
13486 /* We don't want any ancillary chunks written */
13487 mng_info->ping_exclude_bKGD=MagickTrue;
13488 mng_info->ping_exclude_cHRM=MagickTrue;
13489 mng_info->ping_exclude_date=MagickTrue;
13490 mng_info->ping_exclude_EXIF=MagickTrue;
13491 mng_info->ping_exclude_gAMA=MagickTrue;
13492 mng_info->ping_exclude_iCCP=MagickTrue;
13493 /* mng_info->ping_exclude_iTXt=MagickTrue; */
13494 mng_info->ping_exclude_oFFs=MagickTrue;
13495 mng_info->ping_exclude_pHYs=MagickTrue;
13496 mng_info->ping_exclude_sRGB=MagickTrue;
13497 mng_info->ping_exclude_tEXt=MagickTrue;
13498 mng_info->ping_exclude_tRNS=MagickTrue;
13499 mng_info->ping_exclude_vpAg=MagickTrue;
13500 mng_info->ping_exclude_zCCP=MagickTrue;
13501 mng_info->ping_exclude_zTXt=MagickTrue;
13503 status=WriteOnePNGImage(mng_info,image_info,image,exception);
13506 if (status == MagickFalse)
13508 MngInfoFreeStruct(mng_info,&have_mng_structure);
13509 (void) CloseBlob(image);
13510 return(MagickFalse);
13512 (void) CatchImageException(image);
13513 if (GetNextImageInList(image) == (Image *) NULL)
13515 image=SyncNextImageInList(image);
13516 status=SetImageProgress(image,SaveImagesTag,scene++,
13517 GetImageListLength(image));
13519 if (status == MagickFalse)
13522 } while (mng_info->adjoin);
13526 while (GetPreviousImageInList(image) != (Image *) NULL)
13527 image=GetPreviousImageInList(image);
13529 Write the MEND chunk.
13531 (void) WriteBlobMSBULong(image,0x00000000L);
13532 PNGType(chunk,mng_MEND);
13533 LogPNGChunk(logging,mng_MEND,0L);
13534 (void) WriteBlob(image,4,chunk);
13535 (void) WriteBlobMSBULong(image,crc32(0,chunk,4));
13538 Relinquish resources.
13540 (void) CloseBlob(image);
13541 MngInfoFreeStruct(mng_info,&have_mng_structure);
13543 if (logging != MagickFalse)
13544 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit WriteMNGImage()");
13546 return(MagickTrue);
13548 #else /* PNG_LIBPNG_VER > 10011 */
13550 static MagickBooleanType WritePNGImage(const ImageInfo *image_info,Image *image)
13553 printf("Your PNG library is too old: You have libpng-%s\n",
13554 PNG_LIBPNG_VER_STRING);
13556 ThrowBinaryException(CoderError,"PNG library is too old",
13557 image_info->filename);
13560 static MagickBooleanType WriteMNGImage(const ImageInfo *image_info,Image *image)
13562 return(WritePNGImage(image_info,image));
13564 #endif /* PNG_LIBPNG_VER > 10011 */