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,
885 #ifdef MNG_BASI_SUPPORTED
893 basi_compression_method,
895 basi_interlace_method,
918 /* Added at version 6.6.6-7 */
926 /* ping_exclude_iTXt, */
933 ping_exclude_zCCP, /* hex-encoded iCCP */
935 ping_preserve_colormap;
941 Forward declarations.
943 static MagickBooleanType
944 WritePNGImage(const ImageInfo *,Image *,ExceptionInfo *);
946 static MagickBooleanType
947 WriteMNGImage(const ImageInfo *,Image *,ExceptionInfo *);
949 #if defined(JNG_SUPPORTED)
950 static MagickBooleanType
951 WriteJNGImage(const ImageInfo *,Image *,ExceptionInfo *);
954 #if PNG_LIBPNG_VER > 10011
957 #if (MAGICKCORE_QUANTUM_DEPTH >= 16)
958 static MagickBooleanType
959 LosslessReduceDepthOK(Image *image,ExceptionInfo *exception)
961 /* Reduce bit depth if it can be reduced losslessly from 16+ to 8.
963 * This is true if the high byte and the next highest byte of
964 * each sample of the image, the colormap, and the background color
965 * are equal to each other. We check this by seeing if the samples
966 * are unchanged when we scale them down to 8 and back up to Quantum.
968 * We don't use the method GetImageDepth() because it doesn't check
969 * background and doesn't handle PseudoClass specially.
972 #define QuantumToCharToQuantumEqQuantum(quantum) \
973 ((ScaleCharToQuantum((unsigned char) ScaleQuantumToChar(quantum))) == quantum)
976 ok_to_reduce=MagickFalse;
978 if (image->depth >= 16)
985 QuantumToCharToQuantumEqQuantum(image->background_color.red) &&
986 QuantumToCharToQuantumEqQuantum(image->background_color.green) &&
987 QuantumToCharToQuantumEqQuantum(image->background_color.blue) ?
988 MagickTrue : MagickFalse;
990 if (ok_to_reduce != MagickFalse && image->storage_class == PseudoClass)
994 for (indx=0; indx < (ssize_t) image->colors; indx++)
997 QuantumToCharToQuantumEqQuantum(
998 image->colormap[indx].red) &&
999 QuantumToCharToQuantumEqQuantum(
1000 image->colormap[indx].green) &&
1001 QuantumToCharToQuantumEqQuantum(
1002 image->colormap[indx].blue)) ?
1003 MagickTrue : MagickFalse;
1005 if (ok_to_reduce == MagickFalse)
1010 if ((ok_to_reduce != MagickFalse) &&
1011 (image->storage_class != PseudoClass))
1019 for (y=0; y < (ssize_t) image->rows; y++)
1021 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1023 if (p == (const Quantum *) NULL)
1025 ok_to_reduce = MagickFalse;
1029 for (x=(ssize_t) image->columns-1; x >= 0; x--)
1032 QuantumToCharToQuantumEqQuantum(GetPixelRed(image,p)) &&
1033 QuantumToCharToQuantumEqQuantum(GetPixelGreen(image,p)) &&
1034 QuantumToCharToQuantumEqQuantum(GetPixelBlue(image,p)) ?
1035 MagickTrue : MagickFalse;
1037 if (ok_to_reduce == MagickFalse)
1040 p+=GetPixelChannels(image);
1047 if (ok_to_reduce != MagickFalse)
1049 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1050 " OK to reduce PNG bit depth to 8 without loss of info");
1054 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1055 " Not OK to reduce PNG bit depth to 8 without loss of info");
1059 return ok_to_reduce;
1061 #endif /* MAGICKCORE_QUANTUM_DEPTH >= 16 */
1063 static const char* PngColorTypeToString(const unsigned int color_type)
1066 *result = "Unknown";
1070 case PNG_COLOR_TYPE_GRAY:
1073 case PNG_COLOR_TYPE_GRAY_ALPHA:
1074 result = "Gray+Alpha";
1076 case PNG_COLOR_TYPE_PALETTE:
1079 case PNG_COLOR_TYPE_RGB:
1082 case PNG_COLOR_TYPE_RGB_ALPHA:
1083 result = "RGB+Alpha";
1091 Magick_RenderingIntent_to_PNG_RenderingIntent(const RenderingIntent intent)
1095 case PerceptualIntent:
1098 case RelativeIntent:
1101 case SaturationIntent:
1104 case AbsoluteIntent:
1112 static RenderingIntent
1113 Magick_RenderingIntent_from_PNG_RenderingIntent(const int ping_intent)
1115 switch (ping_intent)
1118 return PerceptualIntent;
1121 return RelativeIntent;
1124 return SaturationIntent;
1127 return AbsoluteIntent;
1130 return UndefinedIntent;
1135 Magick_RenderingIntentString_from_PNG_RenderingIntent(const int ping_intent)
1137 switch (ping_intent)
1140 return "Perceptual Intent";
1143 return "Relative Intent";
1146 return "Saturation Intent";
1149 return "Absolute Intent";
1152 return "Undefined Intent";
1156 static inline ssize_t MagickMax(const ssize_t x,const ssize_t y)
1165 Magick_ColorType_from_PNG_ColorType(const int ping_colortype)
1167 switch (ping_colortype)
1185 return "UndefinedColorType";
1190 static inline ssize_t MagickMin(const ssize_t x,const ssize_t y)
1197 #endif /* PNG_LIBPNG_VER > 10011 */
1198 #endif /* MAGICKCORE_PNG_DELEGATE */
1201 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1209 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1211 % IsMNG() returns MagickTrue if the image format type, identified by the
1212 % magick string, is MNG.
1214 % The format of the IsMNG method is:
1216 % MagickBooleanType IsMNG(const unsigned char *magick,const size_t length)
1218 % A description of each parameter follows:
1220 % o magick: compare image format pattern against these bytes.
1222 % o length: Specifies the length of the magick string.
1226 static MagickBooleanType IsMNG(const unsigned char *magick,const size_t length)
1229 return(MagickFalse);
1231 if (memcmp(magick,"\212MNG\r\n\032\n",8) == 0)
1234 return(MagickFalse);
1238 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1246 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1248 % IsJNG() returns MagickTrue if the image format type, identified by the
1249 % magick string, is JNG.
1251 % The format of the IsJNG method is:
1253 % MagickBooleanType IsJNG(const unsigned char *magick,const size_t length)
1255 % A description of each parameter follows:
1257 % o magick: compare image format pattern against these bytes.
1259 % o length: Specifies the length of the magick string.
1263 static MagickBooleanType IsJNG(const unsigned char *magick,const size_t length)
1266 return(MagickFalse);
1268 if (memcmp(magick,"\213JNG\r\n\032\n",8) == 0)
1271 return(MagickFalse);
1275 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1283 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1285 % IsPNG() returns MagickTrue if the image format type, identified by the
1286 % magick string, is PNG.
1288 % The format of the IsPNG method is:
1290 % MagickBooleanType IsPNG(const unsigned char *magick,const size_t length)
1292 % A description of each parameter follows:
1294 % o magick: compare image format pattern against these bytes.
1296 % o length: Specifies the length of the magick string.
1299 static MagickBooleanType IsPNG(const unsigned char *magick,const size_t length)
1302 return(MagickFalse);
1304 if (memcmp(magick,"\211PNG\r\n\032\n",8) == 0)
1307 return(MagickFalse);
1310 #if defined(MAGICKCORE_PNG_DELEGATE)
1311 #if defined(__cplusplus) || defined(c_plusplus)
1315 #if (PNG_LIBPNG_VER > 10011)
1316 static size_t WriteBlobMSBULong(Image *image,const size_t value)
1321 assert(image != (Image *) NULL);
1322 assert(image->signature == MagickSignature);
1323 buffer[0]=(unsigned char) (value >> 24);
1324 buffer[1]=(unsigned char) (value >> 16);
1325 buffer[2]=(unsigned char) (value >> 8);
1326 buffer[3]=(unsigned char) value;
1327 return((size_t) WriteBlob(image,4,buffer));
1330 static void PNGLong(png_bytep p,png_uint_32 value)
1332 *p++=(png_byte) ((value >> 24) & 0xff);
1333 *p++=(png_byte) ((value >> 16) & 0xff);
1334 *p++=(png_byte) ((value >> 8) & 0xff);
1335 *p++=(png_byte) (value & 0xff);
1338 #if defined(JNG_SUPPORTED)
1339 static void PNGsLong(png_bytep p,png_int_32 value)
1341 *p++=(png_byte) ((value >> 24) & 0xff);
1342 *p++=(png_byte) ((value >> 16) & 0xff);
1343 *p++=(png_byte) ((value >> 8) & 0xff);
1344 *p++=(png_byte) (value & 0xff);
1348 static void PNGShort(png_bytep p,png_uint_16 value)
1350 *p++=(png_byte) ((value >> 8) & 0xff);
1351 *p++=(png_byte) (value & 0xff);
1354 static void PNGType(png_bytep p,png_bytep type)
1356 (void) CopyMagickMemory(p,type,4*sizeof(png_byte));
1359 static void LogPNGChunk(MagickBooleanType logging, png_bytep type,
1362 if (logging != MagickFalse)
1363 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1364 " Writing %c%c%c%c chunk, length: %.20g",
1365 type[0],type[1],type[2],type[3],(double) length);
1367 #endif /* PNG_LIBPNG_VER > 10011 */
1369 #if defined(__cplusplus) || defined(c_plusplus)
1373 #if PNG_LIBPNG_VER > 10011
1375 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1379 % R e a d P N G I m a g e %
1383 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1385 % ReadPNGImage() reads a Portable Network Graphics (PNG) or
1386 % Multiple-image Network Graphics (MNG) image file and returns it. It
1387 % allocates the memory necessary for the new Image structure and returns a
1388 % pointer to the new image or set of images.
1390 % MNG support written by Glenn Randers-Pehrson, glennrp@image...
1392 % The format of the ReadPNGImage method is:
1394 % Image *ReadPNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
1396 % A description of each parameter follows:
1398 % o image_info: the image info.
1400 % o exception: return any errors or warnings in this structure.
1402 % To do, more or less in chronological order (as of version 5.5.2,
1403 % November 26, 2002 -- glennrp -- see also "To do" under WriteMNGImage):
1405 % Get 16-bit cheap transparency working.
1407 % (At this point, PNG decoding is supposed to be in full MNG-LC compliance)
1409 % Preserve all unknown and not-yet-handled known chunks found in input
1410 % PNG file and copy them into output PNG files according to the PNG
1413 % (At this point, PNG encoding should be in full MNG compliance)
1415 % Provide options for choice of background to use when the MNG BACK
1416 % chunk is not present or is not mandatory (i.e., leave transparent,
1417 % user specified, MNG BACK, PNG bKGD)
1419 % Implement LOOP/ENDL [done, but could do discretionary loops more
1420 % efficiently by linking in the duplicate frames.].
1422 % Decode and act on the MHDR simplicity profile (offer option to reject
1423 % files or attempt to process them anyway when the profile isn't LC or VLC).
1425 % Upgrade to full MNG without Delta-PNG.
1427 % o BACK [done a while ago except for background image ID]
1428 % o MOVE [done 15 May 1999]
1429 % o CLIP [done 15 May 1999]
1430 % o DISC [done 19 May 1999]
1431 % o SAVE [partially done 19 May 1999 (marks objects frozen)]
1432 % o SEEK [partially done 19 May 1999 (discard function only)]
1436 % o MNG-level tEXt/iTXt/zTXt
1441 % o iTXt (wait for libpng implementation).
1443 % Use the scene signature to discover when an identical scene is
1444 % being reused, and just point to the original image->exception instead
1445 % of storing another set of pixels. This not specific to MNG
1446 % but could be applied generally.
1448 % Upgrade to full MNG with Delta-PNG.
1450 % JNG tEXt/iTXt/zTXt
1452 % We will not attempt to read files containing the CgBI chunk.
1453 % They are really Xcode files meant for display on the iPhone.
1454 % These are not valid PNG files and it is impossible to recover
1455 % the original PNG from files that have been converted to Xcode-PNG,
1456 % since irretrievable loss of color data has occurred due to the
1457 % use of premultiplied alpha.
1460 #if defined(__cplusplus) || defined(c_plusplus)
1465 This the function that does the actual reading of data. It is
1466 the same as the one supplied in libpng, except that it receives the
1467 datastream from the ReadBlob() function instead of standard input.
1469 static void png_get_data(png_structp png_ptr,png_bytep data,png_size_t length)
1474 image=(Image *) png_get_io_ptr(png_ptr);
1480 check=(png_size_t) ReadBlob(image,(size_t) length,data);
1481 if (check != length)
1486 (void) FormatLocaleString(msg,MaxTextExtent,
1487 "Expected %.20g bytes; found %.20g bytes",(double) length,
1489 png_warning(png_ptr,msg);
1490 png_error(png_ptr,"Read Exception");
1495 #if !defined(PNG_READ_EMPTY_PLTE_SUPPORTED) && \
1496 !defined(PNG_MNG_FEATURES_SUPPORTED)
1497 /* We use mng_get_data() instead of png_get_data() if we have a libpng
1498 * older than libpng-1.0.3a, which was the first to allow the empty
1499 * PLTE, or a newer libpng in which PNG_MNG_FEATURES_SUPPORTED was
1500 * ifdef'ed out. Earlier versions would crash if the bKGD chunk was
1501 * encountered after an empty PLTE, so we have to look ahead for bKGD
1502 * chunks and remove them from the datastream that is passed to libpng,
1503 * and store their contents for later use.
1505 static void mng_get_data(png_structp png_ptr,png_bytep data,png_size_t length)
1520 mng_info=(MngInfo *) png_get_io_ptr(png_ptr);
1521 image=(Image *) mng_info->image;
1522 while (mng_info->bytes_in_read_buffer && length)
1524 data[i]=mng_info->read_buffer[i];
1525 mng_info->bytes_in_read_buffer--;
1531 check=(png_size_t) ReadBlob(image,(size_t) length,(char *) data);
1533 if (check != length)
1534 png_error(png_ptr,"Read Exception");
1538 if ((data[0] == 0) && (data[1] == 0) && (data[2] == 0) &&
1541 check=(png_size_t) ReadBlob(image,(size_t) length,
1542 (char *) mng_info->read_buffer);
1543 mng_info->read_buffer[4]=0;
1544 mng_info->bytes_in_read_buffer=4;
1545 if (memcmp(mng_info->read_buffer,mng_PLTE,4) == 0)
1546 mng_info->found_empty_plte=MagickTrue;
1547 if (memcmp(mng_info->read_buffer,mng_IEND,4) == 0)
1549 mng_info->found_empty_plte=MagickFalse;
1550 mng_info->have_saved_bkgd_index=MagickFalse;
1554 if ((data[0] == 0) && (data[1] == 0) && (data[2] == 0) &&
1557 check=(png_size_t) ReadBlob(image,(size_t) length,
1558 (char *) mng_info->read_buffer);
1559 mng_info->read_buffer[4]=0;
1560 mng_info->bytes_in_read_buffer=4;
1561 if (memcmp(mng_info->read_buffer,mng_bKGD,4) == 0)
1562 if (mng_info->found_empty_plte)
1565 Skip the bKGD data byte and CRC.
1568 ReadBlob(image,5,(char *) mng_info->read_buffer);
1569 check=(png_size_t) ReadBlob(image,(size_t) length,
1570 (char *) mng_info->read_buffer);
1571 mng_info->saved_bkgd_index=mng_info->read_buffer[0];
1572 mng_info->have_saved_bkgd_index=MagickTrue;
1573 mng_info->bytes_in_read_buffer=0;
1581 static void png_put_data(png_structp png_ptr,png_bytep data,png_size_t length)
1586 image=(Image *) png_get_io_ptr(png_ptr);
1592 check=(png_size_t) WriteBlob(image,(size_t) length,data);
1594 if (check != length)
1595 png_error(png_ptr,"WriteBlob Failed");
1599 static void png_flush_data(png_structp png_ptr)
1604 #ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
1605 static int PalettesAreEqual(Image *a,Image *b)
1610 if ((a == (Image *) NULL) || (b == (Image *) NULL))
1611 return((int) MagickFalse);
1613 if (a->storage_class != PseudoClass || b->storage_class != PseudoClass)
1614 return((int) MagickFalse);
1616 if (a->colors != b->colors)
1617 return((int) MagickFalse);
1619 for (i=0; i < (ssize_t) a->colors; i++)
1621 if ((a->colormap[i].red != b->colormap[i].red) ||
1622 (a->colormap[i].green != b->colormap[i].green) ||
1623 (a->colormap[i].blue != b->colormap[i].blue))
1624 return((int) MagickFalse);
1627 return((int) MagickTrue);
1631 static void MngInfoDiscardObject(MngInfo *mng_info,int i)
1633 if (i && (i < MNG_MAX_OBJECTS) && (mng_info != (MngInfo *) NULL) &&
1634 mng_info->exists[i] && !mng_info->frozen[i])
1636 #ifdef MNG_OBJECT_BUFFERS
1637 if (mng_info->ob[i] != (MngBuffer *) NULL)
1639 if (mng_info->ob[i]->reference_count > 0)
1640 mng_info->ob[i]->reference_count--;
1642 if (mng_info->ob[i]->reference_count == 0)
1644 if (mng_info->ob[i]->image != (Image *) NULL)
1645 mng_info->ob[i]->image=DestroyImage(mng_info->ob[i]->image);
1647 mng_info->ob[i]=DestroyString(mng_info->ob[i]);
1650 mng_info->ob[i]=(MngBuffer *) NULL;
1652 mng_info->exists[i]=MagickFalse;
1653 mng_info->invisible[i]=MagickFalse;
1654 mng_info->viewable[i]=MagickFalse;
1655 mng_info->frozen[i]=MagickFalse;
1656 mng_info->x_off[i]=0;
1657 mng_info->y_off[i]=0;
1658 mng_info->object_clip[i].left=0;
1659 mng_info->object_clip[i].right=(ssize_t) PNG_UINT_31_MAX;
1660 mng_info->object_clip[i].top=0;
1661 mng_info->object_clip[i].bottom=(ssize_t) PNG_UINT_31_MAX;
1665 static void MngInfoFreeStruct(MngInfo *mng_info,
1666 MagickBooleanType *have_mng_structure)
1668 if (*have_mng_structure != MagickFalse && (mng_info != (MngInfo *) NULL))
1673 for (i=1; i < MNG_MAX_OBJECTS; i++)
1674 MngInfoDiscardObject(mng_info,i);
1676 if (mng_info->global_plte != (png_colorp) NULL)
1677 mng_info->global_plte=(png_colorp)
1678 RelinquishMagickMemory(mng_info->global_plte);
1680 mng_info=(MngInfo *) RelinquishMagickMemory(mng_info);
1681 *have_mng_structure=MagickFalse;
1685 static MngBox mng_minimum_box(MngBox box1,MngBox box2)
1691 if (box.left < box2.left)
1694 if (box.top < box2.top)
1697 if (box.right > box2.right)
1698 box.right=box2.right;
1700 if (box.bottom > box2.bottom)
1701 box.bottom=box2.bottom;
1706 static MngBox mng_read_box(MngBox previous_box,char delta_type,unsigned char *p)
1712 Read clipping boundaries from DEFI, CLIP, FRAM, or PAST chunk.
1714 box.left=(ssize_t) ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]);
1715 box.right=(ssize_t) ((p[4] << 24) | (p[5] << 16) | (p[6] << 8) | p[7]);
1716 box.top=(ssize_t) ((p[8] << 24) | (p[9] << 16) | (p[10] << 8) | p[11]);
1717 box.bottom=(ssize_t) ((p[12] << 24) | (p[13] << 16) | (p[14] << 8) | p[15]);
1718 if (delta_type != 0)
1720 box.left+=previous_box.left;
1721 box.right+=previous_box.right;
1722 box.top+=previous_box.top;
1723 box.bottom+=previous_box.bottom;
1729 static MngPair mng_read_pair(MngPair previous_pair,int delta_type,
1735 Read two ssize_ts from CLON, MOVE or PAST chunk
1737 pair.a=(long) ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]);
1738 pair.b=(long) ((p[4] << 24) | (p[5] << 16) | (p[6] << 8) | p[7]);
1740 if (delta_type != 0)
1742 pair.a+=previous_pair.a;
1743 pair.b+=previous_pair.b;
1749 static long mng_get_long(unsigned char *p)
1751 return((long) ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]));
1754 typedef struct _PNGErrorInfo
1763 static void MagickPNGErrorHandler(png_struct *ping,png_const_charp message)
1774 error_info=(PNGErrorInfo *) png_get_error_ptr(ping);
1775 image=error_info->image;
1776 exception=error_info->exception;
1778 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1779 " libpng-%s error: %s", PNG_LIBPNG_VER_STRING,message);
1781 (void) ThrowMagickException(exception,GetMagickModule(),CoderError,message,
1782 "`%s'",image->filename);
1784 #if (PNG_LIBPNG_VER < 10500)
1785 /* A warning about deprecated use of jmpbuf here is unavoidable if you
1786 * are building with libpng-1.4.x and can be ignored.
1788 longjmp(ping->jmpbuf,1);
1790 png_longjmp(ping,1);
1794 static void MagickPNGWarningHandler(png_struct *ping,png_const_charp message)
1805 if (LocaleCompare(message, "Missing PLTE before tRNS") == 0)
1806 png_error(ping, message);
1808 error_info=(PNGErrorInfo *) png_get_error_ptr(ping);
1809 image=error_info->image;
1810 exception=error_info->exception;
1811 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1812 " libpng-%s warning: %s", PNG_LIBPNG_VER_STRING,message);
1814 (void) ThrowMagickException(exception,GetMagickModule(),CoderWarning,
1815 message,"`%s'",image->filename);
1818 #ifdef PNG_USER_MEM_SUPPORTED
1819 #if PNG_LIBPNG_VER >= 14000
1820 static png_voidp Magick_png_malloc(png_structp png_ptr,png_alloc_size_t size)
1822 static png_voidp Magick_png_malloc(png_structp png_ptr,png_size_t size)
1826 return((png_voidp) AcquireMagickMemory((size_t) size));
1830 Free a pointer. It is removed from the list at the same time.
1832 static png_free_ptr Magick_png_free(png_structp png_ptr,png_voidp ptr)
1835 ptr=RelinquishMagickMemory(ptr);
1836 return((png_free_ptr) NULL);
1840 #if defined(__cplusplus) || defined(c_plusplus)
1845 Magick_png_read_raw_profile(png_struct *ping,Image *image,
1846 const ImageInfo *image_info, png_textp text,int ii,ExceptionInfo *exception)
1851 register unsigned char
1865 unhex[103]={0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,
1866 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,
1867 0,0,0,0,0,0,0,0,0,1, 2,3,4,5,6,7,8,9,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,0, 0,0,0,0,0,0,0,10,11,12,
1873 /* look for newline */
1877 /* look for length */
1878 while (*sp == '\0' || *sp == ' ' || *sp == '\n')
1881 length=(png_uint_32) StringToLong(sp);
1883 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1884 " length: %lu",(unsigned long) length);
1886 while (*sp != ' ' && *sp != '\n')
1889 /* allocate space */
1892 png_warning(ping,"invalid profile length");
1893 return(MagickFalse);
1896 profile=BlobToStringInfo((const void *) NULL,length);
1898 if (profile == (StringInfo *) NULL)
1900 png_warning(ping, "unable to copy profile");
1901 return(MagickFalse);
1904 /* copy profile, skipping white space and column 1 "=" signs */
1905 dp=GetStringInfoDatum(profile);
1908 for (i=0; i < (ssize_t) nibbles; i++)
1910 while (*sp < '0' || (*sp > '9' && *sp < 'a') || *sp > 'f')
1914 png_warning(ping, "ran out of profile data");
1915 profile=DestroyStringInfo(profile);
1916 return(MagickFalse);
1922 *dp=(unsigned char) (16*unhex[(int) *sp++]);
1925 (*dp++)+=unhex[(int) *sp++];
1928 We have already read "Raw profile type.
1930 (void) SetImageProfile(image,&text[ii].key[17],profile,exception);
1931 profile=DestroyStringInfo(profile);
1933 if (image_info->verbose)
1934 (void) printf(" Found a generic profile, type %s\n",&text[ii].key[17]);
1939 #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
1940 static int read_vpag_chunk_callback(png_struct *ping, png_unknown_chunkp chunk)
1946 /* The unknown chunk structure contains the chunk data:
1951 Note that libpng has already taken care of the CRC handling.
1955 if (chunk->name[0] != 118 || chunk->name[1] != 112 ||
1956 chunk->name[2] != 65 ||chunk-> name[3] != 103)
1957 return(0); /* Did not recognize */
1959 /* recognized vpAg */
1961 if (chunk->size != 9)
1962 return(-1); /* Error return */
1964 if (chunk->data[8] != 0)
1965 return(0); /* ImageMagick requires pixel units */
1967 image=(Image *) png_get_user_chunk_ptr(ping);
1969 image->page.width=(size_t) ((chunk->data[0] << 24) |
1970 (chunk->data[1] << 16) | (chunk->data[2] << 8) | chunk->data[3]);
1972 image->page.height=(size_t) ((chunk->data[4] << 24) |
1973 (chunk->data[5] << 16) | (chunk->data[6] << 8) | chunk->data[7]);
1975 /* Return one of the following: */
1976 /* return(-n); chunk had an error */
1977 /* return(0); did not recognize */
1978 /* return(n); success */
1986 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1990 % R e a d O n e P N G I m a g e %
1994 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1996 % ReadOnePNGImage() reads a Portable Network Graphics (PNG) image file
1997 % (minus the 8-byte signature) and returns it. It allocates the memory
1998 % necessary for the new Image structure and returns a pointer to the new
2001 % The format of the ReadOnePNGImage method is:
2003 % Image *ReadOnePNGImage(MngInfo *mng_info, const ImageInfo *image_info,
2004 % ExceptionInfo *exception)
2006 % A description of each parameter follows:
2008 % o mng_info: Specifies a pointer to a MngInfo structure.
2010 % o image_info: the image info.
2012 % o exception: return any errors or warnings in this structure.
2015 static Image *ReadOnePNGImage(MngInfo *mng_info,
2016 const ImageInfo *image_info, ExceptionInfo *exception)
2018 /* Read one PNG image */
2020 /* To do: Read the tIME chunk into the date:modify property */
2021 /* To do: Read the tEXt/Creation Time chunk into the date:create property */
2027 intent, /* "PNG Rendering intent", which is ICC intent + 1 */
2037 ping_interlace_method,
2038 ping_compression_method,
2090 register unsigned char
2108 *volatile ping_pixels;
2110 #ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED
2111 png_byte unused_chunks[]=
2113 104, 73, 83, 84, (png_byte) '\0', /* hIST */
2114 105, 84, 88, 116, (png_byte) '\0', /* iTXt */
2115 112, 67, 65, 76, (png_byte) '\0', /* pCAL */
2116 115, 67, 65, 76, (png_byte) '\0', /* sCAL */
2117 115, 80, 76, 84, (png_byte) '\0', /* sPLT */
2118 116, 73, 77, 69, (png_byte) '\0', /* tIME */
2119 #ifdef PNG_APNG_SUPPORTED /* libpng was built with APNG patch; */
2120 /* ignore the APNG chunks */
2121 97, 99, 84, 76, (png_byte) '\0', /* acTL */
2122 102, 99, 84, 76, (png_byte) '\0', /* fcTL */
2123 102, 100, 65, 84, (png_byte) '\0', /* fdAT */
2128 logging=LogMagickEvent(CoderEvent,GetMagickModule(),
2129 " Enter ReadOnePNGImage()");
2131 #if (PNG_LIBPNG_VER < 10200)
2132 if (image_info->verbose)
2133 printf("Your PNG library (libpng-%s) is rather old.\n",
2134 PNG_LIBPNG_VER_STRING);
2137 #if (PNG_LIBPNG_VER >= 10400)
2138 # ifndef PNG_TRANSFORM_GRAY_TO_RGB /* Added at libpng-1.4.0beta67 */
2139 if (image_info->verbose)
2141 printf("Your PNG library (libpng-%s) is an old beta version.\n",
2142 PNG_LIBPNG_VER_STRING);
2143 printf("Please update it.\n");
2149 quantum_info = (QuantumInfo *) NULL;
2150 image=mng_info->image;
2152 if (logging != MagickFalse)
2154 (void)LogMagickEvent(CoderEvent,GetMagickModule(),
2155 " image->alpha_trait=%d",(int) image->alpha_trait);
2157 (void)LogMagickEvent(CoderEvent,GetMagickModule(),
2158 " image->rendering_intent=%d",(int) image->rendering_intent);
2160 (void)LogMagickEvent(CoderEvent,GetMagickModule(),
2161 " image->colorspace=%d",(int) image->colorspace);
2163 intent=Magick_RenderingIntent_to_PNG_RenderingIntent(image->rendering_intent);
2165 /* Set to an out-of-range color unless tRNS chunk is present */
2166 transparent_color.red=65537;
2167 transparent_color.green=65537;
2168 transparent_color.blue=65537;
2169 transparent_color.alpha=65537;
2174 num_raw_profiles = 0;
2176 ping_found_cHRM = MagickFalse;
2177 ping_found_gAMA = MagickFalse;
2178 ping_found_iCCP = MagickFalse;
2179 ping_found_sRGB = MagickFalse;
2182 Allocate the PNG structures
2184 #ifdef PNG_USER_MEM_SUPPORTED
2185 error_info.image=image;
2186 error_info.exception=exception;
2187 ping=png_create_read_struct_2(PNG_LIBPNG_VER_STRING,&error_info,
2188 MagickPNGErrorHandler,MagickPNGWarningHandler, NULL,
2189 (png_malloc_ptr) Magick_png_malloc,(png_free_ptr) Magick_png_free);
2191 ping=png_create_read_struct(PNG_LIBPNG_VER_STRING,&error_info,
2192 MagickPNGErrorHandler,MagickPNGWarningHandler);
2194 if (ping == (png_struct *) NULL)
2195 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2197 ping_info=png_create_info_struct(ping);
2199 if (ping_info == (png_info *) NULL)
2201 png_destroy_read_struct(&ping,(png_info **) NULL,(png_info **) NULL);
2202 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2205 end_info=png_create_info_struct(ping);
2207 if (end_info == (png_info *) NULL)
2209 png_destroy_read_struct(&ping,&ping_info,(png_info **) NULL);
2210 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2213 ping_pixels=(unsigned char *) NULL;
2215 if (setjmp(png_jmpbuf(ping)))
2218 PNG image is corrupt.
2220 png_destroy_read_struct(&ping,&ping_info,&end_info);
2222 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
2223 UnlockSemaphoreInfo(ping_semaphore);
2226 if (ping_pixels != (unsigned char *) NULL)
2227 ping_pixels=(unsigned char *) RelinquishMagickMemory(ping_pixels);
2229 if (logging != MagickFalse)
2230 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2231 " exit ReadOnePNGImage() with error.");
2233 if (image != (Image *) NULL)
2235 InheritException(exception,exception);
2239 return(GetFirstImageInList(image));
2242 /* { For navigation to end of SETJMP-protected block. Within this
2243 * block, use png_error() instead of Throwing an Exception, to ensure
2244 * that libpng is able to clean up, and that the semaphore is unlocked.
2247 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
2248 LockSemaphoreInfo(ping_semaphore);
2252 Prepare PNG for reading.
2255 mng_info->image_found++;
2256 png_set_sig_bytes(ping,8);
2258 if (LocaleCompare(image_info->magick,"MNG") == 0)
2260 #if defined(PNG_MNG_FEATURES_SUPPORTED)
2261 (void) png_permit_mng_features(ping,PNG_ALL_MNG_FEATURES);
2262 png_set_read_fn(ping,image,png_get_data);
2264 #if defined(PNG_READ_EMPTY_PLTE_SUPPORTED)
2265 png_permit_empty_plte(ping,MagickTrue);
2266 png_set_read_fn(ping,image,png_get_data);
2268 mng_info->image=image;
2269 mng_info->bytes_in_read_buffer=0;
2270 mng_info->found_empty_plte=MagickFalse;
2271 mng_info->have_saved_bkgd_index=MagickFalse;
2272 png_set_read_fn(ping,mng_info,mng_get_data);
2278 png_set_read_fn(ping,image,png_get_data);
2280 #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
2281 /* Ignore unused chunks and all unknown chunks except for vpAg */
2282 png_set_keep_unknown_chunks(ping, 1, NULL, 0);
2283 png_set_keep_unknown_chunks(ping, 2, mng_vpAg, 1);
2284 png_set_keep_unknown_chunks(ping, 1, unused_chunks,
2285 (int)sizeof(unused_chunks)/5);
2286 /* Callback for other unknown chunks */
2287 png_set_read_user_chunk_fn(ping, image, read_vpag_chunk_callback);
2290 #ifdef PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED
2291 /* Disable new libpng-1.5.10 feature */
2292 png_set_check_for_invalid_index (ping, 0);
2295 #if (PNG_LIBPNG_VER < 10400)
2296 # if defined(PNG_USE_PNGGCCRD) && defined(PNG_ASSEMBLER_CODE_SUPPORTED) && \
2297 (PNG_LIBPNG_VER >= 10200) && (PNG_LIBPNG_VER < 10220) && defined(__i386__)
2298 /* Disable thread-unsafe features of pnggccrd */
2299 if (png_access_version_number() >= 10200)
2301 png_uint_32 mmx_disable_mask=0;
2302 png_uint_32 asm_flags;
2304 mmx_disable_mask |= ( PNG_ASM_FLAG_MMX_READ_COMBINE_ROW \
2305 | PNG_ASM_FLAG_MMX_READ_FILTER_SUB \
2306 | PNG_ASM_FLAG_MMX_READ_FILTER_AVG \
2307 | PNG_ASM_FLAG_MMX_READ_FILTER_PAETH );
2308 asm_flags=png_get_asm_flags(ping);
2309 png_set_asm_flags(ping, asm_flags & ~mmx_disable_mask);
2314 png_read_info(ping,ping_info);
2316 png_get_IHDR(ping,ping_info,&ping_width,&ping_height,
2317 &ping_bit_depth,&ping_color_type,
2318 &ping_interlace_method,&ping_compression_method,
2319 &ping_filter_method);
2321 ping_file_depth = ping_bit_depth;
2323 (void) png_get_tRNS(ping, ping_info, &ping_trans_alpha, &ping_num_trans,
2326 (void) png_get_bKGD(ping, ping_info, &ping_background);
2328 if (ping_bit_depth < 8)
2330 png_set_packing(ping);
2334 image->depth=ping_bit_depth;
2335 image->depth=GetImageQuantumDepth(image,MagickFalse);
2336 image->interlace=ping_interlace_method != 0 ? PNGInterlace : NoInterlace;
2338 if (((int) ping_color_type == PNG_COLOR_TYPE_GRAY) ||
2339 ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA))
2341 image->rendering_intent=UndefinedIntent;
2342 intent=Magick_RenderingIntent_to_PNG_RenderingIntent(UndefinedIntent);
2344 (void) ResetMagickMemory(&image->chromaticity,0,
2345 sizeof(image->chromaticity));
2348 if (logging != MagickFalse)
2350 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2351 " PNG width: %.20g, height: %.20g",
2352 (double) ping_width, (double) ping_height);
2354 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2355 " PNG color_type: %d, bit_depth: %d",
2356 ping_color_type, ping_bit_depth);
2358 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2359 " PNG compression_method: %d",
2360 ping_compression_method);
2362 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2363 " PNG interlace_method: %d, filter_method: %d",
2364 ping_interlace_method,ping_filter_method);
2367 if (png_get_valid(ping,ping_info,PNG_INFO_gAMA))
2369 ping_found_gAMA=MagickTrue;
2370 if (logging != MagickFalse)
2371 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2372 " Found PNG gAMA chunk.");
2375 if (png_get_valid(ping,ping_info,PNG_INFO_cHRM))
2377 ping_found_cHRM=MagickTrue;
2378 if (logging != MagickFalse)
2379 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2380 " Found PNG cHRM chunk.");
2383 if (png_get_valid(ping,ping_info,PNG_INFO_iCCP))
2385 ping_found_iCCP=MagickTrue;
2386 if (logging != MagickFalse)
2387 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2388 " Found PNG iCCP chunk.");
2391 if (png_get_valid(ping,ping_info,PNG_INFO_sRGB))
2393 ping_found_sRGB=MagickTrue;
2394 if (logging != MagickFalse)
2395 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2396 " Found PNG sRGB chunk.");
2399 #ifdef PNG_READ_iCCP_SUPPORTED
2400 if (png_get_valid(ping,ping_info,PNG_INFO_iCCP))
2405 #if (PNG_LIBPNG_VER < 10500)
2419 (void) png_get_iCCP(ping,ping_info,&name,(int *) &compression,&info,
2422 if (profile_length != 0)
2427 if (logging != MagickFalse)
2428 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2429 " Reading PNG iCCP chunk.");
2430 profile=BlobToStringInfo(info,profile_length);
2431 if (profile == (StringInfo *) NULL)
2433 png_warning(ping, "ICC profile is NULL");
2434 profile=DestroyStringInfo(profile);
2438 (void) SetImageProfile(image,"icc",profile,exception);
2439 profile=DestroyStringInfo(profile);
2444 #if defined(PNG_READ_sRGB_SUPPORTED)
2446 if (mng_info->have_global_srgb)
2448 image->rendering_intent=Magick_RenderingIntent_from_PNG_RenderingIntent
2449 (mng_info->global_srgb_intent);
2452 if (png_get_sRGB(ping,ping_info,&intent))
2454 image->rendering_intent=Magick_RenderingIntent_from_PNG_RenderingIntent
2457 if (logging != MagickFalse)
2458 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2459 " Reading PNG sRGB chunk: rendering_intent: %d",intent);
2464 if (!png_get_gAMA(ping,ping_info,&file_gamma))
2465 if (mng_info->have_global_gama)
2466 png_set_gAMA(ping,ping_info,mng_info->global_gamma);
2468 if (png_get_gAMA(ping,ping_info,&file_gamma))
2470 image->gamma=(float) file_gamma;
2471 if (logging != MagickFalse)
2472 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2473 " Reading PNG gAMA chunk: gamma: %f",file_gamma);
2477 if (!png_get_valid(ping,ping_info,PNG_INFO_cHRM))
2479 if (mng_info->have_global_chrm != MagickFalse)
2481 (void) png_set_cHRM(ping,ping_info,
2482 mng_info->global_chrm.white_point.x,
2483 mng_info->global_chrm.white_point.y,
2484 mng_info->global_chrm.red_primary.x,
2485 mng_info->global_chrm.red_primary.y,
2486 mng_info->global_chrm.green_primary.x,
2487 mng_info->global_chrm.green_primary.y,
2488 mng_info->global_chrm.blue_primary.x,
2489 mng_info->global_chrm.blue_primary.y);
2493 if (png_get_valid(ping,ping_info,PNG_INFO_cHRM))
2495 (void) png_get_cHRM(ping,ping_info,
2496 &image->chromaticity.white_point.x,
2497 &image->chromaticity.white_point.y,
2498 &image->chromaticity.red_primary.x,
2499 &image->chromaticity.red_primary.y,
2500 &image->chromaticity.green_primary.x,
2501 &image->chromaticity.green_primary.y,
2502 &image->chromaticity.blue_primary.x,
2503 &image->chromaticity.blue_primary.y);
2505 ping_found_cHRM=MagickTrue;
2508 if (image->rendering_intent != UndefinedIntent)
2510 if (ping_found_sRGB != MagickTrue)
2512 png_set_sRGB(ping,ping_info,
2513 Magick_RenderingIntent_to_PNG_RenderingIntent
2514 (image->rendering_intent));
2515 png_set_gAMA(ping,ping_info,1.000f/2.200f);
2516 file_gamma=1.000f/2.200f;
2517 ping_found_sRGB=MagickTrue;
2518 ping_found_cHRM=MagickTrue;
2522 #if defined(PNG_oFFs_SUPPORTED)
2523 if (png_get_valid(ping,ping_info,PNG_INFO_oFFs))
2525 image->page.x=(ssize_t) png_get_x_offset_pixels(ping, ping_info);
2526 image->page.y=(ssize_t) png_get_y_offset_pixels(ping, ping_info);
2528 if (logging != MagickFalse)
2529 if (image->page.x || image->page.y)
2530 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2531 " Reading PNG oFFs chunk: x: %.20g, y: %.20g.",(double)
2532 image->page.x,(double) image->page.y);
2535 #if defined(PNG_pHYs_SUPPORTED)
2536 if (!png_get_valid(ping,ping_info,PNG_INFO_pHYs))
2538 if (mng_info->have_global_phys)
2540 png_set_pHYs(ping,ping_info,
2541 mng_info->global_x_pixels_per_unit,
2542 mng_info->global_y_pixels_per_unit,
2543 mng_info->global_phys_unit_type);
2547 if (png_get_valid(ping,ping_info,PNG_INFO_pHYs))
2550 Set image resolution.
2552 (void) png_get_pHYs(ping,ping_info,&x_resolution,&y_resolution,
2554 image->resolution.x=(double) x_resolution;
2555 image->resolution.y=(double) y_resolution;
2557 if (unit_type == PNG_RESOLUTION_METER)
2559 image->units=PixelsPerCentimeterResolution;
2560 image->resolution.x=(double) x_resolution/100.0;
2561 image->resolution.y=(double) y_resolution/100.0;
2564 if (logging != MagickFalse)
2565 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2566 " Reading PNG pHYs chunk: xres: %.20g, yres: %.20g, units: %d.",
2567 (double) x_resolution,(double) y_resolution,unit_type);
2571 if (png_get_valid(ping,ping_info,PNG_INFO_PLTE))
2576 (void) png_get_PLTE(ping,ping_info,&palette,&number_colors);
2578 if ((number_colors == 0) &&
2579 ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE))
2581 if (mng_info->global_plte_length)
2583 png_set_PLTE(ping,ping_info,mng_info->global_plte,
2584 (int) mng_info->global_plte_length);
2586 if (!png_get_valid(ping,ping_info,PNG_INFO_tRNS))
2588 if (mng_info->global_trns_length)
2591 "global tRNS has more entries than global PLTE");
2595 png_set_tRNS(ping,ping_info,mng_info->global_trns,
2596 (int) mng_info->global_trns_length,NULL);
2599 #ifdef PNG_READ_bKGD_SUPPORTED
2601 #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
2602 mng_info->have_saved_bkgd_index ||
2604 png_get_valid(ping,ping_info,PNG_INFO_bKGD))
2609 #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
2610 if (mng_info->have_saved_bkgd_index)
2611 background.index=mng_info->saved_bkgd_index;
2613 if (png_get_valid(ping, ping_info, PNG_INFO_bKGD))
2614 background.index=ping_background->index;
2616 background.red=(png_uint_16)
2617 mng_info->global_plte[background.index].red;
2619 background.green=(png_uint_16)
2620 mng_info->global_plte[background.index].green;
2622 background.blue=(png_uint_16)
2623 mng_info->global_plte[background.index].blue;
2625 background.gray=(png_uint_16)
2626 mng_info->global_plte[background.index].green;
2628 png_set_bKGD(ping,ping_info,&background);
2633 png_error(ping,"No global PLTE in file");
2637 #ifdef PNG_READ_bKGD_SUPPORTED
2638 if (mng_info->have_global_bkgd &&
2639 (!png_get_valid(ping,ping_info,PNG_INFO_bKGD)))
2640 image->background_color=mng_info->mng_global_bkgd;
2642 if (png_get_valid(ping,ping_info,PNG_INFO_bKGD))
2648 Set image background color.
2650 if (logging != MagickFalse)
2651 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2652 " Reading PNG bKGD chunk.");
2654 /* Scale background components to 16-bit, then scale
2657 if (logging != MagickFalse)
2658 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2659 " raw ping_background=(%d,%d,%d).",ping_background->red,
2660 ping_background->green,ping_background->blue);
2664 if (ping_file_depth == 1)
2667 else if (ping_file_depth == 2)
2670 else if (ping_file_depth == 4)
2673 if (ping_file_depth <= 8)
2676 ping_background->red *= bkgd_scale;
2677 ping_background->green *= bkgd_scale;
2678 ping_background->blue *= bkgd_scale;
2680 if (logging != MagickFalse)
2682 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2683 " bkgd_scale=%d.",bkgd_scale);
2685 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2686 " ping_background=(%d,%d,%d).",ping_background->red,
2687 ping_background->green,ping_background->blue);
2690 image->background_color.red=
2691 ScaleShortToQuantum(ping_background->red);
2693 image->background_color.green=
2694 ScaleShortToQuantum(ping_background->green);
2696 image->background_color.blue=
2697 ScaleShortToQuantum(ping_background->blue);
2699 image->background_color.alpha=OpaqueAlpha;
2701 if (logging != MagickFalse)
2702 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2703 " image->background_color=(%.20g,%.20g,%.20g).",
2704 (double) image->background_color.red,
2705 (double) image->background_color.green,
2706 (double) image->background_color.blue);
2708 #endif /* PNG_READ_bKGD_SUPPORTED */
2710 if (png_get_valid(ping,ping_info,PNG_INFO_tRNS))
2713 Image has a tRNS chunk.
2721 if (logging != MagickFalse)
2722 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2723 " Reading PNG tRNS chunk.");
2725 max_sample = (int) ((one << ping_file_depth) - 1);
2727 if ((ping_color_type == PNG_COLOR_TYPE_GRAY &&
2728 (int)ping_trans_color->gray > max_sample) ||
2729 (ping_color_type == PNG_COLOR_TYPE_RGB &&
2730 ((int)ping_trans_color->red > max_sample ||
2731 (int)ping_trans_color->green > max_sample ||
2732 (int)ping_trans_color->blue > max_sample)))
2734 if (logging != MagickFalse)
2735 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2736 " Ignoring PNG tRNS chunk with out-of-range sample.");
2737 png_free_data(ping, ping_info, PNG_FREE_TRNS, 0);
2738 png_set_invalid(ping,ping_info,PNG_INFO_tRNS);
2739 image->alpha_trait=UndefinedPixelTrait;
2746 scale_to_short = 65535L/((1UL << ping_file_depth)-1);
2748 /* Scale transparent_color to short */
2749 transparent_color.red= scale_to_short*ping_trans_color->red;
2750 transparent_color.green= scale_to_short*ping_trans_color->green;
2751 transparent_color.blue= scale_to_short*ping_trans_color->blue;
2752 transparent_color.alpha= scale_to_short*ping_trans_color->gray;
2754 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
2756 if (logging != MagickFalse)
2758 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2759 " Raw tRNS graylevel is %d.",ping_trans_color->gray);
2761 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2762 " scaled graylevel is %.20g.",transparent_color.alpha);
2764 transparent_color.red=transparent_color.alpha;
2765 transparent_color.green=transparent_color.alpha;
2766 transparent_color.blue=transparent_color.alpha;
2770 #if defined(PNG_READ_sBIT_SUPPORTED)
2771 if (mng_info->have_global_sbit)
2773 if (!png_get_valid(ping,ping_info,PNG_INFO_sBIT))
2774 png_set_sBIT(ping,ping_info,&mng_info->global_sbit);
2777 num_passes=png_set_interlace_handling(ping);
2779 png_read_update_info(ping,ping_info);
2781 ping_rowbytes=png_get_rowbytes(ping,ping_info);
2784 Initialize image structure.
2786 mng_info->image_box.left=0;
2787 mng_info->image_box.right=(ssize_t) ping_width;
2788 mng_info->image_box.top=0;
2789 mng_info->image_box.bottom=(ssize_t) ping_height;
2790 if (mng_info->mng_type == 0)
2792 mng_info->mng_width=ping_width;
2793 mng_info->mng_height=ping_height;
2794 mng_info->frame=mng_info->image_box;
2795 mng_info->clip=mng_info->image_box;
2800 image->page.y=mng_info->y_off[mng_info->object_id];
2803 image->compression=ZipCompression;
2804 image->columns=ping_width;
2805 image->rows=ping_height;
2807 if (((int) ping_color_type == PNG_COLOR_TYPE_GRAY) ||
2808 ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA))
2810 if ((!png_get_valid(ping,ping_info,PNG_INFO_gAMA) ||
2811 image->gamma == 1.0) &&
2812 ping_found_cHRM != MagickTrue && ping_found_sRGB != MagickTrue)
2814 /* Set image->gamma to 1.0, image->rendering_intent to Undefined,
2815 * image->colorspace to GRAY, and reset image->chromaticity.
2817 SetImageColorspace(image,GRAYColorspace,exception);
2821 (void)LogMagickEvent(CoderEvent,GetMagickModule(),
2822 " image->colorspace=%d",(int) image->colorspace);
2824 if (((int) ping_color_type == PNG_COLOR_TYPE_PALETTE) ||
2825 ((int) ping_bit_depth < 16 &&
2826 (int) ping_color_type == PNG_COLOR_TYPE_GRAY))
2831 image->storage_class=PseudoClass;
2833 image->colors=one << ping_file_depth;
2834 #if (MAGICKCORE_QUANTUM_DEPTH == 8)
2835 if (image->colors > 256)
2838 if (image->colors > 65536L)
2839 image->colors=65536L;
2841 if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
2846 (void) png_get_PLTE(ping,ping_info,&palette,&number_colors);
2847 image->colors=(size_t) number_colors;
2849 if (logging != MagickFalse)
2850 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2851 " Reading PNG PLTE chunk: number_colors: %d.",number_colors);
2855 if (image->storage_class == PseudoClass)
2858 Initialize image colormap.
2860 if (AcquireImageColormap(image,image->colors,exception) == MagickFalse)
2861 png_error(ping,"Memory allocation failed");
2863 if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
2868 (void) png_get_PLTE(ping,ping_info,&palette,&number_colors);
2870 for (i=0; i < (ssize_t) number_colors; i++)
2872 image->colormap[i].red=ScaleCharToQuantum(palette[i].red);
2873 image->colormap[i].green=ScaleCharToQuantum(palette[i].green);
2874 image->colormap[i].blue=ScaleCharToQuantum(palette[i].blue);
2877 for ( ; i < (ssize_t) image->colors; i++)
2879 image->colormap[i].red=0;
2880 image->colormap[i].green=0;
2881 image->colormap[i].blue=0;
2890 scale=(QuantumRange/((1UL << ping_file_depth)-1));
2895 for (i=0; i < (ssize_t) image->colors; i++)
2897 image->colormap[i].red=(Quantum) (i*scale);
2898 image->colormap[i].green=(Quantum) (i*scale);
2899 image->colormap[i].blue=(Quantum) (i*scale);
2904 /* Set some properties for reporting by "identify" */
2909 /* encode ping_width, ping_height, ping_file_depth, ping_color_type,
2910 ping_interlace_method in value */
2912 (void) FormatLocaleString(msg,MaxTextExtent,
2913 "%d, %d",(int) ping_width, (int) ping_height);
2914 (void) SetImageProperty(image,"png:IHDR.width,height ",msg,exception);
2916 (void) FormatLocaleString(msg,MaxTextExtent,"%d",(int) ping_file_depth);
2917 (void) SetImageProperty(image,"png:IHDR.bit_depth ",msg,exception);
2919 (void) FormatLocaleString(msg,MaxTextExtent,"%d (%s)",
2920 (int) ping_color_type,
2921 Magick_ColorType_from_PNG_ColorType((int)ping_color_type));
2922 (void) SetImageProperty(image,"png:IHDR.color_type ",msg,exception);
2924 if (ping_interlace_method == 0)
2926 (void) FormatLocaleString(msg,MaxTextExtent,"%d (Not interlaced)",
2927 (int) ping_interlace_method);
2929 else if (ping_interlace_method == 1)
2931 (void) FormatLocaleString(msg,MaxTextExtent,"%d (Adam7 method)",
2932 (int) ping_interlace_method);
2936 (void) FormatLocaleString(msg,MaxTextExtent,"%d (Unknown method)",
2937 (int) ping_interlace_method);
2939 (void) SetImageProperty(image,"png:IHDR.interlace_method",msg,exception);
2941 if (number_colors != 0)
2943 (void) FormatLocaleString(msg,MaxTextExtent,"%d",
2944 (int) number_colors);
2945 (void) SetImageProperty(image,"png:PLTE.number_colors ",msg,
2951 Read image scanlines.
2953 if (image->delay != 0)
2954 mng_info->scenes_found++;
2956 if ((mng_info->mng_type == 0 && (image->ping != MagickFalse)) || (
2957 (image_info->number_scenes != 0) && (mng_info->scenes_found > (ssize_t)
2958 (image_info->first_scene+image_info->number_scenes))))
2960 /* This happens later in non-ping decodes */
2961 if (png_get_valid(ping,ping_info,PNG_INFO_tRNS))
2962 image->storage_class=DirectClass;
2964 if (logging != MagickFalse)
2965 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2966 " Skipping PNG image data for scene %.20g",(double)
2967 mng_info->scenes_found-1);
2968 png_destroy_read_struct(&ping,&ping_info,&end_info);
2970 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
2971 UnlockSemaphoreInfo(ping_semaphore);
2974 if (logging != MagickFalse)
2975 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2976 " exit ReadOnePNGImage().");
2981 if (logging != MagickFalse)
2982 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2983 " Reading PNG IDAT chunk(s)");
2986 ping_pixels=(unsigned char *) AcquireQuantumMemory(image->rows,
2987 ping_rowbytes*sizeof(*ping_pixels));
2990 ping_pixels=(unsigned char *) AcquireQuantumMemory(ping_rowbytes,
2991 sizeof(*ping_pixels));
2993 if (ping_pixels == (unsigned char *) NULL)
2994 png_error(ping,"Memory allocation failed");
2996 if (logging != MagickFalse)
2997 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2998 " Converting PNG pixels to pixel packets");
3000 Convert PNG pixels to pixel packets.
3002 quantum_info=AcquireQuantumInfo(image_info,image);
3004 if (quantum_info == (QuantumInfo *) NULL)
3005 png_error(ping,"Failed to allocate quantum_info");
3007 (void) SetQuantumEndian(image,quantum_info,MSBEndian);
3012 found_transparent_pixel;
3014 found_transparent_pixel=MagickFalse;
3016 if (image->storage_class == DirectClass)
3018 for (pass=0; pass < num_passes; pass++)
3021 Convert image to DirectClass pixel packets.
3023 image->alpha_trait=(((int) ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA) ||
3024 ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) ||
3025 (png_get_valid(ping,ping_info,PNG_INFO_tRNS))) ?
3026 BlendPixelTrait : UndefinedPixelTrait;
3028 for (y=0; y < (ssize_t) image->rows; y++)
3031 row_offset=ping_rowbytes*y;
3036 png_read_row(ping,ping_pixels+row_offset,NULL);
3038 if (pass < num_passes-1)
3041 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
3043 if (q == (Quantum *) NULL)
3046 if ((int) ping_color_type == PNG_COLOR_TYPE_GRAY)
3047 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
3048 GrayQuantum,ping_pixels+row_offset,exception);
3050 else if ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
3051 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
3052 GrayAlphaQuantum,ping_pixels+row_offset,exception);
3054 else if ((int) ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA)
3055 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
3056 RGBAQuantum,ping_pixels+row_offset,exception);
3058 else if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
3059 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
3060 IndexQuantum,ping_pixels+row_offset,exception);
3062 else /* ping_color_type == PNG_COLOR_TYPE_RGB */
3063 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
3064 RGBQuantum,ping_pixels+row_offset,exception);
3066 if (found_transparent_pixel == MagickFalse)
3068 /* Is there a transparent pixel in the row? */
3069 if (y== 0 && logging != MagickFalse)
3070 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3071 " Looking for cheap transparent pixel");
3073 for (x=(ssize_t) image->columns-1; x >= 0; x--)
3075 if ((ping_color_type == PNG_COLOR_TYPE_RGBA ||
3076 ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) &&
3077 (GetPixelAlpha(image,q) != OpaqueAlpha))
3079 if (logging != MagickFalse)
3080 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3083 found_transparent_pixel = MagickTrue;
3086 if ((ping_color_type == PNG_COLOR_TYPE_RGB ||
3087 ping_color_type == PNG_COLOR_TYPE_GRAY) &&
3088 (ScaleQuantumToShort(GetPixelRed(image,q)) ==
3089 transparent_color.red &&
3090 ScaleQuantumToShort(GetPixelGreen(image,q)) ==
3091 transparent_color.green &&
3092 ScaleQuantumToShort(GetPixelBlue(image,q)) ==
3093 transparent_color.blue))
3095 if (logging != MagickFalse)
3096 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3098 found_transparent_pixel = MagickTrue;
3101 q+=GetPixelChannels(image);
3105 if ((image->previous == (Image *) NULL) && (num_passes == 1))
3107 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
3110 if (status == MagickFalse)
3113 if (SyncAuthenticPixels(image,exception) == MagickFalse)
3117 if ((image->previous == (Image *) NULL) && (num_passes != 1))
3119 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
3120 if (status == MagickFalse)
3126 else /* image->storage_class != DirectClass */
3128 for (pass=0; pass < num_passes; pass++)
3137 Convert grayscale image to PseudoClass pixel packets.
3139 if (logging != MagickFalse)
3140 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3141 " Converting grayscale pixels to pixel packets");
3143 image->alpha_trait=ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA ?
3144 BlendPixelTrait : UndefinedPixelTrait;
3146 quantum_scanline=(Quantum *) AcquireQuantumMemory(image->columns,
3147 (image->alpha_trait == BlendPixelTrait? 2 : 1)*
3148 sizeof(*quantum_scanline));
3150 if (quantum_scanline == (Quantum *) NULL)
3151 png_error(ping,"Memory allocation failed");
3153 for (y=0; y < (ssize_t) image->rows; y++)
3156 row_offset=ping_rowbytes*y;
3161 png_read_row(ping,ping_pixels+row_offset,NULL);
3163 if (pass < num_passes-1)
3166 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
3168 if (q == (Quantum *) NULL)
3171 p=ping_pixels+row_offset;
3174 switch (ping_bit_depth)
3178 if (ping_color_type == 4)
3179 for (x=(ssize_t) image->columns-1; x >= 0; x--)
3182 SetPixelAlpha(image,ScaleCharToQuantum((unsigned char) *p++),q);
3183 if (GetPixelAlpha(image,q) != OpaqueAlpha)
3184 found_transparent_pixel = MagickTrue;
3185 q+=GetPixelChannels(image);
3189 for (x=(ssize_t) image->columns-1; x >= 0; x--)
3197 for (x=(ssize_t) image->columns-1; x >= 0; x--)
3199 #if (MAGICKCORE_QUANTUM_DEPTH == 16) || (MAGICKCORE_QUANTUM_DEPTH == 32)
3203 if (image->colors > 256)
3204 quantum=((*p++) << 8);
3210 *r=ScaleShortToQuantum(quantum);
3213 if (ping_color_type == 4)
3215 if (image->colors > 256)
3216 quantum=((*p++) << 8);
3221 SetPixelAlpha(image,ScaleShortToQuantum(quantum),q);
3222 if (GetPixelAlpha(image,q) != OpaqueAlpha)
3223 found_transparent_pixel = MagickTrue;
3224 q+=GetPixelChannels(image);
3227 #else /* MAGICKCORE_QUANTUM_DEPTH == 8 */
3229 p++; /* strip low byte */
3231 if (ping_color_type == 4)
3233 SetPixelAlpha(image,*p++,q);
3234 if (GetPixelAlpha(image,q) != OpaqueAlpha)
3235 found_transparent_pixel = MagickTrue;
3237 q+=GetPixelChannels(image);
3250 Transfer image scanline.
3254 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
3256 if (q == (Quantum *) NULL)
3258 for (x=0; x < (ssize_t) image->columns; x++)
3260 SetPixelIndex(image,*r++,q);
3261 q+=GetPixelChannels(image);
3264 if (SyncAuthenticPixels(image,exception) == MagickFalse)
3267 if ((image->previous == (Image *) NULL) && (num_passes == 1))
3269 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
3272 if (status == MagickFalse)
3277 if ((image->previous == (Image *) NULL) && (num_passes != 1))
3279 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
3281 if (status == MagickFalse)
3285 quantum_scanline=(Quantum *) RelinquishMagickMemory(quantum_scanline);
3288 image->alpha_trait=found_transparent_pixel ? BlendPixelTrait :
3289 UndefinedPixelTrait;
3291 if (logging != MagickFalse)
3293 if (found_transparent_pixel != MagickFalse)
3294 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3295 " Found transparent pixel");
3298 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3299 " No transparent pixel was found");
3301 ping_color_type&=0x03;
3306 if (quantum_info != (QuantumInfo *) NULL)
3307 quantum_info=DestroyQuantumInfo(quantum_info);
3309 if (image->storage_class == PseudoClass)
3314 alpha_trait=image->alpha_trait;
3315 image->alpha_trait=UndefinedPixelTrait;
3316 (void) SyncImage(image,exception);
3317 image->alpha_trait=alpha_trait;
3320 png_read_end(ping,end_info);
3322 if (image_info->number_scenes != 0 && mng_info->scenes_found-1 <
3323 (ssize_t) image_info->first_scene && image->delay != 0)
3325 png_destroy_read_struct(&ping,&ping_info,&end_info);
3326 ping_pixels=(unsigned char *) RelinquishMagickMemory(ping_pixels);
3328 (void) SetImageBackgroundColor(image,exception);
3329 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
3330 UnlockSemaphoreInfo(ping_semaphore);
3332 if (logging != MagickFalse)
3333 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3334 " exit ReadOnePNGImage() early.");
3338 if (png_get_valid(ping,ping_info,PNG_INFO_tRNS))
3344 Image has a transparent background.
3346 storage_class=image->storage_class;
3347 image->alpha_trait=BlendPixelTrait;
3349 /* Balfour fix from imagemagick discourse server, 5 Feb 2010 */
3351 if (storage_class == PseudoClass)
3353 if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
3355 for (x=0; x < ping_num_trans; x++)
3357 image->colormap[x].alpha_trait=BlendPixelTrait;
3358 image->colormap[x].alpha =
3359 ScaleCharToQuantum((unsigned char)ping_trans_alpha[x]);
3363 else if (ping_color_type == PNG_COLOR_TYPE_GRAY)
3365 for (x=0; x < (int) image->colors; x++)
3367 if (ScaleQuantumToShort(image->colormap[x].red) ==
3368 transparent_color.alpha)
3370 image->colormap[x].alpha_trait=BlendPixelTrait;
3371 image->colormap[x].alpha = (Quantum) TransparentAlpha;
3375 (void) SyncImage(image,exception);
3378 #if 1 /* Should have already been done above, but glennrp problem P10
3383 for (y=0; y < (ssize_t) image->rows; y++)
3385 image->storage_class=storage_class;
3386 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
3388 if (q == (Quantum *) NULL)
3392 /* Caution: on a Q8 build, this does not distinguish between
3393 * 16-bit colors that differ only in the low byte
3395 for (x=(ssize_t) image->columns-1; x >= 0; x--)
3397 if (ScaleQuantumToShort(GetPixelRed(image,q)) ==
3398 transparent_color.red &&
3399 ScaleQuantumToShort(GetPixelGreen(image,q)) ==
3400 transparent_color.green &&
3401 ScaleQuantumToShort(GetPixelBlue(image,q)) ==
3402 transparent_color.blue)
3404 SetPixelAlpha(image,TransparentAlpha,q);
3407 #if 0 /* I have not found a case where this is needed. */
3410 SetPixelAlpha(image,q)=(Quantum) OpaqueAlpha;
3414 q+=GetPixelChannels(image);
3417 if (SyncAuthenticPixels(image,exception) == MagickFalse)
3423 image->storage_class=DirectClass;
3426 for (j = 0; j < 2; j++)
3429 status = png_get_text(ping,ping_info,&text,&num_text) != 0 ?
3430 MagickTrue : MagickFalse;
3432 status = png_get_text(ping,end_info,&text,&num_text) != 0 ?
3433 MagickTrue : MagickFalse;
3435 if (status != MagickFalse)
3436 for (i=0; i < (ssize_t) num_text; i++)
3438 /* Check for a profile */
3440 if (logging != MagickFalse)
3441 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3442 " Reading PNG text chunk");
3444 if (memcmp(text[i].key, "Raw profile type ",17) == 0)
3446 (void) Magick_png_read_raw_profile(ping,image,image_info,text,
3456 length=text[i].text_length;
3457 value=(char *) AcquireQuantumMemory(length+MaxTextExtent,
3459 if (value == (char *) NULL)
3461 png_error(ping,"Memory allocation failed");
3465 (void) ConcatenateMagickString(value,text[i].text,length+2);
3467 /* Don't save "density" or "units" property if we have a pHYs
3470 if (!png_get_valid(ping,ping_info,PNG_INFO_pHYs) ||
3471 (LocaleCompare(text[i].key,"density") != 0 &&
3472 LocaleCompare(text[i].key,"units") != 0))
3473 (void) SetImageProperty(image,text[i].key,value,exception);
3475 if (logging != MagickFalse)
3477 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3478 " length: %lu",(unsigned long) length);
3479 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3480 " Keyword: %s",text[i].key);
3483 value=DestroyString(value);
3486 num_text_total += num_text;
3489 #ifdef MNG_OBJECT_BUFFERS
3491 Store the object if necessary.
3493 if (object_id && !mng_info->frozen[object_id])
3495 if (mng_info->ob[object_id] == (MngBuffer *) NULL)
3498 create a new object buffer.
3500 mng_info->ob[object_id]=(MngBuffer *)
3501 AcquireMagickMemory(sizeof(MngBuffer));
3503 if (mng_info->ob[object_id] != (MngBuffer *) NULL)
3505 mng_info->ob[object_id]->image=(Image *) NULL;
3506 mng_info->ob[object_id]->reference_count=1;
3510 if ((mng_info->ob[object_id] == (MngBuffer *) NULL) ||
3511 mng_info->ob[object_id]->frozen)
3513 if (mng_info->ob[object_id] == (MngBuffer *) NULL)
3514 png_error(ping,"Memory allocation failed");
3516 if (mng_info->ob[object_id]->frozen)
3517 png_error(ping,"Cannot overwrite frozen MNG object buffer");
3523 if (mng_info->ob[object_id]->image != (Image *) NULL)
3524 mng_info->ob[object_id]->image=DestroyImage
3525 (mng_info->ob[object_id]->image);
3527 mng_info->ob[object_id]->image=CloneImage(image,0,0,MagickTrue,
3530 if (mng_info->ob[object_id]->image != (Image *) NULL)
3531 mng_info->ob[object_id]->image->file=(FILE *) NULL;
3534 png_error(ping, "Cloning image for object buffer failed");
3536 if (ping_width > 250000L || ping_height > 250000L)
3537 png_error(ping,"PNG Image dimensions are too large.");
3539 mng_info->ob[object_id]->width=ping_width;
3540 mng_info->ob[object_id]->height=ping_height;
3541 mng_info->ob[object_id]->color_type=ping_color_type;
3542 mng_info->ob[object_id]->sample_depth=ping_bit_depth;
3543 mng_info->ob[object_id]->interlace_method=ping_interlace_method;
3544 mng_info->ob[object_id]->compression_method=
3545 ping_compression_method;
3546 mng_info->ob[object_id]->filter_method=ping_filter_method;
3548 if (png_get_valid(ping,ping_info,PNG_INFO_PLTE))
3554 Copy the PLTE to the object buffer.
3556 png_get_PLTE(ping,ping_info,&plte,&number_colors);
3557 mng_info->ob[object_id]->plte_length=number_colors;
3559 for (i=0; i < number_colors; i++)
3561 mng_info->ob[object_id]->plte[i]=plte[i];
3566 mng_info->ob[object_id]->plte_length=0;
3571 /* Set image->alpha_trait to MagickTrue if the input colortype supports
3572 * alpha or if a valid tRNS chunk is present, no matter whether there
3573 * is actual transparency present.
3575 image->alpha_trait=(((int) ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA) ||
3576 ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) ||
3577 (png_get_valid(ping,ping_info,PNG_INFO_tRNS))) ?
3578 BlendPixelTrait : UndefinedPixelTrait;
3580 /* Set more properties for identify to retrieve */
3585 if (num_text_total != 0)
3587 /* libpng doesn't tell us whether they were tEXt, zTXt, or iTXt */
3588 (void) FormatLocaleString(msg,MaxTextExtent,
3589 "%d tEXt/zTXt/iTXt chunks were found", num_text_total);
3590 (void) SetImageProperty(image,"png:text ",msg,
3594 if (num_raw_profiles != 0)
3596 (void) FormatLocaleString(msg,MaxTextExtent,
3597 "%d were found", num_raw_profiles);
3598 (void) SetImageProperty(image,"png:text-encoded profiles",msg,
3602 if (ping_found_cHRM != MagickFalse)
3604 (void) FormatLocaleString(msg,MaxTextExtent,"%s",
3605 "chunk was found (see Chromaticity, above)");
3606 (void) SetImageProperty(image,"png:cHRM ",msg,
3610 if (png_get_valid(ping,ping_info,PNG_INFO_bKGD))
3612 (void) FormatLocaleString(msg,MaxTextExtent,"%s",
3613 "chunk was found (see Background color, above)");
3614 (void) SetImageProperty(image,"png:bKGD ",msg,
3618 (void) FormatLocaleString(msg,MaxTextExtent,"%s",
3621 #if defined(PNG_iCCP_SUPPORTED)
3622 if (ping_found_iCCP != MagickFalse)
3623 (void) SetImageProperty(image,"png:iCCP ",msg,
3627 if (png_get_valid(ping,ping_info,PNG_INFO_tRNS))
3628 (void) SetImageProperty(image,"png:tRNS ",msg,
3631 #if defined(PNG_sRGB_SUPPORTED)
3632 if (ping_found_sRGB != MagickFalse)
3634 (void) FormatLocaleString(msg,MaxTextExtent,
3637 Magick_RenderingIntentString_from_PNG_RenderingIntent(intent));
3638 (void) SetImageProperty(image,"png:sRGB ",msg,
3643 if (ping_found_gAMA != MagickFalse)
3645 (void) FormatLocaleString(msg,MaxTextExtent,
3646 "gamma=%.8g (See Gamma, above)",
3648 (void) SetImageProperty(image,"png:gAMA ",msg,
3652 #if defined(PNG_pHYs_SUPPORTED)
3653 if (png_get_valid(ping,ping_info,PNG_INFO_pHYs))
3655 (void) FormatLocaleString(msg,MaxTextExtent,
3656 "x_res=%.10g, y_res=%.10g, units=%d",
3657 (double) x_resolution,(double) y_resolution, unit_type);
3658 (void) SetImageProperty(image,"png:pHYs ",msg,
3663 #if defined(PNG_oFFs_SUPPORTED)
3664 if (png_get_valid(ping,ping_info,PNG_INFO_oFFs))
3666 (void) FormatLocaleString(msg,MaxTextExtent,"x_off=%.20g, y_off=%.20g",
3667 (double) image->page.x,(double) image->page.y);
3668 (void) SetImageProperty(image,"png:oFFs ",msg,
3673 if ((image->page.width != 0 && image->page.width != image->columns) ||
3674 (image->page.height != 0 && image->page.height != image->rows))
3676 (void) FormatLocaleString(msg,MaxTextExtent,
3677 "width=%.20g, height=%.20g",
3678 (double) image->page.width,(double) image->page.height);
3679 (void) SetImageProperty(image,"png:vpAg ",msg,
3685 Relinquish resources.
3687 png_destroy_read_struct(&ping,&ping_info,&end_info);
3689 ping_pixels=(unsigned char *) RelinquishMagickMemory(ping_pixels);
3691 if (logging != MagickFalse)
3692 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3693 " exit ReadOnePNGImage()");
3695 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
3696 UnlockSemaphoreInfo(ping_semaphore);
3699 /* } for navigation to beginning of SETJMP-protected block, revert to
3700 * Throwing an Exception when an error occurs.
3705 /* end of reading one PNG image */
3708 static Image *ReadPNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
3723 magic_number[MaxTextExtent];
3731 assert(image_info != (const ImageInfo *) NULL);
3732 assert(image_info->signature == MagickSignature);
3734 if (image_info->debug != MagickFalse)
3735 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
3736 image_info->filename);
3738 assert(exception != (ExceptionInfo *) NULL);
3739 assert(exception->signature == MagickSignature);
3740 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter ReadPNGImage()");
3741 image=AcquireImage(image_info,exception);
3742 mng_info=(MngInfo *) NULL;
3743 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
3745 if (status == MagickFalse)
3746 ThrowReaderException(FileOpenError,"UnableToOpenFile");
3749 Verify PNG signature.
3751 count=ReadBlob(image,8,(unsigned char *) magic_number);
3753 if (count < 8 || memcmp(magic_number,"\211PNG\r\n\032\n",8) != 0)
3754 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
3757 Allocate a MngInfo structure.
3759 have_mng_structure=MagickFalse;
3760 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
3762 if (mng_info == (MngInfo *) NULL)
3763 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
3766 Initialize members of the MngInfo structure.
3768 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
3769 mng_info->image=image;
3770 have_mng_structure=MagickTrue;
3773 image=ReadOnePNGImage(mng_info,image_info,exception);
3774 MngInfoFreeStruct(mng_info,&have_mng_structure);
3776 if (image == (Image *) NULL)
3778 if (previous != (Image *) NULL)
3780 if (previous->signature != MagickSignature)
3781 ThrowReaderException(CorruptImageError,"CorruptImage");
3783 (void) CloseBlob(previous);
3784 (void) DestroyImageList(previous);
3787 if (logging != MagickFalse)
3788 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3789 "exit ReadPNGImage() with error");
3791 return((Image *) NULL);
3794 (void) CloseBlob(image);
3796 if ((image->columns == 0) || (image->rows == 0))
3798 if (logging != MagickFalse)
3799 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3800 "exit ReadPNGImage() with error.");
3802 ThrowReaderException(CorruptImageError,"CorruptImage");
3805 if ((IssRGBColorspace(image->colorspace) != MagickFalse) &&
3806 ((image->gamma < .45) || (image->gamma > .46)))
3807 SetImageColorspace(image,RGBColorspace,exception);
3809 if (LocaleCompare(image_info->magick,"PNG24") == 0)
3811 (void) SetImageType(image,TrueColorType,exception);
3812 image->alpha_trait=UndefinedPixelTrait;
3815 if (LocaleCompare(image_info->magick,"PNG32") == 0)
3816 (void) SetImageType(image,TrueColorMatteType,exception);
3818 if (logging != MagickFalse)
3819 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3820 " page.w: %.20g, page.h: %.20g,page.x: %.20g, page.y: %.20g.",
3821 (double) image->page.width,(double) image->page.height,
3822 (double) image->page.x,(double) image->page.y);
3824 if (logging != MagickFalse)
3825 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit ReadPNGImage()");
3832 #if defined(JNG_SUPPORTED)
3834 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3838 % R e a d O n e J N G I m a g e %
3842 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3844 % ReadOneJNGImage() reads a JPEG Network Graphics (JNG) image file
3845 % (minus the 8-byte signature) and returns it. It allocates the memory
3846 % necessary for the new Image structure and returns a pointer to the new
3849 % JNG support written by Glenn Randers-Pehrson, glennrp@image...
3851 % The format of the ReadOneJNGImage method is:
3853 % Image *ReadOneJNGImage(MngInfo *mng_info, const ImageInfo *image_info,
3854 % ExceptionInfo *exception)
3856 % A description of each parameter follows:
3858 % o mng_info: Specifies a pointer to a MngInfo structure.
3860 % o image_info: the image info.
3862 % o exception: return any errors or warnings in this structure.
3865 static Image *ReadOneJNGImage(MngInfo *mng_info,
3866 const ImageInfo *image_info, ExceptionInfo *exception)
3893 jng_image_sample_depth,
3894 jng_image_compression_method,
3895 jng_image_interlace_method,
3896 jng_alpha_sample_depth,
3897 jng_alpha_compression_method,
3898 jng_alpha_filter_method,
3899 jng_alpha_interlace_method;
3901 register const Quantum
3911 register unsigned char
3922 jng_alpha_compression_method=0;
3923 jng_alpha_sample_depth=8;
3927 alpha_image=(Image *) NULL;
3928 color_image=(Image *) NULL;
3929 alpha_image_info=(ImageInfo *) NULL;
3930 color_image_info=(ImageInfo *) NULL;
3932 logging=LogMagickEvent(CoderEvent,GetMagickModule(),
3933 " Enter ReadOneJNGImage()");
3935 image=mng_info->image;
3937 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
3940 Allocate next image structure.
3942 if (logging != MagickFalse)
3943 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3944 " AcquireNextImage()");
3946 AcquireNextImage(image_info,image,exception);
3948 if (GetNextImageInList(image) == (Image *) NULL)
3949 return((Image *) NULL);
3951 image=SyncNextImageInList(image);
3953 mng_info->image=image;
3956 Signature bytes have already been read.
3959 read_JSEP=MagickFalse;
3960 reading_idat=MagickFalse;
3961 skip_to_iend=MagickFalse;
3965 type[MaxTextExtent];
3974 Read a new JNG chunk.
3976 status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
3977 2*GetBlobSize(image));
3979 if (status == MagickFalse)
3983 (void) ConcatenateMagickString(type,"errr",MaxTextExtent);
3984 length=ReadBlobMSBLong(image);
3985 count=(unsigned int) ReadBlob(image,4,(unsigned char *) type);
3987 if (logging != MagickFalse)
3988 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3989 " Reading JNG chunk type %c%c%c%c, length: %.20g",
3990 type[0],type[1],type[2],type[3],(double) length);
3992 if (length > PNG_UINT_31_MAX || count == 0)
3993 ThrowReaderException(CorruptImageError,"CorruptImage");
3996 chunk=(unsigned char *) NULL;
4000 chunk=(unsigned char *) AcquireQuantumMemory(length,sizeof(*chunk));
4002 if (chunk == (unsigned char *) NULL)
4003 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
4005 for (i=0; i < (ssize_t) length; i++)
4006 chunk[i]=(unsigned char) ReadBlobByte(image);
4011 (void) ReadBlobMSBLong(image); /* read crc word */
4016 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4021 if (memcmp(type,mng_JHDR,4) == 0)
4025 jng_width=(size_t) ((p[0] << 24) | (p[1] << 16) |
4026 (p[2] << 8) | p[3]);
4027 jng_height=(size_t) ((p[4] << 24) | (p[5] << 16) |
4028 (p[6] << 8) | p[7]);
4029 jng_color_type=p[8];
4030 jng_image_sample_depth=p[9];
4031 jng_image_compression_method=p[10];
4032 jng_image_interlace_method=p[11];
4034 image->interlace=jng_image_interlace_method != 0 ? PNGInterlace :
4037 jng_alpha_sample_depth=p[12];
4038 jng_alpha_compression_method=p[13];
4039 jng_alpha_filter_method=p[14];
4040 jng_alpha_interlace_method=p[15];
4042 if (logging != MagickFalse)
4044 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4045 " jng_width: %16lu",(unsigned long) jng_width);
4047 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4048 " jng_width: %16lu",(unsigned long) jng_height);
4050 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4051 " jng_color_type: %16d",jng_color_type);
4053 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4054 " jng_image_sample_depth: %3d",
4055 jng_image_sample_depth);
4057 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4058 " jng_image_compression_method:%3d",
4059 jng_image_compression_method);
4061 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4062 " jng_image_interlace_method: %3d",
4063 jng_image_interlace_method);
4065 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4066 " jng_alpha_sample_depth: %3d",
4067 jng_alpha_sample_depth);
4069 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4070 " jng_alpha_compression_method:%3d",
4071 jng_alpha_compression_method);
4073 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4074 " jng_alpha_filter_method: %3d",
4075 jng_alpha_filter_method);
4077 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4078 " jng_alpha_interlace_method: %3d",
4079 jng_alpha_interlace_method);
4084 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4090 if ((reading_idat == MagickFalse) && (read_JSEP == MagickFalse) &&
4091 ((memcmp(type,mng_JDAT,4) == 0) || (memcmp(type,mng_JdAA,4) == 0) ||
4092 (memcmp(type,mng_IDAT,4) == 0) || (memcmp(type,mng_JDAA,4) == 0)))
4095 o create color_image
4096 o open color_blob, attached to color_image
4097 o if (color type has alpha)
4098 open alpha_blob, attached to alpha_image
4101 color_image_info=(ImageInfo *)AcquireMagickMemory(sizeof(ImageInfo));
4103 if (color_image_info == (ImageInfo *) NULL)
4104 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
4106 GetImageInfo(color_image_info);
4107 color_image=AcquireImage(color_image_info,exception);
4109 if (color_image == (Image *) NULL)
4110 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
4112 if (logging != MagickFalse)
4113 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4114 " Creating color_blob.");
4116 (void) AcquireUniqueFilename(color_image->filename);
4117 status=OpenBlob(color_image_info,color_image,WriteBinaryBlobMode,
4120 if (status == MagickFalse)
4121 return((Image *) NULL);
4123 if ((image_info->ping == MagickFalse) && (jng_color_type >= 12))
4125 alpha_image_info=(ImageInfo *)
4126 AcquireMagickMemory(sizeof(ImageInfo));
4128 if (alpha_image_info == (ImageInfo *) NULL)
4129 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
4131 GetImageInfo(alpha_image_info);
4132 alpha_image=AcquireImage(alpha_image_info,exception);
4134 if (alpha_image == (Image *) NULL)
4136 alpha_image=DestroyImage(alpha_image);
4137 ThrowReaderException(ResourceLimitError,
4138 "MemoryAllocationFailed");
4141 if (logging != MagickFalse)
4142 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4143 " Creating alpha_blob.");
4145 (void) AcquireUniqueFilename(alpha_image->filename);
4146 status=OpenBlob(alpha_image_info,alpha_image,WriteBinaryBlobMode,
4149 if (status == MagickFalse)
4150 return((Image *) NULL);
4152 if (jng_alpha_compression_method == 0)
4157 if (logging != MagickFalse)
4158 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4159 " Writing IHDR chunk to alpha_blob.");
4161 (void) WriteBlob(alpha_image,8,(const unsigned char *)
4162 "\211PNG\r\n\032\n");
4164 (void) WriteBlobMSBULong(alpha_image,13L);
4165 PNGType(data,mng_IHDR);
4166 LogPNGChunk(logging,mng_IHDR,13L);
4167 PNGLong(data+4,jng_width);
4168 PNGLong(data+8,jng_height);
4169 data[12]=jng_alpha_sample_depth;
4170 data[13]=0; /* color_type gray */
4171 data[14]=0; /* compression method 0 */
4172 data[15]=0; /* filter_method 0 */
4173 data[16]=0; /* interlace_method 0 */
4174 (void) WriteBlob(alpha_image,17,data);
4175 (void) WriteBlobMSBULong(alpha_image,crc32(0,data,17));
4178 reading_idat=MagickTrue;
4181 if (memcmp(type,mng_JDAT,4) == 0)
4183 /* Copy chunk to color_image->blob */
4185 if (logging != MagickFalse)
4186 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4187 " Copying JDAT chunk data to color_blob.");
4189 (void) WriteBlob(color_image,length,chunk);
4192 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4197 if (memcmp(type,mng_IDAT,4) == 0)
4202 /* Copy IDAT header and chunk data to alpha_image->blob */
4204 if (image_info->ping == MagickFalse)
4206 if (logging != MagickFalse)
4207 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4208 " Copying IDAT chunk data to alpha_blob.");
4210 (void) WriteBlobMSBULong(alpha_image,(size_t) length);
4211 PNGType(data,mng_IDAT);
4212 LogPNGChunk(logging,mng_IDAT,length);
4213 (void) WriteBlob(alpha_image,4,data);
4214 (void) WriteBlob(alpha_image,length,chunk);
4215 (void) WriteBlobMSBULong(alpha_image,
4216 crc32(crc32(0,data,4),chunk,(uInt) length));
4220 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4225 if ((memcmp(type,mng_JDAA,4) == 0) || (memcmp(type,mng_JdAA,4) == 0))
4227 /* Copy chunk data to alpha_image->blob */
4229 if (image_info->ping == MagickFalse)
4231 if (logging != MagickFalse)
4232 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4233 " Copying JDAA chunk data to alpha_blob.");
4235 (void) WriteBlob(alpha_image,length,chunk);
4239 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4244 if (memcmp(type,mng_JSEP,4) == 0)
4246 read_JSEP=MagickTrue;
4249 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4254 if (memcmp(type,mng_bKGD,4) == 0)
4258 image->background_color.red=ScaleCharToQuantum(p[1]);
4259 image->background_color.green=image->background_color.red;
4260 image->background_color.blue=image->background_color.red;
4265 image->background_color.red=ScaleCharToQuantum(p[1]);
4266 image->background_color.green=ScaleCharToQuantum(p[3]);
4267 image->background_color.blue=ScaleCharToQuantum(p[5]);
4270 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4274 if (memcmp(type,mng_gAMA,4) == 0)
4277 image->gamma=((float) mng_get_long(p))*0.00001;
4279 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4283 if (memcmp(type,mng_cHRM,4) == 0)
4287 image->chromaticity.white_point.x=0.00001*mng_get_long(p);
4288 image->chromaticity.white_point.y=0.00001*mng_get_long(&p[4]);
4289 image->chromaticity.red_primary.x=0.00001*mng_get_long(&p[8]);
4290 image->chromaticity.red_primary.y=0.00001*mng_get_long(&p[12]);
4291 image->chromaticity.green_primary.x=0.00001*mng_get_long(&p[16]);
4292 image->chromaticity.green_primary.y=0.00001*mng_get_long(&p[20]);
4293 image->chromaticity.blue_primary.x=0.00001*mng_get_long(&p[24]);
4294 image->chromaticity.blue_primary.y=0.00001*mng_get_long(&p[28]);
4297 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4301 if (memcmp(type,mng_sRGB,4) == 0)
4305 image->rendering_intent=
4306 Magick_RenderingIntent_from_PNG_RenderingIntent(p[0]);
4307 image->gamma=1.000f/2.200f;
4308 image->chromaticity.red_primary.x=0.6400f;
4309 image->chromaticity.red_primary.y=0.3300f;
4310 image->chromaticity.green_primary.x=0.3000f;
4311 image->chromaticity.green_primary.y=0.6000f;
4312 image->chromaticity.blue_primary.x=0.1500f;
4313 image->chromaticity.blue_primary.y=0.0600f;
4314 image->chromaticity.white_point.x=0.3127f;
4315 image->chromaticity.white_point.y=0.3290f;
4318 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4322 if (memcmp(type,mng_oFFs,4) == 0)
4326 image->page.x=(ssize_t) mng_get_long(p);
4327 image->page.y=(ssize_t) mng_get_long(&p[4]);
4329 if ((int) p[8] != 0)
4331 image->page.x/=10000;
4332 image->page.y/=10000;
4337 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4342 if (memcmp(type,mng_pHYs,4) == 0)
4346 image->resolution.x=(double) mng_get_long(p);
4347 image->resolution.y=(double) mng_get_long(&p[4]);
4348 if ((int) p[8] == PNG_RESOLUTION_METER)
4350 image->units=PixelsPerCentimeterResolution;
4351 image->resolution.x=image->resolution.x/100.0f;
4352 image->resolution.y=image->resolution.y/100.0f;
4356 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4361 if (memcmp(type,mng_iCCP,4) == 0)
4365 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4372 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4374 if (memcmp(type,mng_IEND,4))
4384 Finish up reading image data:
4386 o read main image from color_blob.
4390 o if (color_type has alpha)
4391 if alpha_encoding is PNG
4392 read secondary image from alpha_blob via ReadPNG
4393 if alpha_encoding is JPEG
4394 read secondary image from alpha_blob via ReadJPEG
4398 o copy intensity of secondary image into
4399 alpha samples of main image.
4401 o destroy the secondary image.
4404 (void) CloseBlob(color_image);
4406 if (logging != MagickFalse)
4407 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4408 " Reading jng_image from color_blob.");
4410 (void) FormatLocaleString(color_image_info->filename,MaxTextExtent,"%s",
4411 color_image->filename);
4413 color_image_info->ping=MagickFalse; /* To do: avoid this */
4414 jng_image=ReadImage(color_image_info,exception);
4416 if (jng_image == (Image *) NULL)
4417 return((Image *) NULL);
4419 (void) RelinquishUniqueFileResource(color_image->filename);
4420 color_image=DestroyImage(color_image);
4421 color_image_info=DestroyImageInfo(color_image_info);
4423 if (jng_image == (Image *) NULL)
4424 return((Image *) NULL);
4426 if (logging != MagickFalse)
4427 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4428 " Copying jng_image pixels to main image.");
4430 image->rows=jng_height;
4431 image->columns=jng_width;
4433 for (y=0; y < (ssize_t) image->rows; y++)
4435 s=GetVirtualPixels(jng_image,0,y,image->columns,1,exception);
4436 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
4437 for (x=(ssize_t) image->columns; x != 0; x--)
4439 SetPixelRed(image,GetPixelRed(jng_image,s),q);
4440 SetPixelGreen(image,GetPixelGreen(jng_image,s),q);
4441 SetPixelBlue(image,GetPixelBlue(jng_image,s),q);
4442 q+=GetPixelChannels(image);
4443 s+=GetPixelChannels(jng_image);
4446 if (SyncAuthenticPixels(image,exception) == MagickFalse)
4450 jng_image=DestroyImage(jng_image);
4452 if (image_info->ping == MagickFalse)
4454 if (jng_color_type >= 12)
4456 if (jng_alpha_compression_method == 0)
4460 (void) WriteBlobMSBULong(alpha_image,0x00000000L);
4461 PNGType(data,mng_IEND);
4462 LogPNGChunk(logging,mng_IEND,0L);
4463 (void) WriteBlob(alpha_image,4,data);
4464 (void) WriteBlobMSBULong(alpha_image,crc32(0,data,4));
4467 (void) CloseBlob(alpha_image);
4469 if (logging != MagickFalse)
4470 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4471 " Reading alpha from alpha_blob.");
4473 (void) FormatLocaleString(alpha_image_info->filename,MaxTextExtent,
4474 "%s",alpha_image->filename);
4476 jng_image=ReadImage(alpha_image_info,exception);
4478 if (jng_image != (Image *) NULL)
4479 for (y=0; y < (ssize_t) image->rows; y++)
4481 s=GetVirtualPixels(jng_image,0,y,image->columns,1,
4483 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
4485 if (image->alpha_trait == BlendPixelTrait)
4486 for (x=(ssize_t) image->columns; x != 0; x--)
4488 SetPixelAlpha(image,GetPixelRed(jng_image,s),q);
4489 q+=GetPixelChannels(image);
4490 s+=GetPixelChannels(jng_image);
4494 for (x=(ssize_t) image->columns; x != 0; x--)
4496 SetPixelAlpha(image,GetPixelRed(jng_image,s),q);
4497 if (GetPixelAlpha(image,q) != OpaqueAlpha)
4498 image->alpha_trait=BlendPixelTrait;
4499 q+=GetPixelChannels(image);
4500 s+=GetPixelChannels(jng_image);
4503 if (SyncAuthenticPixels(image,exception) == MagickFalse)
4506 (void) RelinquishUniqueFileResource(alpha_image->filename);
4507 alpha_image=DestroyImage(alpha_image);
4508 alpha_image_info=DestroyImageInfo(alpha_image_info);
4509 if (jng_image != (Image *) NULL)
4510 jng_image=DestroyImage(jng_image);
4514 /* Read the JNG image. */
4516 if (mng_info->mng_type == 0)
4518 mng_info->mng_width=jng_width;
4519 mng_info->mng_height=jng_height;
4522 if (image->page.width == 0 && image->page.height == 0)
4524 image->page.width=jng_width;
4525 image->page.height=jng_height;
4528 if (image->page.x == 0 && image->page.y == 0)
4530 image->page.x=mng_info->x_off[mng_info->object_id];
4531 image->page.y=mng_info->y_off[mng_info->object_id];
4536 image->page.y=mng_info->y_off[mng_info->object_id];
4539 mng_info->image_found++;
4540 status=SetImageProgress(image,LoadImagesTag,2*TellBlob(image),
4541 2*GetBlobSize(image));
4543 if (logging != MagickFalse)
4544 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4545 " exit ReadOneJNGImage()");
4551 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4555 % R e a d J N G I m a g e %
4559 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4561 % ReadJNGImage() reads a JPEG Network Graphics (JNG) image file
4562 % (including the 8-byte signature) and returns it. It allocates the memory
4563 % necessary for the new Image structure and returns a pointer to the new
4566 % JNG support written by Glenn Randers-Pehrson, glennrp@image...
4568 % The format of the ReadJNGImage method is:
4570 % Image *ReadJNGImage(const ImageInfo *image_info, ExceptionInfo
4573 % A description of each parameter follows:
4575 % o image_info: the image info.
4577 % o exception: return any errors or warnings in this structure.
4581 static Image *ReadJNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
4596 magic_number[MaxTextExtent];
4604 assert(image_info != (const ImageInfo *) NULL);
4605 assert(image_info->signature == MagickSignature);
4606 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image_info->filename);
4607 assert(exception != (ExceptionInfo *) NULL);
4608 assert(exception->signature == MagickSignature);
4609 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter ReadJNGImage()");
4610 image=AcquireImage(image_info,exception);
4611 mng_info=(MngInfo *) NULL;
4612 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
4614 if (status == MagickFalse)
4615 return((Image *) NULL);
4617 if (LocaleCompare(image_info->magick,"JNG") != 0)
4618 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
4620 /* Verify JNG signature. */
4622 count=(size_t) ReadBlob(image,8,(unsigned char *) magic_number);
4624 if (count < 8 || memcmp(magic_number,"\213JNG\r\n\032\n",8) != 0)
4625 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
4627 /* Allocate a MngInfo structure. */
4629 have_mng_structure=MagickFalse;
4630 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(*mng_info));
4632 if (mng_info == (MngInfo *) NULL)
4633 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
4635 /* Initialize members of the MngInfo structure. */
4637 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
4638 have_mng_structure=MagickTrue;
4640 mng_info->image=image;
4642 image=ReadOneJNGImage(mng_info,image_info,exception);
4643 MngInfoFreeStruct(mng_info,&have_mng_structure);
4645 if (image == (Image *) NULL)
4647 if (IsImageObject(previous) != MagickFalse)
4649 (void) CloseBlob(previous);
4650 (void) DestroyImageList(previous);
4653 if (logging != MagickFalse)
4654 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4655 "exit ReadJNGImage() with error");
4657 return((Image *) NULL);
4659 (void) CloseBlob(image);
4661 if (image->columns == 0 || image->rows == 0)
4663 if (logging != MagickFalse)
4664 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4665 "exit ReadJNGImage() with error");
4667 ThrowReaderException(CorruptImageError,"CorruptImage");
4670 if (logging != MagickFalse)
4671 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit ReadJNGImage()");
4677 static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
4680 page_geometry[MaxTextExtent];
4713 #if defined(MNG_INSERT_LAYERS)
4715 mng_background_color;
4718 register unsigned char
4733 #if defined(MNG_INSERT_LAYERS)
4738 volatile unsigned int
4739 #ifdef MNG_OBJECT_BUFFERS
4740 mng_background_object=0,
4742 mng_type=0; /* 0: PNG or JNG; 1: MNG; 2: MNG-LC; 3: MNG-VLC */
4745 default_frame_timeout,
4747 #if defined(MNG_INSERT_LAYERS)
4753 /* These delays are all measured in image ticks_per_second,
4754 * not in MNG ticks_per_second
4757 default_frame_delay,
4761 #if defined(MNG_INSERT_LAYERS)
4770 previous_fb.bottom=0;
4772 previous_fb.right=0;
4774 default_fb.bottom=0;
4778 /* Open image file. */
4780 assert(image_info != (const ImageInfo *) NULL);
4781 assert(image_info->signature == MagickSignature);
4782 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image_info->filename);
4783 assert(exception != (ExceptionInfo *) NULL);
4784 assert(exception->signature == MagickSignature);
4785 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter ReadMNGImage()");
4786 image=AcquireImage(image_info,exception);
4787 mng_info=(MngInfo *) NULL;
4788 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
4790 if (status == MagickFalse)
4791 return((Image *) NULL);
4793 first_mng_object=MagickFalse;
4795 have_mng_structure=MagickFalse;
4797 /* Allocate a MngInfo structure. */
4799 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
4801 if (mng_info == (MngInfo *) NULL)
4802 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
4804 /* Initialize members of the MngInfo structure. */
4806 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
4807 mng_info->image=image;
4808 have_mng_structure=MagickTrue;
4810 if (LocaleCompare(image_info->magick,"MNG") == 0)
4813 magic_number[MaxTextExtent];
4815 /* Verify MNG signature. */
4816 count=(size_t) ReadBlob(image,8,(unsigned char *) magic_number);
4817 if (memcmp(magic_number,"\212MNG\r\n\032\n",8) != 0)
4818 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
4820 /* Initialize some nonzero members of the MngInfo structure. */
4821 for (i=0; i < MNG_MAX_OBJECTS; i++)
4823 mng_info->object_clip[i].right=(ssize_t) PNG_UINT_31_MAX;
4824 mng_info->object_clip[i].bottom=(ssize_t) PNG_UINT_31_MAX;
4826 mng_info->exists[0]=MagickTrue;
4829 first_mng_object=MagickTrue;
4831 #if defined(MNG_INSERT_LAYERS)
4832 insert_layers=MagickFalse; /* should be False when converting or mogrifying */
4834 default_frame_delay=0;
4835 default_frame_timeout=0;
4838 mng_info->ticks_per_second=1UL*image->ticks_per_second;
4840 skip_to_iend=MagickFalse;
4841 term_chunk_found=MagickFalse;
4842 mng_info->framing_mode=1;
4843 #if defined(MNG_INSERT_LAYERS)
4844 mandatory_back=MagickFalse;
4846 #if defined(MNG_INSERT_LAYERS)
4847 mng_background_color=image->background_color;
4849 default_fb=mng_info->frame;
4850 previous_fb=mng_info->frame;
4854 type[MaxTextExtent];
4856 if (LocaleCompare(image_info->magick,"MNG") == 0)
4865 (void) ConcatenateMagickString(type,"errr",MaxTextExtent);
4866 length=ReadBlobMSBLong(image);
4867 count=(size_t) ReadBlob(image,4,(unsigned char *) type);
4869 if (logging != MagickFalse)
4870 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4871 " Reading MNG chunk type %c%c%c%c, length: %.20g",
4872 type[0],type[1],type[2],type[3],(double) length);
4874 if (length > PNG_UINT_31_MAX)
4878 ThrowReaderException(CorruptImageError,"CorruptImage");
4881 chunk=(unsigned char *) NULL;
4885 chunk=(unsigned char *) AcquireQuantumMemory(length,sizeof(*chunk));
4887 if (chunk == (unsigned char *) NULL)
4888 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
4890 for (i=0; i < (ssize_t) length; i++)
4891 chunk[i]=(unsigned char) ReadBlobByte(image);
4896 (void) ReadBlobMSBLong(image); /* read crc word */
4898 #if !defined(JNG_SUPPORTED)
4899 if (memcmp(type,mng_JHDR,4) == 0)
4901 skip_to_iend=MagickTrue;
4903 if (mng_info->jhdr_warning == 0)
4904 (void) ThrowMagickException(exception,GetMagickModule(),
4905 CoderError,"JNGCompressNotSupported","`%s'",image->filename);
4907 mng_info->jhdr_warning++;
4910 if (memcmp(type,mng_DHDR,4) == 0)
4912 skip_to_iend=MagickTrue;
4914 if (mng_info->dhdr_warning == 0)
4915 (void) ThrowMagickException(exception,GetMagickModule(),
4916 CoderError,"DeltaPNGNotSupported","`%s'",image->filename);
4918 mng_info->dhdr_warning++;
4920 if (memcmp(type,mng_MEND,4) == 0)
4925 if (memcmp(type,mng_IEND,4) == 0)
4926 skip_to_iend=MagickFalse;
4929 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4931 if (logging != MagickFalse)
4932 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4938 if (memcmp(type,mng_MHDR,4) == 0)
4940 mng_info->mng_width=(size_t) ((p[0] << 24) | (p[1] << 16) |
4941 (p[2] << 8) | p[3]);
4943 mng_info->mng_height=(size_t) ((p[4] << 24) | (p[5] << 16) |
4944 (p[6] << 8) | p[7]);
4946 if (logging != MagickFalse)
4948 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4949 " MNG width: %.20g",(double) mng_info->mng_width);
4950 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4951 " MNG height: %.20g",(double) mng_info->mng_height);
4955 mng_info->ticks_per_second=(size_t) mng_get_long(p);
4957 if (mng_info->ticks_per_second == 0)
4958 default_frame_delay=0;
4961 default_frame_delay=1UL*image->ticks_per_second/
4962 mng_info->ticks_per_second;
4964 frame_delay=default_frame_delay;
4970 simplicity=(size_t) mng_get_long(p);
4973 mng_type=1; /* Full MNG */
4975 if ((simplicity != 0) && ((simplicity | 11) == 11))
4976 mng_type=2; /* LC */
4978 if ((simplicity != 0) && ((simplicity | 9) == 9))
4979 mng_type=3; /* VLC */
4981 #if defined(MNG_INSERT_LAYERS)
4983 insert_layers=MagickTrue;
4985 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
4987 /* Allocate next image structure. */
4988 AcquireNextImage(image_info,image,exception);
4990 if (GetNextImageInList(image) == (Image *) NULL)
4991 return((Image *) NULL);
4993 image=SyncNextImageInList(image);
4994 mng_info->image=image;
4997 if ((mng_info->mng_width > 65535L) ||
4998 (mng_info->mng_height > 65535L))
4999 ThrowReaderException(ImageError,"WidthOrHeightExceedsLimit");
5001 (void) FormatLocaleString(page_geometry,MaxTextExtent,
5002 "%.20gx%.20g+0+0",(double) mng_info->mng_width,(double)
5003 mng_info->mng_height);
5005 mng_info->frame.left=0;
5006 mng_info->frame.right=(ssize_t) mng_info->mng_width;
5007 mng_info->frame.top=0;
5008 mng_info->frame.bottom=(ssize_t) mng_info->mng_height;
5009 mng_info->clip=default_fb=previous_fb=mng_info->frame;
5011 for (i=0; i < MNG_MAX_OBJECTS; i++)
5012 mng_info->object_clip[i]=mng_info->frame;
5014 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5018 if (memcmp(type,mng_TERM,4) == 0)
5029 final_delay=(png_uint_32) mng_get_long(&p[2]);
5030 mng_iterations=(png_uint_32) mng_get_long(&p[6]);
5032 if (mng_iterations == PNG_UINT_31_MAX)
5035 image->iterations=mng_iterations;
5036 term_chunk_found=MagickTrue;
5039 if (logging != MagickFalse)
5041 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5042 " repeat=%d",repeat);
5044 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5045 " final_delay=%.20g",(double) final_delay);
5047 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5048 " image->iterations=%.20g",(double) image->iterations);
5051 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5054 if (memcmp(type,mng_DEFI,4) == 0)
5057 (void) ThrowMagickException(exception,GetMagickModule(),
5058 CoderError,"DEFI chunk found in MNG-VLC datastream","`%s'",
5061 object_id=(p[0] << 8) | p[1];
5063 if (mng_type == 2 && object_id != 0)
5064 (void) ThrowMagickException(exception,GetMagickModule(),
5065 CoderError,"Nonzero object_id in MNG-LC datastream","`%s'",
5068 if (object_id > MNG_MAX_OBJECTS)
5071 Instead of using a warning we should allocate a larger
5072 MngInfo structure and continue.
5074 (void) ThrowMagickException(exception,GetMagickModule(),
5075 CoderError,"object id too large","`%s'",image->filename);
5076 object_id=MNG_MAX_OBJECTS;
5079 if (mng_info->exists[object_id])
5080 if (mng_info->frozen[object_id])
5082 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5083 (void) ThrowMagickException(exception,
5084 GetMagickModule(),CoderError,
5085 "DEFI cannot redefine a frozen MNG object","`%s'",
5090 mng_info->exists[object_id]=MagickTrue;
5093 mng_info->invisible[object_id]=p[2];
5096 Extract object offset info.
5100 mng_info->x_off[object_id]=(ssize_t) ((p[4] << 24) |
5101 (p[5] << 16) | (p[6] << 8) | p[7]);
5103 mng_info->y_off[object_id]=(ssize_t) ((p[8] << 24) |
5104 (p[9] << 16) | (p[10] << 8) | p[11]);
5106 if (logging != MagickFalse)
5108 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5109 " x_off[%d]: %.20g",object_id,(double)
5110 mng_info->x_off[object_id]);
5112 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5113 " y_off[%d]: %.20g",object_id,(double)
5114 mng_info->y_off[object_id]);
5119 Extract object clipping info.
5122 mng_info->object_clip[object_id]=mng_read_box(mng_info->frame,0,
5125 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5128 if (memcmp(type,mng_bKGD,4) == 0)
5130 mng_info->have_global_bkgd=MagickFalse;
5134 mng_info->mng_global_bkgd.red=
5135 ScaleShortToQuantum((unsigned short) ((p[0] << 8) | p[1]));
5137 mng_info->mng_global_bkgd.green=
5138 ScaleShortToQuantum((unsigned short) ((p[2] << 8) | p[3]));
5140 mng_info->mng_global_bkgd.blue=
5141 ScaleShortToQuantum((unsigned short) ((p[4] << 8) | p[5]));
5143 mng_info->have_global_bkgd=MagickTrue;
5146 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5149 if (memcmp(type,mng_BACK,4) == 0)
5151 #if defined(MNG_INSERT_LAYERS)
5153 mandatory_back=p[6];
5158 if (mandatory_back && length > 5)
5160 mng_background_color.red=
5161 ScaleShortToQuantum((unsigned short) ((p[0] << 8) | p[1]));
5163 mng_background_color.green=
5164 ScaleShortToQuantum((unsigned short) ((p[2] << 8) | p[3]));
5166 mng_background_color.blue=
5167 ScaleShortToQuantum((unsigned short) ((p[4] << 8) | p[5]));
5169 mng_background_color.alpha=OpaqueAlpha;
5172 #ifdef MNG_OBJECT_BUFFERS
5174 mng_background_object=(p[7] << 8) | p[8];
5177 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5181 if (memcmp(type,mng_PLTE,4) == 0)
5183 /* Read global PLTE. */
5185 if (length && (length < 769))
5187 if (mng_info->global_plte == (png_colorp) NULL)
5188 mng_info->global_plte=(png_colorp) AcquireQuantumMemory(256,
5189 sizeof(*mng_info->global_plte));
5191 for (i=0; i < (ssize_t) (length/3); i++)
5193 mng_info->global_plte[i].red=p[3*i];
5194 mng_info->global_plte[i].green=p[3*i+1];
5195 mng_info->global_plte[i].blue=p[3*i+2];
5198 mng_info->global_plte_length=(unsigned int) (length/3);
5201 for ( ; i < 256; i++)
5203 mng_info->global_plte[i].red=i;
5204 mng_info->global_plte[i].green=i;
5205 mng_info->global_plte[i].blue=i;
5209 mng_info->global_plte_length=256;
5212 mng_info->global_plte_length=0;
5214 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5218 if (memcmp(type,mng_tRNS,4) == 0)
5220 /* read global tRNS */
5223 for (i=0; i < (ssize_t) length; i++)
5224 mng_info->global_trns[i]=p[i];
5227 for ( ; i < 256; i++)
5228 mng_info->global_trns[i]=255;
5230 mng_info->global_trns_length=(unsigned int) length;
5231 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5234 if (memcmp(type,mng_gAMA,4) == 0)
5241 igamma=mng_get_long(p);
5242 mng_info->global_gamma=((float) igamma)*0.00001;
5243 mng_info->have_global_gama=MagickTrue;
5247 mng_info->have_global_gama=MagickFalse;
5249 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5253 if (memcmp(type,mng_cHRM,4) == 0)
5255 /* Read global cHRM */
5259 mng_info->global_chrm.white_point.x=0.00001*mng_get_long(p);
5260 mng_info->global_chrm.white_point.y=0.00001*mng_get_long(&p[4]);
5261 mng_info->global_chrm.red_primary.x=0.00001*mng_get_long(&p[8]);
5262 mng_info->global_chrm.red_primary.y=0.00001*
5263 mng_get_long(&p[12]);
5264 mng_info->global_chrm.green_primary.x=0.00001*
5265 mng_get_long(&p[16]);
5266 mng_info->global_chrm.green_primary.y=0.00001*
5267 mng_get_long(&p[20]);
5268 mng_info->global_chrm.blue_primary.x=0.00001*
5269 mng_get_long(&p[24]);
5270 mng_info->global_chrm.blue_primary.y=0.00001*
5271 mng_get_long(&p[28]);
5272 mng_info->have_global_chrm=MagickTrue;
5275 mng_info->have_global_chrm=MagickFalse;
5277 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5281 if (memcmp(type,mng_sRGB,4) == 0)
5288 mng_info->global_srgb_intent=
5289 Magick_RenderingIntent_from_PNG_RenderingIntent(p[0]);
5290 mng_info->have_global_srgb=MagickTrue;
5293 mng_info->have_global_srgb=MagickFalse;
5295 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5299 if (memcmp(type,mng_iCCP,4) == 0)
5307 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5312 if (memcmp(type,mng_FRAM,4) == 0)
5315 (void) ThrowMagickException(exception,GetMagickModule(),
5316 CoderError,"FRAM chunk found in MNG-VLC datastream","`%s'",
5319 if ((mng_info->framing_mode == 2) || (mng_info->framing_mode == 4))
5320 image->delay=frame_delay;
5322 frame_delay=default_frame_delay;
5323 frame_timeout=default_frame_timeout;
5328 mng_info->framing_mode=p[0];
5330 if (logging != MagickFalse)
5331 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5332 " Framing_mode=%d",mng_info->framing_mode);
5336 /* Note the delay and frame clipping boundaries. */
5338 p++; /* framing mode */
5340 while (*p && ((p-chunk) < (ssize_t) length))
5341 p++; /* frame name */
5343 p++; /* frame name terminator */
5345 if ((p-chunk) < (ssize_t) (length-4))
5352 change_delay=(*p++);
5353 change_timeout=(*p++);
5354 change_clipping=(*p++);
5355 p++; /* change_sync */
5359 frame_delay=1UL*image->ticks_per_second*
5362 if (mng_info->ticks_per_second != 0)
5363 frame_delay/=mng_info->ticks_per_second;
5366 frame_delay=PNG_UINT_31_MAX;
5368 if (change_delay == 2)
5369 default_frame_delay=frame_delay;
5373 if (logging != MagickFalse)
5374 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5375 " Framing_delay=%.20g",(double) frame_delay);
5380 frame_timeout=1UL*image->ticks_per_second*
5383 if (mng_info->ticks_per_second != 0)
5384 frame_timeout/=mng_info->ticks_per_second;
5387 frame_timeout=PNG_UINT_31_MAX;
5389 if (change_delay == 2)
5390 default_frame_timeout=frame_timeout;
5394 if (logging != MagickFalse)
5395 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5396 " Framing_timeout=%.20g",(double) frame_timeout);
5399 if (change_clipping)
5401 fb=mng_read_box(previous_fb,(char) p[0],&p[1]);
5405 if (logging != MagickFalse)
5406 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5407 " Frame_clip: L=%.20g R=%.20g T=%.20g B=%.20g",
5408 (double) fb.left,(double) fb.right,(double) fb.top,
5409 (double) fb.bottom);
5411 if (change_clipping == 2)
5417 mng_info->clip=mng_minimum_box(fb,mng_info->frame);
5419 subframe_width=(size_t) (mng_info->clip.right
5420 -mng_info->clip.left);
5422 subframe_height=(size_t) (mng_info->clip.bottom
5423 -mng_info->clip.top);
5425 Insert a background layer behind the frame if framing_mode is 4.
5427 #if defined(MNG_INSERT_LAYERS)
5428 if (logging != MagickFalse)
5429 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5430 " subframe_width=%.20g, subframe_height=%.20g",(double)
5431 subframe_width,(double) subframe_height);
5433 if (insert_layers && (mng_info->framing_mode == 4) &&
5434 (subframe_width) && (subframe_height))
5436 /* Allocate next image structure. */
5437 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
5439 AcquireNextImage(image_info,image,exception);
5441 if (GetNextImageInList(image) == (Image *) NULL)
5443 image=DestroyImageList(image);
5444 MngInfoFreeStruct(mng_info,&have_mng_structure);
5445 return((Image *) NULL);
5448 image=SyncNextImageInList(image);
5451 mng_info->image=image;
5453 if (term_chunk_found)
5455 image->start_loop=MagickTrue;
5456 image->iterations=mng_iterations;
5457 term_chunk_found=MagickFalse;
5461 image->start_loop=MagickFalse;
5463 image->columns=subframe_width;
5464 image->rows=subframe_height;
5465 image->page.width=subframe_width;
5466 image->page.height=subframe_height;
5467 image->page.x=mng_info->clip.left;
5468 image->page.y=mng_info->clip.top;
5469 image->background_color=mng_background_color;
5470 image->alpha_trait=UndefinedPixelTrait;
5472 (void) SetImageBackgroundColor(image,exception);
5474 if (logging != MagickFalse)
5475 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5476 " Insert backgd layer, L=%.20g, R=%.20g T=%.20g, B=%.20g",
5477 (double) mng_info->clip.left,(double) mng_info->clip.right,
5478 (double) mng_info->clip.top,(double) mng_info->clip.bottom);
5481 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5484 if (memcmp(type,mng_CLIP,4) == 0)
5493 first_object=(p[0] << 8) | p[1];
5494 last_object=(p[2] << 8) | p[3];
5496 for (i=(int) first_object; i <= (int) last_object; i++)
5498 if (mng_info->exists[i] && !mng_info->frozen[i])
5503 box=mng_info->object_clip[i];
5504 mng_info->object_clip[i]=mng_read_box(box,(char) p[4],&p[5]);
5508 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5511 if (memcmp(type,mng_SAVE,4) == 0)
5513 for (i=1; i < MNG_MAX_OBJECTS; i++)
5514 if (mng_info->exists[i])
5516 mng_info->frozen[i]=MagickTrue;
5517 #ifdef MNG_OBJECT_BUFFERS
5518 if (mng_info->ob[i] != (MngBuffer *) NULL)
5519 mng_info->ob[i]->frozen=MagickTrue;
5524 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5529 if ((memcmp(type,mng_DISC,4) == 0) || (memcmp(type,mng_SEEK,4) == 0))
5531 /* Read DISC or SEEK. */
5533 if ((length == 0) || !memcmp(type,mng_SEEK,4))
5535 for (i=1; i < MNG_MAX_OBJECTS; i++)
5536 MngInfoDiscardObject(mng_info,i);
5544 for (j=0; j < (ssize_t) length; j+=2)
5546 i=p[j] << 8 | p[j+1];
5547 MngInfoDiscardObject(mng_info,i);
5552 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5557 if (memcmp(type,mng_MOVE,4) == 0)
5565 first_object=(p[0] << 8) | p[1];
5566 last_object=(p[2] << 8) | p[3];
5567 for (i=(ssize_t) first_object; i <= (ssize_t) last_object; i++)
5569 if (mng_info->exists[i] && !mng_info->frozen[i])
5577 old_pair.a=mng_info->x_off[i];
5578 old_pair.b=mng_info->y_off[i];
5579 new_pair=mng_read_pair(old_pair,(int) p[4],&p[5]);
5580 mng_info->x_off[i]=new_pair.a;
5581 mng_info->y_off[i]=new_pair.b;
5585 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5589 if (memcmp(type,mng_LOOP,4) == 0)
5591 ssize_t loop_iters=1;
5592 loop_level=chunk[0];
5593 mng_info->loop_active[loop_level]=1; /* mark loop active */
5595 /* Record starting point. */
5596 loop_iters=mng_get_long(&chunk[1]);
5598 if (logging != MagickFalse)
5599 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5600 " LOOP level %.20g has %.20g iterations ",(double) loop_level,
5601 (double) loop_iters);
5603 if (loop_iters == 0)
5604 skipping_loop=loop_level;
5608 mng_info->loop_jump[loop_level]=TellBlob(image);
5609 mng_info->loop_count[loop_level]=loop_iters;
5612 mng_info->loop_iteration[loop_level]=0;
5613 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5617 if (memcmp(type,mng_ENDL,4) == 0)
5619 loop_level=chunk[0];
5621 if (skipping_loop > 0)
5623 if (skipping_loop == loop_level)
5626 Found end of zero-iteration loop.
5629 mng_info->loop_active[loop_level]=0;
5635 if (mng_info->loop_active[loop_level] == 1)
5637 mng_info->loop_count[loop_level]--;
5638 mng_info->loop_iteration[loop_level]++;
5640 if (logging != MagickFalse)
5641 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5642 " ENDL: LOOP level %.20g has %.20g remaining iters ",
5643 (double) loop_level,(double)
5644 mng_info->loop_count[loop_level]);
5646 if (mng_info->loop_count[loop_level] != 0)
5648 offset=SeekBlob(image,mng_info->loop_jump[loop_level],
5652 ThrowReaderException(CorruptImageError,
5653 "ImproperImageHeader");
5664 mng_info->loop_active[loop_level]=0;
5666 for (i=0; i < loop_level; i++)
5667 if (mng_info->loop_active[i] == 1)
5668 last_level=(short) i;
5669 loop_level=last_level;
5674 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5678 if (memcmp(type,mng_CLON,4) == 0)
5680 if (mng_info->clon_warning == 0)
5681 (void) ThrowMagickException(exception,GetMagickModule(),
5682 CoderError,"CLON is not implemented yet","`%s'",
5685 mng_info->clon_warning++;
5688 if (memcmp(type,mng_MAGN,4) == 0)
5703 magn_first=(p[0] << 8) | p[1];
5709 magn_last=(p[2] << 8) | p[3];
5712 magn_last=magn_first;
5713 #ifndef MNG_OBJECT_BUFFERS
5714 if (magn_first || magn_last)
5715 if (mng_info->magn_warning == 0)
5717 (void) ThrowMagickException(exception,
5718 GetMagickModule(),CoderError,
5719 "MAGN is not implemented yet for nonzero objects",
5720 "`%s'",image->filename);
5722 mng_info->magn_warning++;
5732 magn_mx=(p[5] << 8) | p[6];
5741 magn_my=(p[7] << 8) | p[8];
5750 magn_ml=(p[9] << 8) | p[10];
5759 magn_mr=(p[11] << 8) | p[12];
5768 magn_mt=(p[13] << 8) | p[14];
5777 magn_mb=(p[15] << 8) | p[16];
5789 magn_methy=magn_methx;
5792 if (magn_methx > 5 || magn_methy > 5)
5793 if (mng_info->magn_warning == 0)
5795 (void) ThrowMagickException(exception,
5796 GetMagickModule(),CoderError,
5797 "Unknown MAGN method in MNG datastream","`%s'",
5800 mng_info->magn_warning++;
5802 #ifdef MNG_OBJECT_BUFFERS
5803 /* Magnify existing objects in the range magn_first to magn_last */
5805 if (magn_first == 0 || magn_last == 0)
5807 /* Save the magnification factors for object 0 */
5808 mng_info->magn_mb=magn_mb;
5809 mng_info->magn_ml=magn_ml;
5810 mng_info->magn_mr=magn_mr;
5811 mng_info->magn_mt=magn_mt;
5812 mng_info->magn_mx=magn_mx;
5813 mng_info->magn_my=magn_my;
5814 mng_info->magn_methx=magn_methx;
5815 mng_info->magn_methy=magn_methy;
5819 if (memcmp(type,mng_PAST,4) == 0)
5821 if (mng_info->past_warning == 0)
5822 (void) ThrowMagickException(exception,GetMagickModule(),
5823 CoderError,"PAST is not implemented yet","`%s'",
5826 mng_info->past_warning++;
5829 if (memcmp(type,mng_SHOW,4) == 0)
5831 if (mng_info->show_warning == 0)
5832 (void) ThrowMagickException(exception,GetMagickModule(),
5833 CoderError,"SHOW is not implemented yet","`%s'",
5836 mng_info->show_warning++;
5839 if (memcmp(type,mng_sBIT,4) == 0)
5842 mng_info->have_global_sbit=MagickFalse;
5846 mng_info->global_sbit.gray=p[0];
5847 mng_info->global_sbit.red=p[0];
5848 mng_info->global_sbit.green=p[1];
5849 mng_info->global_sbit.blue=p[2];
5850 mng_info->global_sbit.alpha=p[3];
5851 mng_info->have_global_sbit=MagickTrue;
5854 if (memcmp(type,mng_pHYs,4) == 0)
5858 mng_info->global_x_pixels_per_unit=
5859 (size_t) mng_get_long(p);
5860 mng_info->global_y_pixels_per_unit=
5861 (size_t) mng_get_long(&p[4]);
5862 mng_info->global_phys_unit_type=p[8];
5863 mng_info->have_global_phys=MagickTrue;
5867 mng_info->have_global_phys=MagickFalse;
5869 if (memcmp(type,mng_pHYg,4) == 0)
5871 if (mng_info->phyg_warning == 0)
5872 (void) ThrowMagickException(exception,GetMagickModule(),
5873 CoderError,"pHYg is not implemented.","`%s'",image->filename);
5875 mng_info->phyg_warning++;
5877 if (memcmp(type,mng_BASI,4) == 0)
5879 skip_to_iend=MagickTrue;
5881 if (mng_info->basi_warning == 0)
5882 (void) ThrowMagickException(exception,GetMagickModule(),
5883 CoderError,"BASI is not implemented yet","`%s'",
5886 mng_info->basi_warning++;
5887 #ifdef MNG_BASI_SUPPORTED
5888 basi_width=(size_t) ((p[0] << 24) | (p[1] << 16) |
5889 (p[2] << 8) | p[3]);
5890 basi_height=(size_t) ((p[4] << 24) | (p[5] << 16) |
5891 (p[6] << 8) | p[7]);
5892 basi_color_type=p[8];
5893 basi_compression_method=p[9];
5894 basi_filter_type=p[10];
5895 basi_interlace_method=p[11];
5897 basi_red=(p[12] << 8) & p[13];
5903 basi_green=(p[14] << 8) & p[15];
5909 basi_blue=(p[16] << 8) & p[17];
5915 basi_alpha=(p[18] << 8) & p[19];
5919 if (basi_sample_depth == 16)
5926 basi_viewable=p[20];
5932 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5936 if (memcmp(type,mng_IHDR,4)
5937 #if defined(JNG_SUPPORTED)
5938 && memcmp(type,mng_JHDR,4)
5942 /* Not an IHDR or JHDR chunk */
5944 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5949 if (logging != MagickFalse)
5950 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5951 " Processing %c%c%c%c chunk",type[0],type[1],type[2],type[3]);
5953 mng_info->exists[object_id]=MagickTrue;
5954 mng_info->viewable[object_id]=MagickTrue;
5956 if (mng_info->invisible[object_id])
5958 if (logging != MagickFalse)
5959 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5960 " Skipping invisible object");
5962 skip_to_iend=MagickTrue;
5963 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5966 #if defined(MNG_INSERT_LAYERS)
5968 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
5970 image_width=(size_t) mng_get_long(p);
5971 image_height=(size_t) mng_get_long(&p[4]);
5973 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5976 Insert a transparent background layer behind the entire animation
5977 if it is not full screen.
5979 #if defined(MNG_INSERT_LAYERS)
5980 if (insert_layers && mng_type && first_mng_object)
5982 if ((mng_info->clip.left > 0) || (mng_info->clip.top > 0) ||
5983 (image_width < mng_info->mng_width) ||
5984 (mng_info->clip.right < (ssize_t) mng_info->mng_width) ||
5985 (image_height < mng_info->mng_height) ||
5986 (mng_info->clip.bottom < (ssize_t) mng_info->mng_height))
5988 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
5991 Allocate next image structure.
5993 AcquireNextImage(image_info,image,exception);
5995 if (GetNextImageInList(image) == (Image *) NULL)
5997 image=DestroyImageList(image);
5998 MngInfoFreeStruct(mng_info,&have_mng_structure);
5999 return((Image *) NULL);
6002 image=SyncNextImageInList(image);
6004 mng_info->image=image;
6006 if (term_chunk_found)
6008 image->start_loop=MagickTrue;
6009 image->iterations=mng_iterations;
6010 term_chunk_found=MagickFalse;
6014 image->start_loop=MagickFalse;
6016 /* Make a background rectangle. */
6019 image->columns=mng_info->mng_width;
6020 image->rows=mng_info->mng_height;
6021 image->page.width=mng_info->mng_width;
6022 image->page.height=mng_info->mng_height;
6025 image->background_color=mng_background_color;
6026 (void) SetImageBackgroundColor(image,exception);
6027 if (logging != MagickFalse)
6028 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6029 " Inserted transparent background layer, W=%.20g, H=%.20g",
6030 (double) mng_info->mng_width,(double) mng_info->mng_height);
6034 Insert a background layer behind the upcoming image if
6035 framing_mode is 3, and we haven't already inserted one.
6037 if (insert_layers && (mng_info->framing_mode == 3) &&
6038 (subframe_width) && (subframe_height) && (simplicity == 0 ||
6039 (simplicity & 0x08)))
6041 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
6044 Allocate next image structure.
6046 AcquireNextImage(image_info,image,exception);
6048 if (GetNextImageInList(image) == (Image *) NULL)
6050 image=DestroyImageList(image);
6051 MngInfoFreeStruct(mng_info,&have_mng_structure);
6052 return((Image *) NULL);
6055 image=SyncNextImageInList(image);
6058 mng_info->image=image;
6060 if (term_chunk_found)
6062 image->start_loop=MagickTrue;
6063 image->iterations=mng_iterations;
6064 term_chunk_found=MagickFalse;
6068 image->start_loop=MagickFalse;
6071 image->columns=subframe_width;
6072 image->rows=subframe_height;
6073 image->page.width=subframe_width;
6074 image->page.height=subframe_height;
6075 image->page.x=mng_info->clip.left;
6076 image->page.y=mng_info->clip.top;
6077 image->background_color=mng_background_color;
6078 image->alpha_trait=UndefinedPixelTrait;
6079 (void) SetImageBackgroundColor(image,exception);
6081 if (logging != MagickFalse)
6082 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6083 " Insert background layer, L=%.20g, R=%.20g T=%.20g, B=%.20g",
6084 (double) mng_info->clip.left,(double) mng_info->clip.right,
6085 (double) mng_info->clip.top,(double) mng_info->clip.bottom);
6087 #endif /* MNG_INSERT_LAYERS */
6088 first_mng_object=MagickFalse;
6090 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
6093 Allocate next image structure.
6095 AcquireNextImage(image_info,image,exception);
6097 if (GetNextImageInList(image) == (Image *) NULL)
6099 image=DestroyImageList(image);
6100 MngInfoFreeStruct(mng_info,&have_mng_structure);
6101 return((Image *) NULL);
6104 image=SyncNextImageInList(image);
6106 mng_info->image=image;
6107 status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
6108 GetBlobSize(image));
6110 if (status == MagickFalse)
6113 if (term_chunk_found)
6115 image->start_loop=MagickTrue;
6116 term_chunk_found=MagickFalse;
6120 image->start_loop=MagickFalse;
6122 if (mng_info->framing_mode == 1 || mng_info->framing_mode == 3)
6124 image->delay=frame_delay;
6125 frame_delay=default_frame_delay;
6131 image->page.width=mng_info->mng_width;
6132 image->page.height=mng_info->mng_height;
6133 image->page.x=mng_info->x_off[object_id];
6134 image->page.y=mng_info->y_off[object_id];
6135 image->iterations=mng_iterations;
6138 Seek back to the beginning of the IHDR or JHDR chunk's length field.
6141 if (logging != MagickFalse)
6142 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6143 " Seeking back to beginning of %c%c%c%c chunk",type[0],type[1],
6146 offset=SeekBlob(image,-((ssize_t) length+12),SEEK_CUR);
6149 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
6153 mng_info->image=image;
6154 mng_info->mng_type=mng_type;
6155 mng_info->object_id=object_id;
6157 if (memcmp(type,mng_IHDR,4) == 0)
6158 image=ReadOnePNGImage(mng_info,image_info,exception);
6160 #if defined(JNG_SUPPORTED)
6162 image=ReadOneJNGImage(mng_info,image_info,exception);
6165 if (image == (Image *) NULL)
6167 if (IsImageObject(previous) != MagickFalse)
6169 (void) DestroyImageList(previous);
6170 (void) CloseBlob(previous);
6173 MngInfoFreeStruct(mng_info,&have_mng_structure);
6174 return((Image *) NULL);
6177 if (image->columns == 0 || image->rows == 0)
6179 (void) CloseBlob(image);
6180 image=DestroyImageList(image);
6181 MngInfoFreeStruct(mng_info,&have_mng_structure);
6182 return((Image *) NULL);
6185 mng_info->image=image;
6192 if (mng_info->magn_methx || mng_info->magn_methy)
6198 if (logging != MagickFalse)
6199 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6200 " Processing MNG MAGN chunk");
6202 if (mng_info->magn_methx == 1)
6204 magnified_width=mng_info->magn_ml;
6206 if (image->columns > 1)
6207 magnified_width += mng_info->magn_mr;
6209 if (image->columns > 2)
6210 magnified_width += (png_uint_32)
6211 ((image->columns-2)*(mng_info->magn_mx));
6216 magnified_width=(png_uint_32) image->columns;
6218 if (image->columns > 1)
6219 magnified_width += mng_info->magn_ml-1;
6221 if (image->columns > 2)
6222 magnified_width += mng_info->magn_mr-1;
6224 if (image->columns > 3)
6225 magnified_width += (png_uint_32)
6226 ((image->columns-3)*(mng_info->magn_mx-1));
6229 if (mng_info->magn_methy == 1)
6231 magnified_height=mng_info->magn_mt;
6233 if (image->rows > 1)
6234 magnified_height += mng_info->magn_mb;
6236 if (image->rows > 2)
6237 magnified_height += (png_uint_32)
6238 ((image->rows-2)*(mng_info->magn_my));
6243 magnified_height=(png_uint_32) image->rows;
6245 if (image->rows > 1)
6246 magnified_height += mng_info->magn_mt-1;
6248 if (image->rows > 2)
6249 magnified_height += mng_info->magn_mb-1;
6251 if (image->rows > 3)
6252 magnified_height += (png_uint_32)
6253 ((image->rows-3)*(mng_info->magn_my-1));
6256 if (magnified_height > image->rows ||
6257 magnified_width > image->columns)
6284 /* Allocate next image structure. */
6286 if (logging != MagickFalse)
6287 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6288 " Allocate magnified image");
6290 AcquireNextImage(image_info,image,exception);
6292 if (GetNextImageInList(image) == (Image *) NULL)
6294 image=DestroyImageList(image);
6295 MngInfoFreeStruct(mng_info,&have_mng_structure);
6296 return((Image *) NULL);
6299 large_image=SyncNextImageInList(image);
6301 large_image->columns=magnified_width;
6302 large_image->rows=magnified_height;
6304 magn_methx=mng_info->magn_methx;
6305 magn_methy=mng_info->magn_methy;
6307 #if (MAGICKCORE_QUANTUM_DEPTH > 16)
6308 #define QM unsigned short
6309 if (magn_methx != 1 || magn_methy != 1)
6312 Scale pixels to unsigned shorts to prevent
6313 overflow of intermediate values of interpolations
6315 for (y=0; y < (ssize_t) image->rows; y++)
6317 q=GetAuthenticPixels(image,0,y,image->columns,1,
6320 for (x=(ssize_t) image->columns-1; x >= 0; x--)
6322 SetPixelRed(image,ScaleQuantumToShort(
6323 GetPixelRed(image,q)),q);
6324 SetPixelGreen(image,ScaleQuantumToShort(
6325 GetPixelGreen(image,q)),q);
6326 SetPixelBlue(image,ScaleQuantumToShort(
6327 GetPixelBlue(image,q)),q);
6328 SetPixelAlpha(image,ScaleQuantumToShort(
6329 GetPixelAlpha(image,q)),q);
6330 q+=GetPixelChannels(image);
6333 if (SyncAuthenticPixels(image,exception) == MagickFalse)
6341 if (image->alpha_trait == BlendPixelTrait)
6342 (void) SetImageBackgroundColor(large_image,exception);
6346 large_image->background_color.alpha=OpaqueAlpha;
6347 (void) SetImageBackgroundColor(large_image,exception);
6349 if (magn_methx == 4)
6352 if (magn_methx == 5)
6355 if (magn_methy == 4)
6358 if (magn_methy == 5)
6362 /* magnify the rows into the right side of the large image */
6364 if (logging != MagickFalse)
6365 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6366 " Magnify the rows to %.20g",(double) large_image->rows);
6367 m=(ssize_t) mng_info->magn_mt;
6369 length=(size_t) image->columns*GetPixelChannels(image);
6370 next=(Quantum *) AcquireQuantumMemory(length,sizeof(*next));
6371 prev=(Quantum *) AcquireQuantumMemory(length,sizeof(*prev));
6373 if ((prev == (Quantum *) NULL) ||
6374 (next == (Quantum *) NULL))
6376 image=DestroyImageList(image);
6377 MngInfoFreeStruct(mng_info,&have_mng_structure);
6378 ThrowReaderException(ResourceLimitError,
6379 "MemoryAllocationFailed");
6382 n=GetAuthenticPixels(image,0,0,image->columns,1,exception);
6383 (void) CopyMagickMemory(next,n,length);
6385 for (y=0; y < (ssize_t) image->rows; y++)
6388 m=(ssize_t) mng_info->magn_mt;
6390 else if (magn_methy > 1 && y == (ssize_t) image->rows-2)
6391 m=(ssize_t) mng_info->magn_mb;
6393 else if (magn_methy <= 1 && y == (ssize_t) image->rows-1)
6394 m=(ssize_t) mng_info->magn_mb;
6396 else if (magn_methy > 1 && y == (ssize_t) image->rows-1)
6400 m=(ssize_t) mng_info->magn_my;
6406 if (y < (ssize_t) image->rows-1)
6408 n=GetAuthenticPixels(image,0,y+1,image->columns,1,
6410 (void) CopyMagickMemory(next,n,length);
6413 for (i=0; i < m; i++, yy++)
6418 assert(yy < (ssize_t) large_image->rows);
6421 q=GetAuthenticPixels(large_image,0,yy,large_image->columns,
6423 q+=(large_image->columns-image->columns)*
6424 GetPixelChannels(large_image);
6426 for (x=(ssize_t) image->columns-1; x >= 0; x--)
6428 /* To do: get color as function of indexes[x] */
6430 if (image->storage_class == PseudoClass)
6435 if (magn_methy <= 1)
6437 /* replicate previous */
6438 SetPixelRed(large_image,GetPixelRed(image,pixels),q);
6439 SetPixelGreen(large_image,GetPixelGreen(image,
6441 SetPixelBlue(large_image,GetPixelBlue(image,
6443 SetPixelAlpha(large_image,GetPixelAlpha(image,
6447 else if (magn_methy == 2 || magn_methy == 4)
6451 SetPixelRed(large_image,GetPixelRed(image,
6453 SetPixelGreen(large_image,GetPixelGreen(image,
6455 SetPixelBlue(large_image,GetPixelBlue(image,
6457 SetPixelAlpha(large_image,GetPixelAlpha(image,
6464 SetPixelRed(large_image,((QM) (((ssize_t)
6465 (2*i*(GetPixelRed(image,n)
6466 -GetPixelRed(image,pixels)+m))/
6468 +GetPixelRed(image,pixels)))),q);
6469 SetPixelGreen(large_image,((QM) (((ssize_t)
6470 (2*i*(GetPixelGreen(image,n)
6471 -GetPixelGreen(image,pixels)+m))/
6473 +GetPixelGreen(image,pixels)))),q);
6474 SetPixelBlue(large_image,((QM) (((ssize_t)
6475 (2*i*(GetPixelBlue(image,n)
6476 -GetPixelBlue(image,pixels)+m))/
6478 +GetPixelBlue(image,pixels)))),q);
6480 if (image->alpha_trait == BlendPixelTrait)
6481 SetPixelAlpha(large_image, ((QM) (((ssize_t)
6482 (2*i*(GetPixelAlpha(image,n)
6483 -GetPixelAlpha(image,pixels)+m))
6485 GetPixelAlpha(image,pixels)))),q);
6488 if (magn_methy == 4)
6490 /* Replicate nearest */
6491 if (i <= ((m+1) << 1))
6492 SetPixelAlpha(large_image,GetPixelAlpha(image,
6495 SetPixelAlpha(large_image,GetPixelAlpha(image,
6500 else /* if (magn_methy == 3 || magn_methy == 5) */
6502 /* Replicate nearest */
6503 if (i <= ((m+1) << 1))
6505 SetPixelRed(large_image,GetPixelRed(image,
6507 SetPixelGreen(large_image,GetPixelGreen(image,
6509 SetPixelBlue(large_image,GetPixelBlue(image,
6511 SetPixelAlpha(large_image,GetPixelAlpha(image,
6517 SetPixelRed(large_image,GetPixelRed(image,n),q);
6518 SetPixelGreen(large_image,GetPixelGreen(image,n),
6520 SetPixelBlue(large_image,GetPixelBlue(image,n),
6522 SetPixelAlpha(large_image,GetPixelAlpha(image,n),
6526 if (magn_methy == 5)
6528 SetPixelAlpha(large_image,(QM) (((ssize_t) (2*i*
6529 (GetPixelAlpha(image,n)
6530 -GetPixelAlpha(image,pixels))
6531 +m))/((ssize_t) (m*2))
6532 +GetPixelAlpha(image,pixels)),q);
6535 n+=GetPixelChannels(image);
6536 q+=GetPixelChannels(large_image);
6537 pixels+=GetPixelChannels(image);
6540 if (SyncAuthenticPixels(large_image,exception) == 0)
6546 prev=(Quantum *) RelinquishMagickMemory(prev);
6547 next=(Quantum *) RelinquishMagickMemory(next);
6549 length=image->columns;
6551 if (logging != MagickFalse)
6552 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6553 " Delete original image");
6555 DeleteImageFromList(&image);
6559 mng_info->image=image;
6561 /* magnify the columns */
6562 if (logging != MagickFalse)
6563 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6564 " Magnify the columns to %.20g",(double) image->columns);
6566 for (y=0; y < (ssize_t) image->rows; y++)
6571 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
6572 pixels=q+(image->columns-length)*GetPixelChannels(image);
6573 n=pixels+GetPixelChannels(image);
6575 for (x=(ssize_t) (image->columns-length);
6576 x < (ssize_t) image->columns; x++)
6578 /* To do: Rewrite using Get/Set***PixelChannel() */
6580 if (x == (ssize_t) (image->columns-length))
6581 m=(ssize_t) mng_info->magn_ml;
6583 else if (magn_methx > 1 && x == (ssize_t) image->columns-2)
6584 m=(ssize_t) mng_info->magn_mr;
6586 else if (magn_methx <= 1 && x == (ssize_t) image->columns-1)
6587 m=(ssize_t) mng_info->magn_mr;
6589 else if (magn_methx > 1 && x == (ssize_t) image->columns-1)
6593 m=(ssize_t) mng_info->magn_mx;
6595 for (i=0; i < m; i++)
6597 if (magn_methx <= 1)
6599 /* replicate previous */
6600 SetPixelRed(image,GetPixelRed(image,pixels),q);
6601 SetPixelGreen(image,GetPixelGreen(image,pixels),q);
6602 SetPixelBlue(image,GetPixelBlue(image,pixels),q);
6603 SetPixelAlpha(image,GetPixelAlpha(image,pixels),q);
6606 else if (magn_methx == 2 || magn_methx == 4)
6610 SetPixelRed(image,GetPixelRed(image,pixels),q);
6611 SetPixelGreen(image,GetPixelGreen(image,pixels),q);
6612 SetPixelBlue(image,GetPixelBlue(image,pixels),q);
6613 SetPixelAlpha(image,GetPixelAlpha(image,pixels),q);
6616 /* To do: Rewrite using Get/Set***PixelChannel() */
6620 SetPixelRed(image,(QM) ((2*i*(
6621 GetPixelRed(image,n)
6622 -GetPixelRed(image,pixels))+m)
6624 GetPixelRed(image,pixels)),q);
6626 SetPixelGreen(image,(QM) ((2*i*(
6627 GetPixelGreen(image,n)
6628 -GetPixelGreen(image,pixels))+m)
6630 GetPixelGreen(image,pixels)),q);
6632 SetPixelBlue(image,(QM) ((2*i*(
6633 GetPixelBlue(image,n)
6634 -GetPixelBlue(image,pixels))+m)
6636 GetPixelBlue(image,pixels)),q);
6637 if (image->alpha_trait == BlendPixelTrait)
6638 SetPixelAlpha(image,(QM) ((2*i*(
6639 GetPixelAlpha(image,n)
6640 -GetPixelAlpha(image,pixels))+m)
6642 GetPixelAlpha(image,pixels)),q);
6645 if (magn_methx == 4)
6647 /* Replicate nearest */
6648 if (i <= ((m+1) << 1))
6650 SetPixelAlpha(image,
6651 GetPixelAlpha(image,pixels)+0,q);
6655 SetPixelAlpha(image,
6656 GetPixelAlpha(image,n)+0,q);
6661 else /* if (magn_methx == 3 || magn_methx == 5) */
6663 /* Replicate nearest */
6664 if (i <= ((m+1) << 1))
6666 SetPixelRed(image,GetPixelRed(image,pixels),q);
6667 SetPixelGreen(image,GetPixelGreen(image,pixels),q);
6668 SetPixelBlue(image,GetPixelBlue(image,pixels),q);
6669 SetPixelAlpha(image,GetPixelAlpha(image,pixels),q);
6674 SetPixelRed(image,GetPixelRed(image,n),q);
6675 SetPixelGreen(image,GetPixelGreen(image,n),q);
6676 SetPixelBlue(image,GetPixelBlue(image,n),q);
6677 SetPixelAlpha(image,GetPixelAlpha(image,n),q);
6680 if (magn_methx == 5)
6683 SetPixelAlpha(image,
6684 (QM) ((2*i*( GetPixelAlpha(image,n)
6685 -GetPixelAlpha(image,pixels))+m)/
6687 +GetPixelAlpha(image,pixels)),q);
6690 q+=GetPixelChannels(image);
6692 n+=GetPixelChannels(image);
6693 p+=GetPixelChannels(image);
6696 if (SyncAuthenticPixels(image,exception) == MagickFalse)
6699 #if (MAGICKCORE_QUANTUM_DEPTH > 16)
6700 if (magn_methx != 1 || magn_methy != 1)
6703 Rescale pixels to Quantum
6705 for (y=0; y < (ssize_t) image->rows; y++)
6707 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
6709 for (x=(ssize_t) image->columns-1; x >= 0; x--)
6711 SetPixelRed(image,ScaleShortToQuantum(
6712 GetPixelRed(image,q)),q);
6713 SetPixelGreen(image,ScaleShortToQuantum(
6714 GetPixelGreen(image,q)),q);
6715 SetPixelBlue(image,ScaleShortToQuantum(
6716 GetPixelBlue(image,q)),q);
6717 SetPixelAlpha(image,ScaleShortToQuantum(
6718 GetPixelAlpha(image,q)),q);
6719 q+=GetPixelChannels(image);
6722 if (SyncAuthenticPixels(image,exception) == MagickFalse)
6727 if (logging != MagickFalse)
6728 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6729 " Finished MAGN processing");
6734 Crop_box is with respect to the upper left corner of the MNG.
6736 crop_box.left=mng_info->image_box.left+mng_info->x_off[object_id];
6737 crop_box.right=mng_info->image_box.right+mng_info->x_off[object_id];
6738 crop_box.top=mng_info->image_box.top+mng_info->y_off[object_id];
6739 crop_box.bottom=mng_info->image_box.bottom+mng_info->y_off[object_id];
6740 crop_box=mng_minimum_box(crop_box,mng_info->clip);
6741 crop_box=mng_minimum_box(crop_box,mng_info->frame);
6742 crop_box=mng_minimum_box(crop_box,mng_info->object_clip[object_id]);
6743 if ((crop_box.left != (mng_info->image_box.left
6744 +mng_info->x_off[object_id])) ||
6745 (crop_box.right != (mng_info->image_box.right
6746 +mng_info->x_off[object_id])) ||
6747 (crop_box.top != (mng_info->image_box.top
6748 +mng_info->y_off[object_id])) ||
6749 (crop_box.bottom != (mng_info->image_box.bottom
6750 +mng_info->y_off[object_id])))
6752 if (logging != MagickFalse)
6753 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6754 " Crop the PNG image");
6756 if ((crop_box.left < crop_box.right) &&
6757 (crop_box.top < crop_box.bottom))
6766 Crop_info is with respect to the upper left corner of
6769 crop_info.x=(crop_box.left-mng_info->x_off[object_id]);
6770 crop_info.y=(crop_box.top-mng_info->y_off[object_id]);
6771 crop_info.width=(size_t) (crop_box.right-crop_box.left);
6772 crop_info.height=(size_t) (crop_box.bottom-crop_box.top);
6773 image->page.width=image->columns;
6774 image->page.height=image->rows;
6777 im=CropImage(image,&crop_info,exception);
6779 if (im != (Image *) NULL)
6781 image->columns=im->columns;
6782 image->rows=im->rows;
6783 im=DestroyImage(im);
6784 image->page.width=image->columns;
6785 image->page.height=image->rows;
6786 image->page.x=crop_box.left;
6787 image->page.y=crop_box.top;
6794 No pixels in crop area. The MNG spec still requires
6795 a layer, though, so make a single transparent pixel in
6796 the top left corner.
6801 (void) SetImageBackgroundColor(image,exception);
6802 image->page.width=1;
6803 image->page.height=1;
6808 #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
6809 image=mng_info->image;
6813 #if (MAGICKCORE_QUANTUM_DEPTH > 16)
6814 /* PNG does not handle depths greater than 16 so reduce it even
6817 if (image->depth > 16)
6821 #if (MAGICKCORE_QUANTUM_DEPTH > 8)
6822 if (image->depth > 8)
6824 /* To do: fill low byte properly */
6828 if (LosslessReduceDepthOK(image,exception) != MagickFalse)
6832 if (image_info->number_scenes != 0)
6834 if (mng_info->scenes_found >
6835 (ssize_t) (image_info->first_scene+image_info->number_scenes))
6839 if (logging != MagickFalse)
6840 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6841 " Finished reading image datastream.");
6843 } while (LocaleCompare(image_info->magick,"MNG") == 0);
6845 (void) CloseBlob(image);
6847 if (logging != MagickFalse)
6848 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6849 " Finished reading all image datastreams.");
6851 #if defined(MNG_INSERT_LAYERS)
6852 if (insert_layers && !mng_info->image_found && (mng_info->mng_width) &&
6853 (mng_info->mng_height))
6856 Insert a background layer if nothing else was found.
6858 if (logging != MagickFalse)
6859 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6860 " No images found. Inserting a background layer.");
6862 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
6865 Allocate next image structure.
6867 AcquireNextImage(image_info,image,exception);
6868 if (GetNextImageInList(image) == (Image *) NULL)
6870 image=DestroyImageList(image);
6871 MngInfoFreeStruct(mng_info,&have_mng_structure);
6873 if (logging != MagickFalse)
6874 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6875 " Allocation failed, returning NULL.");
6877 return((Image *) NULL);
6879 image=SyncNextImageInList(image);
6881 image->columns=mng_info->mng_width;
6882 image->rows=mng_info->mng_height;
6883 image->page.width=mng_info->mng_width;
6884 image->page.height=mng_info->mng_height;
6887 image->background_color=mng_background_color;
6888 image->alpha_trait=UndefinedPixelTrait;
6890 if (image_info->ping == MagickFalse)
6891 (void) SetImageBackgroundColor(image,exception);
6893 mng_info->image_found++;
6896 image->iterations=mng_iterations;
6898 if (mng_iterations == 1)
6899 image->start_loop=MagickTrue;
6901 while (GetPreviousImageInList(image) != (Image *) NULL)
6904 if (image_count > 10*mng_info->image_found)
6906 if (logging != MagickFalse)
6907 (void) LogMagickEvent(CoderEvent,GetMagickModule()," No beginning");
6909 (void) ThrowMagickException(exception,GetMagickModule(),
6910 CoderError,"Linked list is corrupted, beginning of list not found",
6911 "`%s'",image_info->filename);
6913 return((Image *) NULL);
6916 image=GetPreviousImageInList(image);
6918 if (GetNextImageInList(image) == (Image *) NULL)
6920 if (logging != MagickFalse)
6921 (void) LogMagickEvent(CoderEvent,GetMagickModule()," Corrupt list");
6923 (void) ThrowMagickException(exception,GetMagickModule(),
6924 CoderError,"Linked list is corrupted; next_image is NULL","`%s'",
6925 image_info->filename);
6929 if (mng_info->ticks_per_second && mng_info->image_found > 1 &&
6930 GetNextImageInList(image) ==
6933 if (logging != MagickFalse)
6934 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6935 " First image null");
6937 (void) ThrowMagickException(exception,GetMagickModule(),
6938 CoderError,"image->next for first image is NULL but shouldn't be.",
6939 "`%s'",image_info->filename);
6942 if (mng_info->image_found == 0)
6944 if (logging != MagickFalse)
6945 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6946 " No visible images found.");
6948 (void) ThrowMagickException(exception,GetMagickModule(),
6949 CoderError,"No visible images in file","`%s'",image_info->filename);
6951 if (image != (Image *) NULL)
6952 image=DestroyImageList(image);
6954 MngInfoFreeStruct(mng_info,&have_mng_structure);
6955 return((Image *) NULL);
6958 if (mng_info->ticks_per_second)
6959 final_delay=1UL*MagickMax(image->ticks_per_second,1L)*
6960 final_delay/mng_info->ticks_per_second;
6963 image->start_loop=MagickTrue;
6965 /* Find final nonzero image delay */
6966 final_image_delay=0;
6968 while (GetNextImageInList(image) != (Image *) NULL)
6971 final_image_delay=image->delay;
6973 image=GetNextImageInList(image);
6976 if (final_delay < final_image_delay)
6977 final_delay=final_image_delay;
6979 image->delay=final_delay;
6981 if (logging != MagickFalse)
6982 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6983 " image->delay=%.20g, final_delay=%.20g",(double) image->delay,
6984 (double) final_delay);
6986 if (logging != MagickFalse)
6992 image=GetFirstImageInList(image);
6994 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6995 " Before coalesce:");
6997 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6998 " scene 0 delay=%.20g",(double) image->delay);
7000 while (GetNextImageInList(image) != (Image *) NULL)
7002 image=GetNextImageInList(image);
7003 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7004 " scene %.20g delay=%.20g",(double) scene++,(double) image->delay);
7008 image=GetFirstImageInList(image);
7009 #ifdef MNG_COALESCE_LAYERS
7019 if (logging != MagickFalse)
7020 (void) LogMagickEvent(CoderEvent,GetMagickModule()," Coalesce Images");
7023 next_image=CoalesceImages(image,exception);
7025 if (next_image == (Image *) NULL)
7026 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
7028 image=DestroyImageList(image);
7031 for (next=image; next != (Image *) NULL; next=next_image)
7033 next->page.width=mng_info->mng_width;
7034 next->page.height=mng_info->mng_height;
7037 next->scene=scene++;
7038 next_image=GetNextImageInList(next);
7040 if (next_image == (Image *) NULL)
7043 if (next->delay == 0)
7046 next_image->previous=GetPreviousImageInList(next);
7047 if (GetPreviousImageInList(next) == (Image *) NULL)
7050 next->previous->next=next_image;
7051 next=DestroyImage(next);
7057 while (GetNextImageInList(image) != (Image *) NULL)
7058 image=GetNextImageInList(image);
7060 image->dispose=BackgroundDispose;
7062 if (logging != MagickFalse)
7068 image=GetFirstImageInList(image);
7070 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7071 " After coalesce:");
7073 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7074 " scene 0 delay=%.20g dispose=%.20g",(double) image->delay,
7075 (double) image->dispose);
7077 while (GetNextImageInList(image) != (Image *) NULL)
7079 image=GetNextImageInList(image);
7081 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7082 " scene %.20g delay=%.20g dispose=%.20g",(double) scene++,
7083 (double) image->delay,(double) image->dispose);
7087 image=GetFirstImageInList(image);
7088 MngInfoFreeStruct(mng_info,&have_mng_structure);
7089 have_mng_structure=MagickFalse;
7091 if (logging != MagickFalse)
7092 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit ReadMNGImage()");
7094 return(GetFirstImageInList(image));
7096 #else /* PNG_LIBPNG_VER > 10011 */
7097 static Image *ReadPNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
7099 printf("Your PNG library is too old: You have libpng-%s\n",
7100 PNG_LIBPNG_VER_STRING);
7102 (void) ThrowMagickException(exception,GetMagickModule(),CoderError,
7103 "PNG library is too old","`%s'",image_info->filename);
7105 return(Image *) NULL;
7108 static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
7110 return(ReadPNGImage(image_info,exception));
7112 #endif /* PNG_LIBPNG_VER > 10011 */
7116 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7120 % R e g i s t e r P N G I m a g e %
7124 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7126 % RegisterPNGImage() adds properties for the PNG image format to
7127 % the list of supported formats. The properties include the image format
7128 % tag, a method to read and/or write the format, whether the format
7129 % supports the saving of more than one frame to the same file or blob,
7130 % whether the format supports native in-memory I/O, and a brief
7131 % description of the format.
7133 % The format of the RegisterPNGImage method is:
7135 % size_t RegisterPNGImage(void)
7138 ModuleExport size_t RegisterPNGImage(void)
7141 version[MaxTextExtent];
7149 "See http://www.libpng.org/ for details about the PNG format."
7154 "See http://www.libpng.org/pub/mng/ for details about the JNG\n"
7160 "See http://www.libpng.org/pub/mng/ for details about the MNG\n"
7166 #if defined(PNG_LIBPNG_VER_STRING)
7167 (void) ConcatenateMagickString(version,"libpng ",MaxTextExtent);
7168 (void) ConcatenateMagickString(version,PNG_LIBPNG_VER_STRING,MaxTextExtent);
7170 if (LocaleCompare(PNG_LIBPNG_VER_STRING,png_get_header_ver(NULL)) != 0)
7172 (void) ConcatenateMagickString(version,",",MaxTextExtent);
7173 (void) ConcatenateMagickString(version,png_get_libpng_ver(NULL),
7178 entry=SetMagickInfo("MNG");
7179 entry->seekable_stream=MagickTrue; /* To do: eliminate this. */
7181 #if defined(MAGICKCORE_PNG_DELEGATE)
7182 entry->decoder=(DecodeImageHandler *) ReadMNGImage;
7183 entry->encoder=(EncodeImageHandler *) WriteMNGImage;
7186 entry->magick=(IsImageFormatHandler *) IsMNG;
7187 entry->description=ConstantString("Multiple-image Network Graphics");
7189 if (*version != '\0')
7190 entry->version=ConstantString(version);
7192 entry->module=ConstantString("PNG");
7193 entry->note=ConstantString(MNGNote);
7194 (void) RegisterMagickInfo(entry);
7196 entry=SetMagickInfo("PNG");
7198 #if defined(MAGICKCORE_PNG_DELEGATE)
7199 entry->decoder=(DecodeImageHandler *) ReadPNGImage;
7200 entry->encoder=(EncodeImageHandler *) WritePNGImage;
7203 entry->magick=(IsImageFormatHandler *) IsPNG;
7204 entry->adjoin=MagickFalse;
7205 entry->description=ConstantString("Portable Network Graphics");
7206 entry->module=ConstantString("PNG");
7208 if (*version != '\0')
7209 entry->version=ConstantString(version);
7211 entry->note=ConstantString(PNGNote);
7212 (void) RegisterMagickInfo(entry);
7214 entry=SetMagickInfo("PNG8");
7216 #if defined(MAGICKCORE_PNG_DELEGATE)
7217 entry->decoder=(DecodeImageHandler *) ReadPNGImage;
7218 entry->encoder=(EncodeImageHandler *) WritePNGImage;
7221 entry->magick=(IsImageFormatHandler *) IsPNG;
7222 entry->adjoin=MagickFalse;
7223 entry->description=ConstantString(
7224 "8-bit indexed with optional binary transparency");
7225 entry->module=ConstantString("PNG");
7226 (void) RegisterMagickInfo(entry);
7228 entry=SetMagickInfo("PNG24");
7231 #if defined(ZLIB_VERSION)
7232 (void) ConcatenateMagickString(version,"zlib ",MaxTextExtent);
7233 (void) ConcatenateMagickString(version,ZLIB_VERSION,MaxTextExtent);
7235 if (LocaleCompare(ZLIB_VERSION,zlib_version) != 0)
7237 (void) ConcatenateMagickString(version,",",MaxTextExtent);
7238 (void) ConcatenateMagickString(version,zlib_version,MaxTextExtent);
7242 if (*version != '\0')
7243 entry->version=ConstantString(version);
7245 #if defined(MAGICKCORE_PNG_DELEGATE)
7246 entry->decoder=(DecodeImageHandler *) ReadPNGImage;
7247 entry->encoder=(EncodeImageHandler *) WritePNGImage;
7250 entry->magick=(IsImageFormatHandler *) IsPNG;
7251 entry->adjoin=MagickFalse;
7252 entry->description=ConstantString("opaque 24-bit RGB");
7253 entry->module=ConstantString("PNG");
7254 (void) RegisterMagickInfo(entry);
7256 entry=SetMagickInfo("PNG32");
7258 #if defined(MAGICKCORE_PNG_DELEGATE)
7259 entry->decoder=(DecodeImageHandler *) ReadPNGImage;
7260 entry->encoder=(EncodeImageHandler *) WritePNGImage;
7263 entry->magick=(IsImageFormatHandler *) IsPNG;
7264 entry->adjoin=MagickFalse;
7265 entry->description=ConstantString("opaque or transparent 32-bit RGBA");
7266 entry->module=ConstantString("PNG");
7267 (void) RegisterMagickInfo(entry);
7269 entry=SetMagickInfo("JNG");
7271 #if defined(JNG_SUPPORTED)
7272 #if defined(MAGICKCORE_PNG_DELEGATE)
7273 entry->decoder=(DecodeImageHandler *) ReadJNGImage;
7274 entry->encoder=(EncodeImageHandler *) WriteJNGImage;
7278 entry->magick=(IsImageFormatHandler *) IsJNG;
7279 entry->adjoin=MagickFalse;
7280 entry->description=ConstantString("JPEG Network Graphics");
7281 entry->module=ConstantString("PNG");
7282 entry->note=ConstantString(JNGNote);
7283 (void) RegisterMagickInfo(entry);
7285 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
7286 ping_semaphore=AllocateSemaphoreInfo();
7289 return(MagickImageCoderSignature);
7293 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7297 % U n r e g i s t e r P N G I m a g e %
7301 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7303 % UnregisterPNGImage() removes format registrations made by the
7304 % PNG module from the list of supported formats.
7306 % The format of the UnregisterPNGImage method is:
7308 % UnregisterPNGImage(void)
7311 ModuleExport void UnregisterPNGImage(void)
7313 (void) UnregisterMagickInfo("MNG");
7314 (void) UnregisterMagickInfo("PNG");
7315 (void) UnregisterMagickInfo("PNG8");
7316 (void) UnregisterMagickInfo("PNG24");
7317 (void) UnregisterMagickInfo("PNG32");
7318 (void) UnregisterMagickInfo("JNG");
7320 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
7321 if (ping_semaphore != (SemaphoreInfo *) NULL)
7322 DestroySemaphoreInfo(&ping_semaphore);
7326 #if defined(MAGICKCORE_PNG_DELEGATE)
7327 #if PNG_LIBPNG_VER > 10011
7329 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7333 % W r i t e M N G I m a g e %
7337 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7339 % WriteMNGImage() writes an image in the Portable Network Graphics
7340 % Group's "Multiple-image Network Graphics" encoded image format.
7342 % MNG support written by Glenn Randers-Pehrson, glennrp@image...
7344 % The format of the WriteMNGImage method is:
7346 % MagickBooleanType WriteMNGImage(const ImageInfo *image_info,
7347 % Image *image,ExceptionInfo *exception)
7349 % A description of each parameter follows.
7351 % o image_info: the image info.
7353 % o image: The image.
7355 % o exception: return any errors or warnings in this structure.
7357 % To do (as of version 5.5.2, November 26, 2002 -- glennrp -- see also
7358 % "To do" under ReadPNGImage):
7360 % Preserve all unknown and not-yet-handled known chunks found in input
7361 % PNG file and copy them into output PNG files according to the PNG
7364 % Write the iCCP chunk at MNG level when (icc profile length > 0)
7366 % Improve selection of color type (use indexed-colour or indexed-colour
7367 % with tRNS when 256 or fewer unique RGBA values are present).
7369 % Figure out what to do with "dispose=<restore-to-previous>" (dispose == 3)
7370 % This will be complicated if we limit ourselves to generating MNG-LC
7371 % files. For now we ignore disposal method 3 and simply overlay the next
7374 % Check for identical PLTE's or PLTE/tRNS combinations and use a
7375 % global MNG PLTE or PLTE/tRNS combination when appropriate.
7376 % [mostly done 15 June 1999 but still need to take care of tRNS]
7378 % Check for identical sRGB and replace with a global sRGB (and remove
7379 % gAMA/cHRM if sRGB is found; check for identical gAMA/cHRM and
7380 % replace with global gAMA/cHRM (or with sRGB if appropriate; replace
7381 % local gAMA/cHRM with local sRGB if appropriate).
7383 % Check for identical sBIT chunks and write global ones.
7385 % Provide option to skip writing the signature tEXt chunks.
7387 % Use signatures to detect identical objects and reuse the first
7388 % instance of such objects instead of writing duplicate objects.
7390 % Use a smaller-than-32k value of compression window size when
7393 % Encode JNG datastreams. Mostly done as of 5.5.2; need to write
7394 % ancillary text chunks and save profiles.
7396 % Provide an option to force LC files (to ensure exact framing rate)
7399 % Provide an option to force VLC files instead of LC, even when offsets
7400 % are present. This will involve expanding the embedded images with a
7401 % transparent region at the top and/or left.
7405 Magick_png_write_raw_profile(const ImageInfo *image_info,png_struct *ping,
7406 png_info *ping_info, unsigned char *profile_type, unsigned char
7407 *profile_description, unsigned char *profile_data, png_uint_32 length)
7426 hex[16]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
7428 if (LocaleNCompare((char *) profile_type+1, "ng-chunk-",9) == 0)
7431 if (image_info->verbose)
7433 (void) printf("writing raw profile: type=%s, length=%.20g\n",
7434 (char *) profile_type, (double) length);
7437 #if PNG_LIBPNG_VER >= 14000
7438 text=(png_textp) png_malloc(ping,(png_alloc_size_t) sizeof(png_text));
7440 text=(png_textp) png_malloc(ping,(png_size_t) sizeof(png_text));
7442 description_length=(png_uint_32) strlen((const char *) profile_description);
7443 allocated_length=(png_uint_32) (length*2 + (length >> 5) + 20
7444 + description_length);
7445 #if PNG_LIBPNG_VER >= 14000
7446 text[0].text=(png_charp) png_malloc(ping,
7447 (png_alloc_size_t) allocated_length);
7448 text[0].key=(png_charp) png_malloc(ping, (png_alloc_size_t) 80);
7450 text[0].text=(png_charp) png_malloc(ping, (png_size_t) allocated_length);
7451 text[0].key=(png_charp) png_malloc(ping, (png_size_t) 80);
7453 text[0].key[0]='\0';
7454 (void) ConcatenateMagickString(text[0].key,
7455 "Raw profile type ",MaxTextExtent);
7456 (void) ConcatenateMagickString(text[0].key,(const char *) profile_type,62);
7460 (void) CopyMagickString(dp,(const char *) profile_description,
7462 dp+=description_length;
7464 (void) FormatLocaleString(dp,allocated_length-
7465 (png_size_t) (dp-text[0].text),"%8lu ",(unsigned long) length);
7468 for (i=0; i < (ssize_t) length; i++)
7472 *(dp++)=(char) hex[((*sp >> 4) & 0x0f)];
7473 *(dp++)=(char) hex[((*sp++ ) & 0x0f)];
7478 text[0].text_length=(png_size_t) (dp-text[0].text);
7479 text[0].compression=image_info->compression == NoCompression ||
7480 (image_info->compression == UndefinedCompression &&
7481 text[0].text_length < 128) ? -1 : 0;
7483 if (text[0].text_length <= allocated_length)
7484 png_set_text(ping,ping_info,text,1);
7486 png_free(ping,text[0].text);
7487 png_free(ping,text[0].key);
7488 png_free(ping,text);
7491 static MagickBooleanType Magick_png_write_chunk_from_profile(Image *image,
7492 const char *string, MagickBooleanType logging)
7505 ResetImageProfileIterator(image);
7507 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
7509 profile=GetImageProfile(image,name);
7511 if (profile != (const StringInfo *) NULL)
7516 if (LocaleNCompare(name,string,11) == 0)
7518 if (logging != MagickFalse)
7519 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7520 " Found %s profile",name);
7522 ping_profile=CloneStringInfo(profile);
7523 data=GetStringInfoDatum(ping_profile),
7524 length=(png_uint_32) GetStringInfoLength(ping_profile);
7529 (void) WriteBlobMSBULong(image,length-5); /* data length */
7530 (void) WriteBlob(image,length-1,data+1);
7531 (void) WriteBlobMSBULong(image,crc32(0,data+1,(uInt) length-1));
7532 ping_profile=DestroyStringInfo(ping_profile);
7536 name=GetNextImageProfile(image);
7543 /* Write one PNG image */
7544 static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
7545 const ImageInfo *IMimage_info,Image *IMimage,ExceptionInfo *exception)
7569 ping_trans_alpha[256];
7597 ping_have_cheap_transparency,
7608 /* ping_exclude_EXIF, */
7611 /* ping_exclude_iTXt, */
7616 /* ping_exclude_tRNS, */
7618 ping_exclude_zCCP, /* hex-encoded iCCP */
7621 ping_preserve_colormap,
7622 ping_need_colortype_warning,
7640 *volatile ping_pixels;
7646 ping_interlace_method,
7647 ping_compression_method,
7664 number_semitransparent,
7666 ping_pHYs_unit_type;
7669 ping_pHYs_x_resolution,
7670 ping_pHYs_y_resolution;
7672 logging=LogMagickEvent(CoderEvent,GetMagickModule(),
7673 " Enter WriteOnePNGImage()");
7675 image = CloneImage(IMimage,0,0,MagickFalse,exception);
7676 image_info=(ImageInfo *) CloneImageInfo(IMimage_info);
7677 if (image_info == (ImageInfo *) NULL)
7678 ThrowWriterException(ResourceLimitError, "MemoryAllocationFailed");
7680 /* Initialize some stuff */
7683 ping_interlace_method=0,
7684 ping_compression_method=0,
7685 ping_filter_method=0,
7688 ping_background.red = 0;
7689 ping_background.green = 0;
7690 ping_background.blue = 0;
7691 ping_background.gray = 0;
7692 ping_background.index = 0;
7694 ping_trans_color.red=0;
7695 ping_trans_color.green=0;
7696 ping_trans_color.blue=0;
7697 ping_trans_color.gray=0;
7699 ping_pHYs_unit_type = 0;
7700 ping_pHYs_x_resolution = 0;
7701 ping_pHYs_y_resolution = 0;
7703 ping_have_blob=MagickFalse;
7704 ping_have_color=MagickTrue;
7705 ping_have_non_bw=MagickTrue;
7706 ping_have_PLTE=MagickFalse;
7707 ping_have_bKGD=MagickFalse;
7708 ping_have_pHYs=MagickFalse;
7709 ping_have_tRNS=MagickFalse;
7711 ping_exclude_bKGD=mng_info->ping_exclude_bKGD;
7712 ping_exclude_cHRM=mng_info->ping_exclude_cHRM;
7713 ping_exclude_date=mng_info->ping_exclude_date;
7714 /* ping_exclude_EXIF=mng_info->ping_exclude_EXIF; */
7715 ping_exclude_gAMA=mng_info->ping_exclude_gAMA;
7716 ping_exclude_iCCP=mng_info->ping_exclude_iCCP;
7717 /* ping_exclude_iTXt=mng_info->ping_exclude_iTXt; */
7718 ping_exclude_oFFs=mng_info->ping_exclude_oFFs;
7719 ping_exclude_pHYs=mng_info->ping_exclude_pHYs;
7720 ping_exclude_sRGB=mng_info->ping_exclude_sRGB;
7721 ping_exclude_tEXt=mng_info->ping_exclude_tEXt;
7722 /* ping_exclude_tRNS=mng_info->ping_exclude_tRNS; */
7723 ping_exclude_vpAg=mng_info->ping_exclude_vpAg;
7724 ping_exclude_zCCP=mng_info->ping_exclude_zCCP; /* hex-encoded iCCP in zTXt */
7725 ping_exclude_zTXt=mng_info->ping_exclude_zTXt;
7727 ping_preserve_colormap = mng_info->ping_preserve_colormap;
7728 ping_need_colortype_warning = MagickFalse;
7730 /* Recognize the ICC sRGB profile and convert it to the sRGB chunk,
7731 * i.e., eliminate the ICC profile and set image->rendering_intent.
7732 * Note that this will not involve any changes to the actual pixels
7733 * but merely passes information to applications that read the resulting
7736 if (ping_exclude_sRGB == MagickFalse)
7744 ResetImageProfileIterator(image);
7745 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
7747 profile=GetImageProfile(image,name);
7749 if (profile != (StringInfo *) NULL)
7751 if ((LocaleCompare(name,"ICC") == 0) ||
7752 (LocaleCompare(name,"ICM") == 0))
7757 /* 0: not a known sRGB profile
7758 * 1: HP-Microsoft sRGB v2
7759 * 2: ICC sRGB v4 perceptual
7760 * 3: ICC sRGB v2 perceptual no black-compensation
7763 check_crc[4] = {0, 0xf29e526dUL, 0xbbef7812UL, 0x427ebb21UL},
7764 check_len[4] = {0, 3144, 60960, 3052};
7773 length=(png_uint_32) GetStringInfoLength(profile);
7775 for (icheck=3; icheck > 0; icheck--)
7777 if (length == check_len[icheck])
7779 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7780 " Got a %lu-byte ICC profile (potentially sRGB)",
7781 (unsigned long) length);
7783 data=GetStringInfoDatum(profile);
7784 profile_crc=crc32(0,data,length);
7786 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7787 " with crc=%8x",(unsigned int) profile_crc);
7789 if (profile_crc == check_crc[icheck])
7791 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7793 if (image->rendering_intent==UndefinedIntent)
7794 image->rendering_intent=PerceptualIntent;
7800 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7801 " Got a %lu-byte ICC profile",
7802 (unsigned long) length);
7805 name=GetNextImageProfile(image);
7810 number_semitransparent = 0;
7811 number_transparent = 0;
7813 if (logging != MagickFalse)
7815 if (image->storage_class == UndefinedClass)
7816 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7817 " storage_class=UndefinedClass");
7818 if (image->storage_class == DirectClass)
7819 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7820 " storage_class=DirectClass");
7821 if (image->storage_class == PseudoClass)
7822 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7823 " storage_class=PseudoClass");
7826 if (image->storage_class == PseudoClass &&
7827 (mng_info->write_png8 || mng_info->write_png24 || mng_info->write_png32 ||
7828 (mng_info->write_png_colortype != 0 &&
7829 mng_info->write_png_colortype != 4)))
7831 (void) SyncImage(image,exception);
7832 image->storage_class = DirectClass;
7835 if (ping_preserve_colormap == MagickFalse)
7837 if (image->storage_class != PseudoClass && image->colormap != NULL)
7839 /* Free the bogus colormap; it can cause trouble later */
7840 if (logging != MagickFalse)
7841 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7842 " Freeing bogus colormap");
7843 (void) RelinquishMagickMemory(image->colormap);
7844 image->colormap=NULL;
7848 if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
7849 (void) TransformImageColorspace(image,sRGBColorspace,exception);
7852 Sometimes we get PseudoClass images whose RGB values don't match
7853 the colors in the colormap. This code syncs the RGB values.
7855 if (image->depth <= 8 && image->taint && image->storage_class == PseudoClass)
7856 (void) SyncImage(image,exception);
7858 #if (MAGICKCORE_QUANTUM_DEPTH == 8)
7859 if (image->depth > 8)
7861 if (logging != MagickFalse)
7862 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7863 " Reducing PNG bit depth to 8 since this is a Q8 build.");
7869 /* Respect the -depth option */
7870 if (image->depth < MAGICKCORE_QUANTUM_DEPTH)
7875 if (image->depth > 8)
7877 #if MAGICKCORE_QUANTUM_DEPTH > 16
7878 /* Scale to 16-bit */
7879 LBR16PacketRGBO(image->background_color);
7881 for (y=0; y < (ssize_t) image->rows; y++)
7883 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
7885 if (r == (Quantum *) NULL)
7888 for (x=0; x < (ssize_t) image->columns; x++)
7891 r+=GetPixelChannels(image);
7894 if (SyncAuthenticPixels(image,exception) == MagickFalse)
7898 if (image->storage_class == PseudoClass && image->colormap != NULL)
7900 for (i=0; i < (ssize_t) image->colors; i++)
7902 LBR16PacketRGBO(image->colormap[i]);
7905 #endif /* MAGICKCORE_QUANTUM_DEPTH > 16 */
7908 else if (image->depth > 4)
7910 #if MAGICKCORE_QUANTUM_DEPTH > 8
7911 /* Scale to 8-bit */
7912 LBR08PacketRGBO(image->background_color);
7914 for (y=0; y < (ssize_t) image->rows; y++)
7916 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
7918 if (r == (Quantum *) NULL)
7921 for (x=0; x < (ssize_t) image->columns; x++)
7924 r+=GetPixelChannels(image);
7927 if (SyncAuthenticPixels(image,exception) == MagickFalse)
7931 if (image->storage_class == PseudoClass && image->colormap != NULL)
7933 for (i=0; i < (ssize_t) image->colors; i++)
7935 LBR08PacketRGBO(image->colormap[i]);
7938 #endif /* MAGICKCORE_QUANTUM_DEPTH > 8 */
7941 if (image->depth > 2)
7943 /* Scale to 4-bit */
7944 LBR04PacketRGBO(image->background_color);
7946 for (y=0; y < (ssize_t) image->rows; y++)
7948 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
7950 if (r == (Quantum *) NULL)
7953 for (x=0; x < (ssize_t) image->columns; x++)
7956 r+=GetPixelChannels(image);
7959 if (SyncAuthenticPixels(image,exception) == MagickFalse)
7963 if (image->storage_class == PseudoClass && image->colormap != NULL)
7965 for (i=0; i < (ssize_t) image->colors; i++)
7967 LBR04PacketRGBO(image->colormap[i]);
7972 else if (image->depth > 1)
7974 /* Scale to 2-bit */
7975 LBR02PacketRGBO(image->background_color);
7977 for (y=0; y < (ssize_t) image->rows; y++)
7979 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
7981 if (r == (Quantum *) NULL)
7984 for (x=0; x < (ssize_t) image->columns; x++)
7987 r+=GetPixelChannels(image);
7990 if (SyncAuthenticPixels(image,exception) == MagickFalse)
7994 if (image->storage_class == PseudoClass && image->colormap != NULL)
7996 for (i=0; i < (ssize_t) image->colors; i++)
7998 LBR02PacketRGBO(image->colormap[i]);
8004 /* Scale to 1-bit */
8005 LBR01PacketRGBO(image->background_color);
8007 for (y=0; y < (ssize_t) image->rows; y++)
8009 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8011 if (r == (Quantum *) NULL)
8014 for (x=0; x < (ssize_t) image->columns; x++)
8017 r+=GetPixelChannels(image);
8020 if (SyncAuthenticPixels(image,exception) == MagickFalse)
8024 if (image->storage_class == PseudoClass && image->colormap != NULL)
8026 for (i=0; i < (ssize_t) image->colors; i++)
8028 LBR01PacketRGBO(image->colormap[i]);
8034 /* To do: set to next higher multiple of 8 */
8035 if (image->depth < 8)
8038 #if (MAGICKCORE_QUANTUM_DEPTH > 16)
8039 /* PNG does not handle depths greater than 16 so reduce it even
8042 if (image->depth > 8)
8046 #if (MAGICKCORE_QUANTUM_DEPTH > 8)
8047 if (image->depth > 8)
8049 /* To do: fill low byte properly */
8053 if (image->depth == 16 && mng_info->write_png_depth != 16)
8054 if (mng_info->write_png8 || LosslessReduceDepthOK(image,exception) != MagickFalse)
8058 if (image->storage_class != PseudoClass && mng_info->write_png_colortype &&
8059 (mng_info->write_png_colortype > 4 || (mng_info->write_png_depth >= 8 &&
8060 mng_info->write_png_colortype < 4 &&
8061 image->alpha_trait != BlendPixelTrait)))
8063 /* Avoid the expensive BUILD_PALETTE operation if we're sure that we
8064 * are not going to need the result.
8066 image_colors=image->colors;
8067 number_opaque = image->colors;
8068 if (mng_info->write_png_colortype == 1 ||
8069 mng_info->write_png_colortype == 5)
8070 ping_have_color=MagickFalse;
8072 ping_have_color=MagickTrue;
8073 ping_have_non_bw=MagickFalse;
8075 if (image->alpha_trait == BlendPixelTrait)
8077 number_transparent = 2;
8078 number_semitransparent = 1;
8083 number_transparent = 0;
8084 number_semitransparent = 0;
8092 * Normally we run this just once, but in the case of writing PNG8
8093 * we reduce the transparency to binary and run again, then if there
8094 * are still too many colors we reduce to a simple 4-4-4-1, then 3-3-3-1
8095 * RGBA palette and run again, and then to a simple 3-3-2-1 RGBA
8096 * palette. Then (To do) we take care of a final reduction that is only
8097 * needed if there are still 256 colors present and one of them has both
8098 * transparent and opaque instances.
8101 tried_332 = MagickFalse;
8102 tried_333 = MagickFalse;
8103 tried_444 = MagickFalse;
8108 * Sometimes we get DirectClass images that have 256 colors or fewer.
8109 * This code will build a colormap.
8111 * Also, sometimes we get PseudoClass images with an out-of-date
8112 * colormap. This code will replace the colormap with a new one.
8113 * Sometimes we get PseudoClass images that have more than 256 colors.
8114 * This code will delete the colormap and change the image to
8117 * If image->alpha_trait is MagickFalse, we ignore the alpha channel
8118 * even though it sometimes contains left-over non-opaque values.
8120 * Also we gather some information (number of opaque, transparent,
8121 * and semitransparent pixels, and whether the image has any non-gray
8122 * pixels or only black-and-white pixels) that we might need later.
8124 * Even if the user wants to force GrayAlpha or RGBA (colortype 4 or 6)
8125 * we need to check for bogus non-opaque values, at least.
8133 semitransparent[260],
8136 register const Quantum
8143 if (logging != MagickFalse)
8144 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8145 " Enter BUILD_PALETTE:");
8147 if (logging != MagickFalse)
8149 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8150 " image->columns=%.20g",(double) image->columns);
8151 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8152 " image->rows=%.20g",(double) image->rows);
8153 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8154 " image->alpha_trait=%.20g",(double) image->alpha_trait);
8155 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8156 " image->depth=%.20g",(double) image->depth);
8158 if (image->storage_class == PseudoClass && image->colormap != NULL)
8160 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8161 " Original colormap:");
8162 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8163 " i (red,green,blue,alpha)");
8165 for (i=0; i < 256; i++)
8167 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8168 " %d (%d,%d,%d,%d)",
8170 (int) image->colormap[i].red,
8171 (int) image->colormap[i].green,
8172 (int) image->colormap[i].blue,
8173 (int) image->colormap[i].alpha);
8176 for (i=image->colors - 10; i < (ssize_t) image->colors; i++)
8180 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8181 " %d (%d,%d,%d,%d)",
8183 (int) image->colormap[i].red,
8184 (int) image->colormap[i].green,
8185 (int) image->colormap[i].blue,
8186 (int) image->colormap[i].alpha);
8191 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8192 " image->colors=%d",(int) image->colors);
8194 if (image->colors == 0)
8195 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8196 " (zero means unknown)");
8198 if (ping_preserve_colormap == MagickFalse)
8199 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8200 " Regenerate the colormap");
8205 number_semitransparent = 0;
8206 number_transparent = 0;
8208 for (y=0; y < (ssize_t) image->rows; y++)
8210 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8212 if (q == (Quantum *) NULL)
8215 for (x=0; x < (ssize_t) image->columns; x++)
8217 if (image->alpha_trait != BlendPixelTrait ||
8218 GetPixelAlpha(image,q) == OpaqueAlpha)
8220 if (number_opaque < 259)
8222 if (number_opaque == 0)
8224 GetPixelInfoPixel(image, q, opaque);
8225 opaque[0].alpha=OpaqueAlpha;
8229 for (i=0; i< (ssize_t) number_opaque; i++)
8231 if (IsPixelEquivalent(image,q, opaque+i))
8235 if (i == (ssize_t) number_opaque && number_opaque < 259)
8238 GetPixelInfoPixel(image, q, opaque+i);
8239 opaque[i].alpha=OpaqueAlpha;
8243 else if (GetPixelAlpha(image,q) == TransparentAlpha)
8245 if (number_transparent < 259)
8247 if (number_transparent == 0)
8249 GetPixelInfoPixel(image, q, transparent);
8250 ping_trans_color.red=(unsigned short)
8251 GetPixelRed(image,q);
8252 ping_trans_color.green=(unsigned short)
8253 GetPixelGreen(image,q);
8254 ping_trans_color.blue=(unsigned short)
8255 GetPixelBlue(image,q);
8256 ping_trans_color.gray=(unsigned short)
8257 GetPixelGray(image,q);
8258 number_transparent = 1;
8261 for (i=0; i< (ssize_t) number_transparent; i++)
8263 if (IsPixelEquivalent(image,q, transparent+i))
8267 if (i == (ssize_t) number_transparent &&
8268 number_transparent < 259)
8270 number_transparent++;
8271 GetPixelInfoPixel(image,q,transparent+i);
8277 if (number_semitransparent < 259)
8279 if (number_semitransparent == 0)
8281 GetPixelInfoPixel(image,q,semitransparent);
8282 number_semitransparent = 1;
8285 for (i=0; i< (ssize_t) number_semitransparent; i++)
8287 if (IsPixelEquivalent(image,q, semitransparent+i)
8288 && GetPixelAlpha(image,q) ==
8289 semitransparent[i].alpha)
8293 if (i == (ssize_t) number_semitransparent &&
8294 number_semitransparent < 259)
8296 number_semitransparent++;
8297 GetPixelInfoPixel(image, q, semitransparent+i);
8301 q+=GetPixelChannels(image);
8305 if (mng_info->write_png8 == MagickFalse &&
8306 ping_exclude_bKGD == MagickFalse)
8308 /* Add the background color to the palette, if it
8309 * isn't already there.
8311 if (logging != MagickFalse)
8313 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8314 " Check colormap for background (%d,%d,%d)",
8315 (int) image->background_color.red,
8316 (int) image->background_color.green,
8317 (int) image->background_color.blue);
8319 for (i=0; i<number_opaque; i++)
8321 if (opaque[i].red == image->background_color.red &&
8322 opaque[i].green == image->background_color.green &&
8323 opaque[i].blue == image->background_color.blue)
8326 if (number_opaque < 259 && i == number_opaque)
8328 opaque[i] = image->background_color;
8329 ping_background.index = i;
8331 if (logging != MagickFalse)
8333 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8334 " background_color index is %d",(int) i);
8338 else if (logging != MagickFalse)
8339 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8340 " No room in the colormap to add background color");
8343 image_colors=number_opaque+number_transparent+number_semitransparent;
8345 if (mng_info->write_png8 != MagickFalse && image_colors > 256)
8347 /* No room for the background color; remove it. */
8352 if (logging != MagickFalse)
8354 if (image_colors > 256)
8355 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8356 " image has more than 256 colors");
8359 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8360 " image has %d colors",image_colors);
8363 if (ping_preserve_colormap != MagickFalse)
8366 if (mng_info->write_png_colortype != 7) /* We won't need this info */
8368 ping_have_color=MagickFalse;
8369 ping_have_non_bw=MagickFalse;
8371 if ((IssRGBCompatibleColorspace(image->colorspace) == MagickFalse) ||
8372 (IssRGBColorspace(image->colorspace) != MagickFalse))
8374 ping_have_color=MagickTrue;
8375 ping_have_non_bw=MagickTrue;
8378 if(image_colors > 256)
8380 for (y=0; y < (ssize_t) image->rows; y++)
8382 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8384 if (q == (Quantum *) NULL)
8388 for (x=0; x < (ssize_t) image->columns; x++)
8390 if (GetPixelRed(image,s) != GetPixelGreen(image,s) ||
8391 GetPixelRed(image,s) != GetPixelBlue(image,s))
8393 ping_have_color=MagickTrue;
8394 ping_have_non_bw=MagickTrue;
8397 s+=GetPixelChannels(image);
8400 if (ping_have_color != MagickFalse)
8403 /* Worst case is black-and-white; we are looking at every
8407 if (ping_have_non_bw == MagickFalse)
8410 for (x=0; x < (ssize_t) image->columns; x++)
8412 if (GetPixelRed(image,s) != 0 &&
8413 GetPixelRed(image,s) != QuantumRange)
8415 ping_have_non_bw=MagickTrue;
8418 s+=GetPixelChannels(image);
8425 if (image_colors < 257)
8431 * Initialize image colormap.
8434 if (logging != MagickFalse)
8435 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8436 " Sort the new colormap");
8438 /* Sort palette, transparent first */;
8442 for (i=0; i<number_transparent; i++)
8443 colormap[n++] = transparent[i];
8445 for (i=0; i<number_semitransparent; i++)
8446 colormap[n++] = semitransparent[i];
8448 for (i=0; i<number_opaque; i++)
8449 colormap[n++] = opaque[i];
8451 ping_background.index +=
8452 (number_transparent + number_semitransparent);
8454 /* image_colors < 257; search the colormap instead of the pixels
8455 * to get ping_have_color and ping_have_non_bw
8459 if (ping_have_color == MagickFalse)
8461 if (colormap[i].red != colormap[i].green ||
8462 colormap[i].red != colormap[i].blue)
8464 ping_have_color=MagickTrue;
8465 ping_have_non_bw=MagickTrue;
8470 if (ping_have_non_bw == MagickFalse)
8472 if (colormap[i].red != 0 && colormap[i].red != QuantumRange)
8473 ping_have_non_bw=MagickTrue;
8477 if ((mng_info->ping_exclude_tRNS == MagickFalse ||
8478 (number_transparent == 0 && number_semitransparent == 0)) &&
8479 (((mng_info->write_png_colortype-1) ==
8480 PNG_COLOR_TYPE_PALETTE) ||
8481 (mng_info->write_png_colortype == 0)))
8483 if (logging != MagickFalse)
8485 if (n != (ssize_t) image_colors)
8486 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8487 " image_colors (%d) and n (%d) don't match",
8490 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8491 " AcquireImageColormap");
8494 image->colors = image_colors;
8496 if (AcquireImageColormap(image,image_colors,exception) ==
8498 ThrowWriterException(ResourceLimitError,
8499 "MemoryAllocationFailed");
8501 for (i=0; i< (ssize_t) image_colors; i++)
8502 image->colormap[i] = colormap[i];
8504 if (logging != MagickFalse)
8506 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8507 " image->colors=%d (%d)",
8508 (int) image->colors, image_colors);
8510 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8511 " Update the pixel indexes");
8514 /* Sync the pixel indices with the new colormap */
8516 for (y=0; y < (ssize_t) image->rows; y++)
8518 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8520 if (q == (Quantum *) NULL)
8523 for (x=0; x < (ssize_t) image->columns; x++)
8525 for (i=0; i< (ssize_t) image_colors; i++)
8527 if ((image->alpha_trait != BlendPixelTrait ||
8528 image->colormap[i].alpha == GetPixelAlpha(image,q)) &&
8529 image->colormap[i].red == GetPixelRed(image,q) &&
8530 image->colormap[i].green == GetPixelGreen(image,q) &&
8531 image->colormap[i].blue == GetPixelBlue(image,q))
8533 SetPixelIndex(image,i,q);
8537 q+=GetPixelChannels(image);
8540 if (SyncAuthenticPixels(image,exception) == MagickFalse)
8546 if (logging != MagickFalse)
8548 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8549 " image->colors=%d", (int) image->colors);
8551 if (image->colormap != NULL)
8553 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8554 " i (red,green,blue,alpha)");
8556 for (i=0; i < (ssize_t) image->colors; i++)
8558 if (i < 300 || i >= (ssize_t) image->colors - 10)
8560 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8561 " %d (%d,%d,%d,%d)",
8563 (int) image->colormap[i].red,
8564 (int) image->colormap[i].green,
8565 (int) image->colormap[i].blue,
8566 (int) image->colormap[i].alpha);
8571 if (number_transparent < 257)
8572 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8573 " number_transparent = %d",
8574 number_transparent);
8577 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8578 " number_transparent > 256");
8580 if (number_opaque < 257)
8581 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8582 " number_opaque = %d",
8586 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8587 " number_opaque > 256");
8589 if (number_semitransparent < 257)
8590 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8591 " number_semitransparent = %d",
8592 number_semitransparent);
8595 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8596 " number_semitransparent > 256");
8598 if (ping_have_non_bw == MagickFalse)
8599 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8600 " All pixels and the background are black or white");
8602 else if (ping_have_color == MagickFalse)
8603 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8604 " All pixels and the background are gray");
8607 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8608 " At least one pixel or the background is non-gray");
8610 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8611 " Exit BUILD_PALETTE:");
8614 if (mng_info->write_png8 == MagickFalse)
8617 /* Make any reductions necessary for the PNG8 format */
8618 if (image_colors <= 256 &&
8619 image_colors != 0 && image->colormap != NULL &&
8620 number_semitransparent == 0 &&
8621 number_transparent <= 1)
8624 /* PNG8 can't have semitransparent colors so we threshold the
8625 * opacity to 0 or OpaqueOpacity, and PNG8 can only have one
8626 * transparent color so if more than one is transparent we merge
8627 * them into image->background_color.
8629 if (number_semitransparent != 0 || number_transparent > 1)
8631 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8632 " Thresholding the alpha channel to binary");
8634 for (y=0; y < (ssize_t) image->rows; y++)
8636 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8638 if (r == (Quantum *) NULL)
8641 for (x=0; x < (ssize_t) image->columns; x++)
8643 if (GetPixelAlpha(image,r) < OpaqueAlpha/2)
8645 SetPixelInfoPixel(image,&image->background_color,r);
8646 SetPixelAlpha(image,TransparentAlpha,r);
8649 SetPixelAlpha(image,OpaqueAlpha,r);
8650 r+=GetPixelChannels(image);
8653 if (SyncAuthenticPixels(image,exception) == MagickFalse)
8656 if (image_colors != 0 && image_colors <= 256 &&
8657 image->colormap != NULL)
8658 for (i=0; i<image_colors; i++)
8659 image->colormap[i].alpha =
8660 (image->colormap[i].alpha > TransparentAlpha/2 ?
8661 TransparentAlpha : OpaqueAlpha);
8666 /* PNG8 can't have more than 256 colors so we quantize the pixels and
8667 * background color to the 4-4-4-1, 3-3-3-1 or 3-3-2-1 palette. If the
8668 * image is mostly gray, the 4-4-4-1 palette is likely to end up with 256
8671 if (tried_444 == MagickFalse && (image_colors == 0 || image_colors > 256))
8673 if (logging != MagickFalse)
8674 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8675 " Quantizing the background color to 4-4-4");
8677 tried_444 = MagickTrue;
8679 LBR04PacketRGB(image->background_color);
8681 if (logging != MagickFalse)
8682 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8683 " Quantizing the pixel colors to 4-4-4");
8685 if (image->colormap == NULL)
8687 for (y=0; y < (ssize_t) image->rows; y++)
8689 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8691 if (r == (Quantum *) NULL)
8694 for (x=0; x < (ssize_t) image->columns; x++)
8696 if (GetPixelAlpha(image,r) == OpaqueAlpha)
8698 r+=GetPixelChannels(image);
8701 if (SyncAuthenticPixels(image,exception) == MagickFalse)
8706 else /* Should not reach this; colormap already exists and
8709 if (logging != MagickFalse)
8710 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8711 " Quantizing the colormap to 4-4-4");
8713 for (i=0; i<image_colors; i++)
8715 LBR04PacketRGB(image->colormap[i]);
8721 if (tried_333 == MagickFalse && (image_colors == 0 || image_colors > 256))
8723 if (logging != MagickFalse)
8724 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8725 " Quantizing the background color to 3-3-3");
8727 tried_333 = MagickTrue;
8729 LBR03PacketRGB(image->background_color);
8731 if (logging != MagickFalse)
8732 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8733 " Quantizing the pixel colors to 3-3-3-1");
8735 if (image->colormap == NULL)
8737 for (y=0; y < (ssize_t) image->rows; y++)
8739 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8741 if (r == (Quantum *) NULL)
8744 for (x=0; x < (ssize_t) image->columns; x++)
8746 if (GetPixelAlpha(image,r) == OpaqueAlpha)
8748 r+=GetPixelChannels(image);
8751 if (SyncAuthenticPixels(image,exception) == MagickFalse)
8756 else /* Should not reach this; colormap already exists and
8759 if (logging != MagickFalse)
8760 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8761 " Quantizing the colormap to 3-3-3-1");
8762 for (i=0; i<image_colors; i++)
8764 LBR03PacketRGB(image->colormap[i]);
8770 if (tried_332 == MagickFalse && (image_colors == 0 || image_colors > 256))
8772 if (logging != MagickFalse)
8773 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8774 " Quantizing the background color to 3-3-2");
8776 tried_332 = MagickTrue;
8778 /* Red and green were already done so we only quantize the blue
8782 LBR02PacketBlue(image->background_color);
8784 if (logging != MagickFalse)
8785 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8786 " Quantizing the pixel colors to 3-3-2-1");
8788 if (image->colormap == NULL)
8790 for (y=0; y < (ssize_t) image->rows; y++)
8792 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8794 if (r == (Quantum *) NULL)
8797 for (x=0; x < (ssize_t) image->columns; x++)
8799 if (GetPixelAlpha(image,r) == OpaqueAlpha)
8801 r+=GetPixelChannels(image);
8804 if (SyncAuthenticPixels(image,exception) == MagickFalse)
8809 else /* Should not reach this; colormap already exists and
8812 if (logging != MagickFalse)
8813 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8814 " Quantizing the colormap to 3-3-2-1");
8815 for (i=0; i<image_colors; i++)
8817 LBR02PacketBlue(image->colormap[i]);
8824 if (image_colors == 0 || image_colors > 256)
8826 /* Take care of special case with 256 colors + 1 transparent
8827 * color. We don't need to quantize to 2-3-2-1; we only need to
8828 * eliminate one color, so we'll merge the two darkest red
8829 * colors (0x49, 0, 0) -> (0x24, 0, 0).
8831 if (ScaleQuantumToChar(image->background_color.red) == 0x49 &&
8832 ScaleQuantumToChar(image->background_color.green) == 0x00 &&
8833 ScaleQuantumToChar(image->background_color.blue) == 0x00)
8835 image->background_color.red=ScaleCharToQuantum(0x24);
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 (ScaleQuantumToChar(GetPixelRed(image,r)) == 0x49 &&
8850 ScaleQuantumToChar(GetPixelGreen(image,r)) == 0x00 &&
8851 ScaleQuantumToChar(GetPixelBlue(image,r)) == 0x00 &&
8852 GetPixelAlpha(image,r) == OpaqueAlpha)
8854 SetPixelRed(image,ScaleCharToQuantum(0x24),r);
8856 r+=GetPixelChannels(image);
8859 if (SyncAuthenticPixels(image,exception) == MagickFalse)
8867 for (i=0; i<image_colors; i++)
8869 if (ScaleQuantumToChar(image->colormap[i].red) == 0x49 &&
8870 ScaleQuantumToChar(image->colormap[i].green) == 0x00 &&
8871 ScaleQuantumToChar(image->colormap[i].blue) == 0x00)
8873 image->colormap[i].red=ScaleCharToQuantum(0x24);
8880 /* END OF BUILD_PALETTE */
8882 /* If we are excluding the tRNS chunk and there is transparency,
8883 * then we must write a Gray-Alpha (color-type 4) or RGBA (color-type 6)
8886 if (mng_info->ping_exclude_tRNS != MagickFalse &&
8887 (number_transparent != 0 || number_semitransparent != 0))
8889 unsigned int colortype=mng_info->write_png_colortype;
8891 if (ping_have_color == MagickFalse)
8892 mng_info->write_png_colortype = 5;
8895 mng_info->write_png_colortype = 7;
8897 if (colortype != 0 &&
8898 mng_info->write_png_colortype != colortype)
8899 ping_need_colortype_warning=MagickTrue;
8903 /* See if cheap transparency is possible. It is only possible
8904 * when there is a single transparent color, no semitransparent
8905 * color, and no opaque color that has the same RGB components
8906 * as the transparent color. We only need this information if
8907 * we are writing a PNG with colortype 0 or 2, and we have not
8908 * excluded the tRNS chunk.
8910 if (number_transparent == 1 &&
8911 mng_info->write_png_colortype < 4)
8913 ping_have_cheap_transparency = MagickTrue;
8915 if (number_semitransparent != 0)
8916 ping_have_cheap_transparency = MagickFalse;
8918 else if (image_colors == 0 || image_colors > 256 ||
8919 image->colormap == NULL)
8921 register const Quantum
8924 for (y=0; y < (ssize_t) image->rows; y++)
8926 q=GetVirtualPixels(image,0,y,image->columns,1, exception);
8928 if (q == (Quantum *) NULL)
8931 for (x=0; x < (ssize_t) image->columns; x++)
8933 if (GetPixelAlpha(image,q) != TransparentAlpha &&
8934 (unsigned short) GetPixelRed(image,q) ==
8935 ping_trans_color.red &&
8936 (unsigned short) GetPixelGreen(image,q) ==
8937 ping_trans_color.green &&
8938 (unsigned short) GetPixelBlue(image,q) ==
8939 ping_trans_color.blue)
8941 ping_have_cheap_transparency = MagickFalse;
8945 q+=GetPixelChannels(image);
8948 if (ping_have_cheap_transparency == MagickFalse)
8954 /* Assuming that image->colormap[0] is the one transparent color
8955 * and that all others are opaque.
8957 if (image_colors > 1)
8958 for (i=1; i<image_colors; i++)
8959 if (image->colormap[i].red == image->colormap[0].red &&
8960 image->colormap[i].green == image->colormap[0].green &&
8961 image->colormap[i].blue == image->colormap[0].blue)
8963 ping_have_cheap_transparency = MagickFalse;
8968 if (logging != MagickFalse)
8970 if (ping_have_cheap_transparency == MagickFalse)
8971 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8972 " Cheap transparency is not possible.");
8975 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8976 " Cheap transparency is possible.");
8980 ping_have_cheap_transparency = MagickFalse;
8982 image_depth=image->depth;
8984 quantum_info = (QuantumInfo *) NULL;
8986 image_colors=(int) image->colors;
8987 image_matte=image->alpha_trait == BlendPixelTrait ? MagickTrue : MagickFalse;
8989 mng_info->IsPalette=image->storage_class == PseudoClass &&
8990 image_colors <= 256 && image->colormap != NULL;
8992 if ((mng_info->write_png_colortype == 4 || mng_info->write_png8) &&
8993 (image->colors == 0 || image->colormap == NULL))
8995 image_info=DestroyImageInfo(image_info);
8996 image=DestroyImage(image);
8997 (void) ThrowMagickException(exception,GetMagickModule(),CoderError,
8998 "Cannot write PNG8 or color-type 3; colormap is NULL",
8999 "`%s'",IMimage->filename);
9000 return(MagickFalse);
9004 Allocate the PNG structures
9006 #ifdef PNG_USER_MEM_SUPPORTED
9007 error_info.image=image;
9008 error_info.exception=exception;
9009 ping=png_create_write_struct_2(PNG_LIBPNG_VER_STRING,&error_info,
9010 MagickPNGErrorHandler,MagickPNGWarningHandler,(void *) NULL,
9011 (png_malloc_ptr) Magick_png_malloc,(png_free_ptr) Magick_png_free);
9014 ping=png_create_write_struct(PNG_LIBPNG_VER_STRING,&error_info,
9015 MagickPNGErrorHandler,MagickPNGWarningHandler);
9018 if (ping == (png_struct *) NULL)
9019 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
9021 ping_info=png_create_info_struct(ping);
9023 if (ping_info == (png_info *) NULL)
9025 png_destroy_write_struct(&ping,(png_info **) NULL);
9026 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
9029 png_set_write_fn(ping,image,png_put_data,png_flush_data);
9030 ping_pixels=(unsigned char *) NULL;
9032 if (setjmp(png_jmpbuf(ping)))
9038 if (image_info->verbose)
9039 (void) printf("PNG write has failed.\n");
9041 png_destroy_write_struct(&ping,&ping_info);
9042 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
9043 UnlockSemaphoreInfo(ping_semaphore);
9046 if (ping_pixels != (unsigned char *) NULL)
9047 ping_pixels=(unsigned char *) RelinquishMagickMemory(ping_pixels);
9049 if (quantum_info != (QuantumInfo *) NULL)
9050 quantum_info=DestroyQuantumInfo(quantum_info);
9052 if (ping_have_blob != MagickFalse)
9053 (void) CloseBlob(image);
9054 image_info=DestroyImageInfo(image_info);
9055 image=DestroyImage(image);
9056 return(MagickFalse);
9059 /* { For navigation to end of SETJMP-protected block. Within this
9060 * block, use png_error() instead of Throwing an Exception, to ensure
9061 * that libpng is able to clean up, and that the semaphore is unlocked.
9064 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
9065 LockSemaphoreInfo(ping_semaphore);
9069 Prepare PNG for writing.
9072 #if defined(PNG_MNG_FEATURES_SUPPORTED)
9073 if (mng_info->write_mng)
9075 (void) png_permit_mng_features(ping,PNG_ALL_MNG_FEATURES);
9076 # ifdef PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED
9077 /* Disable new libpng-1.5.10 feature when writing a MNG because
9078 * zero-length PLTE is OK
9080 png_set_check_for_invalid_index (ping, 0);
9085 # ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
9086 if (mng_info->write_mng)
9087 png_permit_empty_plte(ping,MagickTrue);
9094 ping_width=(png_uint_32) image->columns;
9095 ping_height=(png_uint_32) image->rows;
9097 if (mng_info->write_png8 || mng_info->write_png24 || mng_info->write_png32)
9100 if (mng_info->write_png_depth != 0)
9101 image_depth=mng_info->write_png_depth;
9103 /* Adjust requested depth to next higher valid depth if necessary */
9104 if (image_depth > 8)
9107 if ((image_depth > 4) && (image_depth < 8))
9110 if (image_depth == 3)
9113 if (logging != MagickFalse)
9115 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9116 " width=%.20g",(double) ping_width);
9117 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9118 " height=%.20g",(double) ping_height);
9119 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9120 " image_matte=%.20g",(double) image->alpha_trait);
9121 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9122 " image->depth=%.20g",(double) image->depth);
9123 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9124 " Tentative ping_bit_depth=%.20g",(double) image_depth);
9127 save_image_depth=image_depth;
9128 ping_bit_depth=(png_byte) save_image_depth;
9131 #if defined(PNG_pHYs_SUPPORTED)
9132 if (ping_exclude_pHYs == MagickFalse)
9134 if ((image->resolution.x != 0) && (image->resolution.y != 0) &&
9135 (!mng_info->write_mng || !mng_info->equal_physs))
9137 if (logging != MagickFalse)
9138 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9139 " Setting up pHYs chunk");
9141 if (image->units == PixelsPerInchResolution)
9143 ping_pHYs_unit_type=PNG_RESOLUTION_METER;
9144 ping_pHYs_x_resolution=
9145 (png_uint_32) ((100.0*image->resolution.x+0.5)/2.54);
9146 ping_pHYs_y_resolution=
9147 (png_uint_32) ((100.0*image->resolution.y+0.5)/2.54);
9150 else if (image->units == PixelsPerCentimeterResolution)
9152 ping_pHYs_unit_type=PNG_RESOLUTION_METER;
9153 ping_pHYs_x_resolution=(png_uint_32) (100.0*image->resolution.x+0.5);
9154 ping_pHYs_y_resolution=(png_uint_32) (100.0*image->resolution.y+0.5);
9159 ping_pHYs_unit_type=PNG_RESOLUTION_UNKNOWN;
9160 ping_pHYs_x_resolution=(png_uint_32) image->resolution.x;
9161 ping_pHYs_y_resolution=(png_uint_32) image->resolution.y;
9164 if (logging != MagickFalse)
9165 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9166 " Set up PNG pHYs chunk: xres: %.20g, yres: %.20g, units: %d.",
9167 (double) ping_pHYs_x_resolution,(double) ping_pHYs_y_resolution,
9168 (int) ping_pHYs_unit_type);
9169 ping_have_pHYs = MagickTrue;
9174 if (ping_exclude_bKGD == MagickFalse)
9176 if ((!mng_info->adjoin || !mng_info->equal_backgrounds))
9182 if (ping_bit_depth == 8)
9185 if (ping_bit_depth == 4)
9188 if (ping_bit_depth == 2)
9191 if (ping_bit_depth == 1)
9194 ping_background.red=(png_uint_16)
9195 (ScaleQuantumToShort(image->background_color.red) & mask);
9197 ping_background.green=(png_uint_16)
9198 (ScaleQuantumToShort(image->background_color.green) & mask);
9200 ping_background.blue=(png_uint_16)
9201 (ScaleQuantumToShort(image->background_color.blue) & mask);
9203 ping_background.gray=(png_uint_16) ping_background.green;
9206 if (logging != MagickFalse)
9208 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9209 " Setting up bKGD chunk (1)");
9210 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9211 " background_color index is %d",
9212 (int) ping_background.index);
9214 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9215 " ping_bit_depth=%d",ping_bit_depth);
9218 ping_have_bKGD = MagickTrue;
9222 Select the color type.
9227 if (mng_info->IsPalette && mng_info->write_png8)
9230 /* To do: make this a function cause it's used twice, except
9231 for reducing the sample depth from 8. */
9233 number_colors=image_colors;
9235 ping_have_tRNS=MagickFalse;
9240 ping_color_type=(png_byte) PNG_COLOR_TYPE_PALETTE;
9242 if (logging != MagickFalse)
9243 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9244 " Setting up PLTE chunk with %d colors (%d)",
9245 number_colors, image_colors);
9247 for (i=0; i < (ssize_t) number_colors; i++)
9249 palette[i].red=ScaleQuantumToChar(image->colormap[i].red);
9250 palette[i].green=ScaleQuantumToChar(image->colormap[i].green);
9251 palette[i].blue=ScaleQuantumToChar(image->colormap[i].blue);
9252 if (logging != MagickFalse)
9253 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9254 #if MAGICKCORE_QUANTUM_DEPTH == 8
9255 " %3ld (%3d,%3d,%3d)",
9257 " %5ld (%5d,%5d,%5d)",
9259 (long) i,palette[i].red,palette[i].green,palette[i].blue);
9263 ping_have_PLTE=MagickTrue;
9264 image_depth=ping_bit_depth;
9267 if (matte != MagickFalse)
9270 Identify which colormap entry is transparent.
9272 assert(number_colors <= 256);
9273 assert(image->colormap != NULL);
9275 for (i=0; i < (ssize_t) number_transparent; i++)
9276 ping_trans_alpha[i]=0;
9279 ping_num_trans=(unsigned short) (number_transparent +
9280 number_semitransparent);
9282 if (ping_num_trans == 0)
9283 ping_have_tRNS=MagickFalse;
9286 ping_have_tRNS=MagickTrue;
9289 if (ping_exclude_bKGD == MagickFalse)
9292 * Identify which colormap entry is the background color.
9295 for (i=0; i < (ssize_t) MagickMax(1L*number_colors-1L,1L); i++)
9296 if (IsPNGColorEqual(ping_background,image->colormap[i]))
9299 ping_background.index=(png_byte) i;
9301 if (logging != MagickFalse)
9303 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9304 " background_color index is %d",
9305 (int) ping_background.index);
9308 } /* end of write_png8 */
9310 else if (mng_info->write_png24 || mng_info->write_png_colortype == 3)
9312 image_matte=MagickFalse;
9313 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB;
9316 else if (mng_info->write_png32 || mng_info->write_png_colortype == 7)
9318 image_matte=MagickTrue;
9319 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB_ALPHA;
9322 else /* mng_info->write_pngNN not specified */
9324 image_depth=ping_bit_depth;
9326 if (mng_info->write_png_colortype != 0)
9328 ping_color_type=(png_byte) mng_info->write_png_colortype-1;
9330 if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA ||
9331 ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA)
9332 image_matte=MagickTrue;
9335 image_matte=MagickFalse;
9337 if (logging != MagickFalse)
9338 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9339 " PNG colortype %d was specified:",(int) ping_color_type);
9342 else /* write_png_colortype not specified */
9344 if (logging != MagickFalse)
9345 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9346 " Selecting PNG colortype:");
9348 ping_color_type=(png_byte) ((matte != MagickFalse)?
9349 PNG_COLOR_TYPE_RGB_ALPHA:PNG_COLOR_TYPE_RGB);
9351 if (image_info->type == TrueColorType)
9353 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB;
9354 image_matte=MagickFalse;
9357 if (image_info->type == TrueColorMatteType)
9359 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB_ALPHA;
9360 image_matte=MagickTrue;
9363 if (image_info->type == PaletteType ||
9364 image_info->type == PaletteMatteType)
9365 ping_color_type=(png_byte) PNG_COLOR_TYPE_PALETTE;
9367 if (mng_info->write_png_colortype == 0 &&
9368 (image_info->type == UndefinedType ||
9369 image_info->type == OptimizeType))
9371 if (ping_have_color == MagickFalse)
9373 if (image_matte == MagickFalse)
9375 ping_color_type=(png_byte) PNG_COLOR_TYPE_GRAY;
9376 image_matte=MagickFalse;
9381 ping_color_type=(png_byte) PNG_COLOR_TYPE_GRAY_ALPHA;
9382 image_matte=MagickTrue;
9387 if (image_matte == MagickFalse)
9389 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB;
9390 image_matte=MagickFalse;
9395 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGBA;
9396 image_matte=MagickTrue;
9403 if (logging != MagickFalse)
9404 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9405 " Selected PNG colortype=%d",ping_color_type);
9407 if (ping_bit_depth < 8)
9409 if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA ||
9410 ping_color_type == PNG_COLOR_TYPE_RGB ||
9411 ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA)
9415 old_bit_depth=ping_bit_depth;
9417 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
9419 if (image->alpha_trait != BlendPixelTrait && ping_have_non_bw == MagickFalse)
9423 if (ping_color_type == PNG_COLOR_TYPE_PALETTE)
9428 if (image->colors == 0)
9431 png_error(ping,"image has 0 colors");
9434 while ((int) (one << ping_bit_depth) < (ssize_t) image_colors)
9435 ping_bit_depth <<= 1;
9438 if (logging != MagickFalse)
9440 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9441 " Number of colors: %.20g",(double) image_colors);
9443 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9444 " Tentative PNG bit depth: %d",ping_bit_depth);
9447 if (ping_bit_depth < (int) mng_info->write_png_depth)
9448 ping_bit_depth = mng_info->write_png_depth;
9451 image_depth=ping_bit_depth;
9453 if (logging != MagickFalse)
9455 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9456 " Tentative PNG color type: %s (%.20g)",
9457 PngColorTypeToString(ping_color_type),
9458 (double) ping_color_type);
9460 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9461 " image_info->type: %.20g",(double) image_info->type);
9463 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9464 " image_depth: %.20g",(double) image_depth);
9466 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9468 " image->depth: %.20g",(double) image->depth);
9470 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9471 " ping_bit_depth: %.20g",(double) ping_bit_depth);
9474 if (matte != MagickFalse)
9476 if (mng_info->IsPalette)
9478 if (mng_info->write_png_colortype == 0)
9480 ping_color_type=PNG_COLOR_TYPE_GRAY_ALPHA;
9482 if (ping_have_color != MagickFalse)
9483 ping_color_type=PNG_COLOR_TYPE_RGBA;
9487 * Determine if there is any transparent color.
9489 if (number_transparent + number_semitransparent == 0)
9492 No transparent pixels are present. Change 4 or 6 to 0 or 2.
9495 image_matte=MagickFalse;
9497 if (mng_info->write_png_colortype == 0)
9498 ping_color_type&=0x03;
9508 if (ping_bit_depth == 8)
9511 if (ping_bit_depth == 4)
9514 if (ping_bit_depth == 2)
9517 if (ping_bit_depth == 1)
9520 ping_trans_color.red=(png_uint_16)
9521 (ScaleQuantumToShort(image->colormap[0].red) & mask);
9523 ping_trans_color.green=(png_uint_16)
9524 (ScaleQuantumToShort(image->colormap[0].green) & mask);
9526 ping_trans_color.blue=(png_uint_16)
9527 (ScaleQuantumToShort(image->colormap[0].blue) & mask);
9529 ping_trans_color.gray=(png_uint_16)
9530 (ScaleQuantumToShort(GetPixelInfoIntensity(
9531 image->colormap)) & mask);
9533 ping_trans_color.index=(png_byte) 0;
9535 ping_have_tRNS=MagickTrue;
9538 if (ping_have_tRNS != MagickFalse)
9541 * Determine if there is one and only one transparent color
9542 * and if so if it is fully transparent.
9544 if (ping_have_cheap_transparency == MagickFalse)
9545 ping_have_tRNS=MagickFalse;
9548 if (ping_have_tRNS != MagickFalse)
9550 if (mng_info->write_png_colortype == 0)
9551 ping_color_type &= 0x03; /* changes 4 or 6 to 0 or 2 */
9553 if (image_depth == 8)
9555 ping_trans_color.red&=0xff;
9556 ping_trans_color.green&=0xff;
9557 ping_trans_color.blue&=0xff;
9558 ping_trans_color.gray&=0xff;
9564 if (image_depth == 8)
9566 ping_trans_color.red&=0xff;
9567 ping_trans_color.green&=0xff;
9568 ping_trans_color.blue&=0xff;
9569 ping_trans_color.gray&=0xff;
9576 if (ping_have_tRNS != MagickFalse)
9577 image_matte=MagickFalse;
9579 if ((mng_info->IsPalette) &&
9580 mng_info->write_png_colortype-1 != PNG_COLOR_TYPE_PALETTE &&
9581 ping_have_color == MagickFalse &&
9582 (image_matte == MagickFalse || image_depth >= 8))
9586 if (image_matte != MagickFalse)
9587 ping_color_type=PNG_COLOR_TYPE_GRAY_ALPHA;
9589 else if (mng_info->write_png_colortype-1 != PNG_COLOR_TYPE_GRAY_ALPHA)
9591 ping_color_type=PNG_COLOR_TYPE_GRAY;
9593 if (save_image_depth == 16 && image_depth == 8)
9595 if (logging != MagickFalse)
9597 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9598 " Scaling ping_trans_color (0)");
9600 ping_trans_color.gray*=0x0101;
9604 if (image_depth > MAGICKCORE_QUANTUM_DEPTH)
9605 image_depth=MAGICKCORE_QUANTUM_DEPTH;
9607 if ((image_colors == 0) ||
9608 ((ssize_t) (image_colors-1) > (ssize_t) MaxColormapSize))
9609 image_colors=(int) (one << image_depth);
9611 if (image_depth > 8)
9617 if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
9619 if(!mng_info->write_png_depth)
9623 while ((int) (one << ping_bit_depth)
9624 < (ssize_t) image_colors)
9625 ping_bit_depth <<= 1;
9629 else if (ping_color_type ==
9630 PNG_COLOR_TYPE_GRAY && image_colors < 17 &&
9631 mng_info->IsPalette)
9633 /* Check if grayscale is reducible */
9636 depth_4_ok=MagickTrue,
9637 depth_2_ok=MagickTrue,
9638 depth_1_ok=MagickTrue;
9640 for (i=0; i < (ssize_t) image_colors; i++)
9645 intensity=ScaleQuantumToChar(image->colormap[i].red);
9647 if ((intensity & 0x0f) != ((intensity & 0xf0) >> 4))
9648 depth_4_ok=depth_2_ok=depth_1_ok=MagickFalse;
9649 else if ((intensity & 0x03) != ((intensity & 0x0c) >> 2))
9650 depth_2_ok=depth_1_ok=MagickFalse;
9651 else if ((intensity & 0x01) != ((intensity & 0x02) >> 1))
9652 depth_1_ok=MagickFalse;
9655 if (depth_1_ok && mng_info->write_png_depth <= 1)
9658 else if (depth_2_ok && mng_info->write_png_depth <= 2)
9661 else if (depth_4_ok && mng_info->write_png_depth <= 4)
9666 image_depth=ping_bit_depth;
9671 if (mng_info->IsPalette)
9673 number_colors=image_colors;
9675 if (image_depth <= 8)
9680 ping_color_type=(png_byte) PNG_COLOR_TYPE_PALETTE;
9682 if (mng_info->have_write_global_plte && matte == MagickFalse)
9684 png_set_PLTE(ping,ping_info,NULL,0);
9686 if (logging != MagickFalse)
9687 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9688 " Setting up empty PLTE chunk");
9693 for (i=0; i < (ssize_t) number_colors; i++)
9695 palette[i].red=ScaleQuantumToChar(image->colormap[i].red);
9696 palette[i].green=ScaleQuantumToChar(image->colormap[i].green);
9697 palette[i].blue=ScaleQuantumToChar(image->colormap[i].blue);
9700 if (logging != MagickFalse)
9701 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9702 " Setting up PLTE chunk with %d colors",
9705 ping_have_PLTE=MagickTrue;
9708 /* color_type is PNG_COLOR_TYPE_PALETTE */
9709 if (mng_info->write_png_depth == 0)
9717 while ((one << ping_bit_depth) < (size_t) number_colors)
9718 ping_bit_depth <<= 1;
9723 if (matte != MagickFalse)
9726 * Set up trans_colors array.
9728 assert(number_colors <= 256);
9730 ping_num_trans=(unsigned short) (number_transparent +
9731 number_semitransparent);
9733 if (ping_num_trans == 0)
9734 ping_have_tRNS=MagickFalse;
9738 if (logging != MagickFalse)
9740 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9741 " Scaling ping_trans_color (1)");
9743 ping_have_tRNS=MagickTrue;
9745 for (i=0; i < ping_num_trans; i++)
9747 ping_trans_alpha[i]= (png_byte)
9748 ScaleQuantumToChar(image->colormap[i].alpha);
9758 if (image_depth < 8)
9761 if ((save_image_depth == 16) && (image_depth == 8))
9763 if (logging != MagickFalse)
9765 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9766 " Scaling ping_trans_color from (%d,%d,%d)",
9767 (int) ping_trans_color.red,
9768 (int) ping_trans_color.green,
9769 (int) ping_trans_color.blue);
9772 ping_trans_color.red*=0x0101;
9773 ping_trans_color.green*=0x0101;
9774 ping_trans_color.blue*=0x0101;
9775 ping_trans_color.gray*=0x0101;
9777 if (logging != MagickFalse)
9779 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9781 (int) ping_trans_color.red,
9782 (int) ping_trans_color.green,
9783 (int) ping_trans_color.blue);
9788 if (ping_bit_depth < (ssize_t) mng_info->write_png_depth)
9789 ping_bit_depth = (ssize_t) mng_info->write_png_depth;
9792 Adjust background and transparency samples in sub-8-bit grayscale files.
9794 if (ping_bit_depth < 8 && ping_color_type ==
9795 PNG_COLOR_TYPE_GRAY)
9803 maxval=(png_uint_16) ((one << ping_bit_depth)-1);
9805 if (ping_exclude_bKGD == MagickFalse)
9808 ping_background.gray=(png_uint_16) ((maxval/65535.)*
9809 (ScaleQuantumToShort(((GetPixelInfoIntensity(
9810 &image->background_color))) +.5)));
9812 if (logging != MagickFalse)
9813 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9814 " Setting up bKGD chunk (2)");
9815 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9816 " background_color index is %d",
9817 (int) ping_background.index);
9819 ping_have_bKGD = MagickTrue;
9822 if (logging != MagickFalse)
9823 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9824 " Scaling ping_trans_color.gray from %d",
9825 (int)ping_trans_color.gray);
9827 ping_trans_color.gray=(png_uint_16) ((maxval/255.)*(
9828 ping_trans_color.gray)+.5);
9830 if (logging != MagickFalse)
9831 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9832 " to %d", (int)ping_trans_color.gray);
9835 if (ping_exclude_bKGD == MagickFalse)
9837 if (mng_info->IsPalette && (int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
9840 Identify which colormap entry is the background color.
9843 number_colors=image_colors;
9845 for (i=0; i < (ssize_t) MagickMax(1L*number_colors,1L); i++)
9846 if (IsPNGColorEqual(image->background_color,image->colormap[i]))
9849 ping_background.index=(png_byte) i;
9851 if (logging != MagickFalse)
9853 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9854 " Setting up bKGD chunk with index=%d",(int) i);
9857 if (i < (ssize_t) number_colors)
9859 ping_have_bKGD = MagickTrue;
9861 if (logging != MagickFalse)
9863 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9864 " background =(%d,%d,%d)",
9865 (int) ping_background.red,
9866 (int) ping_background.green,
9867 (int) ping_background.blue);
9871 else /* Can't happen */
9873 if (logging != MagickFalse)
9874 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9875 " No room in PLTE to add bKGD color");
9876 ping_have_bKGD = MagickFalse;
9881 if (logging != MagickFalse)
9882 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9883 " PNG color type: %s (%d)", PngColorTypeToString(ping_color_type),
9886 Initialize compression level and filtering.
9888 if (logging != MagickFalse)
9890 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9891 " Setting up deflate compression");
9893 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9894 " Compression buffer size: 32768");
9897 png_set_compression_buffer_size(ping,32768L);
9899 if (logging != MagickFalse)
9900 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9901 " Compression mem level: 9");
9903 png_set_compression_mem_level(ping, 9);
9905 /* Untangle the "-quality" setting:
9907 Undefined is 0; the default is used.
9912 0: Use Z_HUFFMAN_ONLY strategy with the
9913 zlib default compression level
9915 1-9: the zlib compression level
9919 0-4: the PNG filter method
9921 5: libpng adaptive filtering if compression level > 5
9922 libpng filter type "none" if compression level <= 5
9923 or if image is grayscale or palette
9925 6: libpng adaptive filtering
9927 7: "LOCO" filtering (intrapixel differing) if writing
9928 a MNG, othewise "none". Did not work in IM-6.7.0-9
9929 and earlier because of a missing "else".
9931 8: Z_RLE strategy, all filters
9932 Unused prior to IM-6.7.0-10, was same as 6
9934 9: Z_RLE strategy, no PNG filters
9935 Unused prior to IM-6.7.0-10, was same as 6
9937 Note that using the -quality option, not all combinations of
9938 PNG filter type, zlib compression level, and zlib compression
9939 strategy are possible. This will be addressed soon in a
9940 release that accomodates "-define png:compression-strategy", etc.
9944 quality=image->quality == UndefinedCompressionQuality ? 75UL :
9949 if (mng_info->write_png_compression_strategy == 0)
9950 mng_info->write_png_compression_strategy = Z_HUFFMAN_ONLY+1;
9953 else if (mng_info->write_png_compression_level == 0)
9958 level=(int) MagickMin((ssize_t) quality/10,9);
9960 mng_info->write_png_compression_level = level+1;
9963 if (mng_info->write_png_compression_strategy == 0)
9965 if ((quality %10) == 8 || (quality %10) == 9)
9966 #ifdef Z_RLE /* Z_RLE was added to zlib-1.2.0 */
9967 mng_info->write_png_compression_strategy=Z_RLE+1;
9969 mng_info->write_png_compression_strategy = Z_DEFAULT_STRATEGY+1;
9973 if (mng_info->write_png_compression_filter == 0)
9974 mng_info->write_png_compression_filter=((int) quality % 10) + 1;
9976 if (logging != MagickFalse)
9978 if (mng_info->write_png_compression_level)
9979 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9980 " Compression level: %d",
9981 (int) mng_info->write_png_compression_level-1);
9983 if (mng_info->write_png_compression_strategy)
9984 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9985 " Compression strategy: %d",
9986 (int) mng_info->write_png_compression_strategy-1);
9988 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9989 " Setting up filtering");
9991 if (mng_info->write_png_compression_filter == 6)
9992 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9993 " Base filter method: ADAPTIVE");
9994 else if (mng_info->write_png_compression_filter == 0 ||
9995 mng_info->write_png_compression_filter == 1)
9996 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9997 " Base filter method: NONE");
9999 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10000 " Base filter method: %d",
10001 (int) mng_info->write_png_compression_filter-1);
10004 if (mng_info->write_png_compression_level != 0)
10005 png_set_compression_level(ping,mng_info->write_png_compression_level-1);
10007 if (mng_info->write_png_compression_filter == 6)
10009 if (((int) ping_color_type == PNG_COLOR_TYPE_GRAY) ||
10010 ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE) ||
10012 png_set_filter(ping,PNG_FILTER_TYPE_BASE,PNG_NO_FILTERS);
10014 png_set_filter(ping,PNG_FILTER_TYPE_BASE,PNG_ALL_FILTERS);
10016 else if (mng_info->write_png_compression_filter == 7 ||
10017 mng_info->write_png_compression_filter == 10)
10018 png_set_filter(ping,PNG_FILTER_TYPE_BASE,PNG_ALL_FILTERS);
10020 else if (mng_info->write_png_compression_filter == 8)
10022 #if defined(PNG_MNG_FEATURES_SUPPORTED) && defined(PNG_INTRAPIXEL_DIFFERENCING)
10023 if (mng_info->write_mng)
10025 if (((int) ping_color_type == PNG_COLOR_TYPE_RGB) ||
10026 ((int) ping_color_type == PNG_COLOR_TYPE_RGBA))
10027 ping_filter_method=PNG_INTRAPIXEL_DIFFERENCING;
10030 png_set_filter(ping,PNG_FILTER_TYPE_BASE,PNG_NO_FILTERS);
10033 else if (mng_info->write_png_compression_filter == 9)
10034 png_set_filter(ping,PNG_FILTER_TYPE_BASE,PNG_NO_FILTERS);
10036 else if (mng_info->write_png_compression_filter != 0)
10037 png_set_filter(ping,PNG_FILTER_TYPE_BASE,
10038 mng_info->write_png_compression_filter-1);
10040 if (mng_info->write_png_compression_strategy != 0)
10041 png_set_compression_strategy(ping,
10042 mng_info->write_png_compression_strategy-1);
10044 /* Only write the iCCP chunk if we are not writing the sRGB chunk. */
10045 if (ping_exclude_sRGB != MagickFalse ||
10046 (image->rendering_intent == UndefinedIntent))
10048 if ((ping_exclude_tEXt == MagickFalse ||
10049 ping_exclude_zTXt == MagickFalse) &&
10050 (ping_exclude_iCCP == MagickFalse || ping_exclude_zCCP == MagickFalse))
10052 ResetImageProfileIterator(image);
10053 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
10055 profile=GetImageProfile(image,name);
10057 if (profile != (StringInfo *) NULL)
10059 #ifdef PNG_WRITE_iCCP_SUPPORTED
10060 if ((LocaleCompare(name,"ICC") == 0) ||
10061 (LocaleCompare(name,"ICM") == 0))
10064 if (ping_exclude_iCCP == MagickFalse)
10066 png_set_iCCP(ping,ping_info,(png_charp) name,0,
10067 #if (PNG_LIBPNG_VER < 10500)
10068 (png_charp) GetStringInfoDatum(profile),
10070 (png_const_bytep) GetStringInfoDatum(profile),
10072 (png_uint_32) GetStringInfoLength(profile));
10078 if (ping_exclude_zCCP == MagickFalse)
10080 Magick_png_write_raw_profile(image_info,ping,ping_info,
10081 (unsigned char *) name,(unsigned char *) name,
10082 GetStringInfoDatum(profile),
10083 (png_uint_32) GetStringInfoLength(profile));
10087 if (logging != MagickFalse)
10088 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10089 " Setting up text chunk with %s profile",name);
10091 name=GetNextImageProfile(image);
10096 #if defined(PNG_WRITE_sRGB_SUPPORTED)
10097 if ((mng_info->have_write_global_srgb == 0) &&
10098 (image->rendering_intent != UndefinedIntent))
10100 if (ping_exclude_sRGB == MagickFalse)
10103 Note image rendering intent.
10105 if (logging != MagickFalse)
10106 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10107 " Setting up sRGB chunk");
10109 (void) png_set_sRGB(ping,ping_info,(
10110 Magick_RenderingIntent_to_PNG_RenderingIntent(
10111 image->rendering_intent)));
10115 if ((!mng_info->write_mng) || (!png_get_valid(ping,ping_info,PNG_INFO_sRGB)))
10118 if (ping_exclude_gAMA == MagickFalse &&
10119 (ping_exclude_sRGB == MagickFalse ||
10120 (image->gamma < .45 || image->gamma > .46)))
10122 if ((mng_info->have_write_global_gama == 0) && (image->gamma != 0.0))
10126 To do: check for cHRM+gAMA == sRGB, and write sRGB instead.
10128 if (logging != MagickFalse)
10129 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10130 " Setting up gAMA chunk");
10132 png_set_gAMA(ping,ping_info,image->gamma);
10136 if (ping_exclude_cHRM == MagickFalse)
10138 if ((mng_info->have_write_global_chrm == 0) &&
10139 (image->chromaticity.red_primary.x != 0.0))
10142 Note image chromaticity.
10143 To do: check for cHRM+gAMA == sRGB, and write sRGB instead.
10151 wp=image->chromaticity.white_point;
10152 rp=image->chromaticity.red_primary;
10153 gp=image->chromaticity.green_primary;
10154 bp=image->chromaticity.blue_primary;
10156 if (logging != MagickFalse)
10157 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10158 " Setting up cHRM chunk");
10160 png_set_cHRM(ping,ping_info,wp.x,wp.y,rp.x,rp.y,gp.x,gp.y,
10166 ping_interlace_method=image_info->interlace != NoInterlace;
10168 if (mng_info->write_mng)
10169 png_set_sig_bytes(ping,8);
10171 /* Bail out if cannot meet defined png:bit-depth or png:color-type */
10173 if (mng_info->write_png_colortype != 0)
10175 if (mng_info->write_png_colortype-1 == PNG_COLOR_TYPE_GRAY)
10176 if (ping_have_color != MagickFalse)
10178 ping_color_type = PNG_COLOR_TYPE_RGB;
10180 if (ping_bit_depth < 8)
10184 if (mng_info->write_png_colortype-1 == PNG_COLOR_TYPE_GRAY_ALPHA)
10185 if (ping_have_color != MagickFalse)
10186 ping_color_type = PNG_COLOR_TYPE_RGB_ALPHA;
10189 if (ping_need_colortype_warning != MagickFalse ||
10190 ((mng_info->write_png_depth &&
10191 (int) mng_info->write_png_depth != ping_bit_depth) ||
10192 (mng_info->write_png_colortype &&
10193 ((int) mng_info->write_png_colortype-1 != ping_color_type &&
10194 mng_info->write_png_colortype != 7 &&
10195 !(mng_info->write_png_colortype == 5 && ping_color_type == 0)))))
10197 if (logging != MagickFalse)
10199 if (ping_need_colortype_warning != MagickFalse)
10201 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10202 " Image has transparency but tRNS chunk was excluded");
10205 if (mng_info->write_png_depth)
10207 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10208 " Defined png:bit-depth=%u, Computed depth=%u",
10209 mng_info->write_png_depth,
10213 if (mng_info->write_png_colortype)
10215 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10216 " Defined png:color-type=%u, Computed color type=%u",
10217 mng_info->write_png_colortype-1,
10223 "Cannot write image with defined png:bit-depth or png:color-type.");
10226 if (image_matte != MagickFalse && image->alpha_trait != BlendPixelTrait)
10228 /* Add an opaque matte channel */
10229 image->alpha_trait = BlendPixelTrait;
10230 (void) SetImageAlpha(image,OpaqueAlpha,exception);
10232 if (logging != MagickFalse)
10233 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10234 " Added an opaque matte channel");
10237 if (number_transparent != 0 || number_semitransparent != 0)
10239 if (ping_color_type < 4)
10241 ping_have_tRNS=MagickTrue;
10242 if (logging != MagickFalse)
10243 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10244 " Setting ping_have_tRNS=MagickTrue.");
10248 if (logging != MagickFalse)
10249 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10250 " Writing PNG header chunks");
10252 png_set_IHDR(ping,ping_info,ping_width,ping_height,
10253 ping_bit_depth,ping_color_type,
10254 ping_interlace_method,ping_compression_method,
10255 ping_filter_method);
10257 if (ping_color_type == 3 && ping_have_PLTE != MagickFalse)
10259 png_set_PLTE(ping,ping_info,palette,number_colors);
10261 if (logging != MagickFalse)
10263 for (i=0; i< (ssize_t) number_colors; i++)
10265 if (i < ping_num_trans)
10266 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10267 " PLTE[%d] = (%d,%d,%d), tRNS[%d] = (%d)",
10269 (int) palette[i].red,
10270 (int) palette[i].green,
10271 (int) palette[i].blue,
10273 (int) ping_trans_alpha[i]);
10275 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10276 " PLTE[%d] = (%d,%d,%d)",
10278 (int) palette[i].red,
10279 (int) palette[i].green,
10280 (int) palette[i].blue);
10285 if (ping_exclude_bKGD == MagickFalse)
10287 if (ping_have_bKGD != MagickFalse)
10289 png_set_bKGD(ping,ping_info,&ping_background);
10292 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10293 " Setting up bKGD chunk");
10294 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10295 " background color = (%d,%d,%d)",
10296 (int) ping_background.red,
10297 (int) ping_background.green,
10298 (int) ping_background.blue);
10299 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10300 " index = %d, gray=%d",
10301 (int) ping_background.index,
10302 (int) ping_background.gray);
10307 if (ping_exclude_pHYs == MagickFalse)
10309 if (ping_have_pHYs != MagickFalse)
10311 png_set_pHYs(ping,ping_info,
10312 ping_pHYs_x_resolution,
10313 ping_pHYs_y_resolution,
10314 ping_pHYs_unit_type);
10318 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10319 " Setting up pHYs chunk");
10320 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10321 " x_resolution=%lu",
10322 (unsigned long) ping_pHYs_x_resolution);
10323 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10324 " y_resolution=%lu",
10325 (unsigned long) ping_pHYs_y_resolution);
10326 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10328 (unsigned long) ping_pHYs_unit_type);
10333 #if defined(PNG_oFFs_SUPPORTED)
10334 if (ping_exclude_oFFs == MagickFalse)
10336 if (image->page.x || image->page.y)
10338 png_set_oFFs(ping,ping_info,(png_int_32) image->page.x,
10339 (png_int_32) image->page.y, 0);
10341 if (logging != MagickFalse)
10342 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10343 " Setting up oFFs chunk with x=%d, y=%d, units=0",
10344 (int) image->page.x, (int) image->page.y);
10349 if (mng_info->need_blob != MagickFalse)
10351 if (OpenBlob(image_info,image,WriteBinaryBlobMode,exception) ==
10353 png_error(ping,"WriteBlob Failed");
10355 ping_have_blob=MagickTrue;
10358 png_write_info_before_PLTE(ping, ping_info);
10360 if (ping_have_tRNS != MagickFalse && ping_color_type < 4)
10362 if (logging != MagickFalse)
10364 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10365 " Calling png_set_tRNS with num_trans=%d",ping_num_trans);
10368 if (ping_color_type == 3)
10369 (void) png_set_tRNS(ping, ping_info,
10376 (void) png_set_tRNS(ping, ping_info,
10379 &ping_trans_color);
10381 if (logging != MagickFalse)
10383 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10384 " tRNS color =(%d,%d,%d)",
10385 (int) ping_trans_color.red,
10386 (int) ping_trans_color.green,
10387 (int) ping_trans_color.blue);
10392 /* write any png-chunk-b profiles */
10393 (void) Magick_png_write_chunk_from_profile(image,"PNG-chunk-b",logging);
10395 png_write_info(ping,ping_info);
10397 /* write any PNG-chunk-m profiles */
10398 (void) Magick_png_write_chunk_from_profile(image,"PNG-chunk-m",logging);
10400 if (ping_exclude_vpAg == MagickFalse)
10402 if ((image->page.width != 0 && image->page.width != image->columns) ||
10403 (image->page.height != 0 && image->page.height != image->rows))
10408 (void) WriteBlobMSBULong(image,9L); /* data length=8 */
10409 PNGType(chunk,mng_vpAg);
10410 LogPNGChunk(logging,mng_vpAg,9L);
10411 PNGLong(chunk+4,(png_uint_32) image->page.width);
10412 PNGLong(chunk+8,(png_uint_32) image->page.height);
10413 chunk[12]=0; /* unit = pixels */
10414 (void) WriteBlob(image,13,chunk);
10415 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
10419 #if (PNG_LIBPNG_VER == 10206)
10420 /* avoid libpng-1.2.6 bug by setting PNG_HAVE_IDAT flag */
10421 #define PNG_HAVE_IDAT 0x04
10422 ping->mode |= PNG_HAVE_IDAT;
10423 #undef PNG_HAVE_IDAT
10426 png_set_packing(ping);
10430 rowbytes=image->columns;
10431 if (image_depth > 8)
10433 switch (ping_color_type)
10435 case PNG_COLOR_TYPE_RGB:
10439 case PNG_COLOR_TYPE_GRAY_ALPHA:
10443 case PNG_COLOR_TYPE_RGBA:
10451 if (logging != MagickFalse)
10453 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10454 " Writing PNG image data");
10456 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10457 " Allocating %.20g bytes of memory for pixels",(double) rowbytes);
10459 ping_pixels=(unsigned char *) AcquireQuantumMemory(rowbytes,
10460 sizeof(*ping_pixels));
10462 if (ping_pixels == (unsigned char *) NULL)
10463 png_error(ping,"Allocation of memory for pixels failed");
10466 Initialize image scanlines.
10468 quantum_info=AcquireQuantumInfo(image_info,image);
10469 if (quantum_info == (QuantumInfo *) NULL)
10470 png_error(ping,"Memory allocation for quantum_info failed");
10471 quantum_info->format=UndefinedQuantumFormat;
10472 quantum_info->depth=image_depth;
10473 (void) SetQuantumEndian(image,quantum_info,MSBEndian);
10474 num_passes=png_set_interlace_handling(ping);
10476 if ((!mng_info->write_png8 && !mng_info->write_png24 &&
10477 !mng_info->write_png32) &&
10478 (mng_info->IsPalette ||
10479 (image_info->type == BilevelType)) &&
10480 image_matte == MagickFalse &&
10481 ping_have_non_bw == MagickFalse)
10483 /* Palette, Bilevel, or Opaque Monochrome */
10484 register const Quantum
10487 quantum_info->depth=8;
10488 for (pass=0; pass < num_passes; pass++)
10491 Convert PseudoClass image to a PNG monochrome image.
10493 for (y=0; y < (ssize_t) image->rows; y++)
10495 if (logging != MagickFalse && y == 0)
10496 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10497 " Writing row of pixels (0)");
10499 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
10501 if (p == (const Quantum *) NULL)
10504 if (mng_info->IsPalette)
10506 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10507 quantum_info,GrayQuantum,ping_pixels,exception);
10508 if (mng_info->write_png_colortype-1 == PNG_COLOR_TYPE_PALETTE &&
10509 mng_info->write_png_depth &&
10510 mng_info->write_png_depth != old_bit_depth)
10512 /* Undo pixel scaling */
10513 for (i=0; i < (ssize_t) image->columns; i++)
10514 *(ping_pixels+i)=(unsigned char) (*(ping_pixels+i)
10515 >> (8-old_bit_depth));
10521 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10522 quantum_info,RedQuantum,ping_pixels,exception);
10525 if (mng_info->write_png_colortype-1 != PNG_COLOR_TYPE_PALETTE)
10526 for (i=0; i < (ssize_t) image->columns; i++)
10527 *(ping_pixels+i)=(unsigned char) ((*(ping_pixels+i) > 127) ?
10530 if (logging != MagickFalse && y == 0)
10531 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10532 " Writing row of pixels (1)");
10534 png_write_row(ping,ping_pixels);
10536 if (image->previous == (Image *) NULL)
10538 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
10539 if (status == MagickFalse)
10545 else /* Not Palette, Bilevel, or Opaque Monochrome */
10547 if ((!mng_info->write_png8 && !mng_info->write_png24 &&
10548 !mng_info->write_png32) &&
10549 (image_matte != MagickFalse ||
10550 (ping_bit_depth >= MAGICKCORE_QUANTUM_DEPTH)) &&
10551 (mng_info->IsPalette) && ping_have_color == MagickFalse)
10553 register const Quantum
10556 for (pass=0; pass < num_passes; pass++)
10559 for (y=0; y < (ssize_t) image->rows; y++)
10561 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
10563 if (p == (const Quantum *) NULL)
10566 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
10568 if (mng_info->IsPalette)
10569 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10570 quantum_info,GrayQuantum,ping_pixels,exception);
10573 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10574 quantum_info,RedQuantum,ping_pixels,exception);
10576 if (logging != MagickFalse && y == 0)
10577 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10578 " Writing GRAY PNG pixels (2)");
10581 else /* PNG_COLOR_TYPE_GRAY_ALPHA */
10583 if (logging != MagickFalse && y == 0)
10584 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10585 " Writing GRAY_ALPHA PNG pixels (2)");
10587 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10588 quantum_info,GrayAlphaQuantum,ping_pixels,exception);
10591 if (logging != MagickFalse && y == 0)
10592 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10593 " Writing row of pixels (2)");
10595 png_write_row(ping,ping_pixels);
10598 if (image->previous == (Image *) NULL)
10600 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
10601 if (status == MagickFalse)
10609 register const Quantum
10612 for (pass=0; pass < num_passes; pass++)
10614 if ((image_depth > 8) || (mng_info->write_png24 ||
10615 mng_info->write_png32 ||
10616 (!mng_info->write_png8 && !mng_info->IsPalette)))
10618 for (y=0; y < (ssize_t) image->rows; y++)
10620 p=GetVirtualPixels(image,0,y,image->columns,1, exception);
10622 if (p == (const Quantum *) NULL)
10625 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
10627 if (image->storage_class == DirectClass)
10628 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10629 quantum_info,RedQuantum,ping_pixels,exception);
10632 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10633 quantum_info,GrayQuantum,ping_pixels,exception);
10636 else if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
10638 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10639 quantum_info,GrayAlphaQuantum,ping_pixels,
10642 if (logging != MagickFalse && y == 0)
10643 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10644 " Writing GRAY_ALPHA PNG pixels (3)");
10647 else if (image_matte != MagickFalse)
10648 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10649 quantum_info,RGBAQuantum,ping_pixels,exception);
10652 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10653 quantum_info,RGBQuantum,ping_pixels,exception);
10655 if (logging != MagickFalse && y == 0)
10656 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10657 " Writing row of pixels (3)");
10659 png_write_row(ping,ping_pixels);
10664 /* not ((image_depth > 8) || (mng_info->write_png24 ||
10665 mng_info->write_png32 ||
10666 (!mng_info->write_png8 && !mng_info->IsPalette))) */
10668 if ((ping_color_type != PNG_COLOR_TYPE_GRAY) &&
10669 (ping_color_type != PNG_COLOR_TYPE_GRAY_ALPHA))
10671 if (logging != MagickFalse)
10672 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10673 " pass %d, Image Is not GRAY or GRAY_ALPHA",pass);
10675 quantum_info->depth=8;
10679 for (y=0; y < (ssize_t) image->rows; y++)
10681 if (logging != MagickFalse && y == 0)
10682 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10683 " pass %d, Image Is RGB, 16-bit GRAY, or GRAY_ALPHA",pass);
10685 p=GetVirtualPixels(image,0,y,image->columns,1, exception);
10687 if (p == (const Quantum *) NULL)
10690 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
10692 quantum_info->depth=image->depth;
10694 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10695 quantum_info,GrayQuantum,ping_pixels,exception);
10698 else if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
10700 if (logging != MagickFalse && y == 0)
10701 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10702 " Writing GRAY_ALPHA PNG pixels (4)");
10704 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10705 quantum_info,GrayAlphaQuantum,ping_pixels,
10711 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10712 quantum_info,IndexQuantum,ping_pixels,exception);
10714 if (logging != MagickFalse && y <= 2)
10716 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10717 " Writing row of non-gray pixels (4)");
10719 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10720 " ping_pixels[0]=%d,ping_pixels[1]=%d",
10721 (int)ping_pixels[0],(int)ping_pixels[1]);
10724 png_write_row(ping,ping_pixels);
10728 if (image->previous == (Image *) NULL)
10730 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
10731 if (status == MagickFalse)
10738 if (quantum_info != (QuantumInfo *) NULL)
10739 quantum_info=DestroyQuantumInfo(quantum_info);
10741 if (logging != MagickFalse)
10743 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10744 " Wrote PNG image data");
10746 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10747 " Width: %.20g",(double) ping_width);
10749 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10750 " Height: %.20g",(double) ping_height);
10752 if (mng_info->write_png_depth)
10754 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10755 " Defined png:bit-depth: %d",mng_info->write_png_depth);
10758 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10759 " PNG bit-depth written: %d",ping_bit_depth);
10761 if (mng_info->write_png_colortype)
10763 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10764 " Defined png:color-type: %d",mng_info->write_png_colortype-1);
10767 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10768 " PNG color-type written: %d",ping_color_type);
10770 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10771 " PNG Interlace method: %d",ping_interlace_method);
10774 Generate text chunks after IDAT.
10776 if (ping_exclude_tEXt == MagickFalse || ping_exclude_zTXt == MagickFalse)
10778 ResetImagePropertyIterator(image);
10779 property=GetNextImageProperty(image);
10780 while (property != (const char *) NULL)
10785 value=GetImageProperty(image,property,exception);
10787 /* Don't write any "png:" properties; those are just for "identify" */
10788 if (LocaleNCompare(property,"png:",4) != 0 &&
10790 /* Suppress density and units if we wrote a pHYs chunk */
10791 (ping_exclude_pHYs != MagickFalse ||
10792 LocaleCompare(property,"density") != 0 ||
10793 LocaleCompare(property,"units") != 0) &&
10795 /* Suppress the IM-generated Date:create and Date:modify */
10796 (ping_exclude_date == MagickFalse ||
10797 LocaleNCompare(property, "Date:",5) != 0))
10799 if (value != (const char *) NULL)
10802 #if PNG_LIBPNG_VER >= 14000
10803 text=(png_textp) png_malloc(ping,
10804 (png_alloc_size_t) sizeof(png_text));
10806 text=(png_textp) png_malloc(ping,(png_size_t) sizeof(png_text));
10808 text[0].key=(char *) property;
10809 text[0].text=(char *) value;
10810 text[0].text_length=strlen(value);
10812 if (ping_exclude_tEXt != MagickFalse)
10813 text[0].compression=PNG_TEXT_COMPRESSION_zTXt;
10815 else if (ping_exclude_zTXt != MagickFalse)
10816 text[0].compression=PNG_TEXT_COMPRESSION_NONE;
10820 text[0].compression=image_info->compression == NoCompression ||
10821 (image_info->compression == UndefinedCompression &&
10822 text[0].text_length < 128) ? PNG_TEXT_COMPRESSION_NONE :
10823 PNG_TEXT_COMPRESSION_zTXt ;
10826 if (logging != MagickFalse)
10828 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10829 " Setting up text chunk");
10831 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10832 " keyword: %s",text[0].key);
10835 png_set_text(ping,ping_info,text,1);
10836 png_free(ping,text);
10839 property=GetNextImageProperty(image);
10843 /* write any PNG-chunk-e profiles */
10844 (void) Magick_png_write_chunk_from_profile(image,"PNG-chunk-e",logging);
10846 if (logging != MagickFalse)
10847 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10848 " Writing PNG end info");
10850 png_write_end(ping,ping_info);
10852 if (mng_info->need_fram && (int) image->dispose == BackgroundDispose)
10854 if (mng_info->page.x || mng_info->page.y ||
10855 (ping_width != mng_info->page.width) ||
10856 (ping_height != mng_info->page.height))
10862 Write FRAM 4 with clipping boundaries followed by FRAM 1.
10864 (void) WriteBlobMSBULong(image,27L); /* data length=27 */
10865 PNGType(chunk,mng_FRAM);
10866 LogPNGChunk(logging,mng_FRAM,27L);
10868 chunk[5]=0; /* frame name separator (no name) */
10869 chunk[6]=1; /* flag for changing delay, for next frame only */
10870 chunk[7]=0; /* flag for changing frame timeout */
10871 chunk[8]=1; /* flag for changing frame clipping for next frame */
10872 chunk[9]=0; /* flag for changing frame sync_id */
10873 PNGLong(chunk+10,(png_uint_32) (0L)); /* temporary 0 delay */
10874 chunk[14]=0; /* clipping boundaries delta type */
10875 PNGLong(chunk+15,(png_uint_32) (mng_info->page.x)); /* left cb */
10877 (png_uint_32) (mng_info->page.x + ping_width));
10878 PNGLong(chunk+23,(png_uint_32) (mng_info->page.y)); /* top cb */
10880 (png_uint_32) (mng_info->page.y + ping_height));
10881 (void) WriteBlob(image,31,chunk);
10882 (void) WriteBlobMSBULong(image,crc32(0,chunk,31));
10883 mng_info->old_framing_mode=4;
10884 mng_info->framing_mode=1;
10888 mng_info->framing_mode=3;
10890 if (mng_info->write_mng && !mng_info->need_fram &&
10891 ((int) image->dispose == 3))
10892 png_error(ping, "Cannot convert GIF with disposal method 3 to MNG-LC");
10895 Free PNG resources.
10898 png_destroy_write_struct(&ping,&ping_info);
10900 ping_pixels=(unsigned char *) RelinquishMagickMemory(ping_pixels);
10902 if (ping_have_blob != MagickFalse)
10903 (void) CloseBlob(image);
10905 image_info=DestroyImageInfo(image_info);
10906 image=DestroyImage(image);
10908 /* Store bit depth actually written */
10909 s[0]=(char) ping_bit_depth;
10912 (void) SetImageProperty(IMimage,"png:bit-depth-written",s,exception);
10914 if (logging != MagickFalse)
10915 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10916 " exit WriteOnePNGImage()");
10918 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
10919 UnlockSemaphoreInfo(ping_semaphore);
10922 /* } for navigation to beginning of SETJMP-protected block. Revert to
10923 * Throwing an Exception when an error occurs.
10926 return(MagickTrue);
10927 /* End write one PNG image */
10932 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10936 % W r i t e P N G I m a g e %
10940 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10942 % WritePNGImage() writes a Portable Network Graphics (PNG) or
10943 % Multiple-image Network Graphics (MNG) image file.
10945 % MNG support written by Glenn Randers-Pehrson, glennrp@image...
10947 % The format of the WritePNGImage method is:
10949 % MagickBooleanType WritePNGImage(const ImageInfo *image_info,
10950 % Image *image,ExceptionInfo *exception)
10952 % A description of each parameter follows:
10954 % o image_info: the image info.
10956 % o image: The image.
10958 % o exception: return any errors or warnings in this structure.
10960 % Returns MagickTrue on success, MagickFalse on failure.
10962 % Communicating with the PNG encoder:
10964 % While the datastream written is always in PNG format and normally would
10965 % be given the "png" file extension, this method also writes the following
10966 % pseudo-formats which are subsets of png:
10968 % o PNG8: An 8-bit indexed PNG datastream is written. If the image has
10969 % a depth greater than 8, the depth is reduced. If transparency
10970 % is present, the tRNS chunk must only have values 0 and 255
10971 % (i.e., transparency is binary: fully opaque or fully
10972 % transparent). If other values are present they will be
10973 % 50%-thresholded to binary transparency. If more than 256
10974 % colors are present, they will be quantized to the 4-4-4-1,
10975 % 3-3-3-1, or 3-3-2-1 palette. The underlying RGB color
10976 % of any resulting fully-transparent pixels is changed to
10977 % the image's background color.
10979 % If you want better quantization or dithering of the colors
10980 % or alpha than that, you need to do it before calling the
10981 % PNG encoder. The pixels contain 8-bit indices even if
10982 % they could be represented with 1, 2, or 4 bits. Grayscale
10983 % images will be written as indexed PNG files even though the
10984 % PNG grayscale type might be slightly more efficient. Please
10985 % note that writing to the PNG8 format may result in loss
10986 % of color and alpha data.
10988 % o PNG24: An 8-bit per sample RGB PNG datastream is written. The tRNS
10989 % chunk can be present to convey binary transparency by naming
10990 % one of the colors as transparent. The only loss incurred
10991 % is reduction of sample depth to 8. If the image has more
10992 % than one transparent color, has semitransparent pixels, or
10993 % has an opaque pixel with the same RGB components as the
10994 % transparent color, an image is not written.
10996 % o PNG32: An 8-bit per sample RGBA PNG is written. Partial
10997 % transparency is permitted, i.e., the alpha sample for
10998 % each pixel can have any value from 0 to 255. The alpha
10999 % channel is present even if the image is fully opaque.
11000 % The only loss in data is the reduction of the sample depth
11003 % o -define: For more precise control of the PNG output, you can use the
11004 % Image options "png:bit-depth" and "png:color-type". These
11005 % can be set from the commandline with "-define" and also
11006 % from the application programming interfaces. The options
11007 % are case-independent and are converted to lowercase before
11008 % being passed to this encoder.
11010 % png:color-type can be 0, 2, 3, 4, or 6.
11012 % When png:color-type is 0 (Grayscale), png:bit-depth can
11013 % be 1, 2, 4, 8, or 16.
11015 % When png:color-type is 2 (RGB), png:bit-depth can
11018 % When png:color-type is 3 (Indexed), png:bit-depth can
11019 % be 1, 2, 4, or 8. This refers to the number of bits
11020 % used to store the index. The color samples always have
11021 % bit-depth 8 in indexed PNG files.
11023 % When png:color-type is 4 (Gray-Matte) or 6 (RGB-Matte),
11024 % png:bit-depth can be 8 or 16.
11026 % If the image cannot be written without loss with the requested bit-depth
11027 % and color-type, a PNG file will not be written, and the encoder will
11028 % return MagickFalse.
11030 % Since image encoders should not be responsible for the "heavy lifting",
11031 % the user should make sure that ImageMagick has already reduced the
11032 % image depth and number of colors and limit transparency to binary
11033 % transparency prior to attempting to write the image with depth, color,
11034 % or transparency limitations.
11036 % Note that another definition, "png:bit-depth-written" exists, but it
11037 % is not intended for external use. It is only used internally by the
11038 % PNG encoder to inform the JNG encoder of the depth of the alpha channel.
11040 % It is possible to request that the PNG encoder write previously-formatted
11041 % ancillary chunks in the output PNG file, using the "-profile" commandline
11042 % option as shown below or by setting the profile via a programming
11045 % -profile PNG-chunk-x:<file>
11047 % where x is a location flag and <file> is a file containing the chunk
11048 % name in the first 4 bytes, then a colon (":"), followed by the chunk data.
11049 % This encoder will compute the chunk length and CRC, so those must not
11050 % be included in the file.
11052 % "x" can be "b" (before PLTE), "m" (middle, i.e., between PLTE and IDAT),
11053 % or "e" (end, i.e., after IDAT). If you want to write multiple chunks
11054 % of the same type, then add a short unique string after the "x" to prevent
11055 % subsequent profiles from overwriting the preceding ones, e.g.,
11057 % -profile PNG-chunk-b01:file01 -profile PNG-chunk-b02:file02
11059 % As of version 6.6.6 the following optimizations are always done:
11061 % o 32-bit depth is reduced to 16.
11062 % o 16-bit depth is reduced to 8 if all pixels contain samples whose
11063 % high byte and low byte are identical.
11064 % o Palette is sorted to remove unused entries and to put a
11065 % transparent color first, if BUILD_PNG_PALETTE is defined.
11066 % o Opaque matte channel is removed when writing an indexed PNG.
11067 % o Grayscale images are reduced to 1, 2, or 4 bit depth if
11068 % this can be done without loss and a larger bit depth N was not
11069 % requested via the "-define png:bit-depth=N" option.
11070 % o If matte channel is present but only one transparent color is
11071 % present, RGB+tRNS is written instead of RGBA
11072 % o Opaque matte channel is removed (or added, if color-type 4 or 6
11073 % was requested when converting an opaque image).
11075 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11077 static MagickBooleanType WritePNGImage(const ImageInfo *image_info,
11078 Image *image,ExceptionInfo *exception)
11083 have_mng_structure,
11099 assert(image_info != (const ImageInfo *) NULL);
11100 assert(image_info->signature == MagickSignature);
11101 assert(image != (Image *) NULL);
11102 assert(image->signature == MagickSignature);
11103 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
11104 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter WritePNGImage()");
11106 Allocate a MngInfo structure.
11108 have_mng_structure=MagickFalse;
11109 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
11111 if (mng_info == (MngInfo *) NULL)
11112 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
11115 Initialize members of the MngInfo structure.
11117 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
11118 mng_info->image=image;
11119 mng_info->equal_backgrounds=MagickTrue;
11120 have_mng_structure=MagickTrue;
11122 /* See if user has requested a specific PNG subformat */
11124 mng_info->write_png8=LocaleCompare(image_info->magick,"PNG8") == 0;
11125 mng_info->write_png24=LocaleCompare(image_info->magick,"PNG24") == 0;
11126 mng_info->write_png32=LocaleCompare(image_info->magick,"PNG32") == 0;
11128 value=GetImageOption(image_info,"png:format");
11130 if (value != (char *) NULL)
11132 if (LocaleCompare(value,"png8") == 0)
11134 mng_info->write_png8 = MagickTrue;
11135 mng_info->write_png24 = MagickFalse;
11136 mng_info->write_png32 = MagickFalse;
11139 else if (LocaleCompare(value,"png24") == 0)
11141 mng_info->write_png8 = MagickFalse;
11142 mng_info->write_png24 = MagickTrue;
11143 mng_info->write_png32 = MagickFalse;
11146 else if (LocaleCompare(value,"png32") == 0)
11148 mng_info->write_png8 = MagickFalse;
11149 mng_info->write_png24 = MagickFalse;
11150 mng_info->write_png32 = MagickTrue;
11153 if (mng_info->write_png8)
11155 mng_info->write_png_colortype = /* 3 */ 4;
11156 mng_info->write_png_depth = 8;
11160 if (mng_info->write_png24)
11162 mng_info->write_png_colortype = /* 2 */ 3;
11163 mng_info->write_png_depth = 8;
11166 if (image->alpha_trait == BlendPixelTrait)
11167 (void) SetImageType(image,TrueColorMatteType,exception);
11170 (void) SetImageType(image,TrueColorType,exception);
11172 (void) SyncImage(image,exception);
11175 if (mng_info->write_png32)
11177 mng_info->write_png_colortype = /* 6 */ 7;
11178 mng_info->write_png_depth = 8;
11181 if (image->alpha_trait == BlendPixelTrait)
11182 (void) SetImageType(image,TrueColorMatteType,exception);
11185 (void) SetImageType(image,TrueColorType,exception);
11187 (void) SyncImage(image,exception);
11190 value=GetImageOption(image_info,"png:bit-depth");
11192 if (value != (char *) NULL)
11194 if (LocaleCompare(value,"1") == 0)
11195 mng_info->write_png_depth = 1;
11197 else if (LocaleCompare(value,"2") == 0)
11198 mng_info->write_png_depth = 2;
11200 else if (LocaleCompare(value,"4") == 0)
11201 mng_info->write_png_depth = 4;
11203 else if (LocaleCompare(value,"8") == 0)
11204 mng_info->write_png_depth = 8;
11206 else if (LocaleCompare(value,"16") == 0)
11207 mng_info->write_png_depth = 16;
11210 (void) ThrowMagickException(exception,
11211 GetMagickModule(),CoderWarning,
11212 "ignoring invalid defined png:bit-depth",
11215 if (logging != MagickFalse)
11216 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11217 " png:bit-depth=%d was defined.\n",mng_info->write_png_depth);
11220 value=GetImageOption(image_info,"png:color-type");
11222 if (value != (char *) NULL)
11224 /* We must store colortype+1 because 0 is a valid colortype */
11225 if (LocaleCompare(value,"0") == 0)
11226 mng_info->write_png_colortype = 1;
11228 else if (LocaleCompare(value,"1") == 0)
11229 mng_info->write_png_colortype = 2;
11231 else if (LocaleCompare(value,"2") == 0)
11232 mng_info->write_png_colortype = 3;
11234 else if (LocaleCompare(value,"3") == 0)
11235 mng_info->write_png_colortype = 4;
11237 else if (LocaleCompare(value,"4") == 0)
11238 mng_info->write_png_colortype = 5;
11240 else if (LocaleCompare(value,"6") == 0)
11241 mng_info->write_png_colortype = 7;
11244 (void) ThrowMagickException(exception,
11245 GetMagickModule(),CoderWarning,
11246 "ignoring invalid defined png:color-type",
11249 if (logging != MagickFalse)
11250 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11251 " png:color-type=%d was defined.\n",mng_info->write_png_colortype-1);
11254 /* Check for chunks to be excluded:
11256 * The default is to not exclude any known chunks except for any
11257 * listed in the "unused_chunks" array, above.
11259 * Chunks can be listed for exclusion via a "png:exclude-chunk"
11260 * define (in the image properties or in the image artifacts)
11261 * or via a mng_info member. For convenience, in addition
11262 * to or instead of a comma-separated list of chunks, the
11263 * "exclude-chunk" string can be simply "all" or "none".
11265 * The exclude-chunk define takes priority over the mng_info.
11267 * A "png:include-chunk" define takes priority over both the
11268 * mng_info and the "png:exclude-chunk" define. Like the
11269 * "exclude-chunk" string, it can define "all" or "none" as
11270 * well as a comma-separated list. Chunks that are unknown to
11271 * ImageMagick are always excluded, regardless of their "copy-safe"
11272 * status according to the PNG specification, and even if they
11273 * appear in the "include-chunk" list. Such defines appearing among
11274 * the image options take priority over those found among the image
11277 * Finally, all chunks listed in the "unused_chunks" array are
11278 * automatically excluded, regardless of the other instructions
11281 * if you exclude sRGB but not gAMA (recommended), then sRGB chunk
11282 * will not be written and the gAMA chunk will only be written if it
11283 * is not between .45 and .46, or approximately (1.0/2.2).
11285 * If you exclude tRNS and the image has transparency, the colortype
11286 * is forced to be 4 or 6 (GRAY_ALPHA or RGB_ALPHA).
11288 * The -strip option causes StripImage() to set the png:include-chunk
11289 * artifact to "none,trns,gama".
11292 mng_info->ping_exclude_bKGD=MagickFalse;
11293 mng_info->ping_exclude_cHRM=MagickFalse;
11294 mng_info->ping_exclude_date=MagickFalse;
11295 mng_info->ping_exclude_EXIF=MagickFalse; /* hex-encoded EXIF in zTXt */
11296 mng_info->ping_exclude_gAMA=MagickFalse;
11297 mng_info->ping_exclude_iCCP=MagickFalse;
11298 /* mng_info->ping_exclude_iTXt=MagickFalse; */
11299 mng_info->ping_exclude_oFFs=MagickFalse;
11300 mng_info->ping_exclude_pHYs=MagickFalse;
11301 mng_info->ping_exclude_sRGB=MagickFalse;
11302 mng_info->ping_exclude_tEXt=MagickFalse;
11303 mng_info->ping_exclude_tRNS=MagickFalse;
11304 mng_info->ping_exclude_vpAg=MagickFalse;
11305 mng_info->ping_exclude_zCCP=MagickFalse; /* hex-encoded iCCP in zTXt */
11306 mng_info->ping_exclude_zTXt=MagickFalse;
11308 mng_info->ping_preserve_colormap=MagickFalse;
11310 value=GetImageArtifact(image,"png:preserve-colormap");
11312 value=GetImageOption(image_info,"png:preserve-colormap");
11314 mng_info->ping_preserve_colormap=MagickTrue;
11316 /* Thes compression-level, compression-strategy, and compression-filter
11317 * defines take precedence over values from the -quality option.
11319 value=GetImageArtifact(image,"png:compression-level");
11321 value=GetImageOption(image_info,"png:compression-level");
11324 /* We have to add 1 to everything because 0 is a valid input,
11325 * and we want to use 0 (the default) to mean undefined.
11327 if (LocaleCompare(value,"0") == 0)
11328 mng_info->write_png_compression_level = 1;
11330 else if (LocaleCompare(value,"1") == 0)
11331 mng_info->write_png_compression_level = 2;
11333 else if (LocaleCompare(value,"2") == 0)
11334 mng_info->write_png_compression_level = 3;
11336 else if (LocaleCompare(value,"3") == 0)
11337 mng_info->write_png_compression_level = 4;
11339 else if (LocaleCompare(value,"4") == 0)
11340 mng_info->write_png_compression_level = 5;
11342 else if (LocaleCompare(value,"5") == 0)
11343 mng_info->write_png_compression_level = 6;
11345 else if (LocaleCompare(value,"6") == 0)
11346 mng_info->write_png_compression_level = 7;
11348 else if (LocaleCompare(value,"7") == 0)
11349 mng_info->write_png_compression_level = 8;
11351 else if (LocaleCompare(value,"8") == 0)
11352 mng_info->write_png_compression_level = 9;
11354 else if (LocaleCompare(value,"9") == 0)
11355 mng_info->write_png_compression_level = 10;
11358 (void) ThrowMagickException(exception,
11359 GetMagickModule(),CoderWarning,
11360 "ignoring invalid defined png:compression-level",
11364 value=GetImageArtifact(image,"png:compression-strategy");
11366 value=GetImageOption(image_info,"png:compression-strategy");
11370 if (LocaleCompare(value,"0") == 0)
11371 mng_info->write_png_compression_strategy = Z_DEFAULT_STRATEGY+1;
11373 else if (LocaleCompare(value,"1") == 0)
11374 mng_info->write_png_compression_strategy = Z_FILTERED+1;
11376 else if (LocaleCompare(value,"2") == 0)
11377 mng_info->write_png_compression_strategy = Z_HUFFMAN_ONLY+1;
11379 else if (LocaleCompare(value,"3") == 0)
11380 #ifdef Z_RLE /* Z_RLE was added to zlib-1.2.0 */
11381 mng_info->write_png_compression_strategy = Z_RLE+1;
11383 mng_info->write_png_compression_strategy = Z_DEFAULT_STRATEGY+1;
11386 else if (LocaleCompare(value,"4") == 0)
11387 #ifdef Z_FIXED /* Z_FIXED was added to zlib-1.2.2.2 */
11388 mng_info->write_png_compression_strategy = Z_FIXED+1;
11390 mng_info->write_png_compression_strategy = Z_DEFAULT_STRATEGY+1;
11394 (void) ThrowMagickException(exception,
11395 GetMagickModule(),CoderWarning,
11396 "ignoring invalid defined png:compression-strategy",
11400 value=GetImageArtifact(image,"png:compression-filter");
11402 value=GetImageOption(image_info,"png:compression-filter");
11406 /* To do: combinations of filters allowed by libpng
11407 * masks 0x08 through 0xf8
11409 * Implement this as a comma-separated list of 0,1,2,3,4,5
11410 * where 5 is a special case meaning PNG_ALL_FILTERS.
11413 if (LocaleCompare(value,"0") == 0)
11414 mng_info->write_png_compression_filter = 1;
11416 else if (LocaleCompare(value,"1") == 0)
11417 mng_info->write_png_compression_filter = 2;
11419 else if (LocaleCompare(value,"2") == 0)
11420 mng_info->write_png_compression_filter = 3;
11422 else if (LocaleCompare(value,"3") == 0)
11423 mng_info->write_png_compression_filter = 4;
11425 else if (LocaleCompare(value,"4") == 0)
11426 mng_info->write_png_compression_filter = 5;
11428 else if (LocaleCompare(value,"5") == 0)
11429 mng_info->write_png_compression_filter = 6;
11432 (void) ThrowMagickException(exception,
11433 GetMagickModule(),CoderWarning,
11434 "ignoring invalid defined png:compression-filter",
11438 excluding=MagickFalse;
11440 for (source=0; source<1; source++)
11444 value=GetImageArtifact(image,"png:exclude-chunk");
11447 value=GetImageArtifact(image,"png:exclude-chunks");
11451 value=GetImageOption(image_info,"png:exclude-chunk");
11454 value=GetImageOption(image_info,"png:exclude-chunks");
11463 excluding=MagickTrue;
11465 if (logging != MagickFalse)
11468 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11469 " png:exclude-chunk=%s found in image artifacts.\n", value);
11471 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11472 " png:exclude-chunk=%s found in image properties.\n", value);
11475 last=strlen(value);
11477 for (i=0; i<(int) last; i+=5)
11480 if (LocaleNCompare(value+i,"all",3) == 0)
11482 mng_info->ping_exclude_bKGD=MagickTrue;
11483 mng_info->ping_exclude_cHRM=MagickTrue;
11484 mng_info->ping_exclude_date=MagickTrue;
11485 mng_info->ping_exclude_EXIF=MagickTrue;
11486 mng_info->ping_exclude_gAMA=MagickTrue;
11487 mng_info->ping_exclude_iCCP=MagickTrue;
11488 /* mng_info->ping_exclude_iTXt=MagickTrue; */
11489 mng_info->ping_exclude_oFFs=MagickTrue;
11490 mng_info->ping_exclude_pHYs=MagickTrue;
11491 mng_info->ping_exclude_sRGB=MagickTrue;
11492 mng_info->ping_exclude_tEXt=MagickTrue;
11493 mng_info->ping_exclude_tRNS=MagickTrue;
11494 mng_info->ping_exclude_vpAg=MagickTrue;
11495 mng_info->ping_exclude_zCCP=MagickTrue;
11496 mng_info->ping_exclude_zTXt=MagickTrue;
11500 if (LocaleNCompare(value+i,"none",4) == 0)
11502 mng_info->ping_exclude_bKGD=MagickFalse;
11503 mng_info->ping_exclude_cHRM=MagickFalse;
11504 mng_info->ping_exclude_date=MagickFalse;
11505 mng_info->ping_exclude_EXIF=MagickFalse;
11506 mng_info->ping_exclude_gAMA=MagickFalse;
11507 mng_info->ping_exclude_iCCP=MagickFalse;
11508 /* mng_info->ping_exclude_iTXt=MagickFalse; */
11509 mng_info->ping_exclude_oFFs=MagickFalse;
11510 mng_info->ping_exclude_pHYs=MagickFalse;
11511 mng_info->ping_exclude_sRGB=MagickFalse;
11512 mng_info->ping_exclude_tEXt=MagickFalse;
11513 mng_info->ping_exclude_tRNS=MagickFalse;
11514 mng_info->ping_exclude_vpAg=MagickFalse;
11515 mng_info->ping_exclude_zCCP=MagickFalse;
11516 mng_info->ping_exclude_zTXt=MagickFalse;
11519 if (LocaleNCompare(value+i,"bkgd",4) == 0)
11520 mng_info->ping_exclude_bKGD=MagickTrue;
11522 if (LocaleNCompare(value+i,"chrm",4) == 0)
11523 mng_info->ping_exclude_cHRM=MagickTrue;
11525 if (LocaleNCompare(value+i,"date",4) == 0)
11526 mng_info->ping_exclude_date=MagickTrue;
11528 if (LocaleNCompare(value+i,"exif",4) == 0)
11529 mng_info->ping_exclude_EXIF=MagickTrue;
11531 if (LocaleNCompare(value+i,"gama",4) == 0)
11532 mng_info->ping_exclude_gAMA=MagickTrue;
11534 if (LocaleNCompare(value+i,"iccp",4) == 0)
11535 mng_info->ping_exclude_iCCP=MagickTrue;
11538 if (LocaleNCompare(value+i,"itxt",4) == 0)
11539 mng_info->ping_exclude_iTXt=MagickTrue;
11542 if (LocaleNCompare(value+i,"gama",4) == 0)
11543 mng_info->ping_exclude_gAMA=MagickTrue;
11545 if (LocaleNCompare(value+i,"offs",4) == 0)
11546 mng_info->ping_exclude_oFFs=MagickTrue;
11548 if (LocaleNCompare(value+i,"phys",4) == 0)
11549 mng_info->ping_exclude_pHYs=MagickTrue;
11551 if (LocaleNCompare(value+i,"srgb",4) == 0)
11552 mng_info->ping_exclude_sRGB=MagickTrue;
11554 if (LocaleNCompare(value+i,"text",4) == 0)
11555 mng_info->ping_exclude_tEXt=MagickTrue;
11557 if (LocaleNCompare(value+i,"trns",4) == 0)
11558 mng_info->ping_exclude_tRNS=MagickTrue;
11560 if (LocaleNCompare(value+i,"vpag",4) == 0)
11561 mng_info->ping_exclude_vpAg=MagickTrue;
11563 if (LocaleNCompare(value+i,"zccp",4) == 0)
11564 mng_info->ping_exclude_zCCP=MagickTrue;
11566 if (LocaleNCompare(value+i,"ztxt",4) == 0)
11567 mng_info->ping_exclude_zTXt=MagickTrue;
11573 for (source=0; source<1; source++)
11577 value=GetImageArtifact(image,"png:include-chunk");
11580 value=GetImageArtifact(image,"png:include-chunks");
11584 value=GetImageOption(image_info,"png:include-chunk");
11587 value=GetImageOption(image_info,"png:include-chunks");
11595 excluding=MagickTrue;
11597 if (logging != MagickFalse)
11600 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11601 " png:include-chunk=%s found in image artifacts.\n", value);
11603 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11604 " png:include-chunk=%s found in image properties.\n", value);
11607 last=strlen(value);
11609 for (i=0; i<(int) last; i+=5)
11611 if (LocaleNCompare(value+i,"all",3) == 0)
11613 mng_info->ping_exclude_bKGD=MagickFalse;
11614 mng_info->ping_exclude_cHRM=MagickFalse;
11615 mng_info->ping_exclude_date=MagickFalse;
11616 mng_info->ping_exclude_EXIF=MagickFalse;
11617 mng_info->ping_exclude_gAMA=MagickFalse;
11618 mng_info->ping_exclude_iCCP=MagickFalse;
11619 /* mng_info->ping_exclude_iTXt=MagickFalse; */
11620 mng_info->ping_exclude_oFFs=MagickFalse;
11621 mng_info->ping_exclude_pHYs=MagickFalse;
11622 mng_info->ping_exclude_sRGB=MagickFalse;
11623 mng_info->ping_exclude_tEXt=MagickFalse;
11624 mng_info->ping_exclude_tRNS=MagickFalse;
11625 mng_info->ping_exclude_vpAg=MagickFalse;
11626 mng_info->ping_exclude_zCCP=MagickFalse;
11627 mng_info->ping_exclude_zTXt=MagickFalse;
11631 if (LocaleNCompare(value+i,"none",4) == 0)
11633 mng_info->ping_exclude_bKGD=MagickTrue;
11634 mng_info->ping_exclude_cHRM=MagickTrue;
11635 mng_info->ping_exclude_date=MagickTrue;
11636 mng_info->ping_exclude_EXIF=MagickTrue;
11637 mng_info->ping_exclude_gAMA=MagickTrue;
11638 mng_info->ping_exclude_iCCP=MagickTrue;
11639 /* mng_info->ping_exclude_iTXt=MagickTrue; */
11640 mng_info->ping_exclude_oFFs=MagickTrue;
11641 mng_info->ping_exclude_pHYs=MagickTrue;
11642 mng_info->ping_exclude_sRGB=MagickTrue;
11643 mng_info->ping_exclude_tEXt=MagickTrue;
11644 mng_info->ping_exclude_tRNS=MagickTrue;
11645 mng_info->ping_exclude_vpAg=MagickTrue;
11646 mng_info->ping_exclude_zCCP=MagickTrue;
11647 mng_info->ping_exclude_zTXt=MagickTrue;
11650 if (LocaleNCompare(value+i,"bkgd",4) == 0)
11651 mng_info->ping_exclude_bKGD=MagickFalse;
11653 if (LocaleNCompare(value+i,"chrm",4) == 0)
11654 mng_info->ping_exclude_cHRM=MagickFalse;
11656 if (LocaleNCompare(value+i,"date",4) == 0)
11657 mng_info->ping_exclude_date=MagickFalse;
11659 if (LocaleNCompare(value+i,"exif",4) == 0)
11660 mng_info->ping_exclude_EXIF=MagickFalse;
11662 if (LocaleNCompare(value+i,"gama",4) == 0)
11663 mng_info->ping_exclude_gAMA=MagickFalse;
11665 if (LocaleNCompare(value+i,"iccp",4) == 0)
11666 mng_info->ping_exclude_iCCP=MagickFalse;
11669 if (LocaleNCompare(value+i,"itxt",4) == 0)
11670 mng_info->ping_exclude_iTXt=MagickFalse;
11673 if (LocaleNCompare(value+i,"gama",4) == 0)
11674 mng_info->ping_exclude_gAMA=MagickFalse;
11676 if (LocaleNCompare(value+i,"offs",4) == 0)
11677 mng_info->ping_exclude_oFFs=MagickFalse;
11679 if (LocaleNCompare(value+i,"phys",4) == 0)
11680 mng_info->ping_exclude_pHYs=MagickFalse;
11682 if (LocaleNCompare(value+i,"srgb",4) == 0)
11683 mng_info->ping_exclude_sRGB=MagickFalse;
11685 if (LocaleNCompare(value+i,"text",4) == 0)
11686 mng_info->ping_exclude_tEXt=MagickFalse;
11688 if (LocaleNCompare(value+i,"trns",4) == 0)
11689 mng_info->ping_exclude_tRNS=MagickFalse;
11691 if (LocaleNCompare(value+i,"vpag",4) == 0)
11692 mng_info->ping_exclude_vpAg=MagickFalse;
11694 if (LocaleNCompare(value+i,"zccp",4) == 0)
11695 mng_info->ping_exclude_zCCP=MagickFalse;
11697 if (LocaleNCompare(value+i,"ztxt",4) == 0)
11698 mng_info->ping_exclude_zTXt=MagickFalse;
11704 if (excluding != MagickFalse && logging != MagickFalse)
11706 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11707 " Chunks to be excluded from the output png:");
11708 if (mng_info->ping_exclude_bKGD != MagickFalse)
11709 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11711 if (mng_info->ping_exclude_cHRM != MagickFalse)
11712 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11714 if (mng_info->ping_exclude_date != MagickFalse)
11715 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11717 if (mng_info->ping_exclude_EXIF != MagickFalse)
11718 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11720 if (mng_info->ping_exclude_gAMA != MagickFalse)
11721 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11723 if (mng_info->ping_exclude_iCCP != MagickFalse)
11724 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11727 if (mng_info->ping_exclude_iTXt != MagickFalse)
11728 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11731 if (mng_info->ping_exclude_oFFs != MagickFalse)
11732 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11734 if (mng_info->ping_exclude_pHYs != MagickFalse)
11735 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11737 if (mng_info->ping_exclude_sRGB != MagickFalse)
11738 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11740 if (mng_info->ping_exclude_tEXt != MagickFalse)
11741 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11743 if (mng_info->ping_exclude_tRNS != MagickFalse)
11744 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11746 if (mng_info->ping_exclude_vpAg != MagickFalse)
11747 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11749 if (mng_info->ping_exclude_zCCP != MagickFalse)
11750 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11752 if (mng_info->ping_exclude_zTXt != MagickFalse)
11753 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11757 mng_info->need_blob = MagickTrue;
11759 status=WriteOnePNGImage(mng_info,image_info,image,exception);
11761 MngInfoFreeStruct(mng_info,&have_mng_structure);
11763 if (logging != MagickFalse)
11764 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit WritePNGImage()");
11769 #if defined(JNG_SUPPORTED)
11771 /* Write one JNG image */
11772 static MagickBooleanType WriteOneJNGImage(MngInfo *mng_info,
11773 const ImageInfo *image_info,Image *image,ExceptionInfo *exception)
11794 jng_alpha_compression_method,
11795 jng_alpha_sample_depth,
11803 logging=LogMagickEvent(CoderEvent,GetMagickModule(),
11804 " Enter WriteOneJNGImage()");
11806 blob=(unsigned char *) NULL;
11807 jpeg_image=(Image *) NULL;
11808 jpeg_image_info=(ImageInfo *) NULL;
11811 transparent=image_info->type==GrayscaleMatteType ||
11812 image_info->type==TrueColorMatteType || image->alpha_trait == BlendPixelTrait;
11814 jng_quality=image_info->quality == 0UL ? 75UL : image_info->quality%1000;
11816 jng_alpha_compression_method=image->compression==JPEGCompression? 8 : 0;
11818 jng_alpha_quality=image_info->quality == 0UL ? 75UL :
11819 image_info->quality;
11821 if (jng_alpha_quality >= 1000)
11822 jng_alpha_quality /= 1000;
11828 /* Create JPEG blob, image, and image_info */
11829 if (logging != MagickFalse)
11830 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11831 " Creating jpeg_image_info for alpha.");
11833 jpeg_image_info=(ImageInfo *) CloneImageInfo(image_info);
11835 if (jpeg_image_info == (ImageInfo *) NULL)
11836 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
11838 if (logging != MagickFalse)
11839 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11840 " Creating jpeg_image.");
11842 jpeg_image=SeparateImage(image,AlphaChannel,exception);
11843 if (jpeg_image == (Image *) NULL)
11844 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
11845 (void) CopyMagickString(jpeg_image->magick,"JPEG",MaxTextExtent);
11846 jpeg_image->alpha_trait=UndefinedPixelTrait;
11847 jpeg_image->quality=jng_alpha_quality;
11848 jpeg_image_info->type=GrayscaleType;
11849 (void) SetImageType(jpeg_image,GrayscaleType,exception);
11850 (void) AcquireUniqueFilename(jpeg_image->filename);
11851 (void) FormatLocaleString(jpeg_image_info->filename,MaxTextExtent,
11852 "%s",jpeg_image->filename);
11856 jng_alpha_compression_method=0;
11858 jng_alpha_sample_depth=0;
11861 /* To do: check bit depth of PNG alpha channel */
11863 /* Check if image is grayscale. */
11864 if (image_info->type != TrueColorMatteType && image_info->type !=
11865 TrueColorType && IsImageGray(image,exception))
11868 if (logging != MagickFalse)
11870 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11871 " JNG Quality = %d",(int) jng_quality);
11872 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11873 " JNG Color Type = %d",jng_color_type);
11876 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11877 " JNG Alpha Compression = %d",jng_alpha_compression_method);
11878 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11879 " JNG Alpha Depth = %d",jng_alpha_sample_depth);
11880 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11881 " JNG Alpha Quality = %d",(int) jng_alpha_quality);
11887 if (jng_alpha_compression_method==0)
11892 /* Encode alpha as a grayscale PNG blob */
11893 status=OpenBlob(jpeg_image_info,jpeg_image,WriteBinaryBlobMode,
11895 if (logging != MagickFalse)
11896 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11897 " Creating PNG blob.");
11900 (void) CopyMagickString(jpeg_image_info->magick,"PNG",MaxTextExtent);
11901 (void) CopyMagickString(jpeg_image->magick,"PNG",MaxTextExtent);
11902 jpeg_image_info->interlace=NoInterlace;
11904 /* Exclude all ancillary chunks */
11905 (void) SetImageArtifact(jpeg_image,"png:exclude-chunks","all");
11907 blob=ImageToBlob(jpeg_image_info,jpeg_image,&length,
11910 /* Retrieve sample depth used */
11911 value=GetImageProperty(jpeg_image,"png:bit-depth-written",exception);
11912 if (value != (char *) NULL)
11913 jng_alpha_sample_depth= (unsigned int) value[0];
11917 /* Encode alpha as a grayscale JPEG blob */
11919 status=OpenBlob(jpeg_image_info,jpeg_image,WriteBinaryBlobMode,
11922 (void) CopyMagickString(jpeg_image_info->magick,"JPEG",MaxTextExtent);
11923 (void) CopyMagickString(jpeg_image->magick,"JPEG",MaxTextExtent);
11924 jpeg_image_info->interlace=NoInterlace;
11925 if (logging != MagickFalse)
11926 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11927 " Creating blob.");
11928 blob=ImageToBlob(jpeg_image_info,jpeg_image,&length,
11930 jng_alpha_sample_depth=8;
11932 if (logging != MagickFalse)
11933 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11934 " Successfully read jpeg_image into a blob, length=%.20g.",
11938 /* Destroy JPEG image and image_info */
11939 jpeg_image=DestroyImage(jpeg_image);
11940 (void) RelinquishUniqueFileResource(jpeg_image_info->filename);
11941 jpeg_image_info=DestroyImageInfo(jpeg_image_info);
11944 /* Write JHDR chunk */
11945 (void) WriteBlobMSBULong(image,16L); /* chunk data length=16 */
11946 PNGType(chunk,mng_JHDR);
11947 LogPNGChunk(logging,mng_JHDR,16L);
11948 PNGLong(chunk+4,(png_uint_32) image->columns);
11949 PNGLong(chunk+8,(png_uint_32) image->rows);
11950 chunk[12]=jng_color_type;
11951 chunk[13]=8; /* sample depth */
11952 chunk[14]=8; /*jng_image_compression_method */
11953 chunk[15]=(unsigned char) (image_info->interlace == NoInterlace ? 0 : 8);
11954 chunk[16]=jng_alpha_sample_depth;
11955 chunk[17]=jng_alpha_compression_method;
11956 chunk[18]=0; /*jng_alpha_filter_method */
11957 chunk[19]=0; /*jng_alpha_interlace_method */
11958 (void) WriteBlob(image,20,chunk);
11959 (void) WriteBlobMSBULong(image,crc32(0,chunk,20));
11960 if (logging != MagickFalse)
11962 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11963 " JNG width:%15lu",(unsigned long) image->columns);
11965 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11966 " JNG height:%14lu",(unsigned long) image->rows);
11968 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11969 " JNG color type:%10d",jng_color_type);
11971 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11972 " JNG sample depth:%8d",8);
11974 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11975 " JNG compression:%9d",8);
11977 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11978 " JNG interlace:%11d",0);
11980 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11981 " JNG alpha depth:%9d",jng_alpha_sample_depth);
11983 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11984 " JNG alpha compression:%3d",jng_alpha_compression_method);
11986 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11987 " JNG alpha filter:%8d",0);
11989 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11990 " JNG alpha interlace:%5d",0);
11993 /* Write any JNG-chunk-b profiles */
11994 (void) Magick_png_write_chunk_from_profile(image,"JNG-chunk-b",logging);
11997 Write leading ancillary chunks
12003 Write JNG bKGD chunk
12014 if (jng_color_type == 8 || jng_color_type == 12)
12018 (void) WriteBlobMSBULong(image,(size_t) (num_bytes-4L));
12019 PNGType(chunk,mng_bKGD);
12020 LogPNGChunk(logging,mng_bKGD,(size_t) (num_bytes-4L));
12021 red=ScaleQuantumToChar(image->background_color.red);
12022 green=ScaleQuantumToChar(image->background_color.green);
12023 blue=ScaleQuantumToChar(image->background_color.blue);
12030 (void) WriteBlob(image,(size_t) num_bytes,chunk);
12031 (void) WriteBlobMSBULong(image,crc32(0,chunk,(uInt) num_bytes));
12034 if ((image->colorspace == sRGBColorspace || image->rendering_intent))
12037 Write JNG sRGB chunk
12039 (void) WriteBlobMSBULong(image,1L);
12040 PNGType(chunk,mng_sRGB);
12041 LogPNGChunk(logging,mng_sRGB,1L);
12043 if (image->rendering_intent != UndefinedIntent)
12044 chunk[4]=(unsigned char)
12045 Magick_RenderingIntent_to_PNG_RenderingIntent(
12046 (image->rendering_intent));
12049 chunk[4]=(unsigned char)
12050 Magick_RenderingIntent_to_PNG_RenderingIntent(
12051 (PerceptualIntent));
12053 (void) WriteBlob(image,5,chunk);
12054 (void) WriteBlobMSBULong(image,crc32(0,chunk,5));
12058 if (image->gamma != 0.0)
12061 Write JNG gAMA chunk
12063 (void) WriteBlobMSBULong(image,4L);
12064 PNGType(chunk,mng_gAMA);
12065 LogPNGChunk(logging,mng_gAMA,4L);
12066 PNGLong(chunk+4,(png_uint_32) (100000*image->gamma+0.5));
12067 (void) WriteBlob(image,8,chunk);
12068 (void) WriteBlobMSBULong(image,crc32(0,chunk,8));
12071 if ((mng_info->equal_chrms == MagickFalse) &&
12072 (image->chromaticity.red_primary.x != 0.0))
12078 Write JNG cHRM chunk
12080 (void) WriteBlobMSBULong(image,32L);
12081 PNGType(chunk,mng_cHRM);
12082 LogPNGChunk(logging,mng_cHRM,32L);
12083 primary=image->chromaticity.white_point;
12084 PNGLong(chunk+4,(png_uint_32) (100000*primary.x+0.5));
12085 PNGLong(chunk+8,(png_uint_32) (100000*primary.y+0.5));
12086 primary=image->chromaticity.red_primary;
12087 PNGLong(chunk+12,(png_uint_32) (100000*primary.x+0.5));
12088 PNGLong(chunk+16,(png_uint_32) (100000*primary.y+0.5));
12089 primary=image->chromaticity.green_primary;
12090 PNGLong(chunk+20,(png_uint_32) (100000*primary.x+0.5));
12091 PNGLong(chunk+24,(png_uint_32) (100000*primary.y+0.5));
12092 primary=image->chromaticity.blue_primary;
12093 PNGLong(chunk+28,(png_uint_32) (100000*primary.x+0.5));
12094 PNGLong(chunk+32,(png_uint_32) (100000*primary.y+0.5));
12095 (void) WriteBlob(image,36,chunk);
12096 (void) WriteBlobMSBULong(image,crc32(0,chunk,36));
12100 if (image->resolution.x && image->resolution.y && !mng_info->equal_physs)
12103 Write JNG pHYs chunk
12105 (void) WriteBlobMSBULong(image,9L);
12106 PNGType(chunk,mng_pHYs);
12107 LogPNGChunk(logging,mng_pHYs,9L);
12108 if (image->units == PixelsPerInchResolution)
12110 PNGLong(chunk+4,(png_uint_32)
12111 (image->resolution.x*100.0/2.54+0.5));
12113 PNGLong(chunk+8,(png_uint_32)
12114 (image->resolution.y*100.0/2.54+0.5));
12121 if (image->units == PixelsPerCentimeterResolution)
12123 PNGLong(chunk+4,(png_uint_32)
12124 (image->resolution.x*100.0+0.5));
12126 PNGLong(chunk+8,(png_uint_32)
12127 (image->resolution.y*100.0+0.5));
12134 PNGLong(chunk+4,(png_uint_32) (image->resolution.x+0.5));
12135 PNGLong(chunk+8,(png_uint_32) (image->resolution.y+0.5));
12139 (void) WriteBlob(image,13,chunk);
12140 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
12143 if (mng_info->write_mng == 0 && (image->page.x || image->page.y))
12146 Write JNG oFFs chunk
12148 (void) WriteBlobMSBULong(image,9L);
12149 PNGType(chunk,mng_oFFs);
12150 LogPNGChunk(logging,mng_oFFs,9L);
12151 PNGsLong(chunk+4,(ssize_t) (image->page.x));
12152 PNGsLong(chunk+8,(ssize_t) (image->page.y));
12154 (void) WriteBlob(image,13,chunk);
12155 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
12157 if (mng_info->write_mng == 0 && (image->page.width || image->page.height))
12159 (void) WriteBlobMSBULong(image,9L); /* data length=8 */
12160 PNGType(chunk,mng_vpAg);
12161 LogPNGChunk(logging,mng_vpAg,9L);
12162 PNGLong(chunk+4,(png_uint_32) image->page.width);
12163 PNGLong(chunk+8,(png_uint_32) image->page.height);
12164 chunk[12]=0; /* unit = pixels */
12165 (void) WriteBlob(image,13,chunk);
12166 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
12172 if (jng_alpha_compression_method==0)
12180 /* Write IDAT chunk header */
12181 if (logging != MagickFalse)
12182 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12183 " Write IDAT chunks from blob, length=%.20g.",(double)
12186 /* Copy IDAT chunks */
12189 for (i=8; i<(ssize_t) length; i+=len+12)
12191 len=(*p<<24)|((*(p+1))<<16)|((*(p+2))<<8)|(*(p+3));
12194 if (*(p)==73 && *(p+1)==68 && *(p+2)==65 && *(p+3)==84) /* IDAT */
12196 /* Found an IDAT chunk. */
12197 (void) WriteBlobMSBULong(image,(size_t) len);
12198 LogPNGChunk(logging,mng_IDAT,(size_t) len);
12199 (void) WriteBlob(image,(size_t) len+4,p);
12200 (void) WriteBlobMSBULong(image,
12201 crc32(0,p,(uInt) len+4));
12206 if (logging != MagickFalse)
12207 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12208 " Skipping %c%c%c%c chunk, length=%.20g.",
12209 *(p),*(p+1),*(p+2),*(p+3),(double) len);
12216 /* Write JDAA chunk header */
12217 if (logging != MagickFalse)
12218 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12219 " Write JDAA chunk, length=%.20g.",(double) length);
12220 (void) WriteBlobMSBULong(image,(size_t) length);
12221 PNGType(chunk,mng_JDAA);
12222 LogPNGChunk(logging,mng_JDAA,length);
12223 /* Write JDAT chunk(s) data */
12224 (void) WriteBlob(image,4,chunk);
12225 (void) WriteBlob(image,length,blob);
12226 (void) WriteBlobMSBULong(image,crc32(crc32(0,chunk,4),blob,
12229 blob=(unsigned char *) RelinquishMagickMemory(blob);
12232 /* Encode image as a JPEG blob */
12233 if (logging != MagickFalse)
12234 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12235 " Creating jpeg_image_info.");
12236 jpeg_image_info=(ImageInfo *) CloneImageInfo(image_info);
12237 if (jpeg_image_info == (ImageInfo *) NULL)
12238 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
12240 if (logging != MagickFalse)
12241 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12242 " Creating jpeg_image.");
12244 jpeg_image=CloneImage(image,0,0,MagickTrue,exception);
12245 if (jpeg_image == (Image *) NULL)
12246 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
12247 (void) CopyMagickString(jpeg_image->magick,"JPEG",MaxTextExtent);
12249 (void) AcquireUniqueFilename(jpeg_image->filename);
12250 (void) FormatLocaleString(jpeg_image_info->filename,MaxTextExtent,"%s",
12251 jpeg_image->filename);
12253 status=OpenBlob(jpeg_image_info,jpeg_image,WriteBinaryBlobMode,
12256 if (logging != MagickFalse)
12257 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12258 " Created jpeg_image, %.20g x %.20g.",(double) jpeg_image->columns,
12259 (double) jpeg_image->rows);
12261 if (jng_color_type == 8 || jng_color_type == 12)
12262 jpeg_image_info->type=GrayscaleType;
12264 jpeg_image_info->quality=jng_quality;
12265 jpeg_image->quality=jng_quality;
12266 (void) CopyMagickString(jpeg_image_info->magick,"JPEG",MaxTextExtent);
12267 (void) CopyMagickString(jpeg_image->magick,"JPEG",MaxTextExtent);
12269 if (logging != MagickFalse)
12270 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12271 " Creating blob.");
12273 blob=ImageToBlob(jpeg_image_info,jpeg_image,&length,exception);
12275 if (logging != MagickFalse)
12277 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12278 " Successfully read jpeg_image into a blob, length=%.20g.",
12281 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12282 " Write JDAT chunk, length=%.20g.",(double) length);
12285 /* Write JDAT chunk(s) */
12286 (void) WriteBlobMSBULong(image,(size_t) length);
12287 PNGType(chunk,mng_JDAT);
12288 LogPNGChunk(logging,mng_JDAT,length);
12289 (void) WriteBlob(image,4,chunk);
12290 (void) WriteBlob(image,length,blob);
12291 (void) WriteBlobMSBULong(image,crc32(crc32(0,chunk,4),blob,(uInt) length));
12293 jpeg_image=DestroyImage(jpeg_image);
12294 (void) RelinquishUniqueFileResource(jpeg_image_info->filename);
12295 jpeg_image_info=DestroyImageInfo(jpeg_image_info);
12296 blob=(unsigned char *) RelinquishMagickMemory(blob);
12298 /* Write any JNG-chunk-e profiles */
12299 (void) Magick_png_write_chunk_from_profile(image,"JNG-chunk-e",logging);
12301 /* Write IEND chunk */
12302 (void) WriteBlobMSBULong(image,0L);
12303 PNGType(chunk,mng_IEND);
12304 LogPNGChunk(logging,mng_IEND,0);
12305 (void) WriteBlob(image,4,chunk);
12306 (void) WriteBlobMSBULong(image,crc32(0,chunk,4));
12308 if (logging != MagickFalse)
12309 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12310 " exit WriteOneJNGImage()");
12317 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12321 % W r i t e J N G I m a g e %
12325 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12327 % WriteJNGImage() writes a JPEG Network Graphics (JNG) image file.
12329 % JNG support written by Glenn Randers-Pehrson, glennrp@image...
12331 % The format of the WriteJNGImage method is:
12333 % MagickBooleanType WriteJNGImage(const ImageInfo *image_info,
12334 % Image *image,ExceptionInfo *exception)
12336 % A description of each parameter follows:
12338 % o image_info: the image info.
12340 % o image: The image.
12342 % o exception: return any errors or warnings in this structure.
12344 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12346 static MagickBooleanType WriteJNGImage(const ImageInfo *image_info,Image *image,
12347 ExceptionInfo *exception)
12350 have_mng_structure,
12360 assert(image_info != (const ImageInfo *) NULL);
12361 assert(image_info->signature == MagickSignature);
12362 assert(image != (Image *) NULL);
12363 assert(image->signature == MagickSignature);
12364 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
12365 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter WriteJNGImage()");
12366 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
12367 if (status == MagickFalse)
12371 Allocate a MngInfo structure.
12373 have_mng_structure=MagickFalse;
12374 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
12375 if (mng_info == (MngInfo *) NULL)
12376 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
12378 Initialize members of the MngInfo structure.
12380 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
12381 mng_info->image=image;
12382 have_mng_structure=MagickTrue;
12384 (void) WriteBlob(image,8,(const unsigned char *) "\213JNG\r\n\032\n");
12386 status=WriteOneJNGImage(mng_info,image_info,image,exception);
12387 (void) CloseBlob(image);
12389 (void) CatchImageException(image);
12390 MngInfoFreeStruct(mng_info,&have_mng_structure);
12391 if (logging != MagickFalse)
12392 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit WriteJNGImage()");
12397 static MagickBooleanType WriteMNGImage(const ImageInfo *image_info,Image *image,
12398 ExceptionInfo *exception)
12407 have_mng_structure,
12410 volatile MagickBooleanType
12422 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
12423 defined(PNG_MNG_FEATURES_SUPPORTED)
12426 all_images_are_gray,
12436 volatile unsigned int
12447 #if (PNG_LIBPNG_VER < 10200)
12448 if (image_info->verbose)
12449 printf("Your PNG library (libpng-%s) is rather old.\n",
12450 PNG_LIBPNG_VER_STRING);
12456 assert(image_info != (const ImageInfo *) NULL);
12457 assert(image_info->signature == MagickSignature);
12458 assert(image != (Image *) NULL);
12459 assert(image->signature == MagickSignature);
12460 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
12461 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter WriteMNGImage()");
12462 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
12463 if (status == MagickFalse)
12467 Allocate a MngInfo structure.
12469 have_mng_structure=MagickFalse;
12470 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
12471 if (mng_info == (MngInfo *) NULL)
12472 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
12474 Initialize members of the MngInfo structure.
12476 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
12477 mng_info->image=image;
12478 have_mng_structure=MagickTrue;
12479 write_mng=LocaleCompare(image_info->magick,"MNG") == 0;
12482 * See if user has requested a specific PNG subformat to be used
12483 * for all of the PNGs in the MNG being written, e.g.,
12485 * convert *.png png8:animation.mng
12487 * To do: check -define png:bit_depth and png:color_type as well,
12488 * or perhaps use mng:bit_depth and mng:color_type instead for
12492 mng_info->write_png8=LocaleCompare(image_info->magick,"PNG8") == 0;
12493 mng_info->write_png24=LocaleCompare(image_info->magick,"PNG24") == 0;
12494 mng_info->write_png32=LocaleCompare(image_info->magick,"PNG32") == 0;
12496 write_jng=MagickFalse;
12497 if (image_info->compression == JPEGCompression)
12498 write_jng=MagickTrue;
12500 mng_info->adjoin=image_info->adjoin &&
12501 (GetNextImageInList(image) != (Image *) NULL) && write_mng;
12503 if (logging != MagickFalse)
12505 /* Log some info about the input */
12509 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12510 " Checking input image(s)");
12512 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12513 " Image_info depth: %.20g",(double) image_info->depth);
12515 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12516 " Type: %d",image_info->type);
12519 for (p=image; p != (Image *) NULL; p=GetNextImageInList(p))
12521 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12522 " Scene: %.20g",(double) scene++);
12524 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12525 " Image depth: %.20g",(double) p->depth);
12527 if (p->alpha_trait)
12528 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12532 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12535 if (p->storage_class == PseudoClass)
12536 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12537 " Storage class: PseudoClass");
12540 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12541 " Storage class: DirectClass");
12544 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12545 " Number of colors: %.20g",(double) p->colors);
12548 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12549 " Number of colors: unspecified");
12551 if (mng_info->adjoin == MagickFalse)
12556 use_global_plte=MagickFalse;
12557 all_images_are_gray=MagickFalse;
12558 #ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
12559 need_local_plte=MagickTrue;
12561 need_defi=MagickFalse;
12562 need_matte=MagickFalse;
12563 mng_info->framing_mode=1;
12564 mng_info->old_framing_mode=1;
12567 if (image_info->page != (char *) NULL)
12570 Determine image bounding box.
12572 SetGeometry(image,&mng_info->page);
12573 (void) ParseMetaGeometry(image_info->page,&mng_info->page.x,
12574 &mng_info->page.y,&mng_info->page.width,&mng_info->page.height);
12586 mng_info->page=image->page;
12587 need_geom=MagickTrue;
12588 if (mng_info->page.width || mng_info->page.height)
12589 need_geom=MagickFalse;
12591 Check all the scenes.
12593 initial_delay=image->delay;
12594 need_iterations=MagickFalse;
12595 mng_info->equal_chrms=image->chromaticity.red_primary.x != 0.0;
12596 mng_info->equal_physs=MagickTrue,
12597 mng_info->equal_gammas=MagickTrue;
12598 mng_info->equal_srgbs=MagickTrue;
12599 mng_info->equal_backgrounds=MagickTrue;
12601 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
12602 defined(PNG_MNG_FEATURES_SUPPORTED)
12603 all_images_are_gray=MagickTrue;
12604 mng_info->equal_palettes=MagickFalse;
12605 need_local_plte=MagickFalse;
12607 for (next_image=image; next_image != (Image *) NULL; )
12611 if ((next_image->columns+next_image->page.x) > mng_info->page.width)
12612 mng_info->page.width=next_image->columns+next_image->page.x;
12614 if ((next_image->rows+next_image->page.y) > mng_info->page.height)
12615 mng_info->page.height=next_image->rows+next_image->page.y;
12618 if (next_image->page.x || next_image->page.y)
12619 need_defi=MagickTrue;
12621 if (next_image->alpha_trait)
12622 need_matte=MagickTrue;
12624 if ((int) next_image->dispose >= BackgroundDispose)
12625 if (next_image->alpha_trait || next_image->page.x || next_image->page.y ||
12626 ((next_image->columns < mng_info->page.width) &&
12627 (next_image->rows < mng_info->page.height)))
12628 mng_info->need_fram=MagickTrue;
12630 if (next_image->iterations)
12631 need_iterations=MagickTrue;
12633 final_delay=next_image->delay;
12635 if (final_delay != initial_delay || final_delay > 1UL*
12636 next_image->ticks_per_second)
12637 mng_info->need_fram=1;
12639 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
12640 defined(PNG_MNG_FEATURES_SUPPORTED)
12642 check for global palette possibility.
12644 if (image->alpha_trait == BlendPixelTrait)
12645 need_local_plte=MagickTrue;
12647 if (need_local_plte == 0)
12649 if (IsImageGray(image,exception) == MagickFalse)
12650 all_images_are_gray=MagickFalse;
12651 mng_info->equal_palettes=PalettesAreEqual(image,next_image);
12652 if (use_global_plte == 0)
12653 use_global_plte=mng_info->equal_palettes;
12654 need_local_plte=!mng_info->equal_palettes;
12657 if (GetNextImageInList(next_image) != (Image *) NULL)
12659 if (next_image->background_color.red !=
12660 next_image->next->background_color.red ||
12661 next_image->background_color.green !=
12662 next_image->next->background_color.green ||
12663 next_image->background_color.blue !=
12664 next_image->next->background_color.blue)
12665 mng_info->equal_backgrounds=MagickFalse;
12667 if (next_image->gamma != next_image->next->gamma)
12668 mng_info->equal_gammas=MagickFalse;
12670 if (next_image->rendering_intent !=
12671 next_image->next->rendering_intent)
12672 mng_info->equal_srgbs=MagickFalse;
12674 if ((next_image->units != next_image->next->units) ||
12675 (next_image->resolution.x != next_image->next->resolution.x) ||
12676 (next_image->resolution.y != next_image->next->resolution.y))
12677 mng_info->equal_physs=MagickFalse;
12679 if (mng_info->equal_chrms)
12681 if (next_image->chromaticity.red_primary.x !=
12682 next_image->next->chromaticity.red_primary.x ||
12683 next_image->chromaticity.red_primary.y !=
12684 next_image->next->chromaticity.red_primary.y ||
12685 next_image->chromaticity.green_primary.x !=
12686 next_image->next->chromaticity.green_primary.x ||
12687 next_image->chromaticity.green_primary.y !=
12688 next_image->next->chromaticity.green_primary.y ||
12689 next_image->chromaticity.blue_primary.x !=
12690 next_image->next->chromaticity.blue_primary.x ||
12691 next_image->chromaticity.blue_primary.y !=
12692 next_image->next->chromaticity.blue_primary.y ||
12693 next_image->chromaticity.white_point.x !=
12694 next_image->next->chromaticity.white_point.x ||
12695 next_image->chromaticity.white_point.y !=
12696 next_image->next->chromaticity.white_point.y)
12697 mng_info->equal_chrms=MagickFalse;
12701 next_image=GetNextImageInList(next_image);
12703 if (image_count < 2)
12705 mng_info->equal_backgrounds=MagickFalse;
12706 mng_info->equal_chrms=MagickFalse;
12707 mng_info->equal_gammas=MagickFalse;
12708 mng_info->equal_srgbs=MagickFalse;
12709 mng_info->equal_physs=MagickFalse;
12710 use_global_plte=MagickFalse;
12711 #ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
12712 need_local_plte=MagickTrue;
12714 need_iterations=MagickFalse;
12717 if (mng_info->need_fram == MagickFalse)
12720 Only certain framing rates 100/n are exactly representable without
12721 the FRAM chunk but we'll allow some slop in VLC files
12723 if (final_delay == 0)
12725 if (need_iterations != MagickFalse)
12728 It's probably a GIF with loop; don't run it *too* fast.
12730 if (mng_info->adjoin)
12733 (void) ThrowMagickException(exception,GetMagickModule(),
12735 "input has zero delay between all frames; assuming",
12740 mng_info->ticks_per_second=0;
12742 if (final_delay != 0)
12743 mng_info->ticks_per_second=(png_uint_32)
12744 (image->ticks_per_second/final_delay);
12745 if (final_delay > 50)
12746 mng_info->ticks_per_second=2;
12748 if (final_delay > 75)
12749 mng_info->ticks_per_second=1;
12751 if (final_delay > 125)
12752 mng_info->need_fram=MagickTrue;
12754 if (need_defi && final_delay > 2 && (final_delay != 4) &&
12755 (final_delay != 5) && (final_delay != 10) && (final_delay != 20) &&
12756 (final_delay != 25) && (final_delay != 50) && (final_delay !=
12757 1UL*image->ticks_per_second))
12758 mng_info->need_fram=MagickTrue; /* make it exact; cannot be VLC */
12761 if (mng_info->need_fram != MagickFalse)
12762 mng_info->ticks_per_second=1UL*image->ticks_per_second;
12764 If pseudocolor, we should also check to see if all the
12765 palettes are identical and write a global PLTE if they are.
12769 Write the MNG version 1.0 signature and MHDR chunk.
12771 (void) WriteBlob(image,8,(const unsigned char *) "\212MNG\r\n\032\n");
12772 (void) WriteBlobMSBULong(image,28L); /* chunk data length=28 */
12773 PNGType(chunk,mng_MHDR);
12774 LogPNGChunk(logging,mng_MHDR,28L);
12775 PNGLong(chunk+4,(png_uint_32) mng_info->page.width);
12776 PNGLong(chunk+8,(png_uint_32) mng_info->page.height);
12777 PNGLong(chunk+12,mng_info->ticks_per_second);
12778 PNGLong(chunk+16,0L); /* layer count=unknown */
12779 PNGLong(chunk+20,0L); /* frame count=unknown */
12780 PNGLong(chunk+24,0L); /* play time=unknown */
12785 if (need_defi || mng_info->need_fram || use_global_plte)
12786 PNGLong(chunk+28,27L); /* simplicity=LC+JNG */
12789 PNGLong(chunk+28,25L); /* simplicity=VLC+JNG */
12794 if (need_defi || mng_info->need_fram || use_global_plte)
12795 PNGLong(chunk+28,19L); /* simplicity=LC+JNG, no transparency */
12798 PNGLong(chunk+28,17L); /* simplicity=VLC+JNG, no transparency */
12806 if (need_defi || mng_info->need_fram || use_global_plte)
12807 PNGLong(chunk+28,11L); /* simplicity=LC */
12810 PNGLong(chunk+28,9L); /* simplicity=VLC */
12815 if (need_defi || mng_info->need_fram || use_global_plte)
12816 PNGLong(chunk+28,3L); /* simplicity=LC, no transparency */
12819 PNGLong(chunk+28,1L); /* simplicity=VLC, no transparency */
12822 (void) WriteBlob(image,32,chunk);
12823 (void) WriteBlobMSBULong(image,crc32(0,chunk,32));
12824 option=GetImageOption(image_info,"mng:need-cacheoff");
12825 if (option != (const char *) NULL)
12831 Write "nEED CACHEOFF" to turn playback caching off for streaming MNG.
12833 PNGType(chunk,mng_nEED);
12834 length=CopyMagickString((char *) chunk+4,"CACHEOFF",20);
12835 (void) WriteBlobMSBULong(image,(size_t) length);
12836 LogPNGChunk(logging,mng_nEED,(size_t) length);
12838 (void) WriteBlob(image,length,chunk);
12839 (void) WriteBlobMSBULong(image,crc32(0,chunk,(uInt) length));
12841 if ((GetPreviousImageInList(image) == (Image *) NULL) &&
12842 (GetNextImageInList(image) != (Image *) NULL) &&
12843 (image->iterations != 1))
12846 Write MNG TERM chunk
12848 (void) WriteBlobMSBULong(image,10L); /* data length=10 */
12849 PNGType(chunk,mng_TERM);
12850 LogPNGChunk(logging,mng_TERM,10L);
12851 chunk[4]=3; /* repeat animation */
12852 chunk[5]=0; /* show last frame when done */
12853 PNGLong(chunk+6,(png_uint_32) (mng_info->ticks_per_second*
12854 final_delay/MagickMax(image->ticks_per_second,1)));
12856 if (image->iterations == 0)
12857 PNGLong(chunk+10,PNG_UINT_31_MAX);
12860 PNGLong(chunk+10,(png_uint_32) image->iterations);
12862 if (logging != MagickFalse)
12864 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12865 " TERM delay: %.20g",(double) (mng_info->ticks_per_second*
12866 final_delay/MagickMax(image->ticks_per_second,1)));
12868 if (image->iterations == 0)
12869 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12870 " TERM iterations: %.20g",(double) PNG_UINT_31_MAX);
12873 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12874 " Image iterations: %.20g",(double) image->iterations);
12876 (void) WriteBlob(image,14,chunk);
12877 (void) WriteBlobMSBULong(image,crc32(0,chunk,14));
12880 To do: check for cHRM+gAMA == sRGB, and write sRGB instead.
12882 if ((image->colorspace == sRGBColorspace || image->rendering_intent) &&
12883 mng_info->equal_srgbs)
12886 Write MNG sRGB chunk
12888 (void) WriteBlobMSBULong(image,1L);
12889 PNGType(chunk,mng_sRGB);
12890 LogPNGChunk(logging,mng_sRGB,1L);
12892 if (image->rendering_intent != UndefinedIntent)
12893 chunk[4]=(unsigned char)
12894 Magick_RenderingIntent_to_PNG_RenderingIntent(
12895 (image->rendering_intent));
12898 chunk[4]=(unsigned char)
12899 Magick_RenderingIntent_to_PNG_RenderingIntent(
12900 (PerceptualIntent));
12902 (void) WriteBlob(image,5,chunk);
12903 (void) WriteBlobMSBULong(image,crc32(0,chunk,5));
12904 mng_info->have_write_global_srgb=MagickTrue;
12909 if (image->gamma && mng_info->equal_gammas)
12912 Write MNG gAMA chunk
12914 (void) WriteBlobMSBULong(image,4L);
12915 PNGType(chunk,mng_gAMA);
12916 LogPNGChunk(logging,mng_gAMA,4L);
12917 PNGLong(chunk+4,(png_uint_32) (100000*image->gamma+0.5));
12918 (void) WriteBlob(image,8,chunk);
12919 (void) WriteBlobMSBULong(image,crc32(0,chunk,8));
12920 mng_info->have_write_global_gama=MagickTrue;
12922 if (mng_info->equal_chrms)
12928 Write MNG cHRM chunk
12930 (void) WriteBlobMSBULong(image,32L);
12931 PNGType(chunk,mng_cHRM);
12932 LogPNGChunk(logging,mng_cHRM,32L);
12933 primary=image->chromaticity.white_point;
12934 PNGLong(chunk+4,(png_uint_32) (100000*primary.x+0.5));
12935 PNGLong(chunk+8,(png_uint_32) (100000*primary.y+0.5));
12936 primary=image->chromaticity.red_primary;
12937 PNGLong(chunk+12,(png_uint_32) (100000*primary.x+0.5));
12938 PNGLong(chunk+16,(png_uint_32) (100000*primary.y+0.5));
12939 primary=image->chromaticity.green_primary;
12940 PNGLong(chunk+20,(png_uint_32) (100000*primary.x+0.5));
12941 PNGLong(chunk+24,(png_uint_32) (100000*primary.y+0.5));
12942 primary=image->chromaticity.blue_primary;
12943 PNGLong(chunk+28,(png_uint_32) (100000*primary.x+0.5));
12944 PNGLong(chunk+32,(png_uint_32) (100000*primary.y+0.5));
12945 (void) WriteBlob(image,36,chunk);
12946 (void) WriteBlobMSBULong(image,crc32(0,chunk,36));
12947 mng_info->have_write_global_chrm=MagickTrue;
12950 if (image->resolution.x && image->resolution.y && mng_info->equal_physs)
12953 Write MNG pHYs chunk
12955 (void) WriteBlobMSBULong(image,9L);
12956 PNGType(chunk,mng_pHYs);
12957 LogPNGChunk(logging,mng_pHYs,9L);
12959 if (image->units == PixelsPerInchResolution)
12961 PNGLong(chunk+4,(png_uint_32)
12962 (image->resolution.x*100.0/2.54+0.5));
12964 PNGLong(chunk+8,(png_uint_32)
12965 (image->resolution.y*100.0/2.54+0.5));
12972 if (image->units == PixelsPerCentimeterResolution)
12974 PNGLong(chunk+4,(png_uint_32)
12975 (image->resolution.x*100.0+0.5));
12977 PNGLong(chunk+8,(png_uint_32)
12978 (image->resolution.y*100.0+0.5));
12985 PNGLong(chunk+4,(png_uint_32) (image->resolution.x+0.5));
12986 PNGLong(chunk+8,(png_uint_32) (image->resolution.y+0.5));
12990 (void) WriteBlob(image,13,chunk);
12991 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
12994 Write MNG BACK chunk and global bKGD chunk, if the image is transparent
12995 or does not cover the entire frame.
12997 if (write_mng && (image->alpha_trait || image->page.x > 0 ||
12998 image->page.y > 0 || (image->page.width &&
12999 (image->page.width+image->page.x < mng_info->page.width))
13000 || (image->page.height && (image->page.height+image->page.y
13001 < mng_info->page.height))))
13003 (void) WriteBlobMSBULong(image,6L);
13004 PNGType(chunk,mng_BACK);
13005 LogPNGChunk(logging,mng_BACK,6L);
13006 red=ScaleQuantumToShort(image->background_color.red);
13007 green=ScaleQuantumToShort(image->background_color.green);
13008 blue=ScaleQuantumToShort(image->background_color.blue);
13009 PNGShort(chunk+4,red);
13010 PNGShort(chunk+6,green);
13011 PNGShort(chunk+8,blue);
13012 (void) WriteBlob(image,10,chunk);
13013 (void) WriteBlobMSBULong(image,crc32(0,chunk,10));
13014 if (mng_info->equal_backgrounds)
13016 (void) WriteBlobMSBULong(image,6L);
13017 PNGType(chunk,mng_bKGD);
13018 LogPNGChunk(logging,mng_bKGD,6L);
13019 (void) WriteBlob(image,10,chunk);
13020 (void) WriteBlobMSBULong(image,crc32(0,chunk,10));
13024 #ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
13025 if ((need_local_plte == MagickFalse) &&
13026 (image->storage_class == PseudoClass) &&
13027 (all_images_are_gray == MagickFalse))
13033 Write MNG PLTE chunk
13035 data_length=3*image->colors;
13036 (void) WriteBlobMSBULong(image,data_length);
13037 PNGType(chunk,mng_PLTE);
13038 LogPNGChunk(logging,mng_PLTE,data_length);
13040 for (i=0; i < (ssize_t) image->colors; i++)
13042 chunk[4+i*3]=(unsigned char) (ScaleQuantumToChar(
13043 image->colormap[i].red) & 0xff);
13044 chunk[5+i*3]=(unsigned char) (ScaleQuantumToChar(
13045 image->colormap[i].green) & 0xff);
13046 chunk[6+i*3]=(unsigned char) (ScaleQuantumToChar(
13047 image->colormap[i].blue) & 0xff);
13050 (void) WriteBlob(image,data_length+4,chunk);
13051 (void) WriteBlobMSBULong(image,crc32(0,chunk,(uInt) (data_length+4)));
13052 mng_info->have_write_global_plte=MagickTrue;
13058 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
13059 defined(PNG_MNG_FEATURES_SUPPORTED)
13060 mng_info->equal_palettes=MagickFalse;
13064 if (mng_info->adjoin)
13066 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
13067 defined(PNG_MNG_FEATURES_SUPPORTED)
13069 If we aren't using a global palette for the entire MNG, check to
13070 see if we can use one for two or more consecutive images.
13072 if (need_local_plte && use_global_plte && !all_images_are_gray)
13074 if (mng_info->IsPalette)
13077 When equal_palettes is true, this image has the same palette
13078 as the previous PseudoClass image
13080 mng_info->have_write_global_plte=mng_info->equal_palettes;
13081 mng_info->equal_palettes=PalettesAreEqual(image,image->next);
13082 if (mng_info->equal_palettes && !mng_info->have_write_global_plte)
13085 Write MNG PLTE chunk
13090 data_length=3*image->colors;
13091 (void) WriteBlobMSBULong(image,data_length);
13092 PNGType(chunk,mng_PLTE);
13093 LogPNGChunk(logging,mng_PLTE,data_length);
13095 for (i=0; i < (ssize_t) image->colors; i++)
13097 chunk[4+i*3]=ScaleQuantumToChar(image->colormap[i].red);
13098 chunk[5+i*3]=ScaleQuantumToChar(image->colormap[i].green);
13099 chunk[6+i*3]=ScaleQuantumToChar(image->colormap[i].blue);
13102 (void) WriteBlob(image,data_length+4,chunk);
13103 (void) WriteBlobMSBULong(image,crc32(0,chunk,
13104 (uInt) (data_length+4)));
13105 mng_info->have_write_global_plte=MagickTrue;
13109 mng_info->have_write_global_plte=MagickFalse;
13120 previous_x=mng_info->page.x;
13121 previous_y=mng_info->page.y;
13128 mng_info->page=image->page;
13129 if ((mng_info->page.x != previous_x) ||
13130 (mng_info->page.y != previous_y))
13132 (void) WriteBlobMSBULong(image,12L); /* data length=12 */
13133 PNGType(chunk,mng_DEFI);
13134 LogPNGChunk(logging,mng_DEFI,12L);
13135 chunk[4]=0; /* object 0 MSB */
13136 chunk[5]=0; /* object 0 LSB */
13137 chunk[6]=0; /* visible */
13138 chunk[7]=0; /* abstract */
13139 PNGLong(chunk+8,(png_uint_32) mng_info->page.x);
13140 PNGLong(chunk+12,(png_uint_32) mng_info->page.y);
13141 (void) WriteBlob(image,16,chunk);
13142 (void) WriteBlobMSBULong(image,crc32(0,chunk,16));
13147 mng_info->write_mng=write_mng;
13149 if ((int) image->dispose >= 3)
13150 mng_info->framing_mode=3;
13152 if (mng_info->need_fram && mng_info->adjoin &&
13153 ((image->delay != mng_info->delay) ||
13154 (mng_info->framing_mode != mng_info->old_framing_mode)))
13156 if (image->delay == mng_info->delay)
13159 Write a MNG FRAM chunk with the new framing mode.
13161 (void) WriteBlobMSBULong(image,1L); /* data length=1 */
13162 PNGType(chunk,mng_FRAM);
13163 LogPNGChunk(logging,mng_FRAM,1L);
13164 chunk[4]=(unsigned char) mng_info->framing_mode;
13165 (void) WriteBlob(image,5,chunk);
13166 (void) WriteBlobMSBULong(image,crc32(0,chunk,5));
13171 Write a MNG FRAM chunk with the delay.
13173 (void) WriteBlobMSBULong(image,10L); /* data length=10 */
13174 PNGType(chunk,mng_FRAM);
13175 LogPNGChunk(logging,mng_FRAM,10L);
13176 chunk[4]=(unsigned char) mng_info->framing_mode;
13177 chunk[5]=0; /* frame name separator (no name) */
13178 chunk[6]=2; /* flag for changing default delay */
13179 chunk[7]=0; /* flag for changing frame timeout */
13180 chunk[8]=0; /* flag for changing frame clipping */
13181 chunk[9]=0; /* flag for changing frame sync_id */
13182 PNGLong(chunk+10,(png_uint_32)
13183 ((mng_info->ticks_per_second*
13184 image->delay)/MagickMax(image->ticks_per_second,1)));
13185 (void) WriteBlob(image,14,chunk);
13186 (void) WriteBlobMSBULong(image,crc32(0,chunk,14));
13187 mng_info->delay=(png_uint_32) image->delay;
13189 mng_info->old_framing_mode=mng_info->framing_mode;
13192 #if defined(JNG_SUPPORTED)
13193 if (image_info->compression == JPEGCompression)
13198 if (logging != MagickFalse)
13199 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
13200 " Writing JNG object.");
13201 /* To do: specify the desired alpha compression method. */
13202 write_info=CloneImageInfo(image_info);
13203 write_info->compression=UndefinedCompression;
13204 status=WriteOneJNGImage(mng_info,write_info,image,exception);
13205 write_info=DestroyImageInfo(write_info);
13210 if (logging != MagickFalse)
13211 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
13212 " Writing PNG object.");
13214 mng_info->need_blob = MagickFalse;
13215 mng_info->ping_preserve_colormap = MagickFalse;
13217 /* We don't want any ancillary chunks written */
13218 mng_info->ping_exclude_bKGD=MagickTrue;
13219 mng_info->ping_exclude_cHRM=MagickTrue;
13220 mng_info->ping_exclude_date=MagickTrue;
13221 mng_info->ping_exclude_EXIF=MagickTrue;
13222 mng_info->ping_exclude_gAMA=MagickTrue;
13223 mng_info->ping_exclude_iCCP=MagickTrue;
13224 /* mng_info->ping_exclude_iTXt=MagickTrue; */
13225 mng_info->ping_exclude_oFFs=MagickTrue;
13226 mng_info->ping_exclude_pHYs=MagickTrue;
13227 mng_info->ping_exclude_sRGB=MagickTrue;
13228 mng_info->ping_exclude_tEXt=MagickTrue;
13229 mng_info->ping_exclude_tRNS=MagickTrue;
13230 mng_info->ping_exclude_vpAg=MagickTrue;
13231 mng_info->ping_exclude_zCCP=MagickTrue;
13232 mng_info->ping_exclude_zTXt=MagickTrue;
13234 status=WriteOnePNGImage(mng_info,image_info,image,exception);
13237 if (status == MagickFalse)
13239 MngInfoFreeStruct(mng_info,&have_mng_structure);
13240 (void) CloseBlob(image);
13241 return(MagickFalse);
13243 (void) CatchImageException(image);
13244 if (GetNextImageInList(image) == (Image *) NULL)
13246 image=SyncNextImageInList(image);
13247 status=SetImageProgress(image,SaveImagesTag,scene++,
13248 GetImageListLength(image));
13250 if (status == MagickFalse)
13253 } while (mng_info->adjoin);
13257 while (GetPreviousImageInList(image) != (Image *) NULL)
13258 image=GetPreviousImageInList(image);
13260 Write the MEND chunk.
13262 (void) WriteBlobMSBULong(image,0x00000000L);
13263 PNGType(chunk,mng_MEND);
13264 LogPNGChunk(logging,mng_MEND,0L);
13265 (void) WriteBlob(image,4,chunk);
13266 (void) WriteBlobMSBULong(image,crc32(0,chunk,4));
13269 Relinquish resources.
13271 (void) CloseBlob(image);
13272 MngInfoFreeStruct(mng_info,&have_mng_structure);
13274 if (logging != MagickFalse)
13275 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit WriteMNGImage()");
13277 return(MagickTrue);
13279 #else /* PNG_LIBPNG_VER > 10011 */
13281 static MagickBooleanType WritePNGImage(const ImageInfo *image_info,Image *image)
13284 printf("Your PNG library is too old: You have libpng-%s\n",
13285 PNG_LIBPNG_VER_STRING);
13287 ThrowBinaryException(CoderError,"PNG library is too old",
13288 image_info->filename);
13291 static MagickBooleanType WriteMNGImage(const ImageInfo *image_info,Image *image)
13293 return(WritePNGImage(image_info,image));
13295 #endif /* PNG_LIBPNG_VER > 10011 */