2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13 % Read/Write Portable Network Graphics Image Format %
17 % Glenn Randers-Pehrson %
21 % Copyright 1999-2013 ImageMagick Studio LLC, a non-profit organization %
22 % dedicated to making software imaging solutions freely available. %
24 % You may not use this file except in compliance with the License. You may %
25 % obtain a copy of the License at %
27 % http://www.imagemagick.org/script/license.php %
29 % Unless required by applicable law or agreed to in writing, software %
30 % distributed under the License is distributed on an "AS IS" BASIS, %
31 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
32 % See the License for the specific language governing permissions and %
33 % limitations under the License. %
35 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
44 #include "MagickCore/studio.h"
45 #include "MagickCore/artifact.h"
46 #include "MagickCore/attribute.h"
47 #include "MagickCore/blob.h"
48 #include "MagickCore/blob-private.h"
49 #include "MagickCore/cache.h"
50 #include "MagickCore/channel.h"
51 #include "MagickCore/color.h"
52 #include "MagickCore/color-private.h"
53 #include "MagickCore/colormap.h"
54 #include "MagickCore/colorspace.h"
55 #include "MagickCore/colorspace-private.h"
56 #include "MagickCore/constitute.h"
57 #include "MagickCore/enhance.h"
58 #include "MagickCore/exception.h"
59 #include "MagickCore/exception-private.h"
60 #include "MagickCore/geometry.h"
61 #include "MagickCore/histogram.h"
62 #include "MagickCore/image.h"
63 #include "MagickCore/image-private.h"
64 #include "MagickCore/layer.h"
65 #include "MagickCore/list.h"
66 #include "MagickCore/log.h"
67 #include "MagickCore/MagickCore.h"
68 #include "MagickCore/memory_.h"
69 #include "MagickCore/module.h"
70 #include "MagickCore/monitor.h"
71 #include "MagickCore/monitor-private.h"
72 #include "MagickCore/option.h"
73 #include "MagickCore/pixel.h"
74 #include "MagickCore/pixel-accessor.h"
75 #include "MagickCore/profile.h"
76 #include "MagickCore/property.h"
77 #include "MagickCore/quantum-private.h"
78 #include "MagickCore/resource_.h"
79 #include "MagickCore/semaphore.h"
80 #include "MagickCore/quantum-private.h"
81 #include "MagickCore/static.h"
82 #include "MagickCore/statistic.h"
83 #include "MagickCore/string_.h"
84 #include "MagickCore/string-private.h"
85 #include "MagickCore/transform.h"
86 #include "MagickCore/utility.h"
87 #if defined(MAGICKCORE_PNG_DELEGATE)
89 /* Suppress libpng pedantic warnings that were added in
90 * libpng-1.2.41 and libpng-1.4.0. If you are working on
91 * migration to libpng-1.5, remove these defines and then
92 * fix any code that generates warnings.
94 /* #define PNG_DEPRECATED Use of this function is deprecated */
95 /* #define PNG_USE_RESULT The result of this function must be checked */
96 /* #define PNG_NORETURN This function does not return */
97 /* #define PNG_ALLOCATED The result of the function is new memory */
98 /* #define PNG_DEPSTRUCT Access to this struct member is deprecated */
100 /* PNG_PTR_NORETURN does not work on some platforms, in libpng-1.5.x */
101 #define PNG_PTR_NORETURN
106 /* ImageMagick differences */
107 #define first_scene scene
109 #if PNG_LIBPNG_VER > 10011
111 Optional declarations. Define or undefine them as you like.
113 /* #define PNG_DEBUG -- turning this on breaks VisualC compiling */
116 Features under construction. Define these to work on them.
118 #undef MNG_OBJECT_BUFFERS
119 #undef MNG_BASI_SUPPORTED
120 #define MNG_COALESCE_LAYERS /* In 5.4.4, this interfered with MMAP'ed files. */
121 #define MNG_INSERT_LAYERS /* Troublesome, but seem to work as of 5.4.4 */
122 #if defined(MAGICKCORE_JPEG_DELEGATE)
123 # define JNG_SUPPORTED /* Not finished as of 5.5.2. See "To do" comments. */
125 #if !defined(RGBColorMatchExact)
126 #define IsPNGColorEqual(color,target) \
127 (((color).red == (target).red) && \
128 ((color).green == (target).green) && \
129 ((color).blue == (target).blue))
132 /* Macros for left-bit-replication to ensure that pixels
133 * and PixelInfos all have the same image->depth, and for use
134 * in PNG8 quantization.
138 /* LBR01: Replicate top bit */
140 #define LBR01PacketRed(pixelpacket) \
141 (pixelpacket).red=(ScaleQuantumToChar((pixelpacket).red) < 0x10 ? \
144 #define LBR01PacketGreen(pixelpacket) \
145 (pixelpacket).green=(ScaleQuantumToChar((pixelpacket).green) < 0x10 ? \
148 #define LBR01PacketBlue(pixelpacket) \
149 (pixelpacket).blue=(ScaleQuantumToChar((pixelpacket).blue) < 0x10 ? \
152 #define LBR01PacketAlpha(pixelpacket) \
153 (pixelpacket).alpha=(ScaleQuantumToChar((pixelpacket).alpha) < 0x10 ? \
156 #define LBR01PacketRGB(pixelpacket) \
158 LBR01PacketRed((pixelpacket)); \
159 LBR01PacketGreen((pixelpacket)); \
160 LBR01PacketBlue((pixelpacket)); \
163 #define LBR01PacketRGBO(pixelpacket) \
165 LBR01PacketRGB((pixelpacket)); \
166 LBR01PacketAlpha((pixelpacket)); \
169 #define LBR01PixelRed(pixel) \
170 (SetPixelRed(image, \
171 ScaleQuantumToChar(GetPixelRed(image,(pixel))) < 0x10 ? \
172 0 : QuantumRange,(pixel)));
174 #define LBR01PixelGreen(pixel) \
175 (SetPixelGreen(image, \
176 ScaleQuantumToChar(GetPixelGreen(image,(pixel))) < 0x10 ? \
177 0 : QuantumRange,(pixel)));
179 #define LBR01PixelBlue(pixel) \
180 (SetPixelBlue(image, \
181 ScaleQuantumToChar(GetPixelBlue(image,(pixel))) < 0x10 ? \
182 0 : QuantumRange,(pixel)));
184 #define LBR01PixelAlpha(pixel) \
185 (SetPixelAlpha(image, \
186 ScaleQuantumToChar(GetPixelAlpha(image,(pixel))) < 0x10 ? \
187 0 : QuantumRange,(pixel)));
189 #define LBR01PixelRGB(pixel) \
191 LBR01PixelRed((pixel)); \
192 LBR01PixelGreen((pixel)); \
193 LBR01PixelBlue((pixel)); \
196 #define LBR01PixelRGBA(pixel) \
198 LBR01PixelRGB((pixel)); \
199 LBR01PixelAlpha((pixel)); \
202 /* LBR02: Replicate top 2 bits */
204 #define LBR02PacketRed(pixelpacket) \
206 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).red) & 0xc0; \
207 (pixelpacket).red=ScaleCharToQuantum( \
208 (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))); \
210 #define LBR02PacketGreen(pixelpacket) \
212 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).green) & 0xc0; \
213 (pixelpacket).green=ScaleCharToQuantum( \
214 (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))); \
216 #define LBR02PacketBlue(pixelpacket) \
218 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).blue) & 0xc0; \
219 (pixelpacket).blue=ScaleCharToQuantum( \
220 (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))); \
222 #define LBR02PacketAlpha(pixelpacket) \
224 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).alpha) & 0xc0; \
225 (pixelpacket).alpha=ScaleCharToQuantum( \
226 (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))); \
229 #define LBR02PacketRGB(pixelpacket) \
231 LBR02PacketRed((pixelpacket)); \
232 LBR02PacketGreen((pixelpacket)); \
233 LBR02PacketBlue((pixelpacket)); \
236 #define LBR02PacketRGBO(pixelpacket) \
238 LBR02PacketRGB((pixelpacket)); \
239 LBR02PacketAlpha((pixelpacket)); \
242 #define LBR02PixelRed(pixel) \
244 unsigned char lbr_bits=ScaleQuantumToChar(GetPixelRed(image,(pixel))) \
246 SetPixelRed(image, ScaleCharToQuantum( \
247 (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))), \
250 #define LBR02PixelGreen(pixel) \
252 unsigned char lbr_bits=ScaleQuantumToChar(GetPixelGreen(image,(pixel)))\
254 SetPixelGreen(image, ScaleCharToQuantum( \
255 (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))), \
258 #define LBR02PixelBlue(pixel) \
260 unsigned char lbr_bits= \
261 ScaleQuantumToChar(GetPixelBlue(image,(pixel))) & 0xc0; \
262 SetPixelBlue(image, ScaleCharToQuantum( \
263 (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))), \
266 #define LBR02PixelAlpha(pixel) \
268 unsigned char lbr_bits= \
269 ScaleQuantumToChar(GetPixelAlpha(image,(pixel))) & 0xc0; \
270 SetPixelAlpha(image, ScaleCharToQuantum( \
271 (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))), \
275 #define LBR02PixelRGB(pixel) \
277 LBR02PixelRed((pixel)); \
278 LBR02PixelGreen((pixel)); \
279 LBR02PixelBlue((pixel)); \
282 #define LBR02PixelRGBA(pixel) \
284 LBR02PixelRGB((pixel)); \
285 LBR02PixelAlpha((pixel)); \
288 /* LBR03: Replicate top 3 bits (only used with opaque pixels during
289 PNG8 quantization) */
291 #define LBR03PacketRed(pixelpacket) \
293 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).red) & 0xe0; \
294 (pixelpacket).red=ScaleCharToQuantum( \
295 (lbr_bits | (lbr_bits >> 3) | (lbr_bits >> 6))); \
297 #define LBR03PacketGreen(pixelpacket) \
299 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).green) & 0xe0; \
300 (pixelpacket).green=ScaleCharToQuantum( \
301 (lbr_bits | (lbr_bits >> 3) | (lbr_bits >> 6))); \
303 #define LBR03PacketBlue(pixelpacket) \
305 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).blue) & 0xe0; \
306 (pixelpacket).blue=ScaleCharToQuantum( \
307 (lbr_bits | (lbr_bits >> 3) | (lbr_bits >> 6))); \
310 #define LBR03PacketRGB(pixelpacket) \
312 LBR03PacketRed((pixelpacket)); \
313 LBR03PacketGreen((pixelpacket)); \
314 LBR03PacketBlue((pixelpacket)); \
317 #define LBR03PixelRed(pixel) \
319 unsigned char lbr_bits=ScaleQuantumToChar(GetPixelRed(image,(pixel))) \
321 SetPixelRed(image, ScaleCharToQuantum( \
322 (lbr_bits | (lbr_bits >> 3) | (lbr_bits >> 6))), (pixel)); \
324 #define LBR03Green(pixel) \
326 unsigned char lbr_bits=ScaleQuantumToChar(GetPixelGreen(image,(pixel)))\
328 SetPixelGreen(image, ScaleCharToQuantum( \
329 (lbr_bits | (lbr_bits >> 3) | (lbr_bits >> 6))), (pixel)); \
331 #define LBR03Blue(pixel) \
333 unsigned char lbr_bits=ScaleQuantumToChar(GetPixelBlue(image,(pixel))) \
335 SetPixelBlue(image, ScaleCharToQuantum( \
336 (lbr_bits | (lbr_bits >> 3) | (lbr_bits >> 6))), (pixel)); \
339 #define LBR03RGB(pixel) \
341 LBR03PixelRed((pixel)); \
342 LBR03Green((pixel)); \
343 LBR03Blue((pixel)); \
346 /* LBR04: Replicate top 4 bits */
348 #define LBR04PacketRed(pixelpacket) \
350 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).red) & 0xf0; \
351 (pixelpacket).red=ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))); \
353 #define LBR04PacketGreen(pixelpacket) \
355 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).green) & 0xf0; \
356 (pixelpacket).green=ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))); \
358 #define LBR04PacketBlue(pixelpacket) \
360 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).blue) & 0xf0; \
361 (pixelpacket).blue=ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))); \
363 #define LBR04PacketAlpha(pixelpacket) \
365 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).alpha) & 0xf0; \
366 (pixelpacket).alpha=ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))); \
369 #define LBR04PacketRGB(pixelpacket) \
371 LBR04PacketRed((pixelpacket)); \
372 LBR04PacketGreen((pixelpacket)); \
373 LBR04PacketBlue((pixelpacket)); \
376 #define LBR04PacketRGBO(pixelpacket) \
378 LBR04PacketRGB((pixelpacket)); \
379 LBR04PacketAlpha((pixelpacket)); \
382 #define LBR04PixelRed(pixel) \
384 unsigned char lbr_bits=ScaleQuantumToChar(GetPixelRed(image,(pixel))) \
387 ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))), (pixel)); \
389 #define LBR04PixelGreen(pixel) \
391 unsigned char lbr_bits=ScaleQuantumToChar(GetPixelGreen(image,(pixel)))\
393 SetPixelGreen(image,\
394 ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))), (pixel)); \
396 #define LBR04PixelBlue(pixel) \
398 unsigned char lbr_bits= \
399 ScaleQuantumToChar(GetPixelBlue(image,(pixel))) & 0xf0; \
401 ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))), (pixel)); \
403 #define LBR04PixelAlpha(pixel) \
405 unsigned char lbr_bits= \
406 ScaleQuantumToChar(GetPixelAlpha(image,(pixel))) & 0xf0; \
407 SetPixelAlpha(image,\
408 ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))), (pixel)); \
411 #define LBR04PixelRGB(pixel) \
413 LBR04PixelRed((pixel)); \
414 LBR04PixelGreen((pixel)); \
415 LBR04PixelBlue((pixel)); \
418 #define LBR04PixelRGBA(pixel) \
420 LBR04PixelRGB((pixel)); \
421 LBR04PixelAlpha((pixel)); \
425 #if MAGICKCORE_QUANTUM_DEPTH > 8
426 /* LBR08: Replicate top 8 bits */
428 #define LBR08PacketRed(pixelpacket) \
430 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).red); \
431 (pixelpacket).red=ScaleCharToQuantum((lbr_bits)); \
433 #define LBR08PacketGreen(pixelpacket) \
435 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).green); \
436 (pixelpacket).green=ScaleCharToQuantum((lbr_bits)); \
438 #define LBR08PacketBlue(pixelpacket) \
440 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).blue); \
441 (pixelpacket).blue=ScaleCharToQuantum((lbr_bits)); \
443 #define LBR08PacketAlpha(pixelpacket) \
445 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).alpha); \
446 (pixelpacket).alpha=ScaleCharToQuantum((lbr_bits)); \
449 #define LBR08PacketRGB(pixelpacket) \
451 LBR08PacketRed((pixelpacket)); \
452 LBR08PacketGreen((pixelpacket)); \
453 LBR08PacketBlue((pixelpacket)); \
456 #define LBR08PacketRGBO(pixelpacket) \
458 LBR08PacketRGB((pixelpacket)); \
459 LBR08PacketAlpha((pixelpacket)); \
462 #define LBR08PixelRed(pixel) \
464 unsigned char lbr_bits= \
465 ScaleQuantumToChar(GetPixelRed(image,(pixel))); \
467 ScaleCharToQuantum((lbr_bits)), (pixel)); \
469 #define LBR08PixelGreen(pixel) \
471 unsigned char lbr_bits= \
472 ScaleQuantumToChar(GetPixelGreen(image,(pixel))); \
473 SetPixelGreen(image,\
474 ScaleCharToQuantum((lbr_bits)), (pixel)); \
476 #define LBR08PixelBlue(pixel) \
478 unsigned char lbr_bits= \
479 ScaleQuantumToChar(GetPixelBlue(image,(pixel))); \
481 ScaleCharToQuantum((lbr_bits)), (pixel)); \
483 #define LBR08PixelAlpha(pixel) \
485 unsigned char lbr_bits= \
486 ScaleQuantumToChar(GetPixelAlpha(image,(pixel))); \
487 SetPixelAlpha(image,\
488 ScaleCharToQuantum((lbr_bits)), (pixel)); \
491 #define LBR08PixelRGB(pixel) \
493 LBR08PixelRed((pixel)); \
494 LBR08PixelGreen((pixel)); \
495 LBR08PixelBlue((pixel)); \
498 #define LBR08PixelRGBA(pixel) \
500 LBR08PixelRGB((pixel)); \
501 LBR08PixelAlpha((pixel)); \
503 #endif /* MAGICKCORE_QUANTUM_DEPTH > 8 */
506 #if MAGICKCORE_QUANTUM_DEPTH > 16
507 /* LBR16: Replicate top 16 bits */
509 #define LBR16PacketRed(pixelpacket) \
511 unsigned short lbr_bits=ScaleQuantumToShort((pixelpacket).red); \
512 (pixelpacket).red=ScaleShortToQuantum((lbr_bits)); \
514 #define LBR16PacketGreen(pixelpacket) \
516 unsigned short lbr_bits=ScaleQuantumToShort((pixelpacket).green); \
517 (pixelpacket).green=ScaleShortToQuantum((lbr_bits)); \
519 #define LBR16PacketBlue(pixelpacket) \
521 unsigned short lbr_bits=ScaleQuantumToShort((pixelpacket).blue); \
522 (pixelpacket).blue=ScaleShortToQuantum((lbr_bits)); \
524 #define LBR16PacketAlpha(pixelpacket) \
526 unsigned short lbr_bits=ScaleQuantumToShort((pixelpacket).alpha); \
527 (pixelpacket).alpha=ScaleShortToQuantum((lbr_bits)); \
530 #define LBR16PacketRGB(pixelpacket) \
532 LBR16PacketRed((pixelpacket)); \
533 LBR16PacketGreen((pixelpacket)); \
534 LBR16PacketBlue((pixelpacket)); \
537 #define LBR16PacketRGBO(pixelpacket) \
539 LBR16PacketRGB((pixelpacket)); \
540 LBR16PacketAlpha((pixelpacket)); \
543 #define LBR16PixelRed(pixel) \
545 unsigned short lbr_bits= \
546 ScaleQuantumToShort(GetPixelRed(image,(pixel))); \
548 ScaleShortToQuantum((lbr_bits)),(pixel)); \
550 #define LBR16PixelGreen(pixel) \
552 unsigned short lbr_bits= \
553 ScaleQuantumToShort(GetPixelGreen(image,(pixel))); \
554 SetPixelGreen(image,\
555 ScaleShortToQuantum((lbr_bits)),(pixel)); \
557 #define LBR16PixelBlue(pixel) \
559 unsigned short lbr_bits= \
560 ScaleQuantumToShort(GetPixelBlue(image,(pixel))); \
562 ScaleShortToQuantum((lbr_bits)),(pixel)); \
564 #define LBR16PixelAlpha(pixel) \
566 unsigned short lbr_bits= \
567 ScaleQuantumToShort(GetPixelAlpha(image,(pixel))); \
568 SetPixelAlpha(image,\
569 ScaleShortToQuantum((lbr_bits)),(pixel)); \
572 #define LBR16PixelRGB(pixel) \
574 LBR16PixelRed((pixel)); \
575 LBR16PixelGreen((pixel)); \
576 LBR16PixelBlue((pixel)); \
579 #define LBR16PixelRGBA(pixel) \
581 LBR16PixelRGB((pixel)); \
582 LBR16PixelAlpha((pixel)); \
584 #endif /* MAGICKCORE_QUANTUM_DEPTH > 16 */
587 Establish thread safety.
588 setjmp/longjmp is claimed to be safe on these platforms:
589 setjmp/longjmp is alleged to be unsafe on these platforms:
591 #ifndef SETJMP_IS_THREAD_SAFE
592 #define PNG_SETJMP_NOT_THREAD_SAFE
595 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
597 *ping_semaphore = (SemaphoreInfo *) NULL;
601 This temporary until I set up malloc'ed object attributes array.
602 Recompile with MNG_MAX_OBJECTS=65536L to avoid this limit but
605 #define MNG_MAX_OBJECTS 256
608 If this not defined, spec is interpreted strictly. If it is
609 defined, an attempt will be made to recover from some errors,
611 o global PLTE too short
616 Don't try to define PNG_MNG_FEATURES_SUPPORTED here. Make sure
617 it's defined in libpng/pngconf.h, version 1.0.9 or later. It won't work
618 with earlier versions of libpng. From libpng-1.0.3a to libpng-1.0.8,
619 PNG_READ|WRITE_EMPTY_PLTE were used but those have been deprecated in
620 libpng in favor of PNG_MNG_FEATURES_SUPPORTED, so we set them here.
621 PNG_MNG_FEATURES_SUPPORTED is disabled by default in libpng-1.0.9 and
622 will be enabled by default in libpng-1.2.0.
624 #ifdef PNG_MNG_FEATURES_SUPPORTED
625 # ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
626 # define PNG_READ_EMPTY_PLTE_SUPPORTED
628 # ifndef PNG_WRITE_EMPTY_PLTE_SUPPORTED
629 # define PNG_WRITE_EMPTY_PLTE_SUPPORTED
634 Maximum valid size_t in PNG/MNG chunks is (2^31)-1
635 This macro is only defined in libpng-1.0.3 and later.
636 Previously it was PNG_MAX_UINT but that was deprecated in libpng-1.2.6
638 #ifndef PNG_UINT_31_MAX
639 #define PNG_UINT_31_MAX (png_uint_32) 0x7fffffffL
643 Constant strings for known chunk types. If you need to add a chunk,
644 add a string holding the name here. To make the code more
645 portable, we use ASCII numbers like this, not characters.
648 static png_byte mng_MHDR[5]={ 77, 72, 68, 82, (png_byte) '\0'};
649 static png_byte mng_BACK[5]={ 66, 65, 67, 75, (png_byte) '\0'};
650 static png_byte mng_BASI[5]={ 66, 65, 83, 73, (png_byte) '\0'};
651 static png_byte mng_CLIP[5]={ 67, 76, 73, 80, (png_byte) '\0'};
652 static png_byte mng_CLON[5]={ 67, 76, 79, 78, (png_byte) '\0'};
653 static png_byte mng_DEFI[5]={ 68, 69, 70, 73, (png_byte) '\0'};
654 static png_byte mng_DHDR[5]={ 68, 72, 68, 82, (png_byte) '\0'};
655 static png_byte mng_DISC[5]={ 68, 73, 83, 67, (png_byte) '\0'};
656 static png_byte mng_ENDL[5]={ 69, 78, 68, 76, (png_byte) '\0'};
657 static png_byte mng_FRAM[5]={ 70, 82, 65, 77, (png_byte) '\0'};
658 static png_byte mng_IEND[5]={ 73, 69, 78, 68, (png_byte) '\0'};
659 static png_byte mng_IHDR[5]={ 73, 72, 68, 82, (png_byte) '\0'};
660 static png_byte mng_JHDR[5]={ 74, 72, 68, 82, (png_byte) '\0'};
661 static png_byte mng_LOOP[5]={ 76, 79, 79, 80, (png_byte) '\0'};
662 static png_byte mng_MAGN[5]={ 77, 65, 71, 78, (png_byte) '\0'};
663 static png_byte mng_MEND[5]={ 77, 69, 78, 68, (png_byte) '\0'};
664 static png_byte mng_MOVE[5]={ 77, 79, 86, 69, (png_byte) '\0'};
665 static png_byte mng_PAST[5]={ 80, 65, 83, 84, (png_byte) '\0'};
666 static png_byte mng_PLTE[5]={ 80, 76, 84, 69, (png_byte) '\0'};
667 static png_byte mng_SAVE[5]={ 83, 65, 86, 69, (png_byte) '\0'};
668 static png_byte mng_SEEK[5]={ 83, 69, 69, 75, (png_byte) '\0'};
669 static png_byte mng_SHOW[5]={ 83, 72, 79, 87, (png_byte) '\0'};
670 static png_byte mng_TERM[5]={ 84, 69, 82, 77, (png_byte) '\0'};
671 static png_byte mng_bKGD[5]={ 98, 75, 71, 68, (png_byte) '\0'};
672 static png_byte mng_cHRM[5]={ 99, 72, 82, 77, (png_byte) '\0'};
673 static png_byte mng_gAMA[5]={103, 65, 77, 65, (png_byte) '\0'};
674 static png_byte mng_iCCP[5]={105, 67, 67, 80, (png_byte) '\0'};
675 static png_byte mng_nEED[5]={110, 69, 69, 68, (png_byte) '\0'};
676 static png_byte mng_pHYg[5]={112, 72, 89, 103, (png_byte) '\0'};
677 static png_byte mng_vpAg[5]={118, 112, 65, 103, (png_byte) '\0'};
678 static png_byte mng_pHYs[5]={112, 72, 89, 115, (png_byte) '\0'};
679 static png_byte mng_sBIT[5]={115, 66, 73, 84, (png_byte) '\0'};
680 static png_byte mng_sRGB[5]={115, 82, 71, 66, (png_byte) '\0'};
681 static png_byte mng_tRNS[5]={116, 82, 78, 83, (png_byte) '\0'};
683 #if defined(JNG_SUPPORTED)
684 static png_byte mng_IDAT[5]={ 73, 68, 65, 84, (png_byte) '\0'};
685 static png_byte mng_JDAT[5]={ 74, 68, 65, 84, (png_byte) '\0'};
686 static png_byte mng_JDAA[5]={ 74, 68, 65, 65, (png_byte) '\0'};
687 static png_byte mng_JdAA[5]={ 74, 100, 65, 65, (png_byte) '\0'};
688 static png_byte mng_JSEP[5]={ 74, 83, 69, 80, (png_byte) '\0'};
689 static png_byte mng_oFFs[5]={111, 70, 70, 115, (png_byte) '\0'};
693 Other known chunks that are not yet supported by ImageMagick:
694 static png_byte mng_hIST[5]={104, 73, 83, 84, (png_byte) '\0'};
695 static png_byte mng_iCCP[5]={105, 67, 67, 80, (png_byte) '\0'};
696 static png_byte mng_iTXt[5]={105, 84, 88, 116, (png_byte) '\0'};
697 static png_byte mng_sPLT[5]={115, 80, 76, 84, (png_byte) '\0'};
698 static png_byte mng_sTER[5]={115, 84, 69, 82, (png_byte) '\0'};
699 static png_byte mng_tEXt[5]={116, 69, 88, 116, (png_byte) '\0'};
700 static png_byte mng_tIME[5]={116, 73, 77, 69, (png_byte) '\0'};
701 static png_byte mng_zTXt[5]={122, 84, 88, 116, (png_byte) '\0'};
704 typedef struct _MngBox
713 typedef struct _MngPair
720 #ifdef MNG_OBJECT_BUFFERS
721 typedef struct _MngBuffer
753 typedef struct _MngInfo
756 #ifdef MNG_OBJECT_BUFFERS
758 *ob[MNG_MAX_OBJECTS];
769 #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
770 bytes_in_read_buffer,
776 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
777 defined(PNG_MNG_FEATURES_SUPPORTED)
789 have_saved_bkgd_index,
790 have_write_global_chrm,
791 have_write_global_gama,
792 have_write_global_plte,
793 have_write_global_srgb,
807 x_off[MNG_MAX_OBJECTS],
808 y_off[MNG_MAX_OBJECTS];
814 object_clip[MNG_MAX_OBJECTS];
817 /* These flags could be combined into one byte */
818 exists[MNG_MAX_OBJECTS],
819 frozen[MNG_MAX_OBJECTS],
821 invisible[MNG_MAX_OBJECTS],
822 viewable[MNG_MAX_OBJECTS];
834 #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
852 global_x_pixels_per_unit,
853 global_y_pixels_per_unit,
863 global_phys_unit_type,
878 write_png_compression_level,
879 write_png_compression_strategy,
880 write_png_compression_filter,
887 #ifdef MNG_BASI_SUPPORTED
895 basi_compression_method,
897 basi_interlace_method,
920 /* Added at version 6.6.6-7 */
928 /* ping_exclude_iTXt, */
935 ping_exclude_zCCP, /* hex-encoded iCCP */
937 ping_preserve_colormap;
943 Forward declarations.
945 static MagickBooleanType
946 WritePNGImage(const ImageInfo *,Image *,ExceptionInfo *);
948 static MagickBooleanType
949 WriteMNGImage(const ImageInfo *,Image *,ExceptionInfo *);
951 #if defined(JNG_SUPPORTED)
952 static MagickBooleanType
953 WriteJNGImage(const ImageInfo *,Image *,ExceptionInfo *);
956 #if PNG_LIBPNG_VER > 10011
959 #if (MAGICKCORE_QUANTUM_DEPTH >= 16)
960 static MagickBooleanType
961 LosslessReduceDepthOK(Image *image,ExceptionInfo *exception)
963 /* Reduce bit depth if it can be reduced losslessly from 16+ to 8.
965 * This is true if the high byte and the next highest byte of
966 * each sample of the image, the colormap, and the background color
967 * are equal to each other. We check this by seeing if the samples
968 * are unchanged when we scale them down to 8 and back up to Quantum.
970 * We don't use the method GetImageDepth() because it doesn't check
971 * background and doesn't handle PseudoClass specially.
974 #define QuantumToCharToQuantumEqQuantum(quantum) \
975 ((ScaleCharToQuantum((unsigned char) ScaleQuantumToChar(quantum))) == quantum)
978 ok_to_reduce=MagickFalse;
980 if (image->depth >= 16)
987 QuantumToCharToQuantumEqQuantum(image->background_color.red) &&
988 QuantumToCharToQuantumEqQuantum(image->background_color.green) &&
989 QuantumToCharToQuantumEqQuantum(image->background_color.blue) ?
990 MagickTrue : MagickFalse;
992 if (ok_to_reduce != MagickFalse && image->storage_class == PseudoClass)
996 for (indx=0; indx < (ssize_t) image->colors; indx++)
999 QuantumToCharToQuantumEqQuantum(
1000 image->colormap[indx].red) &&
1001 QuantumToCharToQuantumEqQuantum(
1002 image->colormap[indx].green) &&
1003 QuantumToCharToQuantumEqQuantum(
1004 image->colormap[indx].blue)) ?
1005 MagickTrue : MagickFalse;
1007 if (ok_to_reduce == MagickFalse)
1012 if ((ok_to_reduce != MagickFalse) &&
1013 (image->storage_class != PseudoClass))
1021 for (y=0; y < (ssize_t) image->rows; y++)
1023 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1025 if (p == (const Quantum *) NULL)
1027 ok_to_reduce = MagickFalse;
1031 for (x=(ssize_t) image->columns-1; x >= 0; x--)
1034 QuantumToCharToQuantumEqQuantum(GetPixelRed(image,p)) &&
1035 QuantumToCharToQuantumEqQuantum(GetPixelGreen(image,p)) &&
1036 QuantumToCharToQuantumEqQuantum(GetPixelBlue(image,p)) ?
1037 MagickTrue : MagickFalse;
1039 if (ok_to_reduce == MagickFalse)
1042 p+=GetPixelChannels(image);
1049 if (ok_to_reduce != MagickFalse)
1051 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1052 " OK to reduce PNG bit depth to 8 without loss of info");
1056 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1057 " Not OK to reduce PNG bit depth to 8 without loss of info");
1061 return ok_to_reduce;
1063 #endif /* MAGICKCORE_QUANTUM_DEPTH >= 16 */
1065 static const char* PngColorTypeToString(const unsigned int color_type)
1068 *result = "Unknown";
1072 case PNG_COLOR_TYPE_GRAY:
1075 case PNG_COLOR_TYPE_GRAY_ALPHA:
1076 result = "Gray+Alpha";
1078 case PNG_COLOR_TYPE_PALETTE:
1081 case PNG_COLOR_TYPE_RGB:
1084 case PNG_COLOR_TYPE_RGB_ALPHA:
1085 result = "RGB+Alpha";
1093 Magick_RenderingIntent_to_PNG_RenderingIntent(const RenderingIntent intent)
1097 case PerceptualIntent:
1100 case RelativeIntent:
1103 case SaturationIntent:
1106 case AbsoluteIntent:
1114 static RenderingIntent
1115 Magick_RenderingIntent_from_PNG_RenderingIntent(const int ping_intent)
1117 switch (ping_intent)
1120 return PerceptualIntent;
1123 return RelativeIntent;
1126 return SaturationIntent;
1129 return AbsoluteIntent;
1132 return UndefinedIntent;
1137 Magick_RenderingIntentString_from_PNG_RenderingIntent(const int ping_intent)
1139 switch (ping_intent)
1142 return "Perceptual Intent";
1145 return "Relative Intent";
1148 return "Saturation Intent";
1151 return "Absolute Intent";
1154 return "Undefined Intent";
1158 static inline ssize_t MagickMax(const ssize_t x,const ssize_t y)
1167 Magick_ColorType_from_PNG_ColorType(const int ping_colortype)
1169 switch (ping_colortype)
1187 return "UndefinedColorType";
1192 static inline ssize_t MagickMin(const ssize_t x,const ssize_t y)
1199 #endif /* PNG_LIBPNG_VER > 10011 */
1200 #endif /* MAGICKCORE_PNG_DELEGATE */
1203 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1211 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1213 % IsMNG() returns MagickTrue if the image format type, identified by the
1214 % magick string, is MNG.
1216 % The format of the IsMNG method is:
1218 % MagickBooleanType IsMNG(const unsigned char *magick,const size_t length)
1220 % A description of each parameter follows:
1222 % o magick: compare image format pattern against these bytes.
1224 % o length: Specifies the length of the magick string.
1228 static MagickBooleanType IsMNG(const unsigned char *magick,const size_t length)
1231 return(MagickFalse);
1233 if (memcmp(magick,"\212MNG\r\n\032\n",8) == 0)
1236 return(MagickFalse);
1240 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1248 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1250 % IsJNG() returns MagickTrue if the image format type, identified by the
1251 % magick string, is JNG.
1253 % The format of the IsJNG method is:
1255 % MagickBooleanType IsJNG(const unsigned char *magick,const size_t length)
1257 % A description of each parameter follows:
1259 % o magick: compare image format pattern against these bytes.
1261 % o length: Specifies the length of the magick string.
1265 static MagickBooleanType IsJNG(const unsigned char *magick,const size_t length)
1268 return(MagickFalse);
1270 if (memcmp(magick,"\213JNG\r\n\032\n",8) == 0)
1273 return(MagickFalse);
1277 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1285 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1287 % IsPNG() returns MagickTrue if the image format type, identified by the
1288 % magick string, is PNG.
1290 % The format of the IsPNG method is:
1292 % MagickBooleanType IsPNG(const unsigned char *magick,const size_t length)
1294 % A description of each parameter follows:
1296 % o magick: compare image format pattern against these bytes.
1298 % o length: Specifies the length of the magick string.
1301 static MagickBooleanType IsPNG(const unsigned char *magick,const size_t length)
1304 return(MagickFalse);
1306 if (memcmp(magick,"\211PNG\r\n\032\n",8) == 0)
1309 return(MagickFalse);
1312 #if defined(MAGICKCORE_PNG_DELEGATE)
1313 #if defined(__cplusplus) || defined(c_plusplus)
1317 #if (PNG_LIBPNG_VER > 10011)
1318 static size_t WriteBlobMSBULong(Image *image,const size_t value)
1323 assert(image != (Image *) NULL);
1324 assert(image->signature == MagickSignature);
1325 buffer[0]=(unsigned char) (value >> 24);
1326 buffer[1]=(unsigned char) (value >> 16);
1327 buffer[2]=(unsigned char) (value >> 8);
1328 buffer[3]=(unsigned char) value;
1329 return((size_t) WriteBlob(image,4,buffer));
1332 static void PNGLong(png_bytep p,png_uint_32 value)
1334 *p++=(png_byte) ((value >> 24) & 0xff);
1335 *p++=(png_byte) ((value >> 16) & 0xff);
1336 *p++=(png_byte) ((value >> 8) & 0xff);
1337 *p++=(png_byte) (value & 0xff);
1340 #if defined(JNG_SUPPORTED)
1341 static void PNGsLong(png_bytep p,png_int_32 value)
1343 *p++=(png_byte) ((value >> 24) & 0xff);
1344 *p++=(png_byte) ((value >> 16) & 0xff);
1345 *p++=(png_byte) ((value >> 8) & 0xff);
1346 *p++=(png_byte) (value & 0xff);
1350 static void PNGShort(png_bytep p,png_uint_16 value)
1352 *p++=(png_byte) ((value >> 8) & 0xff);
1353 *p++=(png_byte) (value & 0xff);
1356 static void PNGType(png_bytep p,png_bytep type)
1358 (void) CopyMagickMemory(p,type,4*sizeof(png_byte));
1361 static void LogPNGChunk(MagickBooleanType logging, png_bytep type,
1364 if (logging != MagickFalse)
1365 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1366 " Writing %c%c%c%c chunk, length: %.20g",
1367 type[0],type[1],type[2],type[3],(double) length);
1369 #endif /* PNG_LIBPNG_VER > 10011 */
1371 #if defined(__cplusplus) || defined(c_plusplus)
1375 #if PNG_LIBPNG_VER > 10011
1377 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1381 % R e a d P N G I m a g e %
1385 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1387 % ReadPNGImage() reads a Portable Network Graphics (PNG) or
1388 % Multiple-image Network Graphics (MNG) image file and returns it. It
1389 % allocates the memory necessary for the new Image structure and returns a
1390 % pointer to the new image or set of images.
1392 % MNG support written by Glenn Randers-Pehrson, glennrp@image...
1394 % The format of the ReadPNGImage method is:
1396 % Image *ReadPNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
1398 % A description of each parameter follows:
1400 % o image_info: the image info.
1402 % o exception: return any errors or warnings in this structure.
1404 % To do, more or less in chronological order (as of version 5.5.2,
1405 % November 26, 2002 -- glennrp -- see also "To do" under WriteMNGImage):
1407 % Get 16-bit cheap transparency working.
1409 % (At this point, PNG decoding is supposed to be in full MNG-LC compliance)
1411 % Preserve all unknown and not-yet-handled known chunks found in input
1412 % PNG file and copy them into output PNG files according to the PNG
1415 % (At this point, PNG encoding should be in full MNG compliance)
1417 % Provide options for choice of background to use when the MNG BACK
1418 % chunk is not present or is not mandatory (i.e., leave transparent,
1419 % user specified, MNG BACK, PNG bKGD)
1421 % Implement LOOP/ENDL [done, but could do discretionary loops more
1422 % efficiently by linking in the duplicate frames.].
1424 % Decode and act on the MHDR simplicity profile (offer option to reject
1425 % files or attempt to process them anyway when the profile isn't LC or VLC).
1427 % Upgrade to full MNG without Delta-PNG.
1429 % o BACK [done a while ago except for background image ID]
1430 % o MOVE [done 15 May 1999]
1431 % o CLIP [done 15 May 1999]
1432 % o DISC [done 19 May 1999]
1433 % o SAVE [partially done 19 May 1999 (marks objects frozen)]
1434 % o SEEK [partially done 19 May 1999 (discard function only)]
1438 % o MNG-level tEXt/iTXt/zTXt
1443 % o iTXt (wait for libpng implementation).
1445 % Use the scene signature to discover when an identical scene is
1446 % being reused, and just point to the original image->exception instead
1447 % of storing another set of pixels. This not specific to MNG
1448 % but could be applied generally.
1450 % Upgrade to full MNG with Delta-PNG.
1452 % JNG tEXt/iTXt/zTXt
1454 % We will not attempt to read files containing the CgBI chunk.
1455 % They are really Xcode files meant for display on the iPhone.
1456 % These are not valid PNG files and it is impossible to recover
1457 % the original PNG from files that have been converted to Xcode-PNG,
1458 % since irretrievable loss of color data has occurred due to the
1459 % use of premultiplied alpha.
1462 #if defined(__cplusplus) || defined(c_plusplus)
1467 This the function that does the actual reading of data. It is
1468 the same as the one supplied in libpng, except that it receives the
1469 datastream from the ReadBlob() function instead of standard input.
1471 static void png_get_data(png_structp png_ptr,png_bytep data,png_size_t length)
1476 image=(Image *) png_get_io_ptr(png_ptr);
1482 check=(png_size_t) ReadBlob(image,(size_t) length,data);
1483 if (check != length)
1488 (void) FormatLocaleString(msg,MaxTextExtent,
1489 "Expected %.20g bytes; found %.20g bytes",(double) length,
1491 png_warning(png_ptr,msg);
1492 png_error(png_ptr,"Read Exception");
1497 #if !defined(PNG_READ_EMPTY_PLTE_SUPPORTED) && \
1498 !defined(PNG_MNG_FEATURES_SUPPORTED)
1499 /* We use mng_get_data() instead of png_get_data() if we have a libpng
1500 * older than libpng-1.0.3a, which was the first to allow the empty
1501 * PLTE, or a newer libpng in which PNG_MNG_FEATURES_SUPPORTED was
1502 * ifdef'ed out. Earlier versions would crash if the bKGD chunk was
1503 * encountered after an empty PLTE, so we have to look ahead for bKGD
1504 * chunks and remove them from the datastream that is passed to libpng,
1505 * and store their contents for later use.
1507 static void mng_get_data(png_structp png_ptr,png_bytep data,png_size_t length)
1522 mng_info=(MngInfo *) png_get_io_ptr(png_ptr);
1523 image=(Image *) mng_info->image;
1524 while (mng_info->bytes_in_read_buffer && length)
1526 data[i]=mng_info->read_buffer[i];
1527 mng_info->bytes_in_read_buffer--;
1533 check=(png_size_t) ReadBlob(image,(size_t) length,(char *) data);
1535 if (check != length)
1536 png_error(png_ptr,"Read Exception");
1540 if ((data[0] == 0) && (data[1] == 0) && (data[2] == 0) &&
1543 check=(png_size_t) ReadBlob(image,(size_t) length,
1544 (char *) mng_info->read_buffer);
1545 mng_info->read_buffer[4]=0;
1546 mng_info->bytes_in_read_buffer=4;
1547 if (memcmp(mng_info->read_buffer,mng_PLTE,4) == 0)
1548 mng_info->found_empty_plte=MagickTrue;
1549 if (memcmp(mng_info->read_buffer,mng_IEND,4) == 0)
1551 mng_info->found_empty_plte=MagickFalse;
1552 mng_info->have_saved_bkgd_index=MagickFalse;
1556 if ((data[0] == 0) && (data[1] == 0) && (data[2] == 0) &&
1559 check=(png_size_t) ReadBlob(image,(size_t) length,
1560 (char *) mng_info->read_buffer);
1561 mng_info->read_buffer[4]=0;
1562 mng_info->bytes_in_read_buffer=4;
1563 if (memcmp(mng_info->read_buffer,mng_bKGD,4) == 0)
1564 if (mng_info->found_empty_plte)
1567 Skip the bKGD data byte and CRC.
1570 ReadBlob(image,5,(char *) mng_info->read_buffer);
1571 check=(png_size_t) ReadBlob(image,(size_t) length,
1572 (char *) mng_info->read_buffer);
1573 mng_info->saved_bkgd_index=mng_info->read_buffer[0];
1574 mng_info->have_saved_bkgd_index=MagickTrue;
1575 mng_info->bytes_in_read_buffer=0;
1583 static void png_put_data(png_structp png_ptr,png_bytep data,png_size_t length)
1588 image=(Image *) png_get_io_ptr(png_ptr);
1594 check=(png_size_t) WriteBlob(image,(size_t) length,data);
1596 if (check != length)
1597 png_error(png_ptr,"WriteBlob Failed");
1601 static void png_flush_data(png_structp png_ptr)
1606 #ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
1607 static int PalettesAreEqual(Image *a,Image *b)
1612 if ((a == (Image *) NULL) || (b == (Image *) NULL))
1613 return((int) MagickFalse);
1615 if (a->storage_class != PseudoClass || b->storage_class != PseudoClass)
1616 return((int) MagickFalse);
1618 if (a->colors != b->colors)
1619 return((int) MagickFalse);
1621 for (i=0; i < (ssize_t) a->colors; i++)
1623 if ((a->colormap[i].red != b->colormap[i].red) ||
1624 (a->colormap[i].green != b->colormap[i].green) ||
1625 (a->colormap[i].blue != b->colormap[i].blue))
1626 return((int) MagickFalse);
1629 return((int) MagickTrue);
1633 static void MngInfoDiscardObject(MngInfo *mng_info,int i)
1635 if (i && (i < MNG_MAX_OBJECTS) && (mng_info != (MngInfo *) NULL) &&
1636 mng_info->exists[i] && !mng_info->frozen[i])
1638 #ifdef MNG_OBJECT_BUFFERS
1639 if (mng_info->ob[i] != (MngBuffer *) NULL)
1641 if (mng_info->ob[i]->reference_count > 0)
1642 mng_info->ob[i]->reference_count--;
1644 if (mng_info->ob[i]->reference_count == 0)
1646 if (mng_info->ob[i]->image != (Image *) NULL)
1647 mng_info->ob[i]->image=DestroyImage(mng_info->ob[i]->image);
1649 mng_info->ob[i]=DestroyString(mng_info->ob[i]);
1652 mng_info->ob[i]=(MngBuffer *) NULL;
1654 mng_info->exists[i]=MagickFalse;
1655 mng_info->invisible[i]=MagickFalse;
1656 mng_info->viewable[i]=MagickFalse;
1657 mng_info->frozen[i]=MagickFalse;
1658 mng_info->x_off[i]=0;
1659 mng_info->y_off[i]=0;
1660 mng_info->object_clip[i].left=0;
1661 mng_info->object_clip[i].right=(ssize_t) PNG_UINT_31_MAX;
1662 mng_info->object_clip[i].top=0;
1663 mng_info->object_clip[i].bottom=(ssize_t) PNG_UINT_31_MAX;
1667 static void MngInfoFreeStruct(MngInfo *mng_info,
1668 MagickBooleanType *have_mng_structure)
1670 if (*have_mng_structure != MagickFalse && (mng_info != (MngInfo *) NULL))
1675 for (i=1; i < MNG_MAX_OBJECTS; i++)
1676 MngInfoDiscardObject(mng_info,i);
1678 if (mng_info->global_plte != (png_colorp) NULL)
1679 mng_info->global_plte=(png_colorp)
1680 RelinquishMagickMemory(mng_info->global_plte);
1682 mng_info=(MngInfo *) RelinquishMagickMemory(mng_info);
1683 *have_mng_structure=MagickFalse;
1687 static MngBox mng_minimum_box(MngBox box1,MngBox box2)
1693 if (box.left < box2.left)
1696 if (box.top < box2.top)
1699 if (box.right > box2.right)
1700 box.right=box2.right;
1702 if (box.bottom > box2.bottom)
1703 box.bottom=box2.bottom;
1708 static MngBox mng_read_box(MngBox previous_box,char delta_type,unsigned char *p)
1714 Read clipping boundaries from DEFI, CLIP, FRAM, or PAST chunk.
1716 box.left=(ssize_t) ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]);
1717 box.right=(ssize_t) ((p[4] << 24) | (p[5] << 16) | (p[6] << 8) | p[7]);
1718 box.top=(ssize_t) ((p[8] << 24) | (p[9] << 16) | (p[10] << 8) | p[11]);
1719 box.bottom=(ssize_t) ((p[12] << 24) | (p[13] << 16) | (p[14] << 8) | p[15]);
1720 if (delta_type != 0)
1722 box.left+=previous_box.left;
1723 box.right+=previous_box.right;
1724 box.top+=previous_box.top;
1725 box.bottom+=previous_box.bottom;
1731 static MngPair mng_read_pair(MngPair previous_pair,int delta_type,
1737 Read two ssize_ts from CLON, MOVE or PAST chunk
1739 pair.a=(long) ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]);
1740 pair.b=(long) ((p[4] << 24) | (p[5] << 16) | (p[6] << 8) | p[7]);
1742 if (delta_type != 0)
1744 pair.a+=previous_pair.a;
1745 pair.b+=previous_pair.b;
1751 static long mng_get_long(unsigned char *p)
1753 return((long) ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]));
1756 typedef struct _PNGErrorInfo
1765 static void MagickPNGErrorHandler(png_struct *ping,png_const_charp message)
1776 error_info=(PNGErrorInfo *) png_get_error_ptr(ping);
1777 image=error_info->image;
1778 exception=error_info->exception;
1780 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1781 " libpng-%s error: %s", PNG_LIBPNG_VER_STRING,message);
1783 (void) ThrowMagickException(exception,GetMagickModule(),CoderError,message,
1784 "`%s'",image->filename);
1786 #if (PNG_LIBPNG_VER < 10500)
1787 /* A warning about deprecated use of jmpbuf here is unavoidable if you
1788 * are building with libpng-1.4.x and can be ignored.
1790 longjmp(ping->jmpbuf,1);
1792 png_longjmp(ping,1);
1796 static void MagickPNGWarningHandler(png_struct *ping,png_const_charp message)
1807 if (LocaleCompare(message, "Missing PLTE before tRNS") == 0)
1808 png_error(ping, message);
1810 error_info=(PNGErrorInfo *) png_get_error_ptr(ping);
1811 image=error_info->image;
1812 exception=error_info->exception;
1813 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1814 " libpng-%s warning: %s", PNG_LIBPNG_VER_STRING,message);
1816 (void) ThrowMagickException(exception,GetMagickModule(),CoderWarning,
1817 message,"`%s'",image->filename);
1820 #ifdef PNG_USER_MEM_SUPPORTED
1821 #if PNG_LIBPNG_VER >= 14000
1822 static png_voidp Magick_png_malloc(png_structp png_ptr,png_alloc_size_t size)
1824 static png_voidp Magick_png_malloc(png_structp png_ptr,png_size_t size)
1828 return((png_voidp) AcquireMagickMemory((size_t) size));
1832 Free a pointer. It is removed from the list at the same time.
1834 static png_free_ptr Magick_png_free(png_structp png_ptr,png_voidp ptr)
1837 ptr=RelinquishMagickMemory(ptr);
1838 return((png_free_ptr) NULL);
1842 #if defined(__cplusplus) || defined(c_plusplus)
1847 Magick_png_read_raw_profile(png_struct *ping,Image *image,
1848 const ImageInfo *image_info, png_textp text,int ii,ExceptionInfo *exception)
1853 register unsigned char
1867 unhex[103]={0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,
1868 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,
1869 0,0,0,0,0,0,0,0,0,1, 2,3,4,5,6,7,8,9,0,0,
1870 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,
1871 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,10,11,12,
1875 /* look for newline */
1879 /* look for length */
1880 while (*sp == '\0' || *sp == ' ' || *sp == '\n')
1883 length=(png_uint_32) StringToLong(sp);
1885 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1886 " length: %lu",(unsigned long) length);
1888 while (*sp != ' ' && *sp != '\n')
1891 /* allocate space */
1894 png_warning(ping,"invalid profile length");
1895 return(MagickFalse);
1898 profile=BlobToStringInfo((const void *) NULL,length);
1900 if (profile == (StringInfo *) NULL)
1902 png_warning(ping, "unable to copy profile");
1903 return(MagickFalse);
1906 /* copy profile, skipping white space and column 1 "=" signs */
1907 dp=GetStringInfoDatum(profile);
1910 for (i=0; i < (ssize_t) nibbles; i++)
1912 while (*sp < '0' || (*sp > '9' && *sp < 'a') || *sp > 'f')
1916 png_warning(ping, "ran out of profile data");
1917 profile=DestroyStringInfo(profile);
1918 return(MagickFalse);
1924 *dp=(unsigned char) (16*unhex[(int) *sp++]);
1927 (*dp++)+=unhex[(int) *sp++];
1930 We have already read "Raw profile type.
1932 (void) SetImageProfile(image,&text[ii].key[17],profile,exception);
1933 profile=DestroyStringInfo(profile);
1935 if (image_info->verbose)
1936 (void) printf(" Found a generic profile, type %s\n",&text[ii].key[17]);
1941 #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
1942 static int read_vpag_chunk_callback(png_struct *ping, png_unknown_chunkp chunk)
1948 /* The unknown chunk structure contains the chunk data:
1953 Note that libpng has already taken care of the CRC handling.
1957 if (chunk->name[0] != 118 || chunk->name[1] != 112 ||
1958 chunk->name[2] != 65 ||chunk-> name[3] != 103)
1959 return(0); /* Did not recognize */
1961 /* recognized vpAg */
1963 if (chunk->size != 9)
1964 return(-1); /* Error return */
1966 if (chunk->data[8] != 0)
1967 return(0); /* ImageMagick requires pixel units */
1969 image=(Image *) png_get_user_chunk_ptr(ping);
1971 image->page.width=(size_t) ((chunk->data[0] << 24) |
1972 (chunk->data[1] << 16) | (chunk->data[2] << 8) | chunk->data[3]);
1974 image->page.height=(size_t) ((chunk->data[4] << 24) |
1975 (chunk->data[5] << 16) | (chunk->data[6] << 8) | chunk->data[7]);
1977 /* Return one of the following: */
1978 /* return(-n); chunk had an error */
1979 /* return(0); did not recognize */
1980 /* return(n); success */
1988 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1992 % R e a d O n e P N G I m a g e %
1996 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1998 % ReadOnePNGImage() reads a Portable Network Graphics (PNG) image file
1999 % (minus the 8-byte signature) and returns it. It allocates the memory
2000 % necessary for the new Image structure and returns a pointer to the new
2003 % The format of the ReadOnePNGImage method is:
2005 % Image *ReadOnePNGImage(MngInfo *mng_info, const ImageInfo *image_info,
2006 % ExceptionInfo *exception)
2008 % A description of each parameter follows:
2010 % o mng_info: Specifies a pointer to a MngInfo structure.
2012 % o image_info: the image info.
2014 % o exception: return any errors or warnings in this structure.
2017 static Image *ReadOnePNGImage(MngInfo *mng_info,
2018 const ImageInfo *image_info, ExceptionInfo *exception)
2020 /* Read one PNG image */
2022 /* To do: Read the tIME chunk into the date:modify property */
2023 /* To do: Read the tEXt/Creation Time chunk into the date:create property */
2029 intent, /* "PNG Rendering intent", which is ICC intent + 1 */
2039 ping_interlace_method,
2040 ping_compression_method,
2092 register unsigned char
2110 *volatile ping_pixels;
2112 #ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED
2113 png_byte unused_chunks[]=
2115 104, 73, 83, 84, (png_byte) '\0', /* hIST */
2116 105, 84, 88, 116, (png_byte) '\0', /* iTXt */
2117 112, 67, 65, 76, (png_byte) '\0', /* pCAL */
2118 115, 67, 65, 76, (png_byte) '\0', /* sCAL */
2119 115, 80, 76, 84, (png_byte) '\0', /* sPLT */
2120 116, 73, 77, 69, (png_byte) '\0', /* tIME */
2121 #ifdef PNG_APNG_SUPPORTED /* libpng was built with APNG patch; */
2122 /* ignore the APNG chunks */
2123 97, 99, 84, 76, (png_byte) '\0', /* acTL */
2124 102, 99, 84, 76, (png_byte) '\0', /* fcTL */
2125 102, 100, 65, 84, (png_byte) '\0', /* fdAT */
2130 logging=LogMagickEvent(CoderEvent,GetMagickModule(),
2131 " Enter ReadOnePNGImage()");
2133 #if (PNG_LIBPNG_VER < 10200)
2134 if (image_info->verbose)
2135 printf("Your PNG library (libpng-%s) is rather old.\n",
2136 PNG_LIBPNG_VER_STRING);
2139 #if (PNG_LIBPNG_VER >= 10400)
2140 # ifndef PNG_TRANSFORM_GRAY_TO_RGB /* Added at libpng-1.4.0beta67 */
2141 if (image_info->verbose)
2143 printf("Your PNG library (libpng-%s) is an old beta version.\n",
2144 PNG_LIBPNG_VER_STRING);
2145 printf("Please update it.\n");
2151 quantum_info = (QuantumInfo *) NULL;
2152 image=mng_info->image;
2154 if (logging != MagickFalse)
2156 (void)LogMagickEvent(CoderEvent,GetMagickModule(),
2157 " image->alpha_trait=%d",(int) image->alpha_trait);
2159 (void)LogMagickEvent(CoderEvent,GetMagickModule(),
2160 " image->rendering_intent=%d",(int) image->rendering_intent);
2162 (void)LogMagickEvent(CoderEvent,GetMagickModule(),
2163 " image->colorspace=%d",(int) image->colorspace);
2165 intent=Magick_RenderingIntent_to_PNG_RenderingIntent(image->rendering_intent);
2167 /* Set to an out-of-range color unless tRNS chunk is present */
2168 transparent_color.red=65537;
2169 transparent_color.green=65537;
2170 transparent_color.blue=65537;
2171 transparent_color.alpha=65537;
2176 num_raw_profiles = 0;
2178 ping_found_cHRM = MagickFalse;
2179 ping_found_gAMA = MagickFalse;
2180 ping_found_iCCP = MagickFalse;
2181 ping_found_sRGB = MagickFalse;
2184 Allocate the PNG structures
2186 #ifdef PNG_USER_MEM_SUPPORTED
2187 error_info.image=image;
2188 error_info.exception=exception;
2189 ping=png_create_read_struct_2(PNG_LIBPNG_VER_STRING,&error_info,
2190 MagickPNGErrorHandler,MagickPNGWarningHandler, NULL,
2191 (png_malloc_ptr) Magick_png_malloc,(png_free_ptr) Magick_png_free);
2193 ping=png_create_read_struct(PNG_LIBPNG_VER_STRING,&error_info,
2194 MagickPNGErrorHandler,MagickPNGWarningHandler);
2196 if (ping == (png_struct *) NULL)
2197 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2199 ping_info=png_create_info_struct(ping);
2201 if (ping_info == (png_info *) NULL)
2203 png_destroy_read_struct(&ping,(png_info **) NULL,(png_info **) NULL);
2204 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2207 end_info=png_create_info_struct(ping);
2209 if (end_info == (png_info *) NULL)
2211 png_destroy_read_struct(&ping,&ping_info,(png_info **) NULL);
2212 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2215 ping_pixels=(unsigned char *) NULL;
2217 if (setjmp(png_jmpbuf(ping)))
2220 PNG image is corrupt.
2222 png_destroy_read_struct(&ping,&ping_info,&end_info);
2224 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
2225 UnlockSemaphoreInfo(ping_semaphore);
2228 if (ping_pixels != (unsigned char *) NULL)
2229 ping_pixels=(unsigned char *) RelinquishMagickMemory(ping_pixels);
2231 if (logging != MagickFalse)
2232 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2233 " exit ReadOnePNGImage() with error.");
2235 if (image != (Image *) NULL)
2237 InheritException(exception,exception);
2241 return(GetFirstImageInList(image));
2244 /* { For navigation to end of SETJMP-protected block. Within this
2245 * block, use png_error() instead of Throwing an Exception, to ensure
2246 * that libpng is able to clean up, and that the semaphore is unlocked.
2249 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
2250 LockSemaphoreInfo(ping_semaphore);
2254 Prepare PNG for reading.
2257 mng_info->image_found++;
2258 png_set_sig_bytes(ping,8);
2260 if (LocaleCompare(image_info->magick,"MNG") == 0)
2262 #if defined(PNG_MNG_FEATURES_SUPPORTED)
2263 (void) png_permit_mng_features(ping,PNG_ALL_MNG_FEATURES);
2264 png_set_read_fn(ping,image,png_get_data);
2266 #if defined(PNG_READ_EMPTY_PLTE_SUPPORTED)
2267 png_permit_empty_plte(ping,MagickTrue);
2268 png_set_read_fn(ping,image,png_get_data);
2270 mng_info->image=image;
2271 mng_info->bytes_in_read_buffer=0;
2272 mng_info->found_empty_plte=MagickFalse;
2273 mng_info->have_saved_bkgd_index=MagickFalse;
2274 png_set_read_fn(ping,mng_info,mng_get_data);
2280 png_set_read_fn(ping,image,png_get_data);
2282 #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
2283 /* Ignore unused chunks and all unknown chunks except for vpAg */
2284 png_set_keep_unknown_chunks(ping, 1, NULL, 0);
2285 png_set_keep_unknown_chunks(ping, 2, mng_vpAg, 1);
2286 png_set_keep_unknown_chunks(ping, 1, unused_chunks,
2287 (int)sizeof(unused_chunks)/5);
2288 /* Callback for other unknown chunks */
2289 png_set_read_user_chunk_fn(ping, image, read_vpag_chunk_callback);
2292 #ifdef PNG_SET_USER_LIMITS_SUPPORTED
2293 # if (PNG_LIBPNG_VER >= 10400)
2294 /* Limit the size of the chunk storage cache used for sPLT, text,
2295 * and unknown chunks.
2297 png_set_chunk_cache_max(ping, 32767);
2301 #ifdef PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED
2302 /* Disable new libpng-1.5.10 feature */
2303 png_set_check_for_invalid_index (ping, 0);
2306 #if (PNG_LIBPNG_VER < 10400)
2307 # if defined(PNG_USE_PNGGCCRD) && defined(PNG_ASSEMBLER_CODE_SUPPORTED) && \
2308 (PNG_LIBPNG_VER >= 10200) && (PNG_LIBPNG_VER < 10220) && defined(__i386__)
2309 /* Disable thread-unsafe features of pnggccrd */
2310 if (png_access_version_number() >= 10200)
2312 png_uint_32 mmx_disable_mask=0;
2313 png_uint_32 asm_flags;
2315 mmx_disable_mask |= ( PNG_ASM_FLAG_MMX_READ_COMBINE_ROW \
2316 | PNG_ASM_FLAG_MMX_READ_FILTER_SUB \
2317 | PNG_ASM_FLAG_MMX_READ_FILTER_AVG \
2318 | PNG_ASM_FLAG_MMX_READ_FILTER_PAETH );
2319 asm_flags=png_get_asm_flags(ping);
2320 png_set_asm_flags(ping, asm_flags & ~mmx_disable_mask);
2325 png_read_info(ping,ping_info);
2327 png_get_IHDR(ping,ping_info,&ping_width,&ping_height,
2328 &ping_bit_depth,&ping_color_type,
2329 &ping_interlace_method,&ping_compression_method,
2330 &ping_filter_method);
2332 ping_file_depth = ping_bit_depth;
2334 /* Save bit-depth and color-type in case we later want to write a PNG00 */
2339 (void) FormatLocaleString(msg,MaxTextExtent,"%d",(int) ping_color_type);
2340 (void) SetImageProperty(image,"png:IHDR.color-type-orig ",msg,exception);
2342 (void) FormatLocaleString(msg,MaxTextExtent,"%d",(int) ping_bit_depth);
2343 (void) SetImageProperty(image,"png:IHDR.bit-depth-orig ",msg,exception);
2346 (void) png_get_tRNS(ping, ping_info, &ping_trans_alpha, &ping_num_trans,
2349 (void) png_get_bKGD(ping, ping_info, &ping_background);
2351 if (ping_bit_depth < 8)
2353 png_set_packing(ping);
2357 image->depth=ping_bit_depth;
2358 image->depth=GetImageQuantumDepth(image,MagickFalse);
2359 image->interlace=ping_interlace_method != 0 ? PNGInterlace : NoInterlace;
2361 if (((int) ping_color_type == PNG_COLOR_TYPE_GRAY) ||
2362 ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA))
2364 image->rendering_intent=UndefinedIntent;
2365 intent=Magick_RenderingIntent_to_PNG_RenderingIntent(UndefinedIntent);
2367 (void) ResetMagickMemory(&image->chromaticity,0,
2368 sizeof(image->chromaticity));
2371 if (logging != MagickFalse)
2373 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2374 " PNG width: %.20g, height: %.20g",
2375 (double) ping_width, (double) ping_height);
2377 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2378 " PNG color_type: %d, bit_depth: %d",
2379 ping_color_type, ping_bit_depth);
2381 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2382 " PNG compression_method: %d",
2383 ping_compression_method);
2385 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2386 " PNG interlace_method: %d, filter_method: %d",
2387 ping_interlace_method,ping_filter_method);
2390 if (png_get_valid(ping,ping_info,PNG_INFO_gAMA))
2392 ping_found_gAMA=MagickTrue;
2393 if (logging != MagickFalse)
2394 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2395 " Found PNG gAMA chunk.");
2398 if (png_get_valid(ping,ping_info,PNG_INFO_cHRM))
2400 ping_found_cHRM=MagickTrue;
2401 if (logging != MagickFalse)
2402 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2403 " Found PNG cHRM chunk.");
2406 if (png_get_valid(ping,ping_info,PNG_INFO_iCCP))
2408 ping_found_iCCP=MagickTrue;
2409 if (logging != MagickFalse)
2410 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2411 " Found PNG iCCP chunk.");
2414 if (png_get_valid(ping,ping_info,PNG_INFO_sRGB))
2416 ping_found_sRGB=MagickTrue;
2417 if (logging != MagickFalse)
2418 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2419 " Found PNG sRGB chunk.");
2422 #ifdef PNG_READ_iCCP_SUPPORTED
2423 if (png_get_valid(ping,ping_info,PNG_INFO_iCCP))
2428 #if (PNG_LIBPNG_VER < 10500)
2442 (void) png_get_iCCP(ping,ping_info,&name,(int *) &compression,&info,
2445 if (profile_length != 0)
2450 if (logging != MagickFalse)
2451 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2452 " Reading PNG iCCP chunk.");
2453 profile=BlobToStringInfo(info,profile_length);
2454 if (profile == (StringInfo *) NULL)
2456 png_warning(ping, "ICC profile is NULL");
2457 profile=DestroyStringInfo(profile);
2461 (void) SetImageProfile(image,"icc",profile,exception);
2462 profile=DestroyStringInfo(profile);
2467 #if defined(PNG_READ_sRGB_SUPPORTED)
2469 if (mng_info->have_global_srgb)
2471 image->rendering_intent=Magick_RenderingIntent_from_PNG_RenderingIntent
2472 (mng_info->global_srgb_intent);
2475 if (png_get_sRGB(ping,ping_info,&intent))
2477 image->rendering_intent=Magick_RenderingIntent_from_PNG_RenderingIntent
2480 if (logging != MagickFalse)
2481 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2482 " Reading PNG sRGB chunk: rendering_intent: %d",intent);
2487 if (!png_get_gAMA(ping,ping_info,&file_gamma))
2488 if (mng_info->have_global_gama)
2489 png_set_gAMA(ping,ping_info,mng_info->global_gamma);
2491 if (png_get_gAMA(ping,ping_info,&file_gamma))
2493 image->gamma=(float) file_gamma;
2494 if (logging != MagickFalse)
2495 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2496 " Reading PNG gAMA chunk: gamma: %f",file_gamma);
2500 if (!png_get_valid(ping,ping_info,PNG_INFO_cHRM))
2502 if (mng_info->have_global_chrm != MagickFalse)
2504 (void) png_set_cHRM(ping,ping_info,
2505 mng_info->global_chrm.white_point.x,
2506 mng_info->global_chrm.white_point.y,
2507 mng_info->global_chrm.red_primary.x,
2508 mng_info->global_chrm.red_primary.y,
2509 mng_info->global_chrm.green_primary.x,
2510 mng_info->global_chrm.green_primary.y,
2511 mng_info->global_chrm.blue_primary.x,
2512 mng_info->global_chrm.blue_primary.y);
2516 if (png_get_valid(ping,ping_info,PNG_INFO_cHRM))
2518 (void) png_get_cHRM(ping,ping_info,
2519 &image->chromaticity.white_point.x,
2520 &image->chromaticity.white_point.y,
2521 &image->chromaticity.red_primary.x,
2522 &image->chromaticity.red_primary.y,
2523 &image->chromaticity.green_primary.x,
2524 &image->chromaticity.green_primary.y,
2525 &image->chromaticity.blue_primary.x,
2526 &image->chromaticity.blue_primary.y);
2528 ping_found_cHRM=MagickTrue;
2531 if (image->rendering_intent != UndefinedIntent)
2533 if (ping_found_sRGB != MagickTrue)
2535 png_set_sRGB(ping,ping_info,
2536 Magick_RenderingIntent_to_PNG_RenderingIntent
2537 (image->rendering_intent));
2538 png_set_gAMA(ping,ping_info,1.000f/2.200f);
2539 file_gamma=1.000f/2.200f;
2540 ping_found_sRGB=MagickTrue;
2541 ping_found_cHRM=MagickTrue;
2545 #if defined(PNG_oFFs_SUPPORTED)
2546 if (png_get_valid(ping,ping_info,PNG_INFO_oFFs))
2548 image->page.x=(ssize_t) png_get_x_offset_pixels(ping, ping_info);
2549 image->page.y=(ssize_t) png_get_y_offset_pixels(ping, ping_info);
2551 if (logging != MagickFalse)
2552 if (image->page.x || image->page.y)
2553 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2554 " Reading PNG oFFs chunk: x: %.20g, y: %.20g.",(double)
2555 image->page.x,(double) image->page.y);
2558 #if defined(PNG_pHYs_SUPPORTED)
2559 if (!png_get_valid(ping,ping_info,PNG_INFO_pHYs))
2561 if (mng_info->have_global_phys)
2563 png_set_pHYs(ping,ping_info,
2564 mng_info->global_x_pixels_per_unit,
2565 mng_info->global_y_pixels_per_unit,
2566 mng_info->global_phys_unit_type);
2570 if (png_get_valid(ping,ping_info,PNG_INFO_pHYs))
2573 Set image resolution.
2575 (void) png_get_pHYs(ping,ping_info,&x_resolution,&y_resolution,
2577 image->resolution.x=(double) x_resolution;
2578 image->resolution.y=(double) y_resolution;
2580 if (unit_type == PNG_RESOLUTION_METER)
2582 image->units=PixelsPerCentimeterResolution;
2583 image->resolution.x=(double) x_resolution/100.0;
2584 image->resolution.y=(double) y_resolution/100.0;
2587 if (logging != MagickFalse)
2588 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2589 " Reading PNG pHYs chunk: xres: %.20g, yres: %.20g, units: %d.",
2590 (double) x_resolution,(double) y_resolution,unit_type);
2594 if (png_get_valid(ping,ping_info,PNG_INFO_PLTE))
2599 (void) png_get_PLTE(ping,ping_info,&palette,&number_colors);
2601 if ((number_colors == 0) &&
2602 ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE))
2604 if (mng_info->global_plte_length)
2606 png_set_PLTE(ping,ping_info,mng_info->global_plte,
2607 (int) mng_info->global_plte_length);
2609 if (!png_get_valid(ping,ping_info,PNG_INFO_tRNS))
2611 if (mng_info->global_trns_length)
2614 "global tRNS has more entries than global PLTE");
2618 png_set_tRNS(ping,ping_info,mng_info->global_trns,
2619 (int) mng_info->global_trns_length,NULL);
2622 #ifdef PNG_READ_bKGD_SUPPORTED
2624 #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
2625 mng_info->have_saved_bkgd_index ||
2627 png_get_valid(ping,ping_info,PNG_INFO_bKGD))
2632 #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
2633 if (mng_info->have_saved_bkgd_index)
2634 background.index=mng_info->saved_bkgd_index;
2636 if (png_get_valid(ping, ping_info, PNG_INFO_bKGD))
2637 background.index=ping_background->index;
2639 background.red=(png_uint_16)
2640 mng_info->global_plte[background.index].red;
2642 background.green=(png_uint_16)
2643 mng_info->global_plte[background.index].green;
2645 background.blue=(png_uint_16)
2646 mng_info->global_plte[background.index].blue;
2648 background.gray=(png_uint_16)
2649 mng_info->global_plte[background.index].green;
2651 png_set_bKGD(ping,ping_info,&background);
2656 png_error(ping,"No global PLTE in file");
2660 #ifdef PNG_READ_bKGD_SUPPORTED
2661 if (mng_info->have_global_bkgd &&
2662 (!png_get_valid(ping,ping_info,PNG_INFO_bKGD)))
2663 image->background_color=mng_info->mng_global_bkgd;
2665 if (png_get_valid(ping,ping_info,PNG_INFO_bKGD))
2671 Set image background color.
2673 if (logging != MagickFalse)
2674 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2675 " Reading PNG bKGD chunk.");
2677 /* Scale background components to 16-bit, then scale
2680 if (logging != MagickFalse)
2681 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2682 " raw ping_background=(%d,%d,%d).",ping_background->red,
2683 ping_background->green,ping_background->blue);
2687 if (ping_file_depth == 1)
2690 else if (ping_file_depth == 2)
2693 else if (ping_file_depth == 4)
2696 if (ping_file_depth <= 8)
2699 ping_background->red *= bkgd_scale;
2700 ping_background->green *= bkgd_scale;
2701 ping_background->blue *= bkgd_scale;
2703 if (logging != MagickFalse)
2705 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2706 " bkgd_scale=%d.",bkgd_scale);
2708 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2709 " ping_background=(%d,%d,%d).",ping_background->red,
2710 ping_background->green,ping_background->blue);
2713 image->background_color.red=
2714 ScaleShortToQuantum(ping_background->red);
2716 image->background_color.green=
2717 ScaleShortToQuantum(ping_background->green);
2719 image->background_color.blue=
2720 ScaleShortToQuantum(ping_background->blue);
2722 image->background_color.alpha=OpaqueAlpha;
2724 if (logging != MagickFalse)
2725 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2726 " image->background_color=(%.20g,%.20g,%.20g).",
2727 (double) image->background_color.red,
2728 (double) image->background_color.green,
2729 (double) image->background_color.blue);
2731 #endif /* PNG_READ_bKGD_SUPPORTED */
2733 if (png_get_valid(ping,ping_info,PNG_INFO_tRNS))
2736 Image has a tRNS chunk.
2744 if (logging != MagickFalse)
2745 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2746 " Reading PNG tRNS chunk.");
2748 max_sample = (int) ((one << ping_file_depth) - 1);
2750 if ((ping_color_type == PNG_COLOR_TYPE_GRAY &&
2751 (int)ping_trans_color->gray > max_sample) ||
2752 (ping_color_type == PNG_COLOR_TYPE_RGB &&
2753 ((int)ping_trans_color->red > max_sample ||
2754 (int)ping_trans_color->green > max_sample ||
2755 (int)ping_trans_color->blue > max_sample)))
2757 if (logging != MagickFalse)
2758 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2759 " Ignoring PNG tRNS chunk with out-of-range sample.");
2760 png_free_data(ping, ping_info, PNG_FREE_TRNS, 0);
2761 png_set_invalid(ping,ping_info,PNG_INFO_tRNS);
2762 image->alpha_trait=UndefinedPixelTrait;
2769 scale_to_short = 65535L/((1UL << ping_file_depth)-1);
2771 /* Scale transparent_color to short */
2772 transparent_color.red= scale_to_short*ping_trans_color->red;
2773 transparent_color.green= scale_to_short*ping_trans_color->green;
2774 transparent_color.blue= scale_to_short*ping_trans_color->blue;
2775 transparent_color.alpha= scale_to_short*ping_trans_color->gray;
2777 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
2779 if (logging != MagickFalse)
2781 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2782 " Raw tRNS graylevel is %d.",ping_trans_color->gray);
2784 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2785 " scaled graylevel is %.20g.",transparent_color.alpha);
2787 transparent_color.red=transparent_color.alpha;
2788 transparent_color.green=transparent_color.alpha;
2789 transparent_color.blue=transparent_color.alpha;
2793 #if defined(PNG_READ_sBIT_SUPPORTED)
2794 if (mng_info->have_global_sbit)
2796 if (!png_get_valid(ping,ping_info,PNG_INFO_sBIT))
2797 png_set_sBIT(ping,ping_info,&mng_info->global_sbit);
2800 num_passes=png_set_interlace_handling(ping);
2802 png_read_update_info(ping,ping_info);
2804 ping_rowbytes=png_get_rowbytes(ping,ping_info);
2807 Initialize image structure.
2809 mng_info->image_box.left=0;
2810 mng_info->image_box.right=(ssize_t) ping_width;
2811 mng_info->image_box.top=0;
2812 mng_info->image_box.bottom=(ssize_t) ping_height;
2813 if (mng_info->mng_type == 0)
2815 mng_info->mng_width=ping_width;
2816 mng_info->mng_height=ping_height;
2817 mng_info->frame=mng_info->image_box;
2818 mng_info->clip=mng_info->image_box;
2823 image->page.y=mng_info->y_off[mng_info->object_id];
2826 image->compression=ZipCompression;
2827 image->columns=ping_width;
2828 image->rows=ping_height;
2830 if (((int) ping_color_type == PNG_COLOR_TYPE_GRAY) ||
2831 ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA))
2833 if ((!png_get_valid(ping,ping_info,PNG_INFO_gAMA) ||
2834 image->gamma == 1.0) &&
2835 ping_found_cHRM != MagickTrue && ping_found_sRGB != MagickTrue)
2837 /* Set image->gamma to 1.0, image->rendering_intent to Undefined,
2838 * image->colorspace to GRAY, and reset image->chromaticity.
2840 SetImageColorspace(image,GRAYColorspace,exception);
2844 (void)LogMagickEvent(CoderEvent,GetMagickModule(),
2845 " image->colorspace=%d",(int) image->colorspace);
2847 if (((int) ping_color_type == PNG_COLOR_TYPE_PALETTE) ||
2848 ((int) ping_bit_depth < 16 &&
2849 (int) ping_color_type == PNG_COLOR_TYPE_GRAY))
2854 image->storage_class=PseudoClass;
2856 image->colors=one << ping_file_depth;
2857 #if (MAGICKCORE_QUANTUM_DEPTH == 8)
2858 if (image->colors > 256)
2861 if (image->colors > 65536L)
2862 image->colors=65536L;
2864 if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
2869 (void) png_get_PLTE(ping,ping_info,&palette,&number_colors);
2870 image->colors=(size_t) number_colors;
2872 if (logging != MagickFalse)
2873 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2874 " Reading PNG PLTE chunk: number_colors: %d.",number_colors);
2878 if (image->storage_class == PseudoClass)
2881 Initialize image colormap.
2883 if (AcquireImageColormap(image,image->colors,exception) == MagickFalse)
2884 png_error(ping,"Memory allocation failed");
2886 if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
2891 (void) png_get_PLTE(ping,ping_info,&palette,&number_colors);
2893 for (i=0; i < (ssize_t) number_colors; i++)
2895 image->colormap[i].red=ScaleCharToQuantum(palette[i].red);
2896 image->colormap[i].green=ScaleCharToQuantum(palette[i].green);
2897 image->colormap[i].blue=ScaleCharToQuantum(palette[i].blue);
2900 for ( ; i < (ssize_t) image->colors; i++)
2902 image->colormap[i].red=0;
2903 image->colormap[i].green=0;
2904 image->colormap[i].blue=0;
2913 scale=(QuantumRange/((1UL << ping_file_depth)-1));
2918 for (i=0; i < (ssize_t) image->colors; i++)
2920 image->colormap[i].red=(Quantum) (i*scale);
2921 image->colormap[i].green=(Quantum) (i*scale);
2922 image->colormap[i].blue=(Quantum) (i*scale);
2927 /* Set some properties for reporting by "identify" */
2932 /* encode ping_width, ping_height, ping_file_depth, ping_color_type,
2933 ping_interlace_method in value */
2935 (void) FormatLocaleString(msg,MaxTextExtent,
2936 "%d, %d",(int) ping_width, (int) ping_height);
2937 (void) SetImageProperty(image,"png:IHDR.width,height ",msg,exception);
2939 (void) FormatLocaleString(msg,MaxTextExtent,"%d",(int) ping_file_depth);
2940 (void) SetImageProperty(image,"png:IHDR.bit_depth ",msg,exception);
2942 (void) FormatLocaleString(msg,MaxTextExtent,"%d (%s)",
2943 (int) ping_color_type,
2944 Magick_ColorType_from_PNG_ColorType((int)ping_color_type));
2945 (void) SetImageProperty(image,"png:IHDR.color_type ",msg,exception);
2947 if (ping_interlace_method == 0)
2949 (void) FormatLocaleString(msg,MaxTextExtent,"%d (Not interlaced)",
2950 (int) ping_interlace_method);
2952 else if (ping_interlace_method == 1)
2954 (void) FormatLocaleString(msg,MaxTextExtent,"%d (Adam7 method)",
2955 (int) ping_interlace_method);
2959 (void) FormatLocaleString(msg,MaxTextExtent,"%d (Unknown method)",
2960 (int) ping_interlace_method);
2962 (void) SetImageProperty(image,"png:IHDR.interlace_method",msg,exception);
2964 if (number_colors != 0)
2966 (void) FormatLocaleString(msg,MaxTextExtent,"%d",
2967 (int) number_colors);
2968 (void) SetImageProperty(image,"png:PLTE.number_colors ",msg,
2974 Read image scanlines.
2976 if (image->delay != 0)
2977 mng_info->scenes_found++;
2979 if ((mng_info->mng_type == 0 && (image->ping != MagickFalse)) || (
2980 (image_info->number_scenes != 0) && (mng_info->scenes_found > (ssize_t)
2981 (image_info->first_scene+image_info->number_scenes))))
2983 /* This happens later in non-ping decodes */
2984 if (png_get_valid(ping,ping_info,PNG_INFO_tRNS))
2985 image->storage_class=DirectClass;
2987 if (logging != MagickFalse)
2988 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2989 " Skipping PNG image data for scene %.20g",(double)
2990 mng_info->scenes_found-1);
2991 png_destroy_read_struct(&ping,&ping_info,&end_info);
2993 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
2994 UnlockSemaphoreInfo(ping_semaphore);
2997 if (logging != MagickFalse)
2998 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2999 " exit ReadOnePNGImage().");
3004 if (logging != MagickFalse)
3005 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3006 " Reading PNG IDAT chunk(s)");
3009 ping_pixels=(unsigned char *) AcquireQuantumMemory(image->rows,
3010 ping_rowbytes*sizeof(*ping_pixels));
3013 ping_pixels=(unsigned char *) AcquireQuantumMemory(ping_rowbytes,
3014 sizeof(*ping_pixels));
3016 if (ping_pixels == (unsigned char *) NULL)
3017 png_error(ping,"Memory allocation failed");
3019 if (logging != MagickFalse)
3020 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3021 " Converting PNG pixels to pixel packets");
3023 Convert PNG pixels to pixel packets.
3025 quantum_info=AcquireQuantumInfo(image_info,image);
3027 if (quantum_info == (QuantumInfo *) NULL)
3028 png_error(ping,"Failed to allocate quantum_info");
3030 (void) SetQuantumEndian(image,quantum_info,MSBEndian);
3035 found_transparent_pixel;
3037 found_transparent_pixel=MagickFalse;
3039 if (image->storage_class == DirectClass)
3041 for (pass=0; pass < num_passes; pass++)
3044 Convert image to DirectClass pixel packets.
3046 image->alpha_trait=(((int) ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA) ||
3047 ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) ||
3048 (png_get_valid(ping,ping_info,PNG_INFO_tRNS))) ?
3049 BlendPixelTrait : UndefinedPixelTrait;
3051 for (y=0; y < (ssize_t) image->rows; y++)
3054 row_offset=ping_rowbytes*y;
3059 png_read_row(ping,ping_pixels+row_offset,NULL);
3061 if (pass < num_passes-1)
3064 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
3066 if (q == (Quantum *) NULL)
3069 if ((int) ping_color_type == PNG_COLOR_TYPE_GRAY)
3070 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
3071 GrayQuantum,ping_pixels+row_offset,exception);
3073 else if ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
3074 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
3075 GrayAlphaQuantum,ping_pixels+row_offset,exception);
3077 else if ((int) ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA)
3078 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
3079 RGBAQuantum,ping_pixels+row_offset,exception);
3081 else if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
3082 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
3083 IndexQuantum,ping_pixels+row_offset,exception);
3085 else /* ping_color_type == PNG_COLOR_TYPE_RGB */
3086 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
3087 RGBQuantum,ping_pixels+row_offset,exception);
3089 if (found_transparent_pixel == MagickFalse)
3091 /* Is there a transparent pixel in the row? */
3092 if (y== 0 && logging != MagickFalse)
3093 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3094 " Looking for cheap transparent pixel");
3096 for (x=(ssize_t) image->columns-1; x >= 0; x--)
3098 if ((ping_color_type == PNG_COLOR_TYPE_RGBA ||
3099 ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) &&
3100 (GetPixelAlpha(image,q) != OpaqueAlpha))
3102 if (logging != MagickFalse)
3103 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3106 found_transparent_pixel = MagickTrue;
3109 if ((ping_color_type == PNG_COLOR_TYPE_RGB ||
3110 ping_color_type == PNG_COLOR_TYPE_GRAY) &&
3111 (ScaleQuantumToShort(GetPixelRed(image,q)) ==
3112 transparent_color.red &&
3113 ScaleQuantumToShort(GetPixelGreen(image,q)) ==
3114 transparent_color.green &&
3115 ScaleQuantumToShort(GetPixelBlue(image,q)) ==
3116 transparent_color.blue))
3118 if (logging != MagickFalse)
3119 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3121 found_transparent_pixel = MagickTrue;
3124 q+=GetPixelChannels(image);
3128 if ((image->previous == (Image *) NULL) && (num_passes == 1))
3130 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
3133 if (status == MagickFalse)
3136 if (SyncAuthenticPixels(image,exception) == MagickFalse)
3140 if ((image->previous == (Image *) NULL) && (num_passes != 1))
3142 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
3143 if (status == MagickFalse)
3149 else /* image->storage_class != DirectClass */
3151 for (pass=0; pass < num_passes; pass++)
3160 Convert grayscale image to PseudoClass pixel packets.
3162 if (logging != MagickFalse)
3163 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3164 " Converting grayscale pixels to pixel packets");
3166 image->alpha_trait=ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA ?
3167 BlendPixelTrait : UndefinedPixelTrait;
3169 quantum_scanline=(Quantum *) AcquireQuantumMemory(image->columns,
3170 (image->alpha_trait == BlendPixelTrait? 2 : 1)*
3171 sizeof(*quantum_scanline));
3173 if (quantum_scanline == (Quantum *) NULL)
3174 png_error(ping,"Memory allocation failed");
3176 for (y=0; y < (ssize_t) image->rows; y++)
3182 row_offset=ping_rowbytes*y;
3187 png_read_row(ping,ping_pixels+row_offset,NULL);
3189 if (pass < num_passes-1)
3192 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
3194 if (q == (Quantum *) NULL)
3197 p=ping_pixels+row_offset;
3200 switch (ping_bit_depth)
3205 if (ping_color_type == 4)
3206 for (x=(ssize_t) image->columns-1; x >= 0; x--)
3210 alpha=ScaleCharToQuantum((unsigned char)*p++);
3212 SetPixelAlpha(image,alpha,q);
3214 if (alpha != OpaqueAlpha)
3215 found_transparent_pixel = MagickTrue;
3217 q+=GetPixelChannels(image);
3221 for (x=(ssize_t) image->columns-1; x >= 0; x--)
3229 for (x=(ssize_t) image->columns-1; x >= 0; x--)
3231 #if (MAGICKCORE_QUANTUM_DEPTH == 16) || (MAGICKCORE_QUANTUM_DEPTH == 32)
3235 if (image->colors > 256)
3236 quantum=((*p++) << 8);
3242 *r=ScaleShortToQuantum(quantum);
3245 if (ping_color_type == 4)
3247 if (image->colors > 256)
3248 quantum=((*p++) << 8);
3254 alpha=ScaleShortToQuantum(quantum);
3255 SetPixelAlpha(image,alpha,q);
3257 if (alpha != OpaqueAlpha)
3258 found_transparent_pixel = MagickTrue;
3260 q+=GetPixelChannels(image);
3263 #else /* MAGICKCORE_QUANTUM_DEPTH == 8 */
3265 p++; /* strip low byte */
3267 if (ping_color_type == 4)
3269 SetPixelAlpha(image,*p++,q);
3271 if (GetPixelAlpha(image,q) != OpaqueAlpha)
3272 found_transparent_pixel = MagickTrue;
3275 q+=GetPixelChannels(image);
3288 Transfer image scanline.
3292 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
3294 if (q == (Quantum *) NULL)
3296 for (x=0; x < (ssize_t) image->columns; x++)
3298 SetPixelIndex(image,*r++,q);
3299 q+=GetPixelChannels(image);
3302 if (SyncAuthenticPixels(image,exception) == MagickFalse)
3305 if ((image->previous == (Image *) NULL) && (num_passes == 1))
3307 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
3310 if (status == MagickFalse)
3315 if ((image->previous == (Image *) NULL) && (num_passes != 1))
3317 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
3319 if (status == MagickFalse)
3323 quantum_scanline=(Quantum *) RelinquishMagickMemory(quantum_scanline);
3326 image->alpha_trait=found_transparent_pixel ? BlendPixelTrait :
3327 UndefinedPixelTrait;
3329 if (logging != MagickFalse)
3331 if (found_transparent_pixel != MagickFalse)
3332 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3333 " Found transparent pixel");
3336 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3337 " No transparent pixel was found");
3339 ping_color_type&=0x03;
3344 if (quantum_info != (QuantumInfo *) NULL)
3345 quantum_info=DestroyQuantumInfo(quantum_info);
3347 if (image->storage_class == PseudoClass)
3352 alpha_trait=image->alpha_trait;
3353 image->alpha_trait=UndefinedPixelTrait;
3354 (void) SyncImage(image,exception);
3355 image->alpha_trait=alpha_trait;
3358 png_read_end(ping,end_info);
3360 if (image_info->number_scenes != 0 && mng_info->scenes_found-1 <
3361 (ssize_t) image_info->first_scene && image->delay != 0)
3363 png_destroy_read_struct(&ping,&ping_info,&end_info);
3364 ping_pixels=(unsigned char *) RelinquishMagickMemory(ping_pixels);
3366 (void) SetImageBackgroundColor(image,exception);
3367 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
3368 UnlockSemaphoreInfo(ping_semaphore);
3370 if (logging != MagickFalse)
3371 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3372 " exit ReadOnePNGImage() early.");
3376 if (png_get_valid(ping,ping_info,PNG_INFO_tRNS))
3382 Image has a transparent background.
3384 storage_class=image->storage_class;
3385 image->alpha_trait=BlendPixelTrait;
3387 /* Balfour fix from imagemagick discourse server, 5 Feb 2010 */
3389 if (storage_class == PseudoClass)
3391 if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
3393 for (x=0; x < ping_num_trans; x++)
3395 image->colormap[x].alpha_trait=BlendPixelTrait;
3396 image->colormap[x].alpha =
3397 ScaleCharToQuantum((unsigned char)ping_trans_alpha[x]);
3401 else if (ping_color_type == PNG_COLOR_TYPE_GRAY)
3403 for (x=0; x < (int) image->colors; x++)
3405 if (ScaleQuantumToShort(image->colormap[x].red) ==
3406 transparent_color.alpha)
3408 image->colormap[x].alpha_trait=BlendPixelTrait;
3409 image->colormap[x].alpha = (Quantum) TransparentAlpha;
3413 (void) SyncImage(image,exception);
3416 #if 1 /* Should have already been done above, but glennrp problem P10
3421 for (y=0; y < (ssize_t) image->rows; y++)
3423 image->storage_class=storage_class;
3424 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
3426 if (q == (Quantum *) NULL)
3430 /* Caution: on a Q8 build, this does not distinguish between
3431 * 16-bit colors that differ only in the low byte
3433 for (x=(ssize_t) image->columns-1; x >= 0; x--)
3435 if (ScaleQuantumToShort(GetPixelRed(image,q)) ==
3436 transparent_color.red &&
3437 ScaleQuantumToShort(GetPixelGreen(image,q)) ==
3438 transparent_color.green &&
3439 ScaleQuantumToShort(GetPixelBlue(image,q)) ==
3440 transparent_color.blue)
3442 SetPixelAlpha(image,TransparentAlpha,q);
3445 #if 0 /* I have not found a case where this is needed. */
3448 SetPixelAlpha(image,q)=(Quantum) OpaqueAlpha;
3452 q+=GetPixelChannels(image);
3455 if (SyncAuthenticPixels(image,exception) == MagickFalse)
3461 image->storage_class=DirectClass;
3464 for (j = 0; j < 2; j++)
3467 status = png_get_text(ping,ping_info,&text,&num_text) != 0 ?
3468 MagickTrue : MagickFalse;
3470 status = png_get_text(ping,end_info,&text,&num_text) != 0 ?
3471 MagickTrue : MagickFalse;
3473 if (status != MagickFalse)
3474 for (i=0; i < (ssize_t) num_text; i++)
3476 /* Check for a profile */
3478 if (logging != MagickFalse)
3479 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3480 " Reading PNG text chunk");
3482 if (memcmp(text[i].key, "Raw profile type ",17) == 0)
3484 (void) Magick_png_read_raw_profile(ping,image,image_info,text,
3494 length=text[i].text_length;
3495 value=(char *) AcquireQuantumMemory(length+MaxTextExtent,
3497 if (value == (char *) NULL)
3499 png_error(ping,"Memory allocation failed");
3503 (void) ConcatenateMagickString(value,text[i].text,length+2);
3505 /* Don't save "density" or "units" property if we have a pHYs
3508 if (!png_get_valid(ping,ping_info,PNG_INFO_pHYs) ||
3509 (LocaleCompare(text[i].key,"density") != 0 &&
3510 LocaleCompare(text[i].key,"units") != 0))
3511 (void) SetImageProperty(image,text[i].key,value,exception);
3513 if (logging != MagickFalse)
3515 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3516 " length: %lu",(unsigned long) length);
3517 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3518 " Keyword: %s",text[i].key);
3521 value=DestroyString(value);
3524 num_text_total += num_text;
3527 #ifdef MNG_OBJECT_BUFFERS
3529 Store the object if necessary.
3531 if (object_id && !mng_info->frozen[object_id])
3533 if (mng_info->ob[object_id] == (MngBuffer *) NULL)
3536 create a new object buffer.
3538 mng_info->ob[object_id]=(MngBuffer *)
3539 AcquireMagickMemory(sizeof(MngBuffer));
3541 if (mng_info->ob[object_id] != (MngBuffer *) NULL)
3543 mng_info->ob[object_id]->image=(Image *) NULL;
3544 mng_info->ob[object_id]->reference_count=1;
3548 if ((mng_info->ob[object_id] == (MngBuffer *) NULL) ||
3549 mng_info->ob[object_id]->frozen)
3551 if (mng_info->ob[object_id] == (MngBuffer *) NULL)
3552 png_error(ping,"Memory allocation failed");
3554 if (mng_info->ob[object_id]->frozen)
3555 png_error(ping,"Cannot overwrite frozen MNG object buffer");
3561 if (mng_info->ob[object_id]->image != (Image *) NULL)
3562 mng_info->ob[object_id]->image=DestroyImage
3563 (mng_info->ob[object_id]->image);
3565 mng_info->ob[object_id]->image=CloneImage(image,0,0,MagickTrue,
3568 if (mng_info->ob[object_id]->image != (Image *) NULL)
3569 mng_info->ob[object_id]->image->file=(FILE *) NULL;
3572 png_error(ping, "Cloning image for object buffer failed");
3574 if (ping_width > 250000L || ping_height > 250000L)
3575 png_error(ping,"PNG Image dimensions are too large.");
3577 mng_info->ob[object_id]->width=ping_width;
3578 mng_info->ob[object_id]->height=ping_height;
3579 mng_info->ob[object_id]->color_type=ping_color_type;
3580 mng_info->ob[object_id]->sample_depth=ping_bit_depth;
3581 mng_info->ob[object_id]->interlace_method=ping_interlace_method;
3582 mng_info->ob[object_id]->compression_method=
3583 ping_compression_method;
3584 mng_info->ob[object_id]->filter_method=ping_filter_method;
3586 if (png_get_valid(ping,ping_info,PNG_INFO_PLTE))
3592 Copy the PLTE to the object buffer.
3594 png_get_PLTE(ping,ping_info,&plte,&number_colors);
3595 mng_info->ob[object_id]->plte_length=number_colors;
3597 for (i=0; i < number_colors; i++)
3599 mng_info->ob[object_id]->plte[i]=plte[i];
3604 mng_info->ob[object_id]->plte_length=0;
3609 /* Set image->alpha_trait to MagickTrue if the input colortype supports
3610 * alpha or if a valid tRNS chunk is present, no matter whether there
3611 * is actual transparency present.
3613 image->alpha_trait=(((int) ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA) ||
3614 ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) ||
3615 (png_get_valid(ping,ping_info,PNG_INFO_tRNS))) ?
3616 BlendPixelTrait : UndefinedPixelTrait;
3618 #if 0 /* I'm not sure what's wrong here but it does not work. */
3619 if (image->alpha_trait == BlendPixelTrait)
3621 if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
3622 (void) SetImageType(image,GrayscaleMatteType,exception);
3624 else if (ping_color_type == PNG_COLOR_TYPE_PALETTE)
3625 (void) SetImageType(image,PaletteMatteType,exception);
3628 (void) SetImageType(image,TrueColorMatteType,exception);
3633 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
3634 (void) SetImageType(image,GrayscaleType,exception);
3636 else if (ping_color_type == PNG_COLOR_TYPE_PALETTE)
3637 (void) SetImageType(image,PaletteType,exception);
3640 (void) SetImageType(image,TrueColorType,exception);
3644 /* Set more properties for identify to retrieve */
3649 if (num_text_total != 0)
3651 /* libpng doesn't tell us whether they were tEXt, zTXt, or iTXt */
3652 (void) FormatLocaleString(msg,MaxTextExtent,
3653 "%d tEXt/zTXt/iTXt chunks were found", num_text_total);
3654 (void) SetImageProperty(image,"png:text ",msg,
3658 if (num_raw_profiles != 0)
3660 (void) FormatLocaleString(msg,MaxTextExtent,
3661 "%d were found", num_raw_profiles);
3662 (void) SetImageProperty(image,"png:text-encoded profiles",msg,
3666 if (ping_found_cHRM != MagickFalse)
3668 (void) FormatLocaleString(msg,MaxTextExtent,"%s",
3669 "chunk was found (see Chromaticity, above)");
3670 (void) SetImageProperty(image,"png:cHRM ",msg,
3674 if (png_get_valid(ping,ping_info,PNG_INFO_bKGD))
3676 (void) FormatLocaleString(msg,MaxTextExtent,"%s",
3677 "chunk was found (see Background color, above)");
3678 (void) SetImageProperty(image,"png:bKGD ",msg,
3682 (void) FormatLocaleString(msg,MaxTextExtent,"%s",
3685 #if defined(PNG_iCCP_SUPPORTED)
3686 if (ping_found_iCCP != MagickFalse)
3687 (void) SetImageProperty(image,"png:iCCP ",msg,
3691 if (png_get_valid(ping,ping_info,PNG_INFO_tRNS))
3692 (void) SetImageProperty(image,"png:tRNS ",msg,
3695 #if defined(PNG_sRGB_SUPPORTED)
3696 if (ping_found_sRGB != MagickFalse)
3698 (void) FormatLocaleString(msg,MaxTextExtent,
3701 Magick_RenderingIntentString_from_PNG_RenderingIntent(intent));
3702 (void) SetImageProperty(image,"png:sRGB ",msg,
3707 if (ping_found_gAMA != MagickFalse)
3709 (void) FormatLocaleString(msg,MaxTextExtent,
3710 "gamma=%.8g (See Gamma, above)",
3712 (void) SetImageProperty(image,"png:gAMA ",msg,
3716 #if defined(PNG_pHYs_SUPPORTED)
3717 if (png_get_valid(ping,ping_info,PNG_INFO_pHYs))
3719 (void) FormatLocaleString(msg,MaxTextExtent,
3720 "x_res=%.10g, y_res=%.10g, units=%d",
3721 (double) x_resolution,(double) y_resolution, unit_type);
3722 (void) SetImageProperty(image,"png:pHYs ",msg,
3727 #if defined(PNG_oFFs_SUPPORTED)
3728 if (png_get_valid(ping,ping_info,PNG_INFO_oFFs))
3730 (void) FormatLocaleString(msg,MaxTextExtent,"x_off=%.20g, y_off=%.20g",
3731 (double) image->page.x,(double) image->page.y);
3732 (void) SetImageProperty(image,"png:oFFs ",msg,
3737 if ((image->page.width != 0 && image->page.width != image->columns) ||
3738 (image->page.height != 0 && image->page.height != image->rows))
3740 (void) FormatLocaleString(msg,MaxTextExtent,
3741 "width=%.20g, height=%.20g",
3742 (double) image->page.width,(double) image->page.height);
3743 (void) SetImageProperty(image,"png:vpAg ",msg,
3749 Relinquish resources.
3751 png_destroy_read_struct(&ping,&ping_info,&end_info);
3753 ping_pixels=(unsigned char *) RelinquishMagickMemory(ping_pixels);
3755 if (logging != MagickFalse)
3756 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3757 " exit ReadOnePNGImage()");
3759 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
3760 UnlockSemaphoreInfo(ping_semaphore);
3763 /* } for navigation to beginning of SETJMP-protected block, revert to
3764 * Throwing an Exception when an error occurs.
3769 /* end of reading one PNG image */
3772 static Image *ReadPNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
3787 magic_number[MaxTextExtent];
3795 assert(image_info != (const ImageInfo *) NULL);
3796 assert(image_info->signature == MagickSignature);
3798 if (image_info->debug != MagickFalse)
3799 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
3800 image_info->filename);
3802 assert(exception != (ExceptionInfo *) NULL);
3803 assert(exception->signature == MagickSignature);
3804 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter ReadPNGImage()");
3805 image=AcquireImage(image_info,exception);
3806 mng_info=(MngInfo *) NULL;
3807 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
3809 if (status == MagickFalse)
3810 ThrowReaderException(FileOpenError,"UnableToOpenFile");
3813 Verify PNG signature.
3815 count=ReadBlob(image,8,(unsigned char *) magic_number);
3817 if (count < 8 || memcmp(magic_number,"\211PNG\r\n\032\n",8) != 0)
3818 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
3821 Allocate a MngInfo structure.
3823 have_mng_structure=MagickFalse;
3824 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
3826 if (mng_info == (MngInfo *) NULL)
3827 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
3830 Initialize members of the MngInfo structure.
3832 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
3833 mng_info->image=image;
3834 have_mng_structure=MagickTrue;
3837 image=ReadOnePNGImage(mng_info,image_info,exception);
3838 MngInfoFreeStruct(mng_info,&have_mng_structure);
3840 if (image == (Image *) NULL)
3842 if (previous != (Image *) NULL)
3844 if (previous->signature != MagickSignature)
3845 ThrowReaderException(CorruptImageError,"CorruptImage");
3847 (void) CloseBlob(previous);
3848 (void) DestroyImageList(previous);
3851 if (logging != MagickFalse)
3852 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3853 "exit ReadPNGImage() with error");
3855 return((Image *) NULL);
3858 (void) CloseBlob(image);
3860 if ((image->columns == 0) || (image->rows == 0))
3862 if (logging != MagickFalse)
3863 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3864 "exit ReadPNGImage() with error.");
3866 ThrowReaderException(CorruptImageError,"CorruptImage");
3869 if ((IssRGBColorspace(image->colorspace) != MagickFalse) &&
3870 ((image->gamma < .45) || (image->gamma > .46)))
3871 SetImageColorspace(image,RGBColorspace,exception);
3873 if (logging != MagickFalse)
3874 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3875 " page.w: %.20g, page.h: %.20g,page.x: %.20g, page.y: %.20g.",
3876 (double) image->page.width,(double) image->page.height,
3877 (double) image->page.x,(double) image->page.y);
3879 if (logging != MagickFalse)
3880 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit ReadPNGImage()");
3887 #if defined(JNG_SUPPORTED)
3889 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3893 % R e a d O n e J N G I m a g e %
3897 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3899 % ReadOneJNGImage() reads a JPEG Network Graphics (JNG) image file
3900 % (minus the 8-byte signature) and returns it. It allocates the memory
3901 % necessary for the new Image structure and returns a pointer to the new
3904 % JNG support written by Glenn Randers-Pehrson, glennrp@image...
3906 % The format of the ReadOneJNGImage method is:
3908 % Image *ReadOneJNGImage(MngInfo *mng_info, const ImageInfo *image_info,
3909 % ExceptionInfo *exception)
3911 % A description of each parameter follows:
3913 % o mng_info: Specifies a pointer to a MngInfo structure.
3915 % o image_info: the image info.
3917 % o exception: return any errors or warnings in this structure.
3920 static Image *ReadOneJNGImage(MngInfo *mng_info,
3921 const ImageInfo *image_info, ExceptionInfo *exception)
3948 jng_image_sample_depth,
3949 jng_image_compression_method,
3950 jng_image_interlace_method,
3951 jng_alpha_sample_depth,
3952 jng_alpha_compression_method,
3953 jng_alpha_filter_method,
3954 jng_alpha_interlace_method;
3956 register const Quantum
3966 register unsigned char
3977 jng_alpha_compression_method=0;
3978 jng_alpha_sample_depth=8;
3982 alpha_image=(Image *) NULL;
3983 color_image=(Image *) NULL;
3984 alpha_image_info=(ImageInfo *) NULL;
3985 color_image_info=(ImageInfo *) NULL;
3987 logging=LogMagickEvent(CoderEvent,GetMagickModule(),
3988 " Enter ReadOneJNGImage()");
3990 image=mng_info->image;
3992 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
3995 Allocate next image structure.
3997 if (logging != MagickFalse)
3998 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3999 " AcquireNextImage()");
4001 AcquireNextImage(image_info,image,exception);
4003 if (GetNextImageInList(image) == (Image *) NULL)
4004 return((Image *) NULL);
4006 image=SyncNextImageInList(image);
4008 mng_info->image=image;
4011 Signature bytes have already been read.
4014 read_JSEP=MagickFalse;
4015 reading_idat=MagickFalse;
4016 skip_to_iend=MagickFalse;
4020 type[MaxTextExtent];
4029 Read a new JNG chunk.
4031 status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
4032 2*GetBlobSize(image));
4034 if (status == MagickFalse)
4038 (void) ConcatenateMagickString(type,"errr",MaxTextExtent);
4039 length=ReadBlobMSBLong(image);
4040 count=(unsigned int) ReadBlob(image,4,(unsigned char *) type);
4042 if (logging != MagickFalse)
4043 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4044 " Reading JNG chunk type %c%c%c%c, length: %.20g",
4045 type[0],type[1],type[2],type[3],(double) length);
4047 if (length > PNG_UINT_31_MAX || count == 0)
4048 ThrowReaderException(CorruptImageError,"CorruptImage");
4051 chunk=(unsigned char *) NULL;
4055 chunk=(unsigned char *) AcquireQuantumMemory(length,sizeof(*chunk));
4057 if (chunk == (unsigned char *) NULL)
4058 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
4060 for (i=0; i < (ssize_t) length; i++)
4061 chunk[i]=(unsigned char) ReadBlobByte(image);
4066 (void) ReadBlobMSBLong(image); /* read crc word */
4071 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4076 if (memcmp(type,mng_JHDR,4) == 0)
4080 jng_width=(size_t) ((p[0] << 24) | (p[1] << 16) |
4081 (p[2] << 8) | p[3]);
4082 jng_height=(size_t) ((p[4] << 24) | (p[5] << 16) |
4083 (p[6] << 8) | p[7]);
4084 jng_color_type=p[8];
4085 jng_image_sample_depth=p[9];
4086 jng_image_compression_method=p[10];
4087 jng_image_interlace_method=p[11];
4089 image->interlace=jng_image_interlace_method != 0 ? PNGInterlace :
4092 jng_alpha_sample_depth=p[12];
4093 jng_alpha_compression_method=p[13];
4094 jng_alpha_filter_method=p[14];
4095 jng_alpha_interlace_method=p[15];
4097 if (logging != MagickFalse)
4099 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4100 " jng_width: %16lu",(unsigned long) jng_width);
4102 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4103 " jng_width: %16lu",(unsigned long) jng_height);
4105 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4106 " jng_color_type: %16d",jng_color_type);
4108 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4109 " jng_image_sample_depth: %3d",
4110 jng_image_sample_depth);
4112 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4113 " jng_image_compression_method:%3d",
4114 jng_image_compression_method);
4116 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4117 " jng_image_interlace_method: %3d",
4118 jng_image_interlace_method);
4120 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4121 " jng_alpha_sample_depth: %3d",
4122 jng_alpha_sample_depth);
4124 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4125 " jng_alpha_compression_method:%3d",
4126 jng_alpha_compression_method);
4128 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4129 " jng_alpha_filter_method: %3d",
4130 jng_alpha_filter_method);
4132 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4133 " jng_alpha_interlace_method: %3d",
4134 jng_alpha_interlace_method);
4139 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4145 if ((reading_idat == MagickFalse) && (read_JSEP == MagickFalse) &&
4146 ((memcmp(type,mng_JDAT,4) == 0) || (memcmp(type,mng_JdAA,4) == 0) ||
4147 (memcmp(type,mng_IDAT,4) == 0) || (memcmp(type,mng_JDAA,4) == 0)))
4150 o create color_image
4151 o open color_blob, attached to color_image
4152 o if (color type has alpha)
4153 open alpha_blob, attached to alpha_image
4156 color_image_info=(ImageInfo *)AcquireMagickMemory(sizeof(ImageInfo));
4158 if (color_image_info == (ImageInfo *) NULL)
4159 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
4161 GetImageInfo(color_image_info);
4162 color_image=AcquireImage(color_image_info,exception);
4164 if (color_image == (Image *) NULL)
4165 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
4167 if (logging != MagickFalse)
4168 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4169 " Creating color_blob.");
4171 (void) AcquireUniqueFilename(color_image->filename);
4172 status=OpenBlob(color_image_info,color_image,WriteBinaryBlobMode,
4175 if (status == MagickFalse)
4176 return((Image *) NULL);
4178 if ((image_info->ping == MagickFalse) && (jng_color_type >= 12))
4180 alpha_image_info=(ImageInfo *)
4181 AcquireMagickMemory(sizeof(ImageInfo));
4183 if (alpha_image_info == (ImageInfo *) NULL)
4184 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
4186 GetImageInfo(alpha_image_info);
4187 alpha_image=AcquireImage(alpha_image_info,exception);
4189 if (alpha_image == (Image *) NULL)
4191 alpha_image=DestroyImage(alpha_image);
4192 ThrowReaderException(ResourceLimitError,
4193 "MemoryAllocationFailed");
4196 if (logging != MagickFalse)
4197 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4198 " Creating alpha_blob.");
4200 (void) AcquireUniqueFilename(alpha_image->filename);
4201 status=OpenBlob(alpha_image_info,alpha_image,WriteBinaryBlobMode,
4204 if (status == MagickFalse)
4205 return((Image *) NULL);
4207 if (jng_alpha_compression_method == 0)
4212 if (logging != MagickFalse)
4213 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4214 " Writing IHDR chunk to alpha_blob.");
4216 (void) WriteBlob(alpha_image,8,(const unsigned char *)
4217 "\211PNG\r\n\032\n");
4219 (void) WriteBlobMSBULong(alpha_image,13L);
4220 PNGType(data,mng_IHDR);
4221 LogPNGChunk(logging,mng_IHDR,13L);
4222 PNGLong(data+4,jng_width);
4223 PNGLong(data+8,jng_height);
4224 data[12]=jng_alpha_sample_depth;
4225 data[13]=0; /* color_type gray */
4226 data[14]=0; /* compression method 0 */
4227 data[15]=0; /* filter_method 0 */
4228 data[16]=0; /* interlace_method 0 */
4229 (void) WriteBlob(alpha_image,17,data);
4230 (void) WriteBlobMSBULong(alpha_image,crc32(0,data,17));
4233 reading_idat=MagickTrue;
4236 if (memcmp(type,mng_JDAT,4) == 0)
4238 /* Copy chunk to color_image->blob */
4240 if (logging != MagickFalse)
4241 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4242 " Copying JDAT chunk data to color_blob.");
4244 (void) WriteBlob(color_image,length,chunk);
4247 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4252 if (memcmp(type,mng_IDAT,4) == 0)
4257 /* Copy IDAT header and chunk data to alpha_image->blob */
4259 if (image_info->ping == MagickFalse)
4261 if (logging != MagickFalse)
4262 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4263 " Copying IDAT chunk data to alpha_blob.");
4265 (void) WriteBlobMSBULong(alpha_image,(size_t) length);
4266 PNGType(data,mng_IDAT);
4267 LogPNGChunk(logging,mng_IDAT,length);
4268 (void) WriteBlob(alpha_image,4,data);
4269 (void) WriteBlob(alpha_image,length,chunk);
4270 (void) WriteBlobMSBULong(alpha_image,
4271 crc32(crc32(0,data,4),chunk,(uInt) length));
4275 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4280 if ((memcmp(type,mng_JDAA,4) == 0) || (memcmp(type,mng_JdAA,4) == 0))
4282 /* Copy chunk data to alpha_image->blob */
4284 if (image_info->ping == MagickFalse)
4286 if (logging != MagickFalse)
4287 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4288 " Copying JDAA chunk data to alpha_blob.");
4290 (void) WriteBlob(alpha_image,length,chunk);
4294 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4299 if (memcmp(type,mng_JSEP,4) == 0)
4301 read_JSEP=MagickTrue;
4304 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4309 if (memcmp(type,mng_bKGD,4) == 0)
4313 image->background_color.red=ScaleCharToQuantum(p[1]);
4314 image->background_color.green=image->background_color.red;
4315 image->background_color.blue=image->background_color.red;
4320 image->background_color.red=ScaleCharToQuantum(p[1]);
4321 image->background_color.green=ScaleCharToQuantum(p[3]);
4322 image->background_color.blue=ScaleCharToQuantum(p[5]);
4325 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4329 if (memcmp(type,mng_gAMA,4) == 0)
4332 image->gamma=((float) mng_get_long(p))*0.00001;
4334 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4338 if (memcmp(type,mng_cHRM,4) == 0)
4342 image->chromaticity.white_point.x=0.00001*mng_get_long(p);
4343 image->chromaticity.white_point.y=0.00001*mng_get_long(&p[4]);
4344 image->chromaticity.red_primary.x=0.00001*mng_get_long(&p[8]);
4345 image->chromaticity.red_primary.y=0.00001*mng_get_long(&p[12]);
4346 image->chromaticity.green_primary.x=0.00001*mng_get_long(&p[16]);
4347 image->chromaticity.green_primary.y=0.00001*mng_get_long(&p[20]);
4348 image->chromaticity.blue_primary.x=0.00001*mng_get_long(&p[24]);
4349 image->chromaticity.blue_primary.y=0.00001*mng_get_long(&p[28]);
4352 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4356 if (memcmp(type,mng_sRGB,4) == 0)
4360 image->rendering_intent=
4361 Magick_RenderingIntent_from_PNG_RenderingIntent(p[0]);
4362 image->gamma=1.000f/2.200f;
4363 image->chromaticity.red_primary.x=0.6400f;
4364 image->chromaticity.red_primary.y=0.3300f;
4365 image->chromaticity.green_primary.x=0.3000f;
4366 image->chromaticity.green_primary.y=0.6000f;
4367 image->chromaticity.blue_primary.x=0.1500f;
4368 image->chromaticity.blue_primary.y=0.0600f;
4369 image->chromaticity.white_point.x=0.3127f;
4370 image->chromaticity.white_point.y=0.3290f;
4373 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4377 if (memcmp(type,mng_oFFs,4) == 0)
4381 image->page.x=(ssize_t) mng_get_long(p);
4382 image->page.y=(ssize_t) mng_get_long(&p[4]);
4384 if ((int) p[8] != 0)
4386 image->page.x/=10000;
4387 image->page.y/=10000;
4392 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4397 if (memcmp(type,mng_pHYs,4) == 0)
4401 image->resolution.x=(double) mng_get_long(p);
4402 image->resolution.y=(double) mng_get_long(&p[4]);
4403 if ((int) p[8] == PNG_RESOLUTION_METER)
4405 image->units=PixelsPerCentimeterResolution;
4406 image->resolution.x=image->resolution.x/100.0f;
4407 image->resolution.y=image->resolution.y/100.0f;
4411 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4416 if (memcmp(type,mng_iCCP,4) == 0)
4420 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4427 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4429 if (memcmp(type,mng_IEND,4))
4439 Finish up reading image data:
4441 o read main image from color_blob.
4445 o if (color_type has alpha)
4446 if alpha_encoding is PNG
4447 read secondary image from alpha_blob via ReadPNG
4448 if alpha_encoding is JPEG
4449 read secondary image from alpha_blob via ReadJPEG
4453 o copy intensity of secondary image into
4454 alpha samples of main image.
4456 o destroy the secondary image.
4459 (void) CloseBlob(color_image);
4461 if (logging != MagickFalse)
4462 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4463 " Reading jng_image from color_blob.");
4465 (void) FormatLocaleString(color_image_info->filename,MaxTextExtent,"%s",
4466 color_image->filename);
4468 color_image_info->ping=MagickFalse; /* To do: avoid this */
4469 jng_image=ReadImage(color_image_info,exception);
4471 if (jng_image == (Image *) NULL)
4472 return((Image *) NULL);
4474 (void) RelinquishUniqueFileResource(color_image->filename);
4475 color_image=DestroyImage(color_image);
4476 color_image_info=DestroyImageInfo(color_image_info);
4478 if (jng_image == (Image *) NULL)
4479 return((Image *) NULL);
4481 if (logging != MagickFalse)
4482 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4483 " Copying jng_image pixels to main image.");
4485 image->rows=jng_height;
4486 image->columns=jng_width;
4488 for (y=0; y < (ssize_t) image->rows; y++)
4490 s=GetVirtualPixels(jng_image,0,y,image->columns,1,exception);
4491 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
4492 for (x=(ssize_t) image->columns; x != 0; x--)
4494 SetPixelRed(image,GetPixelRed(jng_image,s),q);
4495 SetPixelGreen(image,GetPixelGreen(jng_image,s),q);
4496 SetPixelBlue(image,GetPixelBlue(jng_image,s),q);
4497 q+=GetPixelChannels(image);
4498 s+=GetPixelChannels(jng_image);
4501 if (SyncAuthenticPixels(image,exception) == MagickFalse)
4505 jng_image=DestroyImage(jng_image);
4507 if (image_info->ping == MagickFalse)
4509 if (jng_color_type >= 12)
4511 if (jng_alpha_compression_method == 0)
4515 (void) WriteBlobMSBULong(alpha_image,0x00000000L);
4516 PNGType(data,mng_IEND);
4517 LogPNGChunk(logging,mng_IEND,0L);
4518 (void) WriteBlob(alpha_image,4,data);
4519 (void) WriteBlobMSBULong(alpha_image,crc32(0,data,4));
4522 (void) CloseBlob(alpha_image);
4524 if (logging != MagickFalse)
4525 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4526 " Reading alpha from alpha_blob.");
4528 (void) FormatLocaleString(alpha_image_info->filename,MaxTextExtent,
4529 "%s",alpha_image->filename);
4531 jng_image=ReadImage(alpha_image_info,exception);
4533 if (jng_image != (Image *) NULL)
4534 for (y=0; y < (ssize_t) image->rows; y++)
4536 s=GetVirtualPixels(jng_image,0,y,image->columns,1,
4538 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
4540 if (image->alpha_trait == BlendPixelTrait)
4541 for (x=(ssize_t) image->columns; x != 0; x--)
4543 SetPixelAlpha(image,GetPixelRed(jng_image,s),q);
4544 q+=GetPixelChannels(image);
4545 s+=GetPixelChannels(jng_image);
4549 for (x=(ssize_t) image->columns; x != 0; x--)
4551 SetPixelAlpha(image,GetPixelRed(jng_image,s),q);
4552 if (GetPixelAlpha(image,q) != OpaqueAlpha)
4553 image->alpha_trait=BlendPixelTrait;
4554 q+=GetPixelChannels(image);
4555 s+=GetPixelChannels(jng_image);
4558 if (SyncAuthenticPixels(image,exception) == MagickFalse)
4561 (void) RelinquishUniqueFileResource(alpha_image->filename);
4562 alpha_image=DestroyImage(alpha_image);
4563 alpha_image_info=DestroyImageInfo(alpha_image_info);
4564 if (jng_image != (Image *) NULL)
4565 jng_image=DestroyImage(jng_image);
4569 /* Read the JNG image. */
4571 if (mng_info->mng_type == 0)
4573 mng_info->mng_width=jng_width;
4574 mng_info->mng_height=jng_height;
4577 if (image->page.width == 0 && image->page.height == 0)
4579 image->page.width=jng_width;
4580 image->page.height=jng_height;
4583 if (image->page.x == 0 && image->page.y == 0)
4585 image->page.x=mng_info->x_off[mng_info->object_id];
4586 image->page.y=mng_info->y_off[mng_info->object_id];
4591 image->page.y=mng_info->y_off[mng_info->object_id];
4594 mng_info->image_found++;
4595 status=SetImageProgress(image,LoadImagesTag,2*TellBlob(image),
4596 2*GetBlobSize(image));
4598 if (logging != MagickFalse)
4599 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4600 " exit ReadOneJNGImage()");
4606 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4610 % R e a d J N G I m a g e %
4614 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4616 % ReadJNGImage() reads a JPEG Network Graphics (JNG) image file
4617 % (including the 8-byte signature) and returns it. It allocates the memory
4618 % necessary for the new Image structure and returns a pointer to the new
4621 % JNG support written by Glenn Randers-Pehrson, glennrp@image...
4623 % The format of the ReadJNGImage method is:
4625 % Image *ReadJNGImage(const ImageInfo *image_info, ExceptionInfo
4628 % A description of each parameter follows:
4630 % o image_info: the image info.
4632 % o exception: return any errors or warnings in this structure.
4636 static Image *ReadJNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
4651 magic_number[MaxTextExtent];
4659 assert(image_info != (const ImageInfo *) NULL);
4660 assert(image_info->signature == MagickSignature);
4661 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image_info->filename);
4662 assert(exception != (ExceptionInfo *) NULL);
4663 assert(exception->signature == MagickSignature);
4664 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter ReadJNGImage()");
4665 image=AcquireImage(image_info,exception);
4666 mng_info=(MngInfo *) NULL;
4667 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
4669 if (status == MagickFalse)
4670 return((Image *) NULL);
4672 if (LocaleCompare(image_info->magick,"JNG") != 0)
4673 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
4675 /* Verify JNG signature. */
4677 count=(size_t) ReadBlob(image,8,(unsigned char *) magic_number);
4679 if (count < 8 || memcmp(magic_number,"\213JNG\r\n\032\n",8) != 0)
4680 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
4682 /* Allocate a MngInfo structure. */
4684 have_mng_structure=MagickFalse;
4685 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(*mng_info));
4687 if (mng_info == (MngInfo *) NULL)
4688 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
4690 /* Initialize members of the MngInfo structure. */
4692 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
4693 have_mng_structure=MagickTrue;
4695 mng_info->image=image;
4697 image=ReadOneJNGImage(mng_info,image_info,exception);
4698 MngInfoFreeStruct(mng_info,&have_mng_structure);
4700 if (image == (Image *) NULL)
4702 if (IsImageObject(previous) != MagickFalse)
4704 (void) CloseBlob(previous);
4705 (void) DestroyImageList(previous);
4708 if (logging != MagickFalse)
4709 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4710 "exit ReadJNGImage() with error");
4712 return((Image *) NULL);
4714 (void) CloseBlob(image);
4716 if (image->columns == 0 || image->rows == 0)
4718 if (logging != MagickFalse)
4719 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4720 "exit ReadJNGImage() with error");
4722 ThrowReaderException(CorruptImageError,"CorruptImage");
4725 if (logging != MagickFalse)
4726 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit ReadJNGImage()");
4732 static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
4735 page_geometry[MaxTextExtent];
4768 #if defined(MNG_INSERT_LAYERS)
4770 mng_background_color;
4773 register unsigned char
4788 #if defined(MNG_INSERT_LAYERS)
4793 volatile unsigned int
4794 #ifdef MNG_OBJECT_BUFFERS
4795 mng_background_object=0,
4797 mng_type=0; /* 0: PNG or JNG; 1: MNG; 2: MNG-LC; 3: MNG-VLC */
4800 default_frame_timeout,
4802 #if defined(MNG_INSERT_LAYERS)
4808 /* These delays are all measured in image ticks_per_second,
4809 * not in MNG ticks_per_second
4812 default_frame_delay,
4816 #if defined(MNG_INSERT_LAYERS)
4825 previous_fb.bottom=0;
4827 previous_fb.right=0;
4829 default_fb.bottom=0;
4833 /* Open image file. */
4835 assert(image_info != (const ImageInfo *) NULL);
4836 assert(image_info->signature == MagickSignature);
4837 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image_info->filename);
4838 assert(exception != (ExceptionInfo *) NULL);
4839 assert(exception->signature == MagickSignature);
4840 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter ReadMNGImage()");
4841 image=AcquireImage(image_info,exception);
4842 mng_info=(MngInfo *) NULL;
4843 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
4845 if (status == MagickFalse)
4846 return((Image *) NULL);
4848 first_mng_object=MagickFalse;
4850 have_mng_structure=MagickFalse;
4852 /* Allocate a MngInfo structure. */
4854 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
4856 if (mng_info == (MngInfo *) NULL)
4857 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
4859 /* Initialize members of the MngInfo structure. */
4861 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
4862 mng_info->image=image;
4863 have_mng_structure=MagickTrue;
4865 if (LocaleCompare(image_info->magick,"MNG") == 0)
4868 magic_number[MaxTextExtent];
4870 /* Verify MNG signature. */
4871 count=(size_t) ReadBlob(image,8,(unsigned char *) magic_number);
4872 if (memcmp(magic_number,"\212MNG\r\n\032\n",8) != 0)
4873 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
4875 /* Initialize some nonzero members of the MngInfo structure. */
4876 for (i=0; i < MNG_MAX_OBJECTS; i++)
4878 mng_info->object_clip[i].right=(ssize_t) PNG_UINT_31_MAX;
4879 mng_info->object_clip[i].bottom=(ssize_t) PNG_UINT_31_MAX;
4881 mng_info->exists[0]=MagickTrue;
4884 first_mng_object=MagickTrue;
4886 #if defined(MNG_INSERT_LAYERS)
4887 insert_layers=MagickFalse; /* should be False when converting or mogrifying */
4889 default_frame_delay=0;
4890 default_frame_timeout=0;
4893 mng_info->ticks_per_second=1UL*image->ticks_per_second;
4895 skip_to_iend=MagickFalse;
4896 term_chunk_found=MagickFalse;
4897 mng_info->framing_mode=1;
4898 #if defined(MNG_INSERT_LAYERS)
4899 mandatory_back=MagickFalse;
4901 #if defined(MNG_INSERT_LAYERS)
4902 mng_background_color=image->background_color;
4904 default_fb=mng_info->frame;
4905 previous_fb=mng_info->frame;
4909 type[MaxTextExtent];
4911 if (LocaleCompare(image_info->magick,"MNG") == 0)
4920 (void) ConcatenateMagickString(type,"errr",MaxTextExtent);
4921 length=ReadBlobMSBLong(image);
4922 count=(size_t) ReadBlob(image,4,(unsigned char *) type);
4924 if (logging != MagickFalse)
4925 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4926 " Reading MNG chunk type %c%c%c%c, length: %.20g",
4927 type[0],type[1],type[2],type[3],(double) length);
4929 if (length > PNG_UINT_31_MAX)
4933 ThrowReaderException(CorruptImageError,"CorruptImage");
4936 chunk=(unsigned char *) NULL;
4940 chunk=(unsigned char *) AcquireQuantumMemory(length,sizeof(*chunk));
4942 if (chunk == (unsigned char *) NULL)
4943 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
4945 for (i=0; i < (ssize_t) length; i++)
4946 chunk[i]=(unsigned char) ReadBlobByte(image);
4951 (void) ReadBlobMSBLong(image); /* read crc word */
4953 #if !defined(JNG_SUPPORTED)
4954 if (memcmp(type,mng_JHDR,4) == 0)
4956 skip_to_iend=MagickTrue;
4958 if (mng_info->jhdr_warning == 0)
4959 (void) ThrowMagickException(exception,GetMagickModule(),
4960 CoderError,"JNGCompressNotSupported","`%s'",image->filename);
4962 mng_info->jhdr_warning++;
4965 if (memcmp(type,mng_DHDR,4) == 0)
4967 skip_to_iend=MagickTrue;
4969 if (mng_info->dhdr_warning == 0)
4970 (void) ThrowMagickException(exception,GetMagickModule(),
4971 CoderError,"DeltaPNGNotSupported","`%s'",image->filename);
4973 mng_info->dhdr_warning++;
4975 if (memcmp(type,mng_MEND,4) == 0)
4980 if (memcmp(type,mng_IEND,4) == 0)
4981 skip_to_iend=MagickFalse;
4984 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4986 if (logging != MagickFalse)
4987 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4993 if (memcmp(type,mng_MHDR,4) == 0)
4995 mng_info->mng_width=(size_t) ((p[0] << 24) | (p[1] << 16) |
4996 (p[2] << 8) | p[3]);
4998 mng_info->mng_height=(size_t) ((p[4] << 24) | (p[5] << 16) |
4999 (p[6] << 8) | p[7]);
5001 if (logging != MagickFalse)
5003 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5004 " MNG width: %.20g",(double) mng_info->mng_width);
5005 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5006 " MNG height: %.20g",(double) mng_info->mng_height);
5010 mng_info->ticks_per_second=(size_t) mng_get_long(p);
5012 if (mng_info->ticks_per_second == 0)
5013 default_frame_delay=0;
5016 default_frame_delay=1UL*image->ticks_per_second/
5017 mng_info->ticks_per_second;
5019 frame_delay=default_frame_delay;
5025 simplicity=(size_t) mng_get_long(p);
5028 mng_type=1; /* Full MNG */
5030 if ((simplicity != 0) && ((simplicity | 11) == 11))
5031 mng_type=2; /* LC */
5033 if ((simplicity != 0) && ((simplicity | 9) == 9))
5034 mng_type=3; /* VLC */
5036 #if defined(MNG_INSERT_LAYERS)
5038 insert_layers=MagickTrue;
5040 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
5042 /* Allocate next image structure. */
5043 AcquireNextImage(image_info,image,exception);
5045 if (GetNextImageInList(image) == (Image *) NULL)
5046 return((Image *) NULL);
5048 image=SyncNextImageInList(image);
5049 mng_info->image=image;
5052 if ((mng_info->mng_width > 65535L) ||
5053 (mng_info->mng_height > 65535L))
5054 ThrowReaderException(ImageError,"WidthOrHeightExceedsLimit");
5056 (void) FormatLocaleString(page_geometry,MaxTextExtent,
5057 "%.20gx%.20g+0+0",(double) mng_info->mng_width,(double)
5058 mng_info->mng_height);
5060 mng_info->frame.left=0;
5061 mng_info->frame.right=(ssize_t) mng_info->mng_width;
5062 mng_info->frame.top=0;
5063 mng_info->frame.bottom=(ssize_t) mng_info->mng_height;
5064 mng_info->clip=default_fb=previous_fb=mng_info->frame;
5066 for (i=0; i < MNG_MAX_OBJECTS; i++)
5067 mng_info->object_clip[i]=mng_info->frame;
5069 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5073 if (memcmp(type,mng_TERM,4) == 0)
5084 final_delay=(png_uint_32) mng_get_long(&p[2]);
5085 mng_iterations=(png_uint_32) mng_get_long(&p[6]);
5087 if (mng_iterations == PNG_UINT_31_MAX)
5090 image->iterations=mng_iterations;
5091 term_chunk_found=MagickTrue;
5094 if (logging != MagickFalse)
5096 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5097 " repeat=%d",repeat);
5099 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5100 " final_delay=%.20g",(double) final_delay);
5102 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5103 " image->iterations=%.20g",(double) image->iterations);
5106 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5109 if (memcmp(type,mng_DEFI,4) == 0)
5112 (void) ThrowMagickException(exception,GetMagickModule(),
5113 CoderError,"DEFI chunk found in MNG-VLC datastream","`%s'",
5116 object_id=(p[0] << 8) | p[1];
5118 if (mng_type == 2 && object_id != 0)
5119 (void) ThrowMagickException(exception,GetMagickModule(),
5120 CoderError,"Nonzero object_id in MNG-LC datastream","`%s'",
5123 if (object_id > MNG_MAX_OBJECTS)
5126 Instead of using a warning we should allocate a larger
5127 MngInfo structure and continue.
5129 (void) ThrowMagickException(exception,GetMagickModule(),
5130 CoderError,"object id too large","`%s'",image->filename);
5131 object_id=MNG_MAX_OBJECTS;
5134 if (mng_info->exists[object_id])
5135 if (mng_info->frozen[object_id])
5137 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5138 (void) ThrowMagickException(exception,
5139 GetMagickModule(),CoderError,
5140 "DEFI cannot redefine a frozen MNG object","`%s'",
5145 mng_info->exists[object_id]=MagickTrue;
5148 mng_info->invisible[object_id]=p[2];
5151 Extract object offset info.
5155 mng_info->x_off[object_id]=(ssize_t) ((p[4] << 24) |
5156 (p[5] << 16) | (p[6] << 8) | p[7]);
5158 mng_info->y_off[object_id]=(ssize_t) ((p[8] << 24) |
5159 (p[9] << 16) | (p[10] << 8) | p[11]);
5161 if (logging != MagickFalse)
5163 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5164 " x_off[%d]: %.20g",object_id,(double)
5165 mng_info->x_off[object_id]);
5167 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5168 " y_off[%d]: %.20g",object_id,(double)
5169 mng_info->y_off[object_id]);
5174 Extract object clipping info.
5177 mng_info->object_clip[object_id]=mng_read_box(mng_info->frame,0,
5180 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5183 if (memcmp(type,mng_bKGD,4) == 0)
5185 mng_info->have_global_bkgd=MagickFalse;
5189 mng_info->mng_global_bkgd.red=
5190 ScaleShortToQuantum((unsigned short) ((p[0] << 8) | p[1]));
5192 mng_info->mng_global_bkgd.green=
5193 ScaleShortToQuantum((unsigned short) ((p[2] << 8) | p[3]));
5195 mng_info->mng_global_bkgd.blue=
5196 ScaleShortToQuantum((unsigned short) ((p[4] << 8) | p[5]));
5198 mng_info->have_global_bkgd=MagickTrue;
5201 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5204 if (memcmp(type,mng_BACK,4) == 0)
5206 #if defined(MNG_INSERT_LAYERS)
5208 mandatory_back=p[6];
5213 if (mandatory_back && length > 5)
5215 mng_background_color.red=
5216 ScaleShortToQuantum((unsigned short) ((p[0] << 8) | p[1]));
5218 mng_background_color.green=
5219 ScaleShortToQuantum((unsigned short) ((p[2] << 8) | p[3]));
5221 mng_background_color.blue=
5222 ScaleShortToQuantum((unsigned short) ((p[4] << 8) | p[5]));
5224 mng_background_color.alpha=OpaqueAlpha;
5227 #ifdef MNG_OBJECT_BUFFERS
5229 mng_background_object=(p[7] << 8) | p[8];
5232 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5236 if (memcmp(type,mng_PLTE,4) == 0)
5238 /* Read global PLTE. */
5240 if (length && (length < 769))
5242 if (mng_info->global_plte == (png_colorp) NULL)
5243 mng_info->global_plte=(png_colorp) AcquireQuantumMemory(256,
5244 sizeof(*mng_info->global_plte));
5246 for (i=0; i < (ssize_t) (length/3); i++)
5248 mng_info->global_plte[i].red=p[3*i];
5249 mng_info->global_plte[i].green=p[3*i+1];
5250 mng_info->global_plte[i].blue=p[3*i+2];
5253 mng_info->global_plte_length=(unsigned int) (length/3);
5256 for ( ; i < 256; i++)
5258 mng_info->global_plte[i].red=i;
5259 mng_info->global_plte[i].green=i;
5260 mng_info->global_plte[i].blue=i;
5264 mng_info->global_plte_length=256;
5267 mng_info->global_plte_length=0;
5269 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5273 if (memcmp(type,mng_tRNS,4) == 0)
5275 /* read global tRNS */
5278 for (i=0; i < (ssize_t) length; i++)
5279 mng_info->global_trns[i]=p[i];
5282 for ( ; i < 256; i++)
5283 mng_info->global_trns[i]=255;
5285 mng_info->global_trns_length=(unsigned int) length;
5286 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5289 if (memcmp(type,mng_gAMA,4) == 0)
5296 igamma=mng_get_long(p);
5297 mng_info->global_gamma=((float) igamma)*0.00001;
5298 mng_info->have_global_gama=MagickTrue;
5302 mng_info->have_global_gama=MagickFalse;
5304 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5308 if (memcmp(type,mng_cHRM,4) == 0)
5310 /* Read global cHRM */
5314 mng_info->global_chrm.white_point.x=0.00001*mng_get_long(p);
5315 mng_info->global_chrm.white_point.y=0.00001*mng_get_long(&p[4]);
5316 mng_info->global_chrm.red_primary.x=0.00001*mng_get_long(&p[8]);
5317 mng_info->global_chrm.red_primary.y=0.00001*
5318 mng_get_long(&p[12]);
5319 mng_info->global_chrm.green_primary.x=0.00001*
5320 mng_get_long(&p[16]);
5321 mng_info->global_chrm.green_primary.y=0.00001*
5322 mng_get_long(&p[20]);
5323 mng_info->global_chrm.blue_primary.x=0.00001*
5324 mng_get_long(&p[24]);
5325 mng_info->global_chrm.blue_primary.y=0.00001*
5326 mng_get_long(&p[28]);
5327 mng_info->have_global_chrm=MagickTrue;
5330 mng_info->have_global_chrm=MagickFalse;
5332 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5336 if (memcmp(type,mng_sRGB,4) == 0)
5343 mng_info->global_srgb_intent=
5344 Magick_RenderingIntent_from_PNG_RenderingIntent(p[0]);
5345 mng_info->have_global_srgb=MagickTrue;
5348 mng_info->have_global_srgb=MagickFalse;
5350 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5354 if (memcmp(type,mng_iCCP,4) == 0)
5362 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5367 if (memcmp(type,mng_FRAM,4) == 0)
5370 (void) ThrowMagickException(exception,GetMagickModule(),
5371 CoderError,"FRAM chunk found in MNG-VLC datastream","`%s'",
5374 if ((mng_info->framing_mode == 2) || (mng_info->framing_mode == 4))
5375 image->delay=frame_delay;
5377 frame_delay=default_frame_delay;
5378 frame_timeout=default_frame_timeout;
5383 mng_info->framing_mode=p[0];
5385 if (logging != MagickFalse)
5386 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5387 " Framing_mode=%d",mng_info->framing_mode);
5391 /* Note the delay and frame clipping boundaries. */
5393 p++; /* framing mode */
5395 while (*p && ((p-chunk) < (ssize_t) length))
5396 p++; /* frame name */
5398 p++; /* frame name terminator */
5400 if ((p-chunk) < (ssize_t) (length-4))
5407 change_delay=(*p++);
5408 change_timeout=(*p++);
5409 change_clipping=(*p++);
5410 p++; /* change_sync */
5414 frame_delay=1UL*image->ticks_per_second*
5417 if (mng_info->ticks_per_second != 0)
5418 frame_delay/=mng_info->ticks_per_second;
5421 frame_delay=PNG_UINT_31_MAX;
5423 if (change_delay == 2)
5424 default_frame_delay=frame_delay;
5428 if (logging != MagickFalse)
5429 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5430 " Framing_delay=%.20g",(double) frame_delay);
5435 frame_timeout=1UL*image->ticks_per_second*
5438 if (mng_info->ticks_per_second != 0)
5439 frame_timeout/=mng_info->ticks_per_second;
5442 frame_timeout=PNG_UINT_31_MAX;
5444 if (change_delay == 2)
5445 default_frame_timeout=frame_timeout;
5449 if (logging != MagickFalse)
5450 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5451 " Framing_timeout=%.20g",(double) frame_timeout);
5454 if (change_clipping)
5456 fb=mng_read_box(previous_fb,(char) p[0],&p[1]);
5460 if (logging != MagickFalse)
5461 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5462 " Frame_clip: L=%.20g R=%.20g T=%.20g B=%.20g",
5463 (double) fb.left,(double) fb.right,(double) fb.top,
5464 (double) fb.bottom);
5466 if (change_clipping == 2)
5472 mng_info->clip=mng_minimum_box(fb,mng_info->frame);
5474 subframe_width=(size_t) (mng_info->clip.right
5475 -mng_info->clip.left);
5477 subframe_height=(size_t) (mng_info->clip.bottom
5478 -mng_info->clip.top);
5480 Insert a background layer behind the frame if framing_mode is 4.
5482 #if defined(MNG_INSERT_LAYERS)
5483 if (logging != MagickFalse)
5484 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5485 " subframe_width=%.20g, subframe_height=%.20g",(double)
5486 subframe_width,(double) subframe_height);
5488 if (insert_layers && (mng_info->framing_mode == 4) &&
5489 (subframe_width) && (subframe_height))
5491 /* Allocate next image structure. */
5492 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
5494 AcquireNextImage(image_info,image,exception);
5496 if (GetNextImageInList(image) == (Image *) NULL)
5498 image=DestroyImageList(image);
5499 MngInfoFreeStruct(mng_info,&have_mng_structure);
5500 return((Image *) NULL);
5503 image=SyncNextImageInList(image);
5506 mng_info->image=image;
5508 if (term_chunk_found)
5510 image->start_loop=MagickTrue;
5511 image->iterations=mng_iterations;
5512 term_chunk_found=MagickFalse;
5516 image->start_loop=MagickFalse;
5518 image->columns=subframe_width;
5519 image->rows=subframe_height;
5520 image->page.width=subframe_width;
5521 image->page.height=subframe_height;
5522 image->page.x=mng_info->clip.left;
5523 image->page.y=mng_info->clip.top;
5524 image->background_color=mng_background_color;
5525 image->alpha_trait=UndefinedPixelTrait;
5527 (void) SetImageBackgroundColor(image,exception);
5529 if (logging != MagickFalse)
5530 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5531 " Insert backgd layer, L=%.20g, R=%.20g T=%.20g, B=%.20g",
5532 (double) mng_info->clip.left,(double) mng_info->clip.right,
5533 (double) mng_info->clip.top,(double) mng_info->clip.bottom);
5536 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5539 if (memcmp(type,mng_CLIP,4) == 0)
5548 first_object=(p[0] << 8) | p[1];
5549 last_object=(p[2] << 8) | p[3];
5551 for (i=(int) first_object; i <= (int) last_object; i++)
5553 if (mng_info->exists[i] && !mng_info->frozen[i])
5558 box=mng_info->object_clip[i];
5559 mng_info->object_clip[i]=mng_read_box(box,(char) p[4],&p[5]);
5563 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5566 if (memcmp(type,mng_SAVE,4) == 0)
5568 for (i=1; i < MNG_MAX_OBJECTS; i++)
5569 if (mng_info->exists[i])
5571 mng_info->frozen[i]=MagickTrue;
5572 #ifdef MNG_OBJECT_BUFFERS
5573 if (mng_info->ob[i] != (MngBuffer *) NULL)
5574 mng_info->ob[i]->frozen=MagickTrue;
5579 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5584 if ((memcmp(type,mng_DISC,4) == 0) || (memcmp(type,mng_SEEK,4) == 0))
5586 /* Read DISC or SEEK. */
5588 if ((length == 0) || !memcmp(type,mng_SEEK,4))
5590 for (i=1; i < MNG_MAX_OBJECTS; i++)
5591 MngInfoDiscardObject(mng_info,i);
5599 for (j=0; j < (ssize_t) length; j+=2)
5601 i=p[j] << 8 | p[j+1];
5602 MngInfoDiscardObject(mng_info,i);
5607 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5612 if (memcmp(type,mng_MOVE,4) == 0)
5620 first_object=(p[0] << 8) | p[1];
5621 last_object=(p[2] << 8) | p[3];
5622 for (i=(ssize_t) first_object; i <= (ssize_t) last_object; i++)
5624 if (mng_info->exists[i] && !mng_info->frozen[i])
5632 old_pair.a=mng_info->x_off[i];
5633 old_pair.b=mng_info->y_off[i];
5634 new_pair=mng_read_pair(old_pair,(int) p[4],&p[5]);
5635 mng_info->x_off[i]=new_pair.a;
5636 mng_info->y_off[i]=new_pair.b;
5640 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5644 if (memcmp(type,mng_LOOP,4) == 0)
5646 ssize_t loop_iters=1;
5647 loop_level=chunk[0];
5648 mng_info->loop_active[loop_level]=1; /* mark loop active */
5650 /* Record starting point. */
5651 loop_iters=mng_get_long(&chunk[1]);
5653 if (logging != MagickFalse)
5654 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5655 " LOOP level %.20g has %.20g iterations ",(double) loop_level,
5656 (double) loop_iters);
5658 if (loop_iters == 0)
5659 skipping_loop=loop_level;
5663 mng_info->loop_jump[loop_level]=TellBlob(image);
5664 mng_info->loop_count[loop_level]=loop_iters;
5667 mng_info->loop_iteration[loop_level]=0;
5668 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5672 if (memcmp(type,mng_ENDL,4) == 0)
5674 loop_level=chunk[0];
5676 if (skipping_loop > 0)
5678 if (skipping_loop == loop_level)
5681 Found end of zero-iteration loop.
5684 mng_info->loop_active[loop_level]=0;
5690 if (mng_info->loop_active[loop_level] == 1)
5692 mng_info->loop_count[loop_level]--;
5693 mng_info->loop_iteration[loop_level]++;
5695 if (logging != MagickFalse)
5696 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5697 " ENDL: LOOP level %.20g has %.20g remaining iters ",
5698 (double) loop_level,(double)
5699 mng_info->loop_count[loop_level]);
5701 if (mng_info->loop_count[loop_level] != 0)
5703 offset=SeekBlob(image,mng_info->loop_jump[loop_level],
5707 ThrowReaderException(CorruptImageError,
5708 "ImproperImageHeader");
5719 mng_info->loop_active[loop_level]=0;
5721 for (i=0; i < loop_level; i++)
5722 if (mng_info->loop_active[i] == 1)
5723 last_level=(short) i;
5724 loop_level=last_level;
5729 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5733 if (memcmp(type,mng_CLON,4) == 0)
5735 if (mng_info->clon_warning == 0)
5736 (void) ThrowMagickException(exception,GetMagickModule(),
5737 CoderError,"CLON is not implemented yet","`%s'",
5740 mng_info->clon_warning++;
5743 if (memcmp(type,mng_MAGN,4) == 0)
5758 magn_first=(p[0] << 8) | p[1];
5764 magn_last=(p[2] << 8) | p[3];
5767 magn_last=magn_first;
5768 #ifndef MNG_OBJECT_BUFFERS
5769 if (magn_first || magn_last)
5770 if (mng_info->magn_warning == 0)
5772 (void) ThrowMagickException(exception,
5773 GetMagickModule(),CoderError,
5774 "MAGN is not implemented yet for nonzero objects",
5775 "`%s'",image->filename);
5777 mng_info->magn_warning++;
5787 magn_mx=(p[5] << 8) | p[6];
5796 magn_my=(p[7] << 8) | p[8];
5805 magn_ml=(p[9] << 8) | p[10];
5814 magn_mr=(p[11] << 8) | p[12];
5823 magn_mt=(p[13] << 8) | p[14];
5832 magn_mb=(p[15] << 8) | p[16];
5844 magn_methy=magn_methx;
5847 if (magn_methx > 5 || magn_methy > 5)
5848 if (mng_info->magn_warning == 0)
5850 (void) ThrowMagickException(exception,
5851 GetMagickModule(),CoderError,
5852 "Unknown MAGN method in MNG datastream","`%s'",
5855 mng_info->magn_warning++;
5857 #ifdef MNG_OBJECT_BUFFERS
5858 /* Magnify existing objects in the range magn_first to magn_last */
5860 if (magn_first == 0 || magn_last == 0)
5862 /* Save the magnification factors for object 0 */
5863 mng_info->magn_mb=magn_mb;
5864 mng_info->magn_ml=magn_ml;
5865 mng_info->magn_mr=magn_mr;
5866 mng_info->magn_mt=magn_mt;
5867 mng_info->magn_mx=magn_mx;
5868 mng_info->magn_my=magn_my;
5869 mng_info->magn_methx=magn_methx;
5870 mng_info->magn_methy=magn_methy;
5874 if (memcmp(type,mng_PAST,4) == 0)
5876 if (mng_info->past_warning == 0)
5877 (void) ThrowMagickException(exception,GetMagickModule(),
5878 CoderError,"PAST is not implemented yet","`%s'",
5881 mng_info->past_warning++;
5884 if (memcmp(type,mng_SHOW,4) == 0)
5886 if (mng_info->show_warning == 0)
5887 (void) ThrowMagickException(exception,GetMagickModule(),
5888 CoderError,"SHOW is not implemented yet","`%s'",
5891 mng_info->show_warning++;
5894 if (memcmp(type,mng_sBIT,4) == 0)
5897 mng_info->have_global_sbit=MagickFalse;
5901 mng_info->global_sbit.gray=p[0];
5902 mng_info->global_sbit.red=p[0];
5903 mng_info->global_sbit.green=p[1];
5904 mng_info->global_sbit.blue=p[2];
5905 mng_info->global_sbit.alpha=p[3];
5906 mng_info->have_global_sbit=MagickTrue;
5909 if (memcmp(type,mng_pHYs,4) == 0)
5913 mng_info->global_x_pixels_per_unit=
5914 (size_t) mng_get_long(p);
5915 mng_info->global_y_pixels_per_unit=
5916 (size_t) mng_get_long(&p[4]);
5917 mng_info->global_phys_unit_type=p[8];
5918 mng_info->have_global_phys=MagickTrue;
5922 mng_info->have_global_phys=MagickFalse;
5924 if (memcmp(type,mng_pHYg,4) == 0)
5926 if (mng_info->phyg_warning == 0)
5927 (void) ThrowMagickException(exception,GetMagickModule(),
5928 CoderError,"pHYg is not implemented.","`%s'",image->filename);
5930 mng_info->phyg_warning++;
5932 if (memcmp(type,mng_BASI,4) == 0)
5934 skip_to_iend=MagickTrue;
5936 if (mng_info->basi_warning == 0)
5937 (void) ThrowMagickException(exception,GetMagickModule(),
5938 CoderError,"BASI is not implemented yet","`%s'",
5941 mng_info->basi_warning++;
5942 #ifdef MNG_BASI_SUPPORTED
5943 basi_width=(size_t) ((p[0] << 24) | (p[1] << 16) |
5944 (p[2] << 8) | p[3]);
5945 basi_height=(size_t) ((p[4] << 24) | (p[5] << 16) |
5946 (p[6] << 8) | p[7]);
5947 basi_color_type=p[8];
5948 basi_compression_method=p[9];
5949 basi_filter_type=p[10];
5950 basi_interlace_method=p[11];
5952 basi_red=(p[12] << 8) & p[13];
5958 basi_green=(p[14] << 8) & p[15];
5964 basi_blue=(p[16] << 8) & p[17];
5970 basi_alpha=(p[18] << 8) & p[19];
5974 if (basi_sample_depth == 16)
5981 basi_viewable=p[20];
5987 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5991 if (memcmp(type,mng_IHDR,4)
5992 #if defined(JNG_SUPPORTED)
5993 && memcmp(type,mng_JHDR,4)
5997 /* Not an IHDR or JHDR chunk */
5999 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
6004 if (logging != MagickFalse)
6005 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6006 " Processing %c%c%c%c chunk",type[0],type[1],type[2],type[3]);
6008 mng_info->exists[object_id]=MagickTrue;
6009 mng_info->viewable[object_id]=MagickTrue;
6011 if (mng_info->invisible[object_id])
6013 if (logging != MagickFalse)
6014 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6015 " Skipping invisible object");
6017 skip_to_iend=MagickTrue;
6018 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
6021 #if defined(MNG_INSERT_LAYERS)
6023 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
6025 image_width=(size_t) mng_get_long(p);
6026 image_height=(size_t) mng_get_long(&p[4]);
6028 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
6031 Insert a transparent background layer behind the entire animation
6032 if it is not full screen.
6034 #if defined(MNG_INSERT_LAYERS)
6035 if (insert_layers && mng_type && first_mng_object)
6037 if ((mng_info->clip.left > 0) || (mng_info->clip.top > 0) ||
6038 (image_width < mng_info->mng_width) ||
6039 (mng_info->clip.right < (ssize_t) mng_info->mng_width) ||
6040 (image_height < mng_info->mng_height) ||
6041 (mng_info->clip.bottom < (ssize_t) mng_info->mng_height))
6043 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
6046 Allocate next image structure.
6048 AcquireNextImage(image_info,image,exception);
6050 if (GetNextImageInList(image) == (Image *) NULL)
6052 image=DestroyImageList(image);
6053 MngInfoFreeStruct(mng_info,&have_mng_structure);
6054 return((Image *) NULL);
6057 image=SyncNextImageInList(image);
6059 mng_info->image=image;
6061 if (term_chunk_found)
6063 image->start_loop=MagickTrue;
6064 image->iterations=mng_iterations;
6065 term_chunk_found=MagickFalse;
6069 image->start_loop=MagickFalse;
6071 /* Make a background rectangle. */
6074 image->columns=mng_info->mng_width;
6075 image->rows=mng_info->mng_height;
6076 image->page.width=mng_info->mng_width;
6077 image->page.height=mng_info->mng_height;
6080 image->background_color=mng_background_color;
6081 (void) SetImageBackgroundColor(image,exception);
6082 if (logging != MagickFalse)
6083 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6084 " Inserted transparent background layer, W=%.20g, H=%.20g",
6085 (double) mng_info->mng_width,(double) mng_info->mng_height);
6089 Insert a background layer behind the upcoming image if
6090 framing_mode is 3, and we haven't already inserted one.
6092 if (insert_layers && (mng_info->framing_mode == 3) &&
6093 (subframe_width) && (subframe_height) && (simplicity == 0 ||
6094 (simplicity & 0x08)))
6096 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
6099 Allocate next image structure.
6101 AcquireNextImage(image_info,image,exception);
6103 if (GetNextImageInList(image) == (Image *) NULL)
6105 image=DestroyImageList(image);
6106 MngInfoFreeStruct(mng_info,&have_mng_structure);
6107 return((Image *) NULL);
6110 image=SyncNextImageInList(image);
6113 mng_info->image=image;
6115 if (term_chunk_found)
6117 image->start_loop=MagickTrue;
6118 image->iterations=mng_iterations;
6119 term_chunk_found=MagickFalse;
6123 image->start_loop=MagickFalse;
6126 image->columns=subframe_width;
6127 image->rows=subframe_height;
6128 image->page.width=subframe_width;
6129 image->page.height=subframe_height;
6130 image->page.x=mng_info->clip.left;
6131 image->page.y=mng_info->clip.top;
6132 image->background_color=mng_background_color;
6133 image->alpha_trait=UndefinedPixelTrait;
6134 (void) SetImageBackgroundColor(image,exception);
6136 if (logging != MagickFalse)
6137 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6138 " Insert background layer, L=%.20g, R=%.20g T=%.20g, B=%.20g",
6139 (double) mng_info->clip.left,(double) mng_info->clip.right,
6140 (double) mng_info->clip.top,(double) mng_info->clip.bottom);
6142 #endif /* MNG_INSERT_LAYERS */
6143 first_mng_object=MagickFalse;
6145 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
6148 Allocate next image structure.
6150 AcquireNextImage(image_info,image,exception);
6152 if (GetNextImageInList(image) == (Image *) NULL)
6154 image=DestroyImageList(image);
6155 MngInfoFreeStruct(mng_info,&have_mng_structure);
6156 return((Image *) NULL);
6159 image=SyncNextImageInList(image);
6161 mng_info->image=image;
6162 status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
6163 GetBlobSize(image));
6165 if (status == MagickFalse)
6168 if (term_chunk_found)
6170 image->start_loop=MagickTrue;
6171 term_chunk_found=MagickFalse;
6175 image->start_loop=MagickFalse;
6177 if (mng_info->framing_mode == 1 || mng_info->framing_mode == 3)
6179 image->delay=frame_delay;
6180 frame_delay=default_frame_delay;
6186 image->page.width=mng_info->mng_width;
6187 image->page.height=mng_info->mng_height;
6188 image->page.x=mng_info->x_off[object_id];
6189 image->page.y=mng_info->y_off[object_id];
6190 image->iterations=mng_iterations;
6193 Seek back to the beginning of the IHDR or JHDR chunk's length field.
6196 if (logging != MagickFalse)
6197 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6198 " Seeking back to beginning of %c%c%c%c chunk",type[0],type[1],
6201 offset=SeekBlob(image,-((ssize_t) length+12),SEEK_CUR);
6204 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
6208 mng_info->image=image;
6209 mng_info->mng_type=mng_type;
6210 mng_info->object_id=object_id;
6212 if (memcmp(type,mng_IHDR,4) == 0)
6213 image=ReadOnePNGImage(mng_info,image_info,exception);
6215 #if defined(JNG_SUPPORTED)
6217 image=ReadOneJNGImage(mng_info,image_info,exception);
6220 if (image == (Image *) NULL)
6222 if (IsImageObject(previous) != MagickFalse)
6224 (void) DestroyImageList(previous);
6225 (void) CloseBlob(previous);
6228 MngInfoFreeStruct(mng_info,&have_mng_structure);
6229 return((Image *) NULL);
6232 if (image->columns == 0 || image->rows == 0)
6234 (void) CloseBlob(image);
6235 image=DestroyImageList(image);
6236 MngInfoFreeStruct(mng_info,&have_mng_structure);
6237 return((Image *) NULL);
6240 mng_info->image=image;
6247 if (mng_info->magn_methx || mng_info->magn_methy)
6253 if (logging != MagickFalse)
6254 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6255 " Processing MNG MAGN chunk");
6257 if (mng_info->magn_methx == 1)
6259 magnified_width=mng_info->magn_ml;
6261 if (image->columns > 1)
6262 magnified_width += mng_info->magn_mr;
6264 if (image->columns > 2)
6265 magnified_width += (png_uint_32)
6266 ((image->columns-2)*(mng_info->magn_mx));
6271 magnified_width=(png_uint_32) image->columns;
6273 if (image->columns > 1)
6274 magnified_width += mng_info->magn_ml-1;
6276 if (image->columns > 2)
6277 magnified_width += mng_info->magn_mr-1;
6279 if (image->columns > 3)
6280 magnified_width += (png_uint_32)
6281 ((image->columns-3)*(mng_info->magn_mx-1));
6284 if (mng_info->magn_methy == 1)
6286 magnified_height=mng_info->magn_mt;
6288 if (image->rows > 1)
6289 magnified_height += mng_info->magn_mb;
6291 if (image->rows > 2)
6292 magnified_height += (png_uint_32)
6293 ((image->rows-2)*(mng_info->magn_my));
6298 magnified_height=(png_uint_32) image->rows;
6300 if (image->rows > 1)
6301 magnified_height += mng_info->magn_mt-1;
6303 if (image->rows > 2)
6304 magnified_height += mng_info->magn_mb-1;
6306 if (image->rows > 3)
6307 magnified_height += (png_uint_32)
6308 ((image->rows-3)*(mng_info->magn_my-1));
6311 if (magnified_height > image->rows ||
6312 magnified_width > image->columns)
6339 /* Allocate next image structure. */
6341 if (logging != MagickFalse)
6342 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6343 " Allocate magnified image");
6345 AcquireNextImage(image_info,image,exception);
6347 if (GetNextImageInList(image) == (Image *) NULL)
6349 image=DestroyImageList(image);
6350 MngInfoFreeStruct(mng_info,&have_mng_structure);
6351 return((Image *) NULL);
6354 large_image=SyncNextImageInList(image);
6356 large_image->columns=magnified_width;
6357 large_image->rows=magnified_height;
6359 magn_methx=mng_info->magn_methx;
6360 magn_methy=mng_info->magn_methy;
6362 #if (MAGICKCORE_QUANTUM_DEPTH > 16)
6363 #define QM unsigned short
6364 if (magn_methx != 1 || magn_methy != 1)
6367 Scale pixels to unsigned shorts to prevent
6368 overflow of intermediate values of interpolations
6370 for (y=0; y < (ssize_t) image->rows; y++)
6372 q=GetAuthenticPixels(image,0,y,image->columns,1,
6375 for (x=(ssize_t) image->columns-1; x >= 0; x--)
6377 SetPixelRed(image,ScaleQuantumToShort(
6378 GetPixelRed(image,q)),q);
6379 SetPixelGreen(image,ScaleQuantumToShort(
6380 GetPixelGreen(image,q)),q);
6381 SetPixelBlue(image,ScaleQuantumToShort(
6382 GetPixelBlue(image,q)),q);
6383 SetPixelAlpha(image,ScaleQuantumToShort(
6384 GetPixelAlpha(image,q)),q);
6385 q+=GetPixelChannels(image);
6388 if (SyncAuthenticPixels(image,exception) == MagickFalse)
6396 if (image->alpha_trait == BlendPixelTrait)
6397 (void) SetImageBackgroundColor(large_image,exception);
6401 large_image->background_color.alpha=OpaqueAlpha;
6402 (void) SetImageBackgroundColor(large_image,exception);
6404 if (magn_methx == 4)
6407 if (magn_methx == 5)
6410 if (magn_methy == 4)
6413 if (magn_methy == 5)
6417 /* magnify the rows into the right side of the large image */
6419 if (logging != MagickFalse)
6420 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6421 " Magnify the rows to %.20g",(double) large_image->rows);
6422 m=(ssize_t) mng_info->magn_mt;
6424 length=(size_t) image->columns*GetPixelChannels(image);
6425 next=(Quantum *) AcquireQuantumMemory(length,sizeof(*next));
6426 prev=(Quantum *) AcquireQuantumMemory(length,sizeof(*prev));
6428 if ((prev == (Quantum *) NULL) ||
6429 (next == (Quantum *) NULL))
6431 image=DestroyImageList(image);
6432 MngInfoFreeStruct(mng_info,&have_mng_structure);
6433 ThrowReaderException(ResourceLimitError,
6434 "MemoryAllocationFailed");
6437 n=GetAuthenticPixels(image,0,0,image->columns,1,exception);
6438 (void) CopyMagickMemory(next,n,length);
6440 for (y=0; y < (ssize_t) image->rows; y++)
6443 m=(ssize_t) mng_info->magn_mt;
6445 else if (magn_methy > 1 && y == (ssize_t) image->rows-2)
6446 m=(ssize_t) mng_info->magn_mb;
6448 else if (magn_methy <= 1 && y == (ssize_t) image->rows-1)
6449 m=(ssize_t) mng_info->magn_mb;
6451 else if (magn_methy > 1 && y == (ssize_t) image->rows-1)
6455 m=(ssize_t) mng_info->magn_my;
6461 if (y < (ssize_t) image->rows-1)
6463 n=GetAuthenticPixels(image,0,y+1,image->columns,1,
6465 (void) CopyMagickMemory(next,n,length);
6468 for (i=0; i < m; i++, yy++)
6473 assert(yy < (ssize_t) large_image->rows);
6476 q=GetAuthenticPixels(large_image,0,yy,large_image->columns,
6478 q+=(large_image->columns-image->columns)*
6479 GetPixelChannels(large_image);
6481 for (x=(ssize_t) image->columns-1; x >= 0; x--)
6483 /* To do: get color as function of indexes[x] */
6485 if (image->storage_class == PseudoClass)
6490 if (magn_methy <= 1)
6492 /* replicate previous */
6493 SetPixelRed(large_image,GetPixelRed(image,pixels),q);
6494 SetPixelGreen(large_image,GetPixelGreen(image,
6496 SetPixelBlue(large_image,GetPixelBlue(image,
6498 SetPixelAlpha(large_image,GetPixelAlpha(image,
6502 else if (magn_methy == 2 || magn_methy == 4)
6506 SetPixelRed(large_image,GetPixelRed(image,
6508 SetPixelGreen(large_image,GetPixelGreen(image,
6510 SetPixelBlue(large_image,GetPixelBlue(image,
6512 SetPixelAlpha(large_image,GetPixelAlpha(image,
6519 SetPixelRed(large_image,((QM) (((ssize_t)
6520 (2*i*(GetPixelRed(image,n)
6521 -GetPixelRed(image,pixels)+m))/
6523 +GetPixelRed(image,pixels)))),q);
6524 SetPixelGreen(large_image,((QM) (((ssize_t)
6525 (2*i*(GetPixelGreen(image,n)
6526 -GetPixelGreen(image,pixels)+m))/
6528 +GetPixelGreen(image,pixels)))),q);
6529 SetPixelBlue(large_image,((QM) (((ssize_t)
6530 (2*i*(GetPixelBlue(image,n)
6531 -GetPixelBlue(image,pixels)+m))/
6533 +GetPixelBlue(image,pixels)))),q);
6535 if (image->alpha_trait == BlendPixelTrait)
6536 SetPixelAlpha(large_image, ((QM) (((ssize_t)
6537 (2*i*(GetPixelAlpha(image,n)
6538 -GetPixelAlpha(image,pixels)+m))
6540 GetPixelAlpha(image,pixels)))),q);
6543 if (magn_methy == 4)
6545 /* Replicate nearest */
6546 if (i <= ((m+1) << 1))
6547 SetPixelAlpha(large_image,GetPixelAlpha(image,
6550 SetPixelAlpha(large_image,GetPixelAlpha(image,
6555 else /* if (magn_methy == 3 || magn_methy == 5) */
6557 /* Replicate nearest */
6558 if (i <= ((m+1) << 1))
6560 SetPixelRed(large_image,GetPixelRed(image,
6562 SetPixelGreen(large_image,GetPixelGreen(image,
6564 SetPixelBlue(large_image,GetPixelBlue(image,
6566 SetPixelAlpha(large_image,GetPixelAlpha(image,
6572 SetPixelRed(large_image,GetPixelRed(image,n),q);
6573 SetPixelGreen(large_image,GetPixelGreen(image,n),
6575 SetPixelBlue(large_image,GetPixelBlue(image,n),
6577 SetPixelAlpha(large_image,GetPixelAlpha(image,n),
6581 if (magn_methy == 5)
6583 SetPixelAlpha(large_image,(QM) (((ssize_t) (2*i*
6584 (GetPixelAlpha(image,n)
6585 -GetPixelAlpha(image,pixels))
6586 +m))/((ssize_t) (m*2))
6587 +GetPixelAlpha(image,pixels)),q);
6590 n+=GetPixelChannels(image);
6591 q+=GetPixelChannels(large_image);
6592 pixels+=GetPixelChannels(image);
6595 if (SyncAuthenticPixels(large_image,exception) == 0)
6601 prev=(Quantum *) RelinquishMagickMemory(prev);
6602 next=(Quantum *) RelinquishMagickMemory(next);
6604 length=image->columns;
6606 if (logging != MagickFalse)
6607 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6608 " Delete original image");
6610 DeleteImageFromList(&image);
6614 mng_info->image=image;
6616 /* magnify the columns */
6617 if (logging != MagickFalse)
6618 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6619 " Magnify the columns to %.20g",(double) image->columns);
6621 for (y=0; y < (ssize_t) image->rows; y++)
6626 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
6627 pixels=q+(image->columns-length)*GetPixelChannels(image);
6628 n=pixels+GetPixelChannels(image);
6630 for (x=(ssize_t) (image->columns-length);
6631 x < (ssize_t) image->columns; x++)
6633 /* To do: Rewrite using Get/Set***PixelChannel() */
6635 if (x == (ssize_t) (image->columns-length))
6636 m=(ssize_t) mng_info->magn_ml;
6638 else if (magn_methx > 1 && x == (ssize_t) image->columns-2)
6639 m=(ssize_t) mng_info->magn_mr;
6641 else if (magn_methx <= 1 && x == (ssize_t) image->columns-1)
6642 m=(ssize_t) mng_info->magn_mr;
6644 else if (magn_methx > 1 && x == (ssize_t) image->columns-1)
6648 m=(ssize_t) mng_info->magn_mx;
6650 for (i=0; i < m; i++)
6652 if (magn_methx <= 1)
6654 /* replicate previous */
6655 SetPixelRed(image,GetPixelRed(image,pixels),q);
6656 SetPixelGreen(image,GetPixelGreen(image,pixels),q);
6657 SetPixelBlue(image,GetPixelBlue(image,pixels),q);
6658 SetPixelAlpha(image,GetPixelAlpha(image,pixels),q);
6661 else if (magn_methx == 2 || magn_methx == 4)
6665 SetPixelRed(image,GetPixelRed(image,pixels),q);
6666 SetPixelGreen(image,GetPixelGreen(image,pixels),q);
6667 SetPixelBlue(image,GetPixelBlue(image,pixels),q);
6668 SetPixelAlpha(image,GetPixelAlpha(image,pixels),q);
6671 /* To do: Rewrite using Get/Set***PixelChannel() */
6675 SetPixelRed(image,(QM) ((2*i*(
6676 GetPixelRed(image,n)
6677 -GetPixelRed(image,pixels))+m)
6679 GetPixelRed(image,pixels)),q);
6681 SetPixelGreen(image,(QM) ((2*i*(
6682 GetPixelGreen(image,n)
6683 -GetPixelGreen(image,pixels))+m)
6685 GetPixelGreen(image,pixels)),q);
6687 SetPixelBlue(image,(QM) ((2*i*(
6688 GetPixelBlue(image,n)
6689 -GetPixelBlue(image,pixels))+m)
6691 GetPixelBlue(image,pixels)),q);
6692 if (image->alpha_trait == BlendPixelTrait)
6693 SetPixelAlpha(image,(QM) ((2*i*(
6694 GetPixelAlpha(image,n)
6695 -GetPixelAlpha(image,pixels))+m)
6697 GetPixelAlpha(image,pixels)),q);
6700 if (magn_methx == 4)
6702 /* Replicate nearest */
6703 if (i <= ((m+1) << 1))
6705 SetPixelAlpha(image,
6706 GetPixelAlpha(image,pixels)+0,q);
6710 SetPixelAlpha(image,
6711 GetPixelAlpha(image,n)+0,q);
6716 else /* if (magn_methx == 3 || magn_methx == 5) */
6718 /* Replicate nearest */
6719 if (i <= ((m+1) << 1))
6721 SetPixelRed(image,GetPixelRed(image,pixels),q);
6722 SetPixelGreen(image,GetPixelGreen(image,pixels),q);
6723 SetPixelBlue(image,GetPixelBlue(image,pixels),q);
6724 SetPixelAlpha(image,GetPixelAlpha(image,pixels),q);
6729 SetPixelRed(image,GetPixelRed(image,n),q);
6730 SetPixelGreen(image,GetPixelGreen(image,n),q);
6731 SetPixelBlue(image,GetPixelBlue(image,n),q);
6732 SetPixelAlpha(image,GetPixelAlpha(image,n),q);
6735 if (magn_methx == 5)
6738 SetPixelAlpha(image,
6739 (QM) ((2*i*( GetPixelAlpha(image,n)
6740 -GetPixelAlpha(image,pixels))+m)/
6742 +GetPixelAlpha(image,pixels)),q);
6745 q+=GetPixelChannels(image);
6747 n+=GetPixelChannels(image);
6748 p+=GetPixelChannels(image);
6751 if (SyncAuthenticPixels(image,exception) == MagickFalse)
6754 #if (MAGICKCORE_QUANTUM_DEPTH > 16)
6755 if (magn_methx != 1 || magn_methy != 1)
6758 Rescale pixels to Quantum
6760 for (y=0; y < (ssize_t) image->rows; y++)
6762 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
6764 for (x=(ssize_t) image->columns-1; x >= 0; x--)
6766 SetPixelRed(image,ScaleShortToQuantum(
6767 GetPixelRed(image,q)),q);
6768 SetPixelGreen(image,ScaleShortToQuantum(
6769 GetPixelGreen(image,q)),q);
6770 SetPixelBlue(image,ScaleShortToQuantum(
6771 GetPixelBlue(image,q)),q);
6772 SetPixelAlpha(image,ScaleShortToQuantum(
6773 GetPixelAlpha(image,q)),q);
6774 q+=GetPixelChannels(image);
6777 if (SyncAuthenticPixels(image,exception) == MagickFalse)
6782 if (logging != MagickFalse)
6783 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6784 " Finished MAGN processing");
6789 Crop_box is with respect to the upper left corner of the MNG.
6791 crop_box.left=mng_info->image_box.left+mng_info->x_off[object_id];
6792 crop_box.right=mng_info->image_box.right+mng_info->x_off[object_id];
6793 crop_box.top=mng_info->image_box.top+mng_info->y_off[object_id];
6794 crop_box.bottom=mng_info->image_box.bottom+mng_info->y_off[object_id];
6795 crop_box=mng_minimum_box(crop_box,mng_info->clip);
6796 crop_box=mng_minimum_box(crop_box,mng_info->frame);
6797 crop_box=mng_minimum_box(crop_box,mng_info->object_clip[object_id]);
6798 if ((crop_box.left != (mng_info->image_box.left
6799 +mng_info->x_off[object_id])) ||
6800 (crop_box.right != (mng_info->image_box.right
6801 +mng_info->x_off[object_id])) ||
6802 (crop_box.top != (mng_info->image_box.top
6803 +mng_info->y_off[object_id])) ||
6804 (crop_box.bottom != (mng_info->image_box.bottom
6805 +mng_info->y_off[object_id])))
6807 if (logging != MagickFalse)
6808 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6809 " Crop the PNG image");
6811 if ((crop_box.left < crop_box.right) &&
6812 (crop_box.top < crop_box.bottom))
6821 Crop_info is with respect to the upper left corner of
6824 crop_info.x=(crop_box.left-mng_info->x_off[object_id]);
6825 crop_info.y=(crop_box.top-mng_info->y_off[object_id]);
6826 crop_info.width=(size_t) (crop_box.right-crop_box.left);
6827 crop_info.height=(size_t) (crop_box.bottom-crop_box.top);
6828 image->page.width=image->columns;
6829 image->page.height=image->rows;
6832 im=CropImage(image,&crop_info,exception);
6834 if (im != (Image *) NULL)
6836 image->columns=im->columns;
6837 image->rows=im->rows;
6838 im=DestroyImage(im);
6839 image->page.width=image->columns;
6840 image->page.height=image->rows;
6841 image->page.x=crop_box.left;
6842 image->page.y=crop_box.top;
6849 No pixels in crop area. The MNG spec still requires
6850 a layer, though, so make a single transparent pixel in
6851 the top left corner.
6856 (void) SetImageBackgroundColor(image,exception);
6857 image->page.width=1;
6858 image->page.height=1;
6863 #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
6864 image=mng_info->image;
6868 #if (MAGICKCORE_QUANTUM_DEPTH > 16)
6869 /* PNG does not handle depths greater than 16 so reduce it even
6872 if (image->depth > 16)
6876 #if (MAGICKCORE_QUANTUM_DEPTH > 8)
6877 if (image->depth > 8)
6879 /* To do: fill low byte properly */
6883 if (LosslessReduceDepthOK(image,exception) != MagickFalse)
6887 if (image_info->number_scenes != 0)
6889 if (mng_info->scenes_found >
6890 (ssize_t) (image_info->first_scene+image_info->number_scenes))
6894 if (logging != MagickFalse)
6895 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6896 " Finished reading image datastream.");
6898 } while (LocaleCompare(image_info->magick,"MNG") == 0);
6900 (void) CloseBlob(image);
6902 if (logging != MagickFalse)
6903 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6904 " Finished reading all image datastreams.");
6906 #if defined(MNG_INSERT_LAYERS)
6907 if (insert_layers && !mng_info->image_found && (mng_info->mng_width) &&
6908 (mng_info->mng_height))
6911 Insert a background layer if nothing else was found.
6913 if (logging != MagickFalse)
6914 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6915 " No images found. Inserting a background layer.");
6917 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
6920 Allocate next image structure.
6922 AcquireNextImage(image_info,image,exception);
6923 if (GetNextImageInList(image) == (Image *) NULL)
6925 image=DestroyImageList(image);
6926 MngInfoFreeStruct(mng_info,&have_mng_structure);
6928 if (logging != MagickFalse)
6929 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6930 " Allocation failed, returning NULL.");
6932 return((Image *) NULL);
6934 image=SyncNextImageInList(image);
6936 image->columns=mng_info->mng_width;
6937 image->rows=mng_info->mng_height;
6938 image->page.width=mng_info->mng_width;
6939 image->page.height=mng_info->mng_height;
6942 image->background_color=mng_background_color;
6943 image->alpha_trait=UndefinedPixelTrait;
6945 if (image_info->ping == MagickFalse)
6946 (void) SetImageBackgroundColor(image,exception);
6948 mng_info->image_found++;
6951 image->iterations=mng_iterations;
6953 if (mng_iterations == 1)
6954 image->start_loop=MagickTrue;
6956 while (GetPreviousImageInList(image) != (Image *) NULL)
6959 if (image_count > 10*mng_info->image_found)
6961 if (logging != MagickFalse)
6962 (void) LogMagickEvent(CoderEvent,GetMagickModule()," No beginning");
6964 (void) ThrowMagickException(exception,GetMagickModule(),
6965 CoderError,"Linked list is corrupted, beginning of list not found",
6966 "`%s'",image_info->filename);
6968 return((Image *) NULL);
6971 image=GetPreviousImageInList(image);
6973 if (GetNextImageInList(image) == (Image *) NULL)
6975 if (logging != MagickFalse)
6976 (void) LogMagickEvent(CoderEvent,GetMagickModule()," Corrupt list");
6978 (void) ThrowMagickException(exception,GetMagickModule(),
6979 CoderError,"Linked list is corrupted; next_image is NULL","`%s'",
6980 image_info->filename);
6984 if (mng_info->ticks_per_second && mng_info->image_found > 1 &&
6985 GetNextImageInList(image) ==
6988 if (logging != MagickFalse)
6989 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6990 " First image null");
6992 (void) ThrowMagickException(exception,GetMagickModule(),
6993 CoderError,"image->next for first image is NULL but shouldn't be.",
6994 "`%s'",image_info->filename);
6997 if (mng_info->image_found == 0)
6999 if (logging != MagickFalse)
7000 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7001 " No visible images found.");
7003 (void) ThrowMagickException(exception,GetMagickModule(),
7004 CoderError,"No visible images in file","`%s'",image_info->filename);
7006 if (image != (Image *) NULL)
7007 image=DestroyImageList(image);
7009 MngInfoFreeStruct(mng_info,&have_mng_structure);
7010 return((Image *) NULL);
7013 if (mng_info->ticks_per_second)
7014 final_delay=1UL*MagickMax(image->ticks_per_second,1L)*
7015 final_delay/mng_info->ticks_per_second;
7018 image->start_loop=MagickTrue;
7020 /* Find final nonzero image delay */
7021 final_image_delay=0;
7023 while (GetNextImageInList(image) != (Image *) NULL)
7026 final_image_delay=image->delay;
7028 image=GetNextImageInList(image);
7031 if (final_delay < final_image_delay)
7032 final_delay=final_image_delay;
7034 image->delay=final_delay;
7036 if (logging != MagickFalse)
7037 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7038 " image->delay=%.20g, final_delay=%.20g",(double) image->delay,
7039 (double) final_delay);
7041 if (logging != MagickFalse)
7047 image=GetFirstImageInList(image);
7049 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7050 " Before coalesce:");
7052 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7053 " scene 0 delay=%.20g",(double) image->delay);
7055 while (GetNextImageInList(image) != (Image *) NULL)
7057 image=GetNextImageInList(image);
7058 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7059 " scene %.20g delay=%.20g",(double) scene++,(double) image->delay);
7063 image=GetFirstImageInList(image);
7064 #ifdef MNG_COALESCE_LAYERS
7074 if (logging != MagickFalse)
7075 (void) LogMagickEvent(CoderEvent,GetMagickModule()," Coalesce Images");
7078 next_image=CoalesceImages(image,exception);
7080 if (next_image == (Image *) NULL)
7081 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
7083 image=DestroyImageList(image);
7086 for (next=image; next != (Image *) NULL; next=next_image)
7088 next->page.width=mng_info->mng_width;
7089 next->page.height=mng_info->mng_height;
7092 next->scene=scene++;
7093 next_image=GetNextImageInList(next);
7095 if (next_image == (Image *) NULL)
7098 if (next->delay == 0)
7101 next_image->previous=GetPreviousImageInList(next);
7102 if (GetPreviousImageInList(next) == (Image *) NULL)
7105 next->previous->next=next_image;
7106 next=DestroyImage(next);
7112 while (GetNextImageInList(image) != (Image *) NULL)
7113 image=GetNextImageInList(image);
7115 image->dispose=BackgroundDispose;
7117 if (logging != MagickFalse)
7123 image=GetFirstImageInList(image);
7125 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7126 " After coalesce:");
7128 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7129 " scene 0 delay=%.20g dispose=%.20g",(double) image->delay,
7130 (double) image->dispose);
7132 while (GetNextImageInList(image) != (Image *) NULL)
7134 image=GetNextImageInList(image);
7136 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7137 " scene %.20g delay=%.20g dispose=%.20g",(double) scene++,
7138 (double) image->delay,(double) image->dispose);
7142 image=GetFirstImageInList(image);
7143 MngInfoFreeStruct(mng_info,&have_mng_structure);
7144 have_mng_structure=MagickFalse;
7146 if (logging != MagickFalse)
7147 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit ReadMNGImage()");
7149 return(GetFirstImageInList(image));
7151 #else /* PNG_LIBPNG_VER > 10011 */
7152 static Image *ReadPNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
7154 printf("Your PNG library is too old: You have libpng-%s\n",
7155 PNG_LIBPNG_VER_STRING);
7157 (void) ThrowMagickException(exception,GetMagickModule(),CoderError,
7158 "PNG library is too old","`%s'",image_info->filename);
7160 return(Image *) NULL;
7163 static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
7165 return(ReadPNGImage(image_info,exception));
7167 #endif /* PNG_LIBPNG_VER > 10011 */
7171 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7175 % R e g i s t e r P N G I m a g e %
7179 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7181 % RegisterPNGImage() adds properties for the PNG image format to
7182 % the list of supported formats. The properties include the image format
7183 % tag, a method to read and/or write the format, whether the format
7184 % supports the saving of more than one frame to the same file or blob,
7185 % whether the format supports native in-memory I/O, and a brief
7186 % description of the format.
7188 % The format of the RegisterPNGImage method is:
7190 % size_t RegisterPNGImage(void)
7193 ModuleExport size_t RegisterPNGImage(void)
7196 version[MaxTextExtent];
7204 "See http://www.libpng.org/ for details about the PNG format."
7209 "See http://www.libpng.org/pub/mng/ for details about the JNG\n"
7215 "See http://www.libpng.org/pub/mng/ for details about the MNG\n"
7221 #if defined(PNG_LIBPNG_VER_STRING)
7222 (void) ConcatenateMagickString(version,"libpng ",MaxTextExtent);
7223 (void) ConcatenateMagickString(version,PNG_LIBPNG_VER_STRING,MaxTextExtent);
7225 if (LocaleCompare(PNG_LIBPNG_VER_STRING,png_get_header_ver(NULL)) != 0)
7227 (void) ConcatenateMagickString(version,",",MaxTextExtent);
7228 (void) ConcatenateMagickString(version,png_get_libpng_ver(NULL),
7233 entry=SetMagickInfo("MNG");
7234 entry->seekable_stream=MagickTrue; /* To do: eliminate this. */
7236 #if defined(MAGICKCORE_PNG_DELEGATE)
7237 entry->decoder=(DecodeImageHandler *) ReadMNGImage;
7238 entry->encoder=(EncodeImageHandler *) WriteMNGImage;
7241 entry->magick=(IsImageFormatHandler *) IsMNG;
7242 entry->description=ConstantString("Multiple-image Network Graphics");
7244 if (*version != '\0')
7245 entry->version=ConstantString(version);
7247 entry->module=ConstantString("PNG");
7248 entry->note=ConstantString(MNGNote);
7249 (void) RegisterMagickInfo(entry);
7251 entry=SetMagickInfo("PNG");
7253 #if defined(MAGICKCORE_PNG_DELEGATE)
7254 entry->decoder=(DecodeImageHandler *) ReadPNGImage;
7255 entry->encoder=(EncodeImageHandler *) WritePNGImage;
7258 entry->magick=(IsImageFormatHandler *) IsPNG;
7259 entry->adjoin=MagickFalse;
7260 entry->description=ConstantString("Portable Network Graphics");
7261 entry->module=ConstantString("PNG");
7263 if (*version != '\0')
7264 entry->version=ConstantString(version);
7266 entry->note=ConstantString(PNGNote);
7267 (void) RegisterMagickInfo(entry);
7269 entry=SetMagickInfo("PNG8");
7271 #if defined(MAGICKCORE_PNG_DELEGATE)
7272 entry->decoder=(DecodeImageHandler *) ReadPNGImage;
7273 entry->encoder=(EncodeImageHandler *) WritePNGImage;
7276 entry->magick=(IsImageFormatHandler *) IsPNG;
7277 entry->adjoin=MagickFalse;
7278 entry->description=ConstantString(
7279 "8-bit indexed with optional binary transparency");
7280 entry->module=ConstantString("PNG");
7281 (void) RegisterMagickInfo(entry);
7283 entry=SetMagickInfo("PNG24");
7286 #if defined(ZLIB_VERSION)
7287 (void) ConcatenateMagickString(version,"zlib ",MaxTextExtent);
7288 (void) ConcatenateMagickString(version,ZLIB_VERSION,MaxTextExtent);
7290 if (LocaleCompare(ZLIB_VERSION,zlib_version) != 0)
7292 (void) ConcatenateMagickString(version,",",MaxTextExtent);
7293 (void) ConcatenateMagickString(version,zlib_version,MaxTextExtent);
7297 if (*version != '\0')
7298 entry->version=ConstantString(version);
7300 #if defined(MAGICKCORE_PNG_DELEGATE)
7301 entry->decoder=(DecodeImageHandler *) ReadPNGImage;
7302 entry->encoder=(EncodeImageHandler *) WritePNGImage;
7305 entry->magick=(IsImageFormatHandler *) IsPNG;
7306 entry->adjoin=MagickFalse;
7307 entry->description=ConstantString("opaque or binary transparent 24-bit RGB");
7308 entry->module=ConstantString("PNG");
7309 (void) RegisterMagickInfo(entry);
7311 entry=SetMagickInfo("PNG32");
7313 #if defined(MAGICKCORE_PNG_DELEGATE)
7314 entry->decoder=(DecodeImageHandler *) ReadPNGImage;
7315 entry->encoder=(EncodeImageHandler *) WritePNGImage;
7318 entry->magick=(IsImageFormatHandler *) IsPNG;
7319 entry->adjoin=MagickFalse;
7320 entry->description=ConstantString("opaque or transparent 32-bit RGBA");
7321 entry->module=ConstantString("PNG");
7322 (void) RegisterMagickInfo(entry);
7324 entry=SetMagickInfo("PNG48");
7326 #if defined(MAGICKCORE_PNG_DELEGATE)
7327 entry->decoder=(DecodeImageHandler *) ReadPNGImage;
7328 entry->encoder=(EncodeImageHandler *) WritePNGImage;
7331 entry->magick=(IsImageFormatHandler *) IsPNG;
7332 entry->adjoin=MagickFalse;
7333 entry->description=ConstantString("opaque or binary transparent 48-bit RGB");
7334 entry->module=ConstantString("PNG");
7335 (void) RegisterMagickInfo(entry);
7337 entry=SetMagickInfo("PNG64");
7339 #if defined(MAGICKCORE_PNG_DELEGATE)
7340 entry->decoder=(DecodeImageHandler *) ReadPNGImage;
7341 entry->encoder=(EncodeImageHandler *) WritePNGImage;
7344 entry->magick=(IsImageFormatHandler *) IsPNG;
7345 entry->adjoin=MagickFalse;
7346 entry->description=ConstantString("opaque or transparent 64-bit RGBA");
7347 entry->module=ConstantString("PNG");
7348 (void) RegisterMagickInfo(entry);
7350 entry=SetMagickInfo("PNG00");
7352 #if defined(MAGICKCORE_PNG_DELEGATE)
7353 entry->decoder=(DecodeImageHandler *) ReadPNGImage;
7354 entry->encoder=(EncodeImageHandler *) WritePNGImage;
7357 entry->magick=(IsImageFormatHandler *) IsPNG;
7358 entry->adjoin=MagickFalse;
7359 entry->description=ConstantString("PNG inheriting subformat from original");
7360 entry->module=ConstantString("PNG");
7361 (void) RegisterMagickInfo(entry);
7363 entry=SetMagickInfo("JNG");
7365 #if defined(JNG_SUPPORTED)
7366 #if defined(MAGICKCORE_PNG_DELEGATE)
7367 entry->decoder=(DecodeImageHandler *) ReadJNGImage;
7368 entry->encoder=(EncodeImageHandler *) WriteJNGImage;
7372 entry->magick=(IsImageFormatHandler *) IsJNG;
7373 entry->adjoin=MagickFalse;
7374 entry->description=ConstantString("JPEG Network Graphics");
7375 entry->module=ConstantString("PNG");
7376 entry->note=ConstantString(JNGNote);
7377 (void) RegisterMagickInfo(entry);
7379 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
7380 ping_semaphore=AllocateSemaphoreInfo();
7383 return(MagickImageCoderSignature);
7387 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7391 % U n r e g i s t e r P N G I m a g e %
7395 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7397 % UnregisterPNGImage() removes format registrations made by the
7398 % PNG module from the list of supported formats.
7400 % The format of the UnregisterPNGImage method is:
7402 % UnregisterPNGImage(void)
7405 ModuleExport void UnregisterPNGImage(void)
7407 (void) UnregisterMagickInfo("MNG");
7408 (void) UnregisterMagickInfo("PNG");
7409 (void) UnregisterMagickInfo("PNG8");
7410 (void) UnregisterMagickInfo("PNG24");
7411 (void) UnregisterMagickInfo("PNG32");
7412 (void) UnregisterMagickInfo("PNG48");
7413 (void) UnregisterMagickInfo("PNG64");
7414 (void) UnregisterMagickInfo("PNG00");
7415 (void) UnregisterMagickInfo("JNG");
7417 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
7418 if (ping_semaphore != (SemaphoreInfo *) NULL)
7419 DestroySemaphoreInfo(&ping_semaphore);
7423 #if defined(MAGICKCORE_PNG_DELEGATE)
7424 #if PNG_LIBPNG_VER > 10011
7426 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7430 % W r i t e M N G I m a g e %
7434 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7436 % WriteMNGImage() writes an image in the Portable Network Graphics
7437 % Group's "Multiple-image Network Graphics" encoded image format.
7439 % MNG support written by Glenn Randers-Pehrson, glennrp@image...
7441 % The format of the WriteMNGImage method is:
7443 % MagickBooleanType WriteMNGImage(const ImageInfo *image_info,
7444 % Image *image,ExceptionInfo *exception)
7446 % A description of each parameter follows.
7448 % o image_info: the image info.
7450 % o image: The image.
7452 % o exception: return any errors or warnings in this structure.
7454 % To do (as of version 5.5.2, November 26, 2002 -- glennrp -- see also
7455 % "To do" under ReadPNGImage):
7457 % Preserve all unknown and not-yet-handled known chunks found in input
7458 % PNG file and copy them into output PNG files according to the PNG
7461 % Write the iCCP chunk at MNG level when (icc profile length > 0)
7463 % Improve selection of color type (use indexed-colour or indexed-colour
7464 % with tRNS when 256 or fewer unique RGBA values are present).
7466 % Figure out what to do with "dispose=<restore-to-previous>" (dispose == 3)
7467 % This will be complicated if we limit ourselves to generating MNG-LC
7468 % files. For now we ignore disposal method 3 and simply overlay the next
7471 % Check for identical PLTE's or PLTE/tRNS combinations and use a
7472 % global MNG PLTE or PLTE/tRNS combination when appropriate.
7473 % [mostly done 15 June 1999 but still need to take care of tRNS]
7475 % Check for identical sRGB and replace with a global sRGB (and remove
7476 % gAMA/cHRM if sRGB is found; check for identical gAMA/cHRM and
7477 % replace with global gAMA/cHRM (or with sRGB if appropriate; replace
7478 % local gAMA/cHRM with local sRGB if appropriate).
7480 % Check for identical sBIT chunks and write global ones.
7482 % Provide option to skip writing the signature tEXt chunks.
7484 % Use signatures to detect identical objects and reuse the first
7485 % instance of such objects instead of writing duplicate objects.
7487 % Use a smaller-than-32k value of compression window size when
7490 % Encode JNG datastreams. Mostly done as of 5.5.2; need to write
7491 % ancillary text chunks and save profiles.
7493 % Provide an option to force LC files (to ensure exact framing rate)
7496 % Provide an option to force VLC files instead of LC, even when offsets
7497 % are present. This will involve expanding the embedded images with a
7498 % transparent region at the top and/or left.
7502 Magick_png_write_raw_profile(const ImageInfo *image_info,png_struct *ping,
7503 png_info *ping_info, unsigned char *profile_type, unsigned char
7504 *profile_description, unsigned char *profile_data, png_uint_32 length)
7523 hex[16]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
7525 if (LocaleNCompare((char *) profile_type+1, "ng-chunk-",9) == 0)
7528 if (image_info->verbose)
7530 (void) printf("writing raw profile: type=%s, length=%.20g\n",
7531 (char *) profile_type, (double) length);
7534 #if PNG_LIBPNG_VER >= 14000
7535 text=(png_textp) png_malloc(ping,(png_alloc_size_t) sizeof(png_text));
7537 text=(png_textp) png_malloc(ping,(png_size_t) sizeof(png_text));
7539 description_length=(png_uint_32) strlen((const char *) profile_description);
7540 allocated_length=(png_uint_32) (length*2 + (length >> 5) + 20
7541 + description_length);
7542 #if PNG_LIBPNG_VER >= 14000
7543 text[0].text=(png_charp) png_malloc(ping,
7544 (png_alloc_size_t) allocated_length);
7545 text[0].key=(png_charp) png_malloc(ping, (png_alloc_size_t) 80);
7547 text[0].text=(png_charp) png_malloc(ping, (png_size_t) allocated_length);
7548 text[0].key=(png_charp) png_malloc(ping, (png_size_t) 80);
7550 text[0].key[0]='\0';
7551 (void) ConcatenateMagickString(text[0].key,
7552 "Raw profile type ",MaxTextExtent);
7553 (void) ConcatenateMagickString(text[0].key,(const char *) profile_type,62);
7557 (void) CopyMagickString(dp,(const char *) profile_description,
7559 dp+=description_length;
7561 (void) FormatLocaleString(dp,allocated_length-
7562 (png_size_t) (dp-text[0].text),"%8lu ",(unsigned long) length);
7565 for (i=0; i < (ssize_t) length; i++)
7569 *(dp++)=(char) hex[((*sp >> 4) & 0x0f)];
7570 *(dp++)=(char) hex[((*sp++ ) & 0x0f)];
7575 text[0].text_length=(png_size_t) (dp-text[0].text);
7576 text[0].compression=image_info->compression == NoCompression ||
7577 (image_info->compression == UndefinedCompression &&
7578 text[0].text_length < 128) ? -1 : 0;
7580 if (text[0].text_length <= allocated_length)
7581 png_set_text(ping,ping_info,text,1);
7583 png_free(ping,text[0].text);
7584 png_free(ping,text[0].key);
7585 png_free(ping,text);
7588 static MagickBooleanType Magick_png_write_chunk_from_profile(Image *image,
7589 const char *string, MagickBooleanType logging)
7602 ResetImageProfileIterator(image);
7604 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
7606 profile=GetImageProfile(image,name);
7608 if (profile != (const StringInfo *) NULL)
7613 if (LocaleNCompare(name,string,11) == 0)
7615 if (logging != MagickFalse)
7616 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7617 " Found %s profile",name);
7619 ping_profile=CloneStringInfo(profile);
7620 data=GetStringInfoDatum(ping_profile),
7621 length=(png_uint_32) GetStringInfoLength(ping_profile);
7626 (void) WriteBlobMSBULong(image,length-5); /* data length */
7627 (void) WriteBlob(image,length-1,data+1);
7628 (void) WriteBlobMSBULong(image,crc32(0,data+1,(uInt) length-1));
7629 ping_profile=DestroyStringInfo(ping_profile);
7633 name=GetNextImageProfile(image);
7640 /* Write one PNG image */
7641 static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
7642 const ImageInfo *IMimage_info,Image *IMimage,ExceptionInfo *exception)
7666 ping_trans_alpha[256];
7694 ping_have_cheap_transparency,
7705 /* ping_exclude_EXIF, */
7708 /* ping_exclude_iTXt, */
7713 /* ping_exclude_tRNS, */
7715 ping_exclude_zCCP, /* hex-encoded iCCP */
7718 ping_preserve_colormap,
7719 ping_need_colortype_warning,
7737 *volatile ping_pixels;
7743 ping_interlace_method,
7744 ping_compression_method,
7761 number_semitransparent,
7763 ping_pHYs_unit_type;
7766 ping_pHYs_x_resolution,
7767 ping_pHYs_y_resolution;
7769 logging=LogMagickEvent(CoderEvent,GetMagickModule(),
7770 " Enter WriteOnePNGImage()");
7772 image = CloneImage(IMimage,0,0,MagickFalse,exception);
7773 image_info=(ImageInfo *) CloneImageInfo(IMimage_info);
7774 if (image_info == (ImageInfo *) NULL)
7775 ThrowWriterException(ResourceLimitError, "MemoryAllocationFailed");
7777 /* Initialize some stuff */
7780 ping_interlace_method=0,
7781 ping_compression_method=0,
7782 ping_filter_method=0,
7785 ping_background.red = 0;
7786 ping_background.green = 0;
7787 ping_background.blue = 0;
7788 ping_background.gray = 0;
7789 ping_background.index = 0;
7791 ping_trans_color.red=0;
7792 ping_trans_color.green=0;
7793 ping_trans_color.blue=0;
7794 ping_trans_color.gray=0;
7796 ping_pHYs_unit_type = 0;
7797 ping_pHYs_x_resolution = 0;
7798 ping_pHYs_y_resolution = 0;
7800 ping_have_blob=MagickFalse;
7801 ping_have_color=MagickTrue;
7802 ping_have_non_bw=MagickTrue;
7803 ping_have_PLTE=MagickFalse;
7804 ping_have_bKGD=MagickFalse;
7805 ping_have_pHYs=MagickFalse;
7806 ping_have_tRNS=MagickFalse;
7808 ping_exclude_bKGD=mng_info->ping_exclude_bKGD;
7809 ping_exclude_cHRM=mng_info->ping_exclude_cHRM;
7810 ping_exclude_date=mng_info->ping_exclude_date;
7811 /* ping_exclude_EXIF=mng_info->ping_exclude_EXIF; */
7812 ping_exclude_gAMA=mng_info->ping_exclude_gAMA;
7813 ping_exclude_iCCP=mng_info->ping_exclude_iCCP;
7814 /* ping_exclude_iTXt=mng_info->ping_exclude_iTXt; */
7815 ping_exclude_oFFs=mng_info->ping_exclude_oFFs;
7816 ping_exclude_pHYs=mng_info->ping_exclude_pHYs;
7817 ping_exclude_sRGB=mng_info->ping_exclude_sRGB;
7818 ping_exclude_tEXt=mng_info->ping_exclude_tEXt;
7819 /* ping_exclude_tRNS=mng_info->ping_exclude_tRNS; */
7820 ping_exclude_vpAg=mng_info->ping_exclude_vpAg;
7821 ping_exclude_zCCP=mng_info->ping_exclude_zCCP; /* hex-encoded iCCP in zTXt */
7822 ping_exclude_zTXt=mng_info->ping_exclude_zTXt;
7824 ping_preserve_colormap = mng_info->ping_preserve_colormap;
7825 ping_need_colortype_warning = MagickFalse;
7827 /* Recognize the ICC sRGB profile and convert it to the sRGB chunk,
7828 * i.e., eliminate the ICC profile and set image->rendering_intent.
7829 * Note that this will not involve any changes to the actual pixels
7830 * but merely passes information to applications that read the resulting
7833 if (ping_exclude_sRGB == MagickFalse)
7841 ResetImageProfileIterator(image);
7842 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
7844 profile=GetImageProfile(image,name);
7846 if (profile != (StringInfo *) NULL)
7848 if ((LocaleCompare(name,"ICC") == 0) ||
7849 (LocaleCompare(name,"ICM") == 0))
7854 /* 0: not a known sRGB profile
7855 * 1: HP-Microsoft sRGB v2
7856 * 2: ICC sRGB v4 perceptual
7857 * 3: ICC sRGB v2 perceptual no black-compensation
7860 check_crc[4] = {0, 0xf29e526dUL, 0xbbef7812UL, 0x427ebb21UL},
7861 check_len[4] = {0, 3144, 60960, 3052};
7870 length=(png_uint_32) GetStringInfoLength(profile);
7872 for (icheck=3; icheck > 0; icheck--)
7874 if (length == check_len[icheck])
7876 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7877 " Got a %lu-byte ICC profile (potentially sRGB)",
7878 (unsigned long) length);
7880 data=GetStringInfoDatum(profile);
7881 profile_crc=crc32(0,data,length);
7883 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7884 " with crc=%8x",(unsigned int) profile_crc);
7886 if (profile_crc == check_crc[icheck])
7888 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7890 if (image->rendering_intent==UndefinedIntent)
7891 image->rendering_intent=PerceptualIntent;
7897 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7898 " Got a %lu-byte ICC profile",
7899 (unsigned long) length);
7902 name=GetNextImageProfile(image);
7907 number_semitransparent = 0;
7908 number_transparent = 0;
7910 if (logging != MagickFalse)
7912 if (image->storage_class == UndefinedClass)
7913 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7914 " storage_class=UndefinedClass");
7915 if (image->storage_class == DirectClass)
7916 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7917 " storage_class=DirectClass");
7918 if (image->storage_class == PseudoClass)
7919 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7920 " storage_class=PseudoClass");
7923 if (image->storage_class == PseudoClass &&
7924 (mng_info->write_png8 || mng_info->write_png24 || mng_info->write_png32 ||
7925 mng_info->write_png48 || mng_info->write_png64 ||
7926 (mng_info->write_png_colortype != 1 &&
7927 mng_info->write_png_colortype != 5)))
7929 (void) SyncImage(image,exception);
7930 image->storage_class = DirectClass;
7933 if (ping_preserve_colormap == MagickFalse)
7935 if (image->storage_class != PseudoClass && image->colormap != NULL)
7937 /* Free the bogus colormap; it can cause trouble later */
7938 if (logging != MagickFalse)
7939 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7940 " Freeing bogus colormap");
7941 (void) RelinquishMagickMemory(image->colormap);
7942 image->colormap=NULL;
7946 if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
7947 (void) TransformImageColorspace(image,sRGBColorspace,exception);
7950 Sometimes we get PseudoClass images whose RGB values don't match
7951 the colors in the colormap. This code syncs the RGB values.
7953 if (image->depth <= 8 && image->taint && image->storage_class == PseudoClass)
7954 (void) SyncImage(image,exception);
7956 #if (MAGICKCORE_QUANTUM_DEPTH == 8)
7957 if (image->depth > 8)
7959 if (logging != MagickFalse)
7960 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7961 " Reducing PNG bit depth to 8 since this is a Q8 build.");
7967 /* Respect the -depth option */
7968 if (image->depth < MAGICKCORE_QUANTUM_DEPTH)
7973 if (image->depth > 8)
7975 #if MAGICKCORE_QUANTUM_DEPTH > 16
7976 /* Scale to 16-bit */
7977 LBR16PacketRGBO(image->background_color);
7979 for (y=0; y < (ssize_t) image->rows; y++)
7981 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
7983 if (r == (Quantum *) NULL)
7986 for (x=0; x < (ssize_t) image->columns; x++)
7989 r+=GetPixelChannels(image);
7992 if (SyncAuthenticPixels(image,exception) == MagickFalse)
7996 if (image->storage_class == PseudoClass && image->colormap != NULL)
7998 for (i=0; i < (ssize_t) image->colors; i++)
8000 LBR16PacketRGBO(image->colormap[i]);
8003 #endif /* MAGICKCORE_QUANTUM_DEPTH > 16 */
8006 else if (image->depth > 4)
8008 #if MAGICKCORE_QUANTUM_DEPTH > 8
8009 /* Scale to 8-bit */
8010 LBR08PacketRGBO(image->background_color);
8012 for (y=0; y < (ssize_t) image->rows; y++)
8014 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8016 if (r == (Quantum *) NULL)
8019 for (x=0; x < (ssize_t) image->columns; x++)
8022 r+=GetPixelChannels(image);
8025 if (SyncAuthenticPixels(image,exception) == MagickFalse)
8029 if (image->storage_class == PseudoClass && image->colormap != NULL)
8031 for (i=0; i < (ssize_t) image->colors; i++)
8033 LBR08PacketRGBO(image->colormap[i]);
8036 #endif /* MAGICKCORE_QUANTUM_DEPTH > 8 */
8039 if (image->depth > 2)
8041 /* Scale to 4-bit */
8042 LBR04PacketRGBO(image->background_color);
8044 for (y=0; y < (ssize_t) image->rows; y++)
8046 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8048 if (r == (Quantum *) NULL)
8051 for (x=0; x < (ssize_t) image->columns; x++)
8054 r+=GetPixelChannels(image);
8057 if (SyncAuthenticPixels(image,exception) == MagickFalse)
8061 if (image->storage_class == PseudoClass && image->colormap != NULL)
8063 for (i=0; i < (ssize_t) image->colors; i++)
8065 LBR04PacketRGBO(image->colormap[i]);
8070 else if (image->depth > 1)
8072 /* Scale to 2-bit */
8073 LBR02PacketRGBO(image->background_color);
8075 for (y=0; y < (ssize_t) image->rows; y++)
8077 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8079 if (r == (Quantum *) NULL)
8082 for (x=0; x < (ssize_t) image->columns; x++)
8085 r+=GetPixelChannels(image);
8088 if (SyncAuthenticPixels(image,exception) == MagickFalse)
8092 if (image->storage_class == PseudoClass && image->colormap != NULL)
8094 for (i=0; i < (ssize_t) image->colors; i++)
8096 LBR02PacketRGBO(image->colormap[i]);
8102 /* Scale to 1-bit */
8103 LBR01PacketRGBO(image->background_color);
8105 for (y=0; y < (ssize_t) image->rows; y++)
8107 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8109 if (r == (Quantum *) NULL)
8112 for (x=0; x < (ssize_t) image->columns; x++)
8115 r+=GetPixelChannels(image);
8118 if (SyncAuthenticPixels(image,exception) == MagickFalse)
8122 if (image->storage_class == PseudoClass && image->colormap != NULL)
8124 for (i=0; i < (ssize_t) image->colors; i++)
8126 LBR01PacketRGBO(image->colormap[i]);
8132 /* To do: set to next higher multiple of 8 */
8133 if (image->depth < 8)
8136 #if (MAGICKCORE_QUANTUM_DEPTH > 16)
8137 /* PNG does not handle depths greater than 16 so reduce it even
8140 if (image->depth > 8)
8144 #if (MAGICKCORE_QUANTUM_DEPTH > 8)
8145 if (image->depth > 8)
8147 /* To do: fill low byte properly */
8151 if (image->depth == 16 && mng_info->write_png_depth != 16)
8152 if (mng_info->write_png8 || LosslessReduceDepthOK(image,exception) != MagickFalse)
8156 if (image->storage_class != PseudoClass && mng_info->write_png_colortype &&
8157 (mng_info->write_png_colortype > 4 || (mng_info->write_png_depth >= 8 &&
8158 mng_info->write_png_colortype < 4 &&
8159 image->alpha_trait != BlendPixelTrait)))
8161 /* Avoid the expensive BUILD_PALETTE operation if we're sure that we
8162 * are not going to need the result.
8164 image_colors = (int) image->colors;
8165 number_opaque = (int) image->colors;
8166 if (mng_info->write_png_colortype == 1 ||
8167 mng_info->write_png_colortype == 5)
8168 ping_have_color=MagickFalse;
8170 ping_have_color=MagickTrue;
8171 ping_have_non_bw=MagickFalse;
8173 if (image->alpha_trait == BlendPixelTrait)
8175 number_transparent = 2;
8176 number_semitransparent = 1;
8181 number_transparent = 0;
8182 number_semitransparent = 0;
8190 * Normally we run this just once, but in the case of writing PNG8
8191 * we reduce the transparency to binary and run again, then if there
8192 * are still too many colors we reduce to a simple 4-4-4-1, then 3-3-3-1
8193 * RGBA palette and run again, and then to a simple 3-3-2-1 RGBA
8194 * palette. Then (To do) we take care of a final reduction that is only
8195 * needed if there are still 256 colors present and one of them has both
8196 * transparent and opaque instances.
8199 tried_332 = MagickFalse;
8200 tried_333 = MagickFalse;
8201 tried_444 = MagickFalse;
8206 * Sometimes we get DirectClass images that have 256 colors or fewer.
8207 * This code will build a colormap.
8209 * Also, sometimes we get PseudoClass images with an out-of-date
8210 * colormap. This code will replace the colormap with a new one.
8211 * Sometimes we get PseudoClass images that have more than 256 colors.
8212 * This code will delete the colormap and change the image to
8215 * If image->alpha_trait is MagickFalse, we ignore the alpha channel
8216 * even though it sometimes contains left-over non-opaque values.
8218 * Also we gather some information (number of opaque, transparent,
8219 * and semitransparent pixels, and whether the image has any non-gray
8220 * pixels or only black-and-white pixels) that we might need later.
8222 * Even if the user wants to force GrayAlpha or RGBA (colortype 4 or 6)
8223 * we need to check for bogus non-opaque values, at least.
8231 semitransparent[260],
8234 register const Quantum
8241 if (logging != MagickFalse)
8242 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8243 " Enter BUILD_PALETTE:");
8245 if (logging != MagickFalse)
8247 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8248 " image->columns=%.20g",(double) image->columns);
8249 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8250 " image->rows=%.20g",(double) image->rows);
8251 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8252 " image->alpha_trait=%.20g",(double) image->alpha_trait);
8253 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8254 " image->depth=%.20g",(double) image->depth);
8256 if (image->storage_class == PseudoClass && image->colormap != NULL)
8258 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8259 " Original colormap:");
8260 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8261 " i (red,green,blue,alpha)");
8263 for (i=0; i < 256; i++)
8265 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8266 " %d (%d,%d,%d,%d)",
8268 (int) image->colormap[i].red,
8269 (int) image->colormap[i].green,
8270 (int) image->colormap[i].blue,
8271 (int) image->colormap[i].alpha);
8274 for (i=image->colors - 10; i < (ssize_t) image->colors; i++)
8278 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8279 " %d (%d,%d,%d,%d)",
8281 (int) image->colormap[i].red,
8282 (int) image->colormap[i].green,
8283 (int) image->colormap[i].blue,
8284 (int) image->colormap[i].alpha);
8289 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8290 " image->colors=%d",(int) image->colors);
8292 if (image->colors == 0)
8293 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8294 " (zero means unknown)");
8296 if (ping_preserve_colormap == MagickFalse)
8297 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8298 " Regenerate the colormap");
8303 number_semitransparent = 0;
8304 number_transparent = 0;
8306 for (y=0; y < (ssize_t) image->rows; y++)
8308 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8310 if (q == (Quantum *) NULL)
8313 for (x=0; x < (ssize_t) image->columns; x++)
8315 if (image->alpha_trait != BlendPixelTrait ||
8316 GetPixelAlpha(image,q) == OpaqueAlpha)
8318 if (number_opaque < 259)
8320 if (number_opaque == 0)
8322 GetPixelInfoPixel(image, q, opaque);
8323 opaque[0].alpha=OpaqueAlpha;
8327 for (i=0; i< (ssize_t) number_opaque; i++)
8329 if (IsPixelEquivalent(image,q, opaque+i))
8333 if (i == (ssize_t) number_opaque && number_opaque < 259)
8336 GetPixelInfoPixel(image, q, opaque+i);
8337 opaque[i].alpha=OpaqueAlpha;
8341 else if (GetPixelAlpha(image,q) == TransparentAlpha)
8343 if (number_transparent < 259)
8345 if (number_transparent == 0)
8347 GetPixelInfoPixel(image, q, transparent);
8348 ping_trans_color.red=(unsigned short)
8349 GetPixelRed(image,q);
8350 ping_trans_color.green=(unsigned short)
8351 GetPixelGreen(image,q);
8352 ping_trans_color.blue=(unsigned short)
8353 GetPixelBlue(image,q);
8354 ping_trans_color.gray=(unsigned short)
8355 GetPixelGray(image,q);
8356 number_transparent = 1;
8359 for (i=0; i< (ssize_t) number_transparent; i++)
8361 if (IsPixelEquivalent(image,q, transparent+i))
8365 if (i == (ssize_t) number_transparent &&
8366 number_transparent < 259)
8368 number_transparent++;
8369 GetPixelInfoPixel(image,q,transparent+i);
8375 if (number_semitransparent < 259)
8377 if (number_semitransparent == 0)
8379 GetPixelInfoPixel(image,q,semitransparent);
8380 number_semitransparent = 1;
8383 for (i=0; i< (ssize_t) number_semitransparent; i++)
8385 if (IsPixelEquivalent(image,q, semitransparent+i)
8386 && GetPixelAlpha(image,q) ==
8387 semitransparent[i].alpha)
8391 if (i == (ssize_t) number_semitransparent &&
8392 number_semitransparent < 259)
8394 number_semitransparent++;
8395 GetPixelInfoPixel(image, q, semitransparent+i);
8399 q+=GetPixelChannels(image);
8403 if (mng_info->write_png8 == MagickFalse &&
8404 ping_exclude_bKGD == MagickFalse)
8406 /* Add the background color to the palette, if it
8407 * isn't already there.
8409 if (logging != MagickFalse)
8411 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8412 " Check colormap for background (%d,%d,%d)",
8413 (int) image->background_color.red,
8414 (int) image->background_color.green,
8415 (int) image->background_color.blue);
8417 for (i=0; i<number_opaque; i++)
8419 if (opaque[i].red == image->background_color.red &&
8420 opaque[i].green == image->background_color.green &&
8421 opaque[i].blue == image->background_color.blue)
8424 if (number_opaque < 259 && i == number_opaque)
8426 opaque[i] = image->background_color;
8427 ping_background.index = i;
8429 if (logging != MagickFalse)
8431 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8432 " background_color index is %d",(int) i);
8436 else if (logging != MagickFalse)
8437 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8438 " No room in the colormap to add background color");
8441 image_colors=number_opaque+number_transparent+number_semitransparent;
8443 if (mng_info->write_png8 != MagickFalse && image_colors > 256)
8445 /* No room for the background color; remove it. */
8450 if (logging != MagickFalse)
8452 if (image_colors > 256)
8453 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8454 " image has more than 256 colors");
8457 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8458 " image has %d colors",image_colors);
8461 if (ping_preserve_colormap != MagickFalse)
8464 if (mng_info->write_png_colortype != 7) /* We won't need this info */
8466 ping_have_color=MagickFalse;
8467 ping_have_non_bw=MagickFalse;
8469 if ((IssRGBCompatibleColorspace(image->colorspace) == MagickFalse) ||
8470 (IssRGBColorspace(image->colorspace) != MagickFalse))
8472 ping_have_color=MagickTrue;
8473 ping_have_non_bw=MagickTrue;
8476 if(image_colors > 256)
8478 for (y=0; y < (ssize_t) image->rows; y++)
8480 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8482 if (q == (Quantum *) NULL)
8486 for (x=0; x < (ssize_t) image->columns; x++)
8488 if (GetPixelRed(image,s) != GetPixelGreen(image,s) ||
8489 GetPixelRed(image,s) != GetPixelBlue(image,s))
8491 ping_have_color=MagickTrue;
8492 ping_have_non_bw=MagickTrue;
8495 s+=GetPixelChannels(image);
8498 if (ping_have_color != MagickFalse)
8501 /* Worst case is black-and-white; we are looking at every
8505 if (ping_have_non_bw == MagickFalse)
8508 for (x=0; x < (ssize_t) image->columns; x++)
8510 if (GetPixelRed(image,s) != 0 &&
8511 GetPixelRed(image,s) != QuantumRange)
8513 ping_have_non_bw=MagickTrue;
8516 s+=GetPixelChannels(image);
8523 if (image_colors < 257)
8529 * Initialize image colormap.
8532 if (logging != MagickFalse)
8533 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8534 " Sort the new colormap");
8536 /* Sort palette, transparent first */;
8540 for (i=0; i<number_transparent; i++)
8541 colormap[n++] = transparent[i];
8543 for (i=0; i<number_semitransparent; i++)
8544 colormap[n++] = semitransparent[i];
8546 for (i=0; i<number_opaque; i++)
8547 colormap[n++] = opaque[i];
8549 ping_background.index +=
8550 (number_transparent + number_semitransparent);
8552 /* image_colors < 257; search the colormap instead of the pixels
8553 * to get ping_have_color and ping_have_non_bw
8557 if (ping_have_color == MagickFalse)
8559 if (colormap[i].red != colormap[i].green ||
8560 colormap[i].red != colormap[i].blue)
8562 ping_have_color=MagickTrue;
8563 ping_have_non_bw=MagickTrue;
8568 if (ping_have_non_bw == MagickFalse)
8570 if (colormap[i].red != 0 && colormap[i].red != QuantumRange)
8571 ping_have_non_bw=MagickTrue;
8575 if ((mng_info->ping_exclude_tRNS == MagickFalse ||
8576 (number_transparent == 0 && number_semitransparent == 0)) &&
8577 (((mng_info->write_png_colortype-1) ==
8578 PNG_COLOR_TYPE_PALETTE) ||
8579 (mng_info->write_png_colortype == 0)))
8581 if (logging != MagickFalse)
8583 if (n != (ssize_t) image_colors)
8584 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8585 " image_colors (%d) and n (%d) don't match",
8588 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8589 " AcquireImageColormap");
8592 image->colors = image_colors;
8594 if (AcquireImageColormap(image,image_colors,exception) ==
8596 ThrowWriterException(ResourceLimitError,
8597 "MemoryAllocationFailed");
8599 for (i=0; i< (ssize_t) image_colors; i++)
8600 image->colormap[i] = colormap[i];
8602 if (logging != MagickFalse)
8604 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8605 " image->colors=%d (%d)",
8606 (int) image->colors, image_colors);
8608 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8609 " Update the pixel indexes");
8612 /* Sync the pixel indices with the new colormap */
8614 for (y=0; y < (ssize_t) image->rows; y++)
8616 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8618 if (q == (Quantum *) NULL)
8621 for (x=0; x < (ssize_t) image->columns; x++)
8623 for (i=0; i< (ssize_t) image_colors; i++)
8625 if ((image->alpha_trait != BlendPixelTrait ||
8626 image->colormap[i].alpha == GetPixelAlpha(image,q)) &&
8627 image->colormap[i].red == GetPixelRed(image,q) &&
8628 image->colormap[i].green == GetPixelGreen(image,q) &&
8629 image->colormap[i].blue == GetPixelBlue(image,q))
8631 SetPixelIndex(image,i,q);
8635 q+=GetPixelChannels(image);
8638 if (SyncAuthenticPixels(image,exception) == MagickFalse)
8644 if (logging != MagickFalse)
8646 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8647 " image->colors=%d", (int) image->colors);
8649 if (image->colormap != NULL)
8651 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8652 " i (red,green,blue,alpha)");
8654 for (i=0; i < (ssize_t) image->colors; i++)
8656 if (i < 300 || i >= (ssize_t) image->colors - 10)
8658 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8659 " %d (%d,%d,%d,%d)",
8661 (int) image->colormap[i].red,
8662 (int) image->colormap[i].green,
8663 (int) image->colormap[i].blue,
8664 (int) image->colormap[i].alpha);
8669 if (number_transparent < 257)
8670 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8671 " number_transparent = %d",
8672 number_transparent);
8675 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8676 " number_transparent > 256");
8678 if (number_opaque < 257)
8679 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8680 " number_opaque = %d",
8684 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8685 " number_opaque > 256");
8687 if (number_semitransparent < 257)
8688 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8689 " number_semitransparent = %d",
8690 number_semitransparent);
8693 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8694 " number_semitransparent > 256");
8696 if (ping_have_non_bw == MagickFalse)
8697 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8698 " All pixels and the background are black or white");
8700 else if (ping_have_color == MagickFalse)
8701 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8702 " All pixels and the background are gray");
8705 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8706 " At least one pixel or the background is non-gray");
8708 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8709 " Exit BUILD_PALETTE:");
8712 if (mng_info->write_png8 == MagickFalse)
8715 /* Make any reductions necessary for the PNG8 format */
8716 if (image_colors <= 256 &&
8717 image_colors != 0 && image->colormap != NULL &&
8718 number_semitransparent == 0 &&
8719 number_transparent <= 1)
8722 /* PNG8 can't have semitransparent colors so we threshold the
8723 * opacity to 0 or OpaqueOpacity, and PNG8 can only have one
8724 * transparent color so if more than one is transparent we merge
8725 * them into image->background_color.
8727 if (number_semitransparent != 0 || number_transparent > 1)
8729 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8730 " Thresholding the alpha channel to binary");
8732 for (y=0; y < (ssize_t) image->rows; y++)
8734 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8736 if (r == (Quantum *) NULL)
8739 for (x=0; x < (ssize_t) image->columns; x++)
8741 if (GetPixelAlpha(image,r) < OpaqueAlpha/2)
8743 SetPixelInfoPixel(image,&image->background_color,r);
8744 SetPixelAlpha(image,TransparentAlpha,r);
8747 SetPixelAlpha(image,OpaqueAlpha,r);
8748 r+=GetPixelChannels(image);
8751 if (SyncAuthenticPixels(image,exception) == MagickFalse)
8754 if (image_colors != 0 && image_colors <= 256 &&
8755 image->colormap != NULL)
8756 for (i=0; i<image_colors; i++)
8757 image->colormap[i].alpha =
8758 (image->colormap[i].alpha > TransparentAlpha/2 ?
8759 TransparentAlpha : OpaqueAlpha);
8764 /* PNG8 can't have more than 256 colors so we quantize the pixels and
8765 * background color to the 4-4-4-1, 3-3-3-1 or 3-3-2-1 palette. If the
8766 * image is mostly gray, the 4-4-4-1 palette is likely to end up with 256
8769 if (tried_444 == MagickFalse && (image_colors == 0 || image_colors > 256))
8771 if (logging != MagickFalse)
8772 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8773 " Quantizing the background color to 4-4-4");
8775 tried_444 = MagickTrue;
8777 LBR04PacketRGB(image->background_color);
8779 if (logging != MagickFalse)
8780 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8781 " Quantizing the pixel colors to 4-4-4");
8783 if (image->colormap == NULL)
8785 for (y=0; y < (ssize_t) image->rows; y++)
8787 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8789 if (r == (Quantum *) NULL)
8792 for (x=0; x < (ssize_t) image->columns; x++)
8794 if (GetPixelAlpha(image,r) == OpaqueAlpha)
8796 r+=GetPixelChannels(image);
8799 if (SyncAuthenticPixels(image,exception) == MagickFalse)
8804 else /* Should not reach this; colormap already exists and
8807 if (logging != MagickFalse)
8808 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8809 " Quantizing the colormap to 4-4-4");
8811 for (i=0; i<image_colors; i++)
8813 LBR04PacketRGB(image->colormap[i]);
8819 if (tried_333 == MagickFalse && (image_colors == 0 || image_colors > 256))
8821 if (logging != MagickFalse)
8822 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8823 " Quantizing the background color to 3-3-3");
8825 tried_333 = MagickTrue;
8827 LBR03PacketRGB(image->background_color);
8829 if (logging != MagickFalse)
8830 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8831 " Quantizing the pixel colors to 3-3-3-1");
8833 if (image->colormap == NULL)
8835 for (y=0; y < (ssize_t) image->rows; y++)
8837 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8839 if (r == (Quantum *) NULL)
8842 for (x=0; x < (ssize_t) image->columns; x++)
8844 if (GetPixelAlpha(image,r) == OpaqueAlpha)
8846 r+=GetPixelChannels(image);
8849 if (SyncAuthenticPixels(image,exception) == MagickFalse)
8854 else /* Should not reach this; colormap already exists and
8857 if (logging != MagickFalse)
8858 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8859 " Quantizing the colormap to 3-3-3-1");
8860 for (i=0; i<image_colors; i++)
8862 LBR03PacketRGB(image->colormap[i]);
8868 if (tried_332 == MagickFalse && (image_colors == 0 || image_colors > 256))
8870 if (logging != MagickFalse)
8871 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8872 " Quantizing the background color to 3-3-2");
8874 tried_332 = MagickTrue;
8876 /* Red and green were already done so we only quantize the blue
8880 LBR02PacketBlue(image->background_color);
8882 if (logging != MagickFalse)
8883 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8884 " Quantizing the pixel colors to 3-3-2-1");
8886 if (image->colormap == NULL)
8888 for (y=0; y < (ssize_t) image->rows; y++)
8890 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8892 if (r == (Quantum *) NULL)
8895 for (x=0; x < (ssize_t) image->columns; x++)
8897 if (GetPixelAlpha(image,r) == OpaqueAlpha)
8899 r+=GetPixelChannels(image);
8902 if (SyncAuthenticPixels(image,exception) == MagickFalse)
8907 else /* Should not reach this; colormap already exists and
8910 if (logging != MagickFalse)
8911 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8912 " Quantizing the colormap to 3-3-2-1");
8913 for (i=0; i<image_colors; i++)
8915 LBR02PacketBlue(image->colormap[i]);
8922 if (image_colors == 0 || image_colors > 256)
8924 /* Take care of special case with 256 colors + 1 transparent
8925 * color. We don't need to quantize to 2-3-2-1; we only need to
8926 * eliminate one color, so we'll merge the two darkest red
8927 * colors (0x49, 0, 0) -> (0x24, 0, 0).
8929 if (ScaleQuantumToChar(image->background_color.red) == 0x49 &&
8930 ScaleQuantumToChar(image->background_color.green) == 0x00 &&
8931 ScaleQuantumToChar(image->background_color.blue) == 0x00)
8933 image->background_color.red=ScaleCharToQuantum(0x24);
8936 if (image->colormap == NULL)
8938 for (y=0; y < (ssize_t) image->rows; y++)
8940 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8942 if (r == (Quantum *) NULL)
8945 for (x=0; x < (ssize_t) image->columns; x++)
8947 if (ScaleQuantumToChar(GetPixelRed(image,r)) == 0x49 &&
8948 ScaleQuantumToChar(GetPixelGreen(image,r)) == 0x00 &&
8949 ScaleQuantumToChar(GetPixelBlue(image,r)) == 0x00 &&
8950 GetPixelAlpha(image,r) == OpaqueAlpha)
8952 SetPixelRed(image,ScaleCharToQuantum(0x24),r);
8954 r+=GetPixelChannels(image);
8957 if (SyncAuthenticPixels(image,exception) == MagickFalse)
8965 for (i=0; i<image_colors; i++)
8967 if (ScaleQuantumToChar(image->colormap[i].red) == 0x49 &&
8968 ScaleQuantumToChar(image->colormap[i].green) == 0x00 &&
8969 ScaleQuantumToChar(image->colormap[i].blue) == 0x00)
8971 image->colormap[i].red=ScaleCharToQuantum(0x24);
8978 /* END OF BUILD_PALETTE */
8980 /* If we are excluding the tRNS chunk and there is transparency,
8981 * then we must write a Gray-Alpha (color-type 4) or RGBA (color-type 6)
8984 if (mng_info->ping_exclude_tRNS != MagickFalse &&
8985 (number_transparent != 0 || number_semitransparent != 0))
8987 unsigned int colortype=mng_info->write_png_colortype;
8989 if (ping_have_color == MagickFalse)
8990 mng_info->write_png_colortype = 5;
8993 mng_info->write_png_colortype = 7;
8995 if (colortype != 0 &&
8996 mng_info->write_png_colortype != colortype)
8997 ping_need_colortype_warning=MagickTrue;
9001 /* See if cheap transparency is possible. It is only possible
9002 * when there is a single transparent color, no semitransparent
9003 * color, and no opaque color that has the same RGB components
9004 * as the transparent color. We only need this information if
9005 * we are writing a PNG with colortype 0 or 2, and we have not
9006 * excluded the tRNS chunk.
9008 if (number_transparent == 1 &&
9009 mng_info->write_png_colortype < 4)
9011 ping_have_cheap_transparency = MagickTrue;
9013 if (number_semitransparent != 0)
9014 ping_have_cheap_transparency = MagickFalse;
9016 else if (image_colors == 0 || image_colors > 256 ||
9017 image->colormap == NULL)
9019 register const Quantum
9022 for (y=0; y < (ssize_t) image->rows; y++)
9024 q=GetVirtualPixels(image,0,y,image->columns,1, exception);
9026 if (q == (Quantum *) NULL)
9029 for (x=0; x < (ssize_t) image->columns; x++)
9031 if (GetPixelAlpha(image,q) != TransparentAlpha &&
9032 (unsigned short) GetPixelRed(image,q) ==
9033 ping_trans_color.red &&
9034 (unsigned short) GetPixelGreen(image,q) ==
9035 ping_trans_color.green &&
9036 (unsigned short) GetPixelBlue(image,q) ==
9037 ping_trans_color.blue)
9039 ping_have_cheap_transparency = MagickFalse;
9043 q+=GetPixelChannels(image);
9046 if (ping_have_cheap_transparency == MagickFalse)
9052 /* Assuming that image->colormap[0] is the one transparent color
9053 * and that all others are opaque.
9055 if (image_colors > 1)
9056 for (i=1; i<image_colors; i++)
9057 if (image->colormap[i].red == image->colormap[0].red &&
9058 image->colormap[i].green == image->colormap[0].green &&
9059 image->colormap[i].blue == image->colormap[0].blue)
9061 ping_have_cheap_transparency = MagickFalse;
9066 if (logging != MagickFalse)
9068 if (ping_have_cheap_transparency == MagickFalse)
9069 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9070 " Cheap transparency is not possible.");
9073 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9074 " Cheap transparency is possible.");
9078 ping_have_cheap_transparency = MagickFalse;
9080 image_depth=image->depth;
9082 quantum_info = (QuantumInfo *) NULL;
9084 image_colors=(int) image->colors;
9085 image_matte=image->alpha_trait == BlendPixelTrait ? MagickTrue : MagickFalse;
9087 mng_info->IsPalette=image->storage_class == PseudoClass &&
9088 image_colors <= 256 && image->colormap != NULL;
9090 if ((mng_info->write_png_colortype == 4 || mng_info->write_png8) &&
9091 (image->colors == 0 || image->colormap == NULL))
9093 image_info=DestroyImageInfo(image_info);
9094 image=DestroyImage(image);
9095 (void) ThrowMagickException(exception,GetMagickModule(),CoderError,
9096 "Cannot write PNG8 or color-type 3; colormap is NULL",
9097 "`%s'",IMimage->filename);
9098 return(MagickFalse);
9102 Allocate the PNG structures
9104 #ifdef PNG_USER_MEM_SUPPORTED
9105 error_info.image=image;
9106 error_info.exception=exception;
9107 ping=png_create_write_struct_2(PNG_LIBPNG_VER_STRING,&error_info,
9108 MagickPNGErrorHandler,MagickPNGWarningHandler,(void *) NULL,
9109 (png_malloc_ptr) Magick_png_malloc,(png_free_ptr) Magick_png_free);
9112 ping=png_create_write_struct(PNG_LIBPNG_VER_STRING,&error_info,
9113 MagickPNGErrorHandler,MagickPNGWarningHandler);
9116 if (ping == (png_struct *) NULL)
9117 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
9119 ping_info=png_create_info_struct(ping);
9121 if (ping_info == (png_info *) NULL)
9123 png_destroy_write_struct(&ping,(png_info **) NULL);
9124 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
9127 png_set_write_fn(ping,image,png_put_data,png_flush_data);
9128 ping_pixels=(unsigned char *) NULL;
9130 if (setjmp(png_jmpbuf(ping)))
9136 if (image_info->verbose)
9137 (void) printf("PNG write has failed.\n");
9139 png_destroy_write_struct(&ping,&ping_info);
9140 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
9141 UnlockSemaphoreInfo(ping_semaphore);
9144 if (ping_pixels != (unsigned char *) NULL)
9145 ping_pixels=(unsigned char *) RelinquishMagickMemory(ping_pixels);
9147 if (quantum_info != (QuantumInfo *) NULL)
9148 quantum_info=DestroyQuantumInfo(quantum_info);
9150 if (ping_have_blob != MagickFalse)
9151 (void) CloseBlob(image);
9152 image_info=DestroyImageInfo(image_info);
9153 image=DestroyImage(image);
9154 return(MagickFalse);
9157 /* { For navigation to end of SETJMP-protected block. Within this
9158 * block, use png_error() instead of Throwing an Exception, to ensure
9159 * that libpng is able to clean up, and that the semaphore is unlocked.
9162 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
9163 LockSemaphoreInfo(ping_semaphore);
9167 Prepare PNG for writing.
9170 #if defined(PNG_MNG_FEATURES_SUPPORTED)
9171 if (mng_info->write_mng)
9173 (void) png_permit_mng_features(ping,PNG_ALL_MNG_FEATURES);
9174 # ifdef PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED
9175 /* Disable new libpng-1.5.10 feature when writing a MNG because
9176 * zero-length PLTE is OK
9178 png_set_check_for_invalid_index (ping, 0);
9183 # ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
9184 if (mng_info->write_mng)
9185 png_permit_empty_plte(ping,MagickTrue);
9192 ping_width=(png_uint_32) image->columns;
9193 ping_height=(png_uint_32) image->rows;
9195 if (mng_info->write_png8 || mng_info->write_png24 || mng_info->write_png32)
9198 if (mng_info->write_png48 || mng_info->write_png64)
9201 if (mng_info->write_png_depth != 0)
9202 image_depth=mng_info->write_png_depth;
9204 /* Adjust requested depth to next higher valid depth if necessary */
9205 if (image_depth > 8)
9208 if ((image_depth > 4) && (image_depth < 8))
9211 if (image_depth == 3)
9214 if (logging != MagickFalse)
9216 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9217 " width=%.20g",(double) ping_width);
9218 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9219 " height=%.20g",(double) ping_height);
9220 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9221 " image_matte=%.20g",(double) image->alpha_trait);
9222 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9223 " image->depth=%.20g",(double) image->depth);
9224 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9225 " Tentative ping_bit_depth=%.20g",(double) image_depth);
9228 save_image_depth=image_depth;
9229 ping_bit_depth=(png_byte) save_image_depth;
9232 #if defined(PNG_pHYs_SUPPORTED)
9233 if (ping_exclude_pHYs == MagickFalse)
9235 if ((image->resolution.x != 0) && (image->resolution.y != 0) &&
9236 (!mng_info->write_mng || !mng_info->equal_physs))
9238 if (logging != MagickFalse)
9239 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9240 " Setting up pHYs chunk");
9242 if (image->units == PixelsPerInchResolution)
9244 ping_pHYs_unit_type=PNG_RESOLUTION_METER;
9245 ping_pHYs_x_resolution=
9246 (png_uint_32) ((100.0*image->resolution.x+0.5)/2.54);
9247 ping_pHYs_y_resolution=
9248 (png_uint_32) ((100.0*image->resolution.y+0.5)/2.54);
9251 else if (image->units == PixelsPerCentimeterResolution)
9253 ping_pHYs_unit_type=PNG_RESOLUTION_METER;
9254 ping_pHYs_x_resolution=(png_uint_32) (100.0*image->resolution.x+0.5);
9255 ping_pHYs_y_resolution=(png_uint_32) (100.0*image->resolution.y+0.5);
9260 ping_pHYs_unit_type=PNG_RESOLUTION_UNKNOWN;
9261 ping_pHYs_x_resolution=(png_uint_32) image->resolution.x;
9262 ping_pHYs_y_resolution=(png_uint_32) image->resolution.y;
9265 if (logging != MagickFalse)
9266 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9267 " Set up PNG pHYs chunk: xres: %.20g, yres: %.20g, units: %d.",
9268 (double) ping_pHYs_x_resolution,(double) ping_pHYs_y_resolution,
9269 (int) ping_pHYs_unit_type);
9270 ping_have_pHYs = MagickTrue;
9275 if (ping_exclude_bKGD == MagickFalse)
9277 if ((!mng_info->adjoin || !mng_info->equal_backgrounds))
9283 if (ping_bit_depth == 8)
9286 if (ping_bit_depth == 4)
9289 if (ping_bit_depth == 2)
9292 if (ping_bit_depth == 1)
9295 ping_background.red=(png_uint_16)
9296 (ScaleQuantumToShort(image->background_color.red) & mask);
9298 ping_background.green=(png_uint_16)
9299 (ScaleQuantumToShort(image->background_color.green) & mask);
9301 ping_background.blue=(png_uint_16)
9302 (ScaleQuantumToShort(image->background_color.blue) & mask);
9304 ping_background.gray=(png_uint_16) ping_background.green;
9307 if (logging != MagickFalse)
9309 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9310 " Setting up bKGD chunk (1)");
9311 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9312 " background_color index is %d",
9313 (int) ping_background.index);
9315 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9316 " ping_bit_depth=%d",ping_bit_depth);
9319 ping_have_bKGD = MagickTrue;
9323 Select the color type.
9328 if (mng_info->IsPalette && mng_info->write_png8)
9331 /* To do: make this a function cause it's used twice, except
9332 for reducing the sample depth from 8. */
9334 number_colors=image_colors;
9336 ping_have_tRNS=MagickFalse;
9341 ping_color_type=(png_byte) PNG_COLOR_TYPE_PALETTE;
9343 if (logging != MagickFalse)
9344 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9345 " Setting up PLTE chunk with %d colors (%d)",
9346 number_colors, image_colors);
9348 for (i=0; i < (ssize_t) number_colors; i++)
9350 palette[i].red=ScaleQuantumToChar(image->colormap[i].red);
9351 palette[i].green=ScaleQuantumToChar(image->colormap[i].green);
9352 palette[i].blue=ScaleQuantumToChar(image->colormap[i].blue);
9353 if (logging != MagickFalse)
9354 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9355 #if MAGICKCORE_QUANTUM_DEPTH == 8
9356 " %3ld (%3d,%3d,%3d)",
9358 " %5ld (%5d,%5d,%5d)",
9360 (long) i,palette[i].red,palette[i].green,palette[i].blue);
9364 ping_have_PLTE=MagickTrue;
9365 image_depth=ping_bit_depth;
9368 if (matte != MagickFalse)
9371 Identify which colormap entry is transparent.
9373 assert(number_colors <= 256);
9374 assert(image->colormap != NULL);
9376 for (i=0; i < (ssize_t) number_transparent; i++)
9377 ping_trans_alpha[i]=0;
9380 ping_num_trans=(unsigned short) (number_transparent +
9381 number_semitransparent);
9383 if (ping_num_trans == 0)
9384 ping_have_tRNS=MagickFalse;
9387 ping_have_tRNS=MagickTrue;
9390 if (ping_exclude_bKGD == MagickFalse)
9393 * Identify which colormap entry is the background color.
9396 for (i=0; i < (ssize_t) MagickMax(1L*number_colors-1L,1L); i++)
9397 if (IsPNGColorEqual(ping_background,image->colormap[i]))
9400 ping_background.index=(png_byte) i;
9402 if (logging != MagickFalse)
9404 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9405 " background_color index is %d",
9406 (int) ping_background.index);
9409 } /* end of write_png8 */
9411 else if (mng_info->write_png_colortype == 1)
9413 image_matte=MagickFalse;
9414 ping_color_type=(png_byte) PNG_COLOR_TYPE_GRAY;
9417 else if (mng_info->write_png24 || mng_info->write_png48 ||
9418 mng_info->write_png_colortype == 3)
9420 image_matte=MagickFalse;
9421 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB;
9424 else if (mng_info->write_png32 || mng_info->write_png64 ||
9425 mng_info->write_png_colortype == 7)
9427 image_matte=MagickTrue;
9428 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB_ALPHA;
9431 else /* mng_info->write_pngNN not specified */
9433 image_depth=ping_bit_depth;
9435 if (mng_info->write_png_colortype != 0)
9437 ping_color_type=(png_byte) mng_info->write_png_colortype-1;
9439 if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA ||
9440 ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA)
9441 image_matte=MagickTrue;
9444 image_matte=MagickFalse;
9446 if (logging != MagickFalse)
9447 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9448 " PNG colortype %d was specified:",(int) ping_color_type);
9451 else /* write_png_colortype not specified */
9453 if (logging != MagickFalse)
9454 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9455 " Selecting PNG colortype:");
9457 ping_color_type=(png_byte) ((matte != MagickFalse)?
9458 PNG_COLOR_TYPE_RGB_ALPHA:PNG_COLOR_TYPE_RGB);
9460 if (image_info->type == TrueColorType)
9462 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB;
9463 image_matte=MagickFalse;
9466 if (image_info->type == TrueColorMatteType)
9468 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB_ALPHA;
9469 image_matte=MagickTrue;
9472 if (image_info->type == PaletteType ||
9473 image_info->type == PaletteMatteType)
9474 ping_color_type=(png_byte) PNG_COLOR_TYPE_PALETTE;
9476 if (mng_info->write_png_colortype == 0 &&
9477 (image_info->type == UndefinedType ||
9478 image_info->type == OptimizeType))
9480 if (ping_have_color == MagickFalse)
9482 if (image_matte == MagickFalse)
9484 ping_color_type=(png_byte) PNG_COLOR_TYPE_GRAY;
9485 image_matte=MagickFalse;
9490 ping_color_type=(png_byte) PNG_COLOR_TYPE_GRAY_ALPHA;
9491 image_matte=MagickTrue;
9496 if (image_matte == MagickFalse)
9498 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB;
9499 image_matte=MagickFalse;
9504 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGBA;
9505 image_matte=MagickTrue;
9512 if (logging != MagickFalse)
9513 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9514 " Selected PNG colortype=%d",ping_color_type);
9516 if (ping_bit_depth < 8)
9518 if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA ||
9519 ping_color_type == PNG_COLOR_TYPE_RGB ||
9520 ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA)
9524 old_bit_depth=ping_bit_depth;
9526 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
9528 if (image->alpha_trait != BlendPixelTrait && ping_have_non_bw == MagickFalse)
9532 if (ping_color_type == PNG_COLOR_TYPE_PALETTE)
9537 if (image->colors == 0)
9540 png_error(ping,"image has 0 colors");
9543 while ((int) (one << ping_bit_depth) < (ssize_t) image_colors)
9544 ping_bit_depth <<= 1;
9547 if (logging != MagickFalse)
9549 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9550 " Number of colors: %.20g",(double) image_colors);
9552 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9553 " Tentative PNG bit depth: %d",ping_bit_depth);
9556 if (ping_bit_depth < (int) mng_info->write_png_depth)
9557 ping_bit_depth = mng_info->write_png_depth;
9560 image_depth=ping_bit_depth;
9562 if (logging != MagickFalse)
9564 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9565 " Tentative PNG color type: %s (%.20g)",
9566 PngColorTypeToString(ping_color_type),
9567 (double) ping_color_type);
9569 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9570 " image_info->type: %.20g",(double) image_info->type);
9572 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9573 " image_depth: %.20g",(double) image_depth);
9575 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9577 " image->depth: %.20g",(double) image->depth);
9579 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9580 " ping_bit_depth: %.20g",(double) ping_bit_depth);
9583 if (matte != MagickFalse)
9585 if (mng_info->IsPalette)
9587 if (mng_info->write_png_colortype == 0)
9589 ping_color_type=PNG_COLOR_TYPE_GRAY_ALPHA;
9591 if (ping_have_color != MagickFalse)
9592 ping_color_type=PNG_COLOR_TYPE_RGBA;
9596 * Determine if there is any transparent color.
9598 if (number_transparent + number_semitransparent == 0)
9601 No transparent pixels are present. Change 4 or 6 to 0 or 2.
9604 image_matte=MagickFalse;
9606 if (mng_info->write_png_colortype == 0)
9607 ping_color_type&=0x03;
9617 if (ping_bit_depth == 8)
9620 if (ping_bit_depth == 4)
9623 if (ping_bit_depth == 2)
9626 if (ping_bit_depth == 1)
9629 ping_trans_color.red=(png_uint_16)
9630 (ScaleQuantumToShort(image->colormap[0].red) & mask);
9632 ping_trans_color.green=(png_uint_16)
9633 (ScaleQuantumToShort(image->colormap[0].green) & mask);
9635 ping_trans_color.blue=(png_uint_16)
9636 (ScaleQuantumToShort(image->colormap[0].blue) & mask);
9638 ping_trans_color.gray=(png_uint_16)
9639 (ScaleQuantumToShort(GetPixelInfoIntensity(
9640 image->colormap)) & mask);
9642 ping_trans_color.index=(png_byte) 0;
9644 ping_have_tRNS=MagickTrue;
9647 if (ping_have_tRNS != MagickFalse)
9650 * Determine if there is one and only one transparent color
9651 * and if so if it is fully transparent.
9653 if (ping_have_cheap_transparency == MagickFalse)
9654 ping_have_tRNS=MagickFalse;
9657 if (ping_have_tRNS != MagickFalse)
9659 if (mng_info->write_png_colortype == 0)
9660 ping_color_type &= 0x03; /* changes 4 or 6 to 0 or 2 */
9662 if (image_depth == 8)
9664 ping_trans_color.red&=0xff;
9665 ping_trans_color.green&=0xff;
9666 ping_trans_color.blue&=0xff;
9667 ping_trans_color.gray&=0xff;
9673 if (image_depth == 8)
9675 ping_trans_color.red&=0xff;
9676 ping_trans_color.green&=0xff;
9677 ping_trans_color.blue&=0xff;
9678 ping_trans_color.gray&=0xff;
9685 if (ping_have_tRNS != MagickFalse)
9686 image_matte=MagickFalse;
9688 if ((mng_info->IsPalette) &&
9689 mng_info->write_png_colortype-1 != PNG_COLOR_TYPE_PALETTE &&
9690 ping_have_color == MagickFalse &&
9691 (image_matte == MagickFalse || image_depth >= 8))
9695 if (image_matte != MagickFalse)
9696 ping_color_type=PNG_COLOR_TYPE_GRAY_ALPHA;
9698 else if (mng_info->write_png_colortype-1 != PNG_COLOR_TYPE_GRAY_ALPHA)
9700 ping_color_type=PNG_COLOR_TYPE_GRAY;
9702 if (save_image_depth == 16 && image_depth == 8)
9704 if (logging != MagickFalse)
9706 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9707 " Scaling ping_trans_color (0)");
9709 ping_trans_color.gray*=0x0101;
9713 if (image_depth > MAGICKCORE_QUANTUM_DEPTH)
9714 image_depth=MAGICKCORE_QUANTUM_DEPTH;
9716 if ((image_colors == 0) ||
9717 ((ssize_t) (image_colors-1) > (ssize_t) MaxColormapSize))
9718 image_colors=(int) (one << image_depth);
9720 if (image_depth > 8)
9726 if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
9728 if(!mng_info->write_png_depth)
9732 while ((int) (one << ping_bit_depth)
9733 < (ssize_t) image_colors)
9734 ping_bit_depth <<= 1;
9738 else if (ping_color_type ==
9739 PNG_COLOR_TYPE_GRAY && image_colors < 17 &&
9740 mng_info->IsPalette)
9742 /* Check if grayscale is reducible */
9745 depth_4_ok=MagickTrue,
9746 depth_2_ok=MagickTrue,
9747 depth_1_ok=MagickTrue;
9749 for (i=0; i < (ssize_t) image_colors; i++)
9754 intensity=ScaleQuantumToChar(image->colormap[i].red);
9756 if ((intensity & 0x0f) != ((intensity & 0xf0) >> 4))
9757 depth_4_ok=depth_2_ok=depth_1_ok=MagickFalse;
9758 else if ((intensity & 0x03) != ((intensity & 0x0c) >> 2))
9759 depth_2_ok=depth_1_ok=MagickFalse;
9760 else if ((intensity & 0x01) != ((intensity & 0x02) >> 1))
9761 depth_1_ok=MagickFalse;
9764 if (depth_1_ok && mng_info->write_png_depth <= 1)
9767 else if (depth_2_ok && mng_info->write_png_depth <= 2)
9770 else if (depth_4_ok && mng_info->write_png_depth <= 4)
9775 image_depth=ping_bit_depth;
9780 if (mng_info->IsPalette)
9782 number_colors=image_colors;
9784 if (image_depth <= 8)
9789 ping_color_type=(png_byte) PNG_COLOR_TYPE_PALETTE;
9791 if (mng_info->have_write_global_plte && matte == MagickFalse)
9793 png_set_PLTE(ping,ping_info,NULL,0);
9795 if (logging != MagickFalse)
9796 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9797 " Setting up empty PLTE chunk");
9802 for (i=0; i < (ssize_t) number_colors; i++)
9804 palette[i].red=ScaleQuantumToChar(image->colormap[i].red);
9805 palette[i].green=ScaleQuantumToChar(image->colormap[i].green);
9806 palette[i].blue=ScaleQuantumToChar(image->colormap[i].blue);
9809 if (logging != MagickFalse)
9810 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9811 " Setting up PLTE chunk with %d colors",
9814 ping_have_PLTE=MagickTrue;
9817 /* color_type is PNG_COLOR_TYPE_PALETTE */
9818 if (mng_info->write_png_depth == 0)
9826 while ((one << ping_bit_depth) < (size_t) number_colors)
9827 ping_bit_depth <<= 1;
9832 if (matte != MagickFalse)
9835 * Set up trans_colors array.
9837 assert(number_colors <= 256);
9839 ping_num_trans=(unsigned short) (number_transparent +
9840 number_semitransparent);
9842 if (ping_num_trans == 0)
9843 ping_have_tRNS=MagickFalse;
9847 if (logging != MagickFalse)
9849 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9850 " Scaling ping_trans_color (1)");
9852 ping_have_tRNS=MagickTrue;
9854 for (i=0; i < ping_num_trans; i++)
9856 ping_trans_alpha[i]= (png_byte)
9857 ScaleQuantumToChar(image->colormap[i].alpha);
9867 if (image_depth < 8)
9870 if ((save_image_depth == 16) && (image_depth == 8))
9872 if (logging != MagickFalse)
9874 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9875 " Scaling ping_trans_color from (%d,%d,%d)",
9876 (int) ping_trans_color.red,
9877 (int) ping_trans_color.green,
9878 (int) ping_trans_color.blue);
9881 ping_trans_color.red*=0x0101;
9882 ping_trans_color.green*=0x0101;
9883 ping_trans_color.blue*=0x0101;
9884 ping_trans_color.gray*=0x0101;
9886 if (logging != MagickFalse)
9888 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9890 (int) ping_trans_color.red,
9891 (int) ping_trans_color.green,
9892 (int) ping_trans_color.blue);
9897 if (ping_bit_depth < (ssize_t) mng_info->write_png_depth)
9898 ping_bit_depth = (ssize_t) mng_info->write_png_depth;
9901 Adjust background and transparency samples in sub-8-bit grayscale files.
9903 if (ping_bit_depth < 8 && ping_color_type ==
9904 PNG_COLOR_TYPE_GRAY)
9912 maxval=(png_uint_16) ((one << ping_bit_depth)-1);
9914 if (ping_exclude_bKGD == MagickFalse)
9917 ping_background.gray=(png_uint_16) ((maxval/65535.)*
9918 (ScaleQuantumToShort(((GetPixelInfoIntensity(
9919 &image->background_color))) +.5)));
9921 if (logging != MagickFalse)
9922 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9923 " Setting up bKGD chunk (2)");
9924 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9925 " background_color index is %d",
9926 (int) ping_background.index);
9928 ping_have_bKGD = MagickTrue;
9931 if (logging != MagickFalse)
9932 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9933 " Scaling ping_trans_color.gray from %d",
9934 (int)ping_trans_color.gray);
9936 ping_trans_color.gray=(png_uint_16) ((maxval/255.)*(
9937 ping_trans_color.gray)+.5);
9939 if (logging != MagickFalse)
9940 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9941 " to %d", (int)ping_trans_color.gray);
9944 if (ping_exclude_bKGD == MagickFalse)
9946 if (mng_info->IsPalette && (int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
9949 Identify which colormap entry is the background color.
9952 number_colors=image_colors;
9954 for (i=0; i < (ssize_t) MagickMax(1L*number_colors,1L); i++)
9955 if (IsPNGColorEqual(image->background_color,image->colormap[i]))
9958 ping_background.index=(png_byte) i;
9960 if (logging != MagickFalse)
9962 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9963 " Setting up bKGD chunk with index=%d",(int) i);
9966 if (i < (ssize_t) number_colors)
9968 ping_have_bKGD = MagickTrue;
9970 if (logging != MagickFalse)
9972 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9973 " background =(%d,%d,%d)",
9974 (int) ping_background.red,
9975 (int) ping_background.green,
9976 (int) ping_background.blue);
9980 else /* Can't happen */
9982 if (logging != MagickFalse)
9983 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9984 " No room in PLTE to add bKGD color");
9985 ping_have_bKGD = MagickFalse;
9990 if (logging != MagickFalse)
9991 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9992 " PNG color type: %s (%d)", PngColorTypeToString(ping_color_type),
9995 Initialize compression level and filtering.
9997 if (logging != MagickFalse)
9999 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10000 " Setting up deflate compression");
10002 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10003 " Compression buffer size: 32768");
10006 png_set_compression_buffer_size(ping,32768L);
10008 if (logging != MagickFalse)
10009 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10010 " Compression mem level: 9");
10012 png_set_compression_mem_level(ping, 9);
10014 /* Untangle the "-quality" setting:
10016 Undefined is 0; the default is used.
10021 0: Use Z_HUFFMAN_ONLY strategy with the
10022 zlib default compression level
10024 1-9: the zlib compression level
10028 0-4: the PNG filter method
10030 5: libpng adaptive filtering if compression level > 5
10031 libpng filter type "none" if compression level <= 5
10032 or if image is grayscale or palette
10034 6: libpng adaptive filtering
10036 7: "LOCO" filtering (intrapixel differing) if writing
10037 a MNG, othewise "none". Did not work in IM-6.7.0-9
10038 and earlier because of a missing "else".
10040 8: Z_RLE strategy, all filters
10041 Unused prior to IM-6.7.0-10, was same as 6
10043 9: Z_RLE strategy, no PNG filters
10044 Unused prior to IM-6.7.0-10, was same as 6
10046 Note that using the -quality option, not all combinations of
10047 PNG filter type, zlib compression level, and zlib compression
10048 strategy are possible. This will be addressed soon in a
10049 release that accomodates "-define png:compression-strategy", etc.
10053 quality=image->quality == UndefinedCompressionQuality ? 75UL :
10058 if (mng_info->write_png_compression_strategy == 0)
10059 mng_info->write_png_compression_strategy = Z_HUFFMAN_ONLY+1;
10062 else if (mng_info->write_png_compression_level == 0)
10067 level=(int) MagickMin((ssize_t) quality/10,9);
10069 mng_info->write_png_compression_level = level+1;
10072 if (mng_info->write_png_compression_strategy == 0)
10074 if ((quality %10) == 8 || (quality %10) == 9)
10075 #ifdef Z_RLE /* Z_RLE was added to zlib-1.2.0 */
10076 mng_info->write_png_compression_strategy=Z_RLE+1;
10078 mng_info->write_png_compression_strategy = Z_DEFAULT_STRATEGY+1;
10082 if (mng_info->write_png_compression_filter == 0)
10083 mng_info->write_png_compression_filter=((int) quality % 10) + 1;
10085 if (logging != MagickFalse)
10087 if (mng_info->write_png_compression_level)
10088 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10089 " Compression level: %d",
10090 (int) mng_info->write_png_compression_level-1);
10092 if (mng_info->write_png_compression_strategy)
10093 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10094 " Compression strategy: %d",
10095 (int) mng_info->write_png_compression_strategy-1);
10097 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10098 " Setting up filtering");
10100 if (mng_info->write_png_compression_filter == 6)
10101 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10102 " Base filter method: ADAPTIVE");
10103 else if (mng_info->write_png_compression_filter == 0 ||
10104 mng_info->write_png_compression_filter == 1)
10105 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10106 " Base filter method: NONE");
10108 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10109 " Base filter method: %d",
10110 (int) mng_info->write_png_compression_filter-1);
10113 if (mng_info->write_png_compression_level != 0)
10114 png_set_compression_level(ping,mng_info->write_png_compression_level-1);
10116 if (mng_info->write_png_compression_filter == 6)
10118 if (((int) ping_color_type == PNG_COLOR_TYPE_GRAY) ||
10119 ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE) ||
10121 png_set_filter(ping,PNG_FILTER_TYPE_BASE,PNG_NO_FILTERS);
10123 png_set_filter(ping,PNG_FILTER_TYPE_BASE,PNG_ALL_FILTERS);
10125 else if (mng_info->write_png_compression_filter == 7 ||
10126 mng_info->write_png_compression_filter == 10)
10127 png_set_filter(ping,PNG_FILTER_TYPE_BASE,PNG_ALL_FILTERS);
10129 else if (mng_info->write_png_compression_filter == 8)
10131 #if defined(PNG_MNG_FEATURES_SUPPORTED) && defined(PNG_INTRAPIXEL_DIFFERENCING)
10132 if (mng_info->write_mng)
10134 if (((int) ping_color_type == PNG_COLOR_TYPE_RGB) ||
10135 ((int) ping_color_type == PNG_COLOR_TYPE_RGBA))
10136 ping_filter_method=PNG_INTRAPIXEL_DIFFERENCING;
10139 png_set_filter(ping,PNG_FILTER_TYPE_BASE,PNG_NO_FILTERS);
10142 else if (mng_info->write_png_compression_filter == 9)
10143 png_set_filter(ping,PNG_FILTER_TYPE_BASE,PNG_NO_FILTERS);
10145 else if (mng_info->write_png_compression_filter != 0)
10146 png_set_filter(ping,PNG_FILTER_TYPE_BASE,
10147 mng_info->write_png_compression_filter-1);
10149 if (mng_info->write_png_compression_strategy != 0)
10150 png_set_compression_strategy(ping,
10151 mng_info->write_png_compression_strategy-1);
10153 /* Only write the iCCP chunk if we are not writing the sRGB chunk. */
10154 if (ping_exclude_sRGB != MagickFalse ||
10155 (image->rendering_intent == UndefinedIntent))
10157 if ((ping_exclude_tEXt == MagickFalse ||
10158 ping_exclude_zTXt == MagickFalse) &&
10159 (ping_exclude_iCCP == MagickFalse || ping_exclude_zCCP == MagickFalse))
10161 ResetImageProfileIterator(image);
10162 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
10164 profile=GetImageProfile(image,name);
10166 if (profile != (StringInfo *) NULL)
10168 #ifdef PNG_WRITE_iCCP_SUPPORTED
10169 if ((LocaleCompare(name,"ICC") == 0) ||
10170 (LocaleCompare(name,"ICM") == 0))
10173 if (ping_exclude_iCCP == MagickFalse)
10175 png_set_iCCP(ping,ping_info,(png_charp) name,0,
10176 #if (PNG_LIBPNG_VER < 10500)
10177 (png_charp) GetStringInfoDatum(profile),
10179 (png_const_bytep) GetStringInfoDatum(profile),
10181 (png_uint_32) GetStringInfoLength(profile));
10187 if (ping_exclude_zCCP == MagickFalse)
10189 Magick_png_write_raw_profile(image_info,ping,ping_info,
10190 (unsigned char *) name,(unsigned char *) name,
10191 GetStringInfoDatum(profile),
10192 (png_uint_32) GetStringInfoLength(profile));
10196 if (logging != MagickFalse)
10197 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10198 " Setting up text chunk with %s profile",name);
10200 name=GetNextImageProfile(image);
10205 #if defined(PNG_WRITE_sRGB_SUPPORTED)
10206 if ((mng_info->have_write_global_srgb == 0) &&
10207 (image->rendering_intent != UndefinedIntent))
10209 if (ping_exclude_sRGB == MagickFalse)
10212 Note image rendering intent.
10214 if (logging != MagickFalse)
10215 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10216 " Setting up sRGB chunk");
10218 (void) png_set_sRGB(ping,ping_info,(
10219 Magick_RenderingIntent_to_PNG_RenderingIntent(
10220 image->rendering_intent)));
10224 if ((!mng_info->write_mng) || (!png_get_valid(ping,ping_info,PNG_INFO_sRGB)))
10227 if (ping_exclude_gAMA == MagickFalse &&
10228 (ping_exclude_sRGB == MagickFalse ||
10229 (image->gamma < .45 || image->gamma > .46)))
10231 if ((mng_info->have_write_global_gama == 0) && (image->gamma != 0.0))
10235 To do: check for cHRM+gAMA == sRGB, and write sRGB instead.
10237 if (logging != MagickFalse)
10238 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10239 " Setting up gAMA chunk");
10241 png_set_gAMA(ping,ping_info,image->gamma);
10245 if (ping_exclude_cHRM == MagickFalse)
10247 if ((mng_info->have_write_global_chrm == 0) &&
10248 (image->chromaticity.red_primary.x != 0.0))
10251 Note image chromaticity.
10252 To do: check for cHRM+gAMA == sRGB, and write sRGB instead.
10260 wp=image->chromaticity.white_point;
10261 rp=image->chromaticity.red_primary;
10262 gp=image->chromaticity.green_primary;
10263 bp=image->chromaticity.blue_primary;
10265 if (logging != MagickFalse)
10266 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10267 " Setting up cHRM chunk");
10269 png_set_cHRM(ping,ping_info,wp.x,wp.y,rp.x,rp.y,gp.x,gp.y,
10275 ping_interlace_method=image_info->interlace != NoInterlace;
10277 if (mng_info->write_mng)
10278 png_set_sig_bytes(ping,8);
10280 /* Bail out if cannot meet defined png:bit-depth or png:color-type */
10282 if (mng_info->write_png_colortype != 0)
10284 if (mng_info->write_png_colortype-1 == PNG_COLOR_TYPE_GRAY)
10285 if (ping_have_color != MagickFalse)
10287 ping_color_type = PNG_COLOR_TYPE_RGB;
10289 if (ping_bit_depth < 8)
10293 if (mng_info->write_png_colortype-1 == PNG_COLOR_TYPE_GRAY_ALPHA)
10294 if (ping_have_color != MagickFalse)
10295 ping_color_type = PNG_COLOR_TYPE_RGB_ALPHA;
10298 if (ping_need_colortype_warning != MagickFalse ||
10299 ((mng_info->write_png_depth &&
10300 (int) mng_info->write_png_depth != ping_bit_depth) ||
10301 (mng_info->write_png_colortype &&
10302 ((int) mng_info->write_png_colortype-1 != ping_color_type &&
10303 mng_info->write_png_colortype != 7 &&
10304 !(mng_info->write_png_colortype == 5 && ping_color_type == 0)))))
10306 if (logging != MagickFalse)
10308 if (ping_need_colortype_warning != MagickFalse)
10310 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10311 " Image has transparency but tRNS chunk was excluded");
10314 if (mng_info->write_png_depth)
10316 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10317 " Defined png:bit-depth=%u, Computed depth=%u",
10318 mng_info->write_png_depth,
10322 if (mng_info->write_png_colortype)
10324 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10325 " Defined png:color-type=%u, Computed color type=%u",
10326 mng_info->write_png_colortype-1,
10332 "Cannot write image with defined png:bit-depth or png:color-type.");
10335 if (image_matte != MagickFalse && image->alpha_trait != BlendPixelTrait)
10337 /* Add an opaque matte channel */
10338 image->alpha_trait = BlendPixelTrait;
10339 (void) SetImageAlpha(image,OpaqueAlpha,exception);
10341 if (logging != MagickFalse)
10342 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10343 " Added an opaque matte channel");
10346 if (number_transparent != 0 || number_semitransparent != 0)
10348 if (ping_color_type < 4)
10350 ping_have_tRNS=MagickTrue;
10351 if (logging != MagickFalse)
10352 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10353 " Setting ping_have_tRNS=MagickTrue.");
10357 if (logging != MagickFalse)
10358 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10359 " Writing PNG header chunks");
10361 png_set_IHDR(ping,ping_info,ping_width,ping_height,
10362 ping_bit_depth,ping_color_type,
10363 ping_interlace_method,ping_compression_method,
10364 ping_filter_method);
10366 if (ping_color_type == 3 && ping_have_PLTE != MagickFalse)
10368 png_set_PLTE(ping,ping_info,palette,number_colors);
10370 if (logging != MagickFalse)
10372 for (i=0; i< (ssize_t) number_colors; i++)
10374 if (i < ping_num_trans)
10375 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10376 " PLTE[%d] = (%d,%d,%d), tRNS[%d] = (%d)",
10378 (int) palette[i].red,
10379 (int) palette[i].green,
10380 (int) palette[i].blue,
10382 (int) ping_trans_alpha[i]);
10384 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10385 " PLTE[%d] = (%d,%d,%d)",
10387 (int) palette[i].red,
10388 (int) palette[i].green,
10389 (int) palette[i].blue);
10394 if (ping_exclude_bKGD == MagickFalse)
10396 if (ping_have_bKGD != MagickFalse)
10398 png_set_bKGD(ping,ping_info,&ping_background);
10401 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10402 " Setting up bKGD chunk");
10403 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10404 " background color = (%d,%d,%d)",
10405 (int) ping_background.red,
10406 (int) ping_background.green,
10407 (int) ping_background.blue);
10408 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10409 " index = %d, gray=%d",
10410 (int) ping_background.index,
10411 (int) ping_background.gray);
10416 if (ping_exclude_pHYs == MagickFalse)
10418 if (ping_have_pHYs != MagickFalse)
10420 png_set_pHYs(ping,ping_info,
10421 ping_pHYs_x_resolution,
10422 ping_pHYs_y_resolution,
10423 ping_pHYs_unit_type);
10427 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10428 " Setting up pHYs chunk");
10429 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10430 " x_resolution=%lu",
10431 (unsigned long) ping_pHYs_x_resolution);
10432 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10433 " y_resolution=%lu",
10434 (unsigned long) ping_pHYs_y_resolution);
10435 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10437 (unsigned long) ping_pHYs_unit_type);
10442 #if defined(PNG_oFFs_SUPPORTED)
10443 if (ping_exclude_oFFs == MagickFalse)
10445 if (image->page.x || image->page.y)
10447 png_set_oFFs(ping,ping_info,(png_int_32) image->page.x,
10448 (png_int_32) image->page.y, 0);
10450 if (logging != MagickFalse)
10451 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10452 " Setting up oFFs chunk with x=%d, y=%d, units=0",
10453 (int) image->page.x, (int) image->page.y);
10458 if (mng_info->need_blob != MagickFalse)
10460 if (OpenBlob(image_info,image,WriteBinaryBlobMode,exception) ==
10462 png_error(ping,"WriteBlob Failed");
10464 ping_have_blob=MagickTrue;
10467 png_write_info_before_PLTE(ping, ping_info);
10469 if (ping_have_tRNS != MagickFalse && ping_color_type < 4)
10471 if (logging != MagickFalse)
10473 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10474 " Calling png_set_tRNS with num_trans=%d",ping_num_trans);
10477 if (ping_color_type == 3)
10478 (void) png_set_tRNS(ping, ping_info,
10485 (void) png_set_tRNS(ping, ping_info,
10488 &ping_trans_color);
10490 if (logging != MagickFalse)
10492 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10493 " tRNS color =(%d,%d,%d)",
10494 (int) ping_trans_color.red,
10495 (int) ping_trans_color.green,
10496 (int) ping_trans_color.blue);
10501 /* write any png-chunk-b profiles */
10502 (void) Magick_png_write_chunk_from_profile(image,"PNG-chunk-b",logging);
10504 png_write_info(ping,ping_info);
10506 /* write any PNG-chunk-m profiles */
10507 (void) Magick_png_write_chunk_from_profile(image,"PNG-chunk-m",logging);
10509 if (ping_exclude_vpAg == MagickFalse)
10511 if ((image->page.width != 0 && image->page.width != image->columns) ||
10512 (image->page.height != 0 && image->page.height != image->rows))
10517 (void) WriteBlobMSBULong(image,9L); /* data length=8 */
10518 PNGType(chunk,mng_vpAg);
10519 LogPNGChunk(logging,mng_vpAg,9L);
10520 PNGLong(chunk+4,(png_uint_32) image->page.width);
10521 PNGLong(chunk+8,(png_uint_32) image->page.height);
10522 chunk[12]=0; /* unit = pixels */
10523 (void) WriteBlob(image,13,chunk);
10524 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
10528 #if (PNG_LIBPNG_VER == 10206)
10529 /* avoid libpng-1.2.6 bug by setting PNG_HAVE_IDAT flag */
10530 #define PNG_HAVE_IDAT 0x04
10531 ping->mode |= PNG_HAVE_IDAT;
10532 #undef PNG_HAVE_IDAT
10535 png_set_packing(ping);
10539 rowbytes=image->columns;
10540 if (image_depth > 8)
10542 switch (ping_color_type)
10544 case PNG_COLOR_TYPE_RGB:
10548 case PNG_COLOR_TYPE_GRAY_ALPHA:
10552 case PNG_COLOR_TYPE_RGBA:
10560 if (logging != MagickFalse)
10562 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10563 " Writing PNG image data");
10565 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10566 " Allocating %.20g bytes of memory for pixels",(double) rowbytes);
10568 ping_pixels=(unsigned char *) AcquireQuantumMemory(rowbytes,
10569 sizeof(*ping_pixels));
10571 if (ping_pixels == (unsigned char *) NULL)
10572 png_error(ping,"Allocation of memory for pixels failed");
10575 Initialize image scanlines.
10577 quantum_info=AcquireQuantumInfo(image_info,image);
10578 if (quantum_info == (QuantumInfo *) NULL)
10579 png_error(ping,"Memory allocation for quantum_info failed");
10580 quantum_info->format=UndefinedQuantumFormat;
10581 quantum_info->depth=image_depth;
10582 (void) SetQuantumEndian(image,quantum_info,MSBEndian);
10583 num_passes=png_set_interlace_handling(ping);
10585 if ((!mng_info->write_png8 && !mng_info->write_png24 &&
10586 !mng_info->write_png48 && !mng_info->write_png64 &&
10587 !mng_info->write_png32) &&
10588 (mng_info->IsPalette ||
10589 (image_info->type == BilevelType)) &&
10590 image_matte == MagickFalse &&
10591 ping_have_non_bw == MagickFalse)
10593 /* Palette, Bilevel, or Opaque Monochrome */
10594 register const Quantum
10597 quantum_info->depth=8;
10598 for (pass=0; pass < num_passes; pass++)
10601 Convert PseudoClass image to a PNG monochrome image.
10603 for (y=0; y < (ssize_t) image->rows; y++)
10605 if (logging != MagickFalse && y == 0)
10606 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10607 " Writing row of pixels (0)");
10609 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
10611 if (p == (const Quantum *) NULL)
10614 if (mng_info->IsPalette)
10616 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10617 quantum_info,GrayQuantum,ping_pixels,exception);
10618 if (mng_info->write_png_colortype-1 == PNG_COLOR_TYPE_PALETTE &&
10619 mng_info->write_png_depth &&
10620 mng_info->write_png_depth != old_bit_depth)
10622 /* Undo pixel scaling */
10623 for (i=0; i < (ssize_t) image->columns; i++)
10624 *(ping_pixels+i)=(unsigned char) (*(ping_pixels+i)
10625 >> (8-old_bit_depth));
10631 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10632 quantum_info,RedQuantum,ping_pixels,exception);
10635 if (mng_info->write_png_colortype-1 != PNG_COLOR_TYPE_PALETTE)
10636 for (i=0; i < (ssize_t) image->columns; i++)
10637 *(ping_pixels+i)=(unsigned char) ((*(ping_pixels+i) > 127) ?
10640 if (logging != MagickFalse && y == 0)
10641 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10642 " Writing row of pixels (1)");
10644 png_write_row(ping,ping_pixels);
10646 if (image->previous == (Image *) NULL)
10648 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
10649 if (status == MagickFalse)
10655 else /* Not Palette, Bilevel, or Opaque Monochrome */
10657 if ((!mng_info->write_png8 && !mng_info->write_png24 &&
10658 !mng_info->write_png48 && !mng_info->write_png64 &&
10659 !mng_info->write_png32) && (image_matte != MagickFalse ||
10660 (ping_bit_depth >= MAGICKCORE_QUANTUM_DEPTH)) &&
10661 (mng_info->IsPalette) && ping_have_color == MagickFalse)
10663 register const Quantum
10666 for (pass=0; pass < num_passes; pass++)
10669 for (y=0; y < (ssize_t) image->rows; y++)
10671 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
10673 if (p == (const Quantum *) NULL)
10676 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
10678 if (mng_info->IsPalette)
10679 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10680 quantum_info,GrayQuantum,ping_pixels,exception);
10683 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10684 quantum_info,RedQuantum,ping_pixels,exception);
10686 if (logging != MagickFalse && y == 0)
10687 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10688 " Writing GRAY PNG pixels (2)");
10691 else /* PNG_COLOR_TYPE_GRAY_ALPHA */
10693 if (logging != MagickFalse && y == 0)
10694 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10695 " Writing GRAY_ALPHA PNG pixels (2)");
10697 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10698 quantum_info,GrayAlphaQuantum,ping_pixels,exception);
10701 if (logging != MagickFalse && y == 0)
10702 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10703 " Writing row of pixels (2)");
10705 png_write_row(ping,ping_pixels);
10708 if (image->previous == (Image *) NULL)
10710 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
10711 if (status == MagickFalse)
10719 register const Quantum
10722 for (pass=0; pass < num_passes; pass++)
10724 if ((image_depth > 8) ||
10725 mng_info->write_png24 ||
10726 mng_info->write_png32 ||
10727 mng_info->write_png48 ||
10728 mng_info->write_png64 ||
10729 (!mng_info->write_png8 && !mng_info->IsPalette))
10731 for (y=0; y < (ssize_t) image->rows; y++)
10733 p=GetVirtualPixels(image,0,y,image->columns,1, exception);
10735 if (p == (const Quantum *) NULL)
10738 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
10740 if (image->storage_class == DirectClass)
10741 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10742 quantum_info,RedQuantum,ping_pixels,exception);
10745 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10746 quantum_info,GrayQuantum,ping_pixels,exception);
10749 else if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
10751 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10752 quantum_info,GrayAlphaQuantum,ping_pixels,
10755 if (logging != MagickFalse && y == 0)
10756 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10757 " Writing GRAY_ALPHA PNG pixels (3)");
10760 else if (image_matte != MagickFalse)
10761 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10762 quantum_info,RGBAQuantum,ping_pixels,exception);
10765 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10766 quantum_info,RGBQuantum,ping_pixels,exception);
10768 if (logging != MagickFalse && y == 0)
10769 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10770 " Writing row of pixels (3)");
10772 png_write_row(ping,ping_pixels);
10777 /* not ((image_depth > 8) ||
10778 mng_info->write_png24 || mng_info->write_png32 ||
10779 mng_info->write_png48 || mng_info->write_png64 ||
10780 (!mng_info->write_png8 && !mng_info->IsPalette))
10783 if ((ping_color_type != PNG_COLOR_TYPE_GRAY) &&
10784 (ping_color_type != PNG_COLOR_TYPE_GRAY_ALPHA))
10786 if (logging != MagickFalse)
10787 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10788 " pass %d, Image Is not GRAY or GRAY_ALPHA",pass);
10790 quantum_info->depth=8;
10794 for (y=0; y < (ssize_t) image->rows; y++)
10796 if (logging != MagickFalse && y == 0)
10797 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10798 " pass %d, Image Is RGB, 16-bit GRAY, or GRAY_ALPHA",pass);
10800 p=GetVirtualPixels(image,0,y,image->columns,1, exception);
10802 if (p == (const Quantum *) NULL)
10805 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
10807 quantum_info->depth=image->depth;
10809 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10810 quantum_info,GrayQuantum,ping_pixels,exception);
10813 else if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
10815 if (logging != MagickFalse && y == 0)
10816 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10817 " Writing GRAY_ALPHA PNG pixels (4)");
10819 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10820 quantum_info,GrayAlphaQuantum,ping_pixels,
10826 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10827 quantum_info,IndexQuantum,ping_pixels,exception);
10829 if (logging != MagickFalse && y <= 2)
10831 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10832 " Writing row of non-gray pixels (4)");
10834 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10835 " ping_pixels[0]=%d,ping_pixels[1]=%d",
10836 (int)ping_pixels[0],(int)ping_pixels[1]);
10839 png_write_row(ping,ping_pixels);
10843 if (image->previous == (Image *) NULL)
10845 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
10846 if (status == MagickFalse)
10853 if (quantum_info != (QuantumInfo *) NULL)
10854 quantum_info=DestroyQuantumInfo(quantum_info);
10856 if (logging != MagickFalse)
10858 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10859 " Wrote PNG image data");
10861 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10862 " Width: %.20g",(double) ping_width);
10864 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10865 " Height: %.20g",(double) ping_height);
10867 if (mng_info->write_png_depth)
10869 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10870 " Defined png:bit-depth: %d",mng_info->write_png_depth);
10873 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10874 " PNG bit-depth written: %d",ping_bit_depth);
10876 if (mng_info->write_png_colortype)
10878 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10879 " Defined png:color-type: %d",mng_info->write_png_colortype-1);
10882 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10883 " PNG color-type written: %d",ping_color_type);
10885 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10886 " PNG Interlace method: %d",ping_interlace_method);
10889 Generate text chunks after IDAT.
10891 if (ping_exclude_tEXt == MagickFalse || ping_exclude_zTXt == MagickFalse)
10893 ResetImagePropertyIterator(image);
10894 property=GetNextImageProperty(image);
10895 while (property != (const char *) NULL)
10900 value=GetImageProperty(image,property,exception);
10902 /* Don't write any "png:" properties; those are just for "identify" */
10903 if (LocaleNCompare(property,"png:",4) != 0 &&
10905 /* Suppress density and units if we wrote a pHYs chunk */
10906 (ping_exclude_pHYs != MagickFalse ||
10907 LocaleCompare(property,"density") != 0 ||
10908 LocaleCompare(property,"units") != 0) &&
10910 /* Suppress the IM-generated Date:create and Date:modify */
10911 (ping_exclude_date == MagickFalse ||
10912 LocaleNCompare(property, "Date:",5) != 0))
10914 if (value != (const char *) NULL)
10917 #if PNG_LIBPNG_VER >= 14000
10918 text=(png_textp) png_malloc(ping,
10919 (png_alloc_size_t) sizeof(png_text));
10921 text=(png_textp) png_malloc(ping,(png_size_t) sizeof(png_text));
10923 text[0].key=(char *) property;
10924 text[0].text=(char *) value;
10925 text[0].text_length=strlen(value);
10927 if (ping_exclude_tEXt != MagickFalse)
10928 text[0].compression=PNG_TEXT_COMPRESSION_zTXt;
10930 else if (ping_exclude_zTXt != MagickFalse)
10931 text[0].compression=PNG_TEXT_COMPRESSION_NONE;
10935 text[0].compression=image_info->compression == NoCompression ||
10936 (image_info->compression == UndefinedCompression &&
10937 text[0].text_length < 128) ? PNG_TEXT_COMPRESSION_NONE :
10938 PNG_TEXT_COMPRESSION_zTXt ;
10941 if (logging != MagickFalse)
10943 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10944 " Setting up text chunk");
10946 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10947 " keyword: %s",text[0].key);
10950 png_set_text(ping,ping_info,text,1);
10951 png_free(ping,text);
10954 property=GetNextImageProperty(image);
10958 /* write any PNG-chunk-e profiles */
10959 (void) Magick_png_write_chunk_from_profile(image,"PNG-chunk-e",logging);
10961 if (logging != MagickFalse)
10962 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10963 " Writing PNG end info");
10965 png_write_end(ping,ping_info);
10967 if (mng_info->need_fram && (int) image->dispose == BackgroundDispose)
10969 if (mng_info->page.x || mng_info->page.y ||
10970 (ping_width != mng_info->page.width) ||
10971 (ping_height != mng_info->page.height))
10977 Write FRAM 4 with clipping boundaries followed by FRAM 1.
10979 (void) WriteBlobMSBULong(image,27L); /* data length=27 */
10980 PNGType(chunk,mng_FRAM);
10981 LogPNGChunk(logging,mng_FRAM,27L);
10983 chunk[5]=0; /* frame name separator (no name) */
10984 chunk[6]=1; /* flag for changing delay, for next frame only */
10985 chunk[7]=0; /* flag for changing frame timeout */
10986 chunk[8]=1; /* flag for changing frame clipping for next frame */
10987 chunk[9]=0; /* flag for changing frame sync_id */
10988 PNGLong(chunk+10,(png_uint_32) (0L)); /* temporary 0 delay */
10989 chunk[14]=0; /* clipping boundaries delta type */
10990 PNGLong(chunk+15,(png_uint_32) (mng_info->page.x)); /* left cb */
10992 (png_uint_32) (mng_info->page.x + ping_width));
10993 PNGLong(chunk+23,(png_uint_32) (mng_info->page.y)); /* top cb */
10995 (png_uint_32) (mng_info->page.y + ping_height));
10996 (void) WriteBlob(image,31,chunk);
10997 (void) WriteBlobMSBULong(image,crc32(0,chunk,31));
10998 mng_info->old_framing_mode=4;
10999 mng_info->framing_mode=1;
11003 mng_info->framing_mode=3;
11005 if (mng_info->write_mng && !mng_info->need_fram &&
11006 ((int) image->dispose == 3))
11007 png_error(ping, "Cannot convert GIF with disposal method 3 to MNG-LC");
11010 Free PNG resources.
11013 png_destroy_write_struct(&ping,&ping_info);
11015 ping_pixels=(unsigned char *) RelinquishMagickMemory(ping_pixels);
11017 if (ping_have_blob != MagickFalse)
11018 (void) CloseBlob(image);
11020 image_info=DestroyImageInfo(image_info);
11021 image=DestroyImage(image);
11023 /* Store bit depth actually written */
11024 s[0]=(char) ping_bit_depth;
11027 (void) SetImageProperty(IMimage,"png:bit-depth-written",s,exception);
11029 if (logging != MagickFalse)
11030 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11031 " exit WriteOnePNGImage()");
11033 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
11034 UnlockSemaphoreInfo(ping_semaphore);
11037 /* } for navigation to beginning of SETJMP-protected block. Revert to
11038 * Throwing an Exception when an error occurs.
11041 return(MagickTrue);
11042 /* End write one PNG image */
11047 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11051 % W r i t e P N G I m a g e %
11055 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11057 % WritePNGImage() writes a Portable Network Graphics (PNG) or
11058 % Multiple-image Network Graphics (MNG) image file.
11060 % MNG support written by Glenn Randers-Pehrson, glennrp@image...
11062 % The format of the WritePNGImage method is:
11064 % MagickBooleanType WritePNGImage(const ImageInfo *image_info,
11065 % Image *image,ExceptionInfo *exception)
11067 % A description of each parameter follows:
11069 % o image_info: the image info.
11071 % o image: The image.
11073 % o exception: return any errors or warnings in this structure.
11075 % Returns MagickTrue on success, MagickFalse on failure.
11077 % Communicating with the PNG encoder:
11079 % While the datastream written is always in PNG format and normally would
11080 % be given the "png" file extension, this method also writes the following
11081 % pseudo-formats which are subsets of png:
11083 % o PNG8: An 8-bit indexed PNG datastream is written. If the image has
11084 % a depth greater than 8, the depth is reduced. If transparency
11085 % is present, the tRNS chunk must only have values 0 and 255
11086 % (i.e., transparency is binary: fully opaque or fully
11087 % transparent). If other values are present they will be
11088 % 50%-thresholded to binary transparency. If more than 256
11089 % colors are present, they will be quantized to the 4-4-4-1,
11090 % 3-3-3-1, or 3-3-2-1 palette. The underlying RGB color
11091 % of any resulting fully-transparent pixels is changed to
11092 % the image's background color.
11094 % If you want better quantization or dithering of the colors
11095 % or alpha than that, you need to do it before calling the
11096 % PNG encoder. The pixels contain 8-bit indices even if
11097 % they could be represented with 1, 2, or 4 bits. Grayscale
11098 % images will be written as indexed PNG files even though the
11099 % PNG grayscale type might be slightly more efficient. Please
11100 % note that writing to the PNG8 format may result in loss
11101 % of color and alpha data.
11103 % o PNG24: An 8-bit per sample RGB PNG datastream is written. The tRNS
11104 % chunk can be present to convey binary transparency by naming
11105 % one of the colors as transparent. The only loss incurred
11106 % is reduction of sample depth to 8. If the image has more
11107 % than one transparent color, has semitransparent pixels, or
11108 % has an opaque pixel with the same RGB components as the
11109 % transparent color, an image is not written.
11111 % o PNG32: An 8-bit per sample RGBA PNG is written. Partial
11112 % transparency is permitted, i.e., the alpha sample for
11113 % each pixel can have any value from 0 to 255. The alpha
11114 % channel is present even if the image is fully opaque.
11115 % The only loss in data is the reduction of the sample depth
11118 % o PNG48: A 16-bit per sample RGB PNG datastream is written. The tRNS
11119 % chunk can be present to convey binary transparency by naming
11120 % one of the colors as transparent. If the image has more
11121 % than one transparent color, has semitransparent pixels, or
11122 % has an opaque pixel with the same RGB components as the
11123 % transparent color, an image is not written.
11125 % o PNG64: A 16-bit per sample RGBA PNG is written. Partial
11126 % transparency is permitted, i.e., the alpha sample for
11127 % each pixel can have any value from 0 to 65535. The alpha
11128 % channel is present even if the image is fully opaque.
11130 % o PNG00: A PNG that inherits its colortype and bit-depth from the input
11131 % image, if the input was a PNG, is written. If these values
11132 % cannot be found, then "PNG00" falls back to the regular "PNG"
11135 % o -define: For more precise control of the PNG output, you can use the
11136 % Image options "png:bit-depth" and "png:color-type". These
11137 % can be set from the commandline with "-define" and also
11138 % from the application programming interfaces. The options
11139 % are case-independent and are converted to lowercase before
11140 % being passed to this encoder.
11142 % png:color-type can be 0, 2, 3, 4, or 6.
11144 % When png:color-type is 0 (Grayscale), png:bit-depth can
11145 % be 1, 2, 4, 8, or 16.
11147 % When png:color-type is 2 (RGB), png:bit-depth can
11150 % When png:color-type is 3 (Indexed), png:bit-depth can
11151 % be 1, 2, 4, or 8. This refers to the number of bits
11152 % used to store the index. The color samples always have
11153 % bit-depth 8 in indexed PNG files.
11155 % When png:color-type is 4 (Gray-Matte) or 6 (RGB-Matte),
11156 % png:bit-depth can be 8 or 16.
11158 % If the image cannot be written without loss with the
11159 % requested bit-depth and color-type, a PNG file will not
11160 % be written, a warning will be issued, and the encoder will
11161 % return MagickFalse.
11163 % Since image encoders should not be responsible for the "heavy lifting",
11164 % the user should make sure that ImageMagick has already reduced the
11165 % image depth and number of colors and limit transparency to binary
11166 % transparency prior to attempting to write the image with depth, color,
11167 % or transparency limitations.
11169 % Note that another definition, "png:bit-depth-written" exists, but it
11170 % is not intended for external use. It is only used internally by the
11171 % PNG encoder to inform the JNG encoder of the depth of the alpha channel.
11173 % It is possible to request that the PNG encoder write previously-formatted
11174 % ancillary chunks in the output PNG file, using the "-profile" commandline
11175 % option as shown below or by setting the profile via a programming
11178 % -profile PNG-chunk-x:<file>
11180 % where x is a location flag and <file> is a file containing the chunk
11181 % name in the first 4 bytes, then a colon (":"), followed by the chunk data.
11182 % This encoder will compute the chunk length and CRC, so those must not
11183 % be included in the file.
11185 % "x" can be "b" (before PLTE), "m" (middle, i.e., between PLTE and IDAT),
11186 % or "e" (end, i.e., after IDAT). If you want to write multiple chunks
11187 % of the same type, then add a short unique string after the "x" to prevent
11188 % subsequent profiles from overwriting the preceding ones, e.g.,
11190 % -profile PNG-chunk-b01:file01 -profile PNG-chunk-b02:file02
11192 % As of version 6.6.6 the following optimizations are always done:
11194 % o 32-bit depth is reduced to 16.
11195 % o 16-bit depth is reduced to 8 if all pixels contain samples whose
11196 % high byte and low byte are identical.
11197 % o Palette is sorted to remove unused entries and to put a
11198 % transparent color first, if BUILD_PNG_PALETTE is defined.
11199 % o Opaque matte channel is removed when writing an indexed PNG.
11200 % o Grayscale images are reduced to 1, 2, or 4 bit depth if
11201 % this can be done without loss and a larger bit depth N was not
11202 % requested via the "-define png:bit-depth=N" option.
11203 % o If matte channel is present but only one transparent color is
11204 % present, RGB+tRNS is written instead of RGBA
11205 % o Opaque matte channel is removed (or added, if color-type 4 or 6
11206 % was requested when converting an opaque image).
11208 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11210 static MagickBooleanType WritePNGImage(const ImageInfo *image_info,
11211 Image *image,ExceptionInfo *exception)
11216 have_mng_structure,
11232 assert(image_info != (const ImageInfo *) NULL);
11233 assert(image_info->signature == MagickSignature);
11234 assert(image != (Image *) NULL);
11235 assert(image->signature == MagickSignature);
11236 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
11237 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter WritePNGImage()");
11239 Allocate a MngInfo structure.
11241 have_mng_structure=MagickFalse;
11242 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
11244 if (mng_info == (MngInfo *) NULL)
11245 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
11248 Initialize members of the MngInfo structure.
11250 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
11251 mng_info->image=image;
11252 mng_info->equal_backgrounds=MagickTrue;
11253 have_mng_structure=MagickTrue;
11255 /* See if user has requested a specific PNG subformat */
11257 mng_info->write_png8=LocaleCompare(image_info->magick,"PNG8") == 0;
11258 mng_info->write_png24=LocaleCompare(image_info->magick,"PNG24") == 0;
11259 mng_info->write_png32=LocaleCompare(image_info->magick,"PNG32") == 0;
11260 mng_info->write_png48=LocaleCompare(image_info->magick,"PNG48") == 0;
11261 mng_info->write_png64=LocaleCompare(image_info->magick,"PNG64") == 0;
11263 value=GetImageOption(image_info,"png:format");
11265 if (value != (char *) NULL)
11267 mng_info->write_png8 = MagickFalse;
11268 mng_info->write_png24 = MagickFalse;
11269 mng_info->write_png32 = MagickFalse;
11270 mng_info->write_png48 = MagickFalse;
11271 mng_info->write_png64 = MagickFalse;
11273 if (LocaleCompare(value,"png8") == 0)
11274 mng_info->write_png8 = MagickTrue;
11276 else if (LocaleCompare(value,"png24") == 0)
11277 mng_info->write_png24 = MagickTrue;
11279 else if (LocaleCompare(value,"png32") == 0)
11280 mng_info->write_png32 = MagickTrue;
11282 else if (LocaleCompare(value,"png48") == 0)
11283 mng_info->write_png48 = MagickTrue;
11285 else if (LocaleCompare(value,"png64") == 0)
11286 mng_info->write_png64 = MagickTrue;
11289 if (LocaleCompare(value,"png00") == 0)
11291 /* Retrieve png:IHDR.bit-depth-orig and png:IHDR.color-type-orig
11292 Note that whitespace at the end of the property names must match
11293 that in the corresponding SetImageProperty() calls.
11295 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11296 " Format=%s",value);
11298 value=GetImageProperty(image,"png:IHDR.bit-depth-orig ",exception);
11300 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11301 " png00 inherited bit depth=%s",value);
11303 if (value != (char *) NULL)
11305 if (LocaleCompare(value,"1") == 0)
11306 mng_info->write_png_depth = 1;
11308 else if (LocaleCompare(value,"1") == 0)
11309 mng_info->write_png_depth = 2;
11311 else if (LocaleCompare(value,"2") == 0)
11312 mng_info->write_png_depth = 4;
11314 else if (LocaleCompare(value,"8") == 0)
11315 mng_info->write_png_depth = 8;
11317 else if (LocaleCompare(value,"16") == 0)
11318 mng_info->write_png_depth = 16;
11321 value=GetImageProperty(image,"png:IHDR.color-type-orig ",exception);
11323 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11324 " png00 inherited color type=%s",value);
11326 if (value != (char *) NULL)
11328 if (LocaleCompare(value,"0") == 0)
11329 mng_info->write_png_colortype = 1;
11331 else if (LocaleCompare(value,"2") == 0)
11332 mng_info->write_png_colortype = 3;
11334 else if (LocaleCompare(value,"3") == 0)
11335 mng_info->write_png_colortype = 4;
11337 else if (LocaleCompare(value,"4") == 0)
11338 mng_info->write_png_colortype = 5;
11340 else if (LocaleCompare(value,"6") == 0)
11341 mng_info->write_png_colortype = 7;
11345 if (mng_info->write_png8)
11347 mng_info->write_png_colortype = /* 3 */ 4;
11348 mng_info->write_png_depth = 8;
11352 if (mng_info->write_png24)
11354 mng_info->write_png_colortype = /* 2 */ 3;
11355 mng_info->write_png_depth = 8;
11358 if (image->alpha_trait == BlendPixelTrait)
11359 (void) SetImageType(image,TrueColorMatteType,exception);
11362 (void) SetImageType(image,TrueColorType,exception);
11364 (void) SyncImage(image,exception);
11367 if (mng_info->write_png32)
11369 mng_info->write_png_colortype = /* 6 */ 7;
11370 mng_info->write_png_depth = 8;
11373 if (image->alpha_trait == BlendPixelTrait)
11374 (void) SetImageType(image,TrueColorMatteType,exception);
11377 (void) SetImageType(image,TrueColorType,exception);
11379 (void) SyncImage(image,exception);
11382 if (mng_info->write_png48)
11384 mng_info->write_png_colortype = /* 2 */ 3;
11385 mng_info->write_png_depth = 16;
11388 if (image->alpha_trait == BlendPixelTrait)
11389 (void) SetImageType(image,TrueColorMatteType,exception);
11392 (void) SetImageType(image,TrueColorType,exception);
11394 (void) SyncImage(image,exception);
11397 if (mng_info->write_png64)
11399 mng_info->write_png_colortype = /* 6 */ 7;
11400 mng_info->write_png_depth = 16;
11403 if (image->alpha_trait == BlendPixelTrait)
11404 (void) SetImageType(image,TrueColorMatteType,exception);
11407 (void) SetImageType(image,TrueColorType,exception);
11409 (void) SyncImage(image,exception);
11412 value=GetImageOption(image_info,"png:bit-depth");
11414 if (value != (char *) NULL)
11416 if (LocaleCompare(value,"1") == 0)
11417 mng_info->write_png_depth = 1;
11419 else if (LocaleCompare(value,"2") == 0)
11420 mng_info->write_png_depth = 2;
11422 else if (LocaleCompare(value,"4") == 0)
11423 mng_info->write_png_depth = 4;
11425 else if (LocaleCompare(value,"8") == 0)
11426 mng_info->write_png_depth = 8;
11428 else if (LocaleCompare(value,"16") == 0)
11429 mng_info->write_png_depth = 16;
11432 (void) ThrowMagickException(exception,
11433 GetMagickModule(),CoderWarning,
11434 "ignoring invalid defined png:bit-depth",
11437 if (logging != MagickFalse)
11438 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11439 " png:bit-depth=%d was defined.\n",mng_info->write_png_depth);
11442 value=GetImageOption(image_info,"png:color-type");
11444 if (value != (char *) NULL)
11446 /* We must store colortype+1 because 0 is a valid colortype */
11447 if (LocaleCompare(value,"0") == 0)
11448 mng_info->write_png_colortype = 1;
11450 else if (LocaleCompare(value,"1") == 0)
11451 mng_info->write_png_colortype = 2;
11453 else if (LocaleCompare(value,"2") == 0)
11454 mng_info->write_png_colortype = 3;
11456 else if (LocaleCompare(value,"3") == 0)
11457 mng_info->write_png_colortype = 4;
11459 else if (LocaleCompare(value,"4") == 0)
11460 mng_info->write_png_colortype = 5;
11462 else if (LocaleCompare(value,"6") == 0)
11463 mng_info->write_png_colortype = 7;
11466 (void) ThrowMagickException(exception,
11467 GetMagickModule(),CoderWarning,
11468 "ignoring invalid defined png:color-type",
11471 if (logging != MagickFalse)
11472 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11473 " png:color-type=%d was defined.\n",mng_info->write_png_colortype-1);
11476 /* Check for chunks to be excluded:
11478 * The default is to not exclude any known chunks except for any
11479 * listed in the "unused_chunks" array, above.
11481 * Chunks can be listed for exclusion via a "png:exclude-chunk"
11482 * define (in the image properties or in the image artifacts)
11483 * or via a mng_info member. For convenience, in addition
11484 * to or instead of a comma-separated list of chunks, the
11485 * "exclude-chunk" string can be simply "all" or "none".
11487 * The exclude-chunk define takes priority over the mng_info.
11489 * A "png:include-chunk" define takes priority over both the
11490 * mng_info and the "png:exclude-chunk" define. Like the
11491 * "exclude-chunk" string, it can define "all" or "none" as
11492 * well as a comma-separated list. Chunks that are unknown to
11493 * ImageMagick are always excluded, regardless of their "copy-safe"
11494 * status according to the PNG specification, and even if they
11495 * appear in the "include-chunk" list. Such defines appearing among
11496 * the image options take priority over those found among the image
11499 * Finally, all chunks listed in the "unused_chunks" array are
11500 * automatically excluded, regardless of the other instructions
11503 * if you exclude sRGB but not gAMA (recommended), then sRGB chunk
11504 * will not be written and the gAMA chunk will only be written if it
11505 * is not between .45 and .46, or approximately (1.0/2.2).
11507 * If you exclude tRNS and the image has transparency, the colortype
11508 * is forced to be 4 or 6 (GRAY_ALPHA or RGB_ALPHA).
11510 * The -strip option causes StripImage() to set the png:include-chunk
11511 * artifact to "none,trns,gama".
11514 mng_info->ping_exclude_bKGD=MagickFalse;
11515 mng_info->ping_exclude_cHRM=MagickFalse;
11516 mng_info->ping_exclude_date=MagickFalse;
11517 mng_info->ping_exclude_EXIF=MagickFalse; /* hex-encoded EXIF in zTXt */
11518 mng_info->ping_exclude_gAMA=MagickFalse;
11519 mng_info->ping_exclude_iCCP=MagickFalse;
11520 /* mng_info->ping_exclude_iTXt=MagickFalse; */
11521 mng_info->ping_exclude_oFFs=MagickFalse;
11522 mng_info->ping_exclude_pHYs=MagickFalse;
11523 mng_info->ping_exclude_sRGB=MagickFalse;
11524 mng_info->ping_exclude_tEXt=MagickFalse;
11525 mng_info->ping_exclude_tRNS=MagickFalse;
11526 mng_info->ping_exclude_vpAg=MagickFalse;
11527 mng_info->ping_exclude_zCCP=MagickFalse; /* hex-encoded iCCP in zTXt */
11528 mng_info->ping_exclude_zTXt=MagickFalse;
11530 mng_info->ping_preserve_colormap=MagickFalse;
11532 value=GetImageArtifact(image,"png:preserve-colormap");
11534 value=GetImageOption(image_info,"png:preserve-colormap");
11536 mng_info->ping_preserve_colormap=MagickTrue;
11538 /* Thes compression-level, compression-strategy, and compression-filter
11539 * defines take precedence over values from the -quality option.
11541 value=GetImageArtifact(image,"png:compression-level");
11543 value=GetImageOption(image_info,"png:compression-level");
11546 /* We have to add 1 to everything because 0 is a valid input,
11547 * and we want to use 0 (the default) to mean undefined.
11549 if (LocaleCompare(value,"0") == 0)
11550 mng_info->write_png_compression_level = 1;
11552 else if (LocaleCompare(value,"1") == 0)
11553 mng_info->write_png_compression_level = 2;
11555 else if (LocaleCompare(value,"2") == 0)
11556 mng_info->write_png_compression_level = 3;
11558 else if (LocaleCompare(value,"3") == 0)
11559 mng_info->write_png_compression_level = 4;
11561 else if (LocaleCompare(value,"4") == 0)
11562 mng_info->write_png_compression_level = 5;
11564 else if (LocaleCompare(value,"5") == 0)
11565 mng_info->write_png_compression_level = 6;
11567 else if (LocaleCompare(value,"6") == 0)
11568 mng_info->write_png_compression_level = 7;
11570 else if (LocaleCompare(value,"7") == 0)
11571 mng_info->write_png_compression_level = 8;
11573 else if (LocaleCompare(value,"8") == 0)
11574 mng_info->write_png_compression_level = 9;
11576 else if (LocaleCompare(value,"9") == 0)
11577 mng_info->write_png_compression_level = 10;
11580 (void) ThrowMagickException(exception,
11581 GetMagickModule(),CoderWarning,
11582 "ignoring invalid defined png:compression-level",
11586 value=GetImageArtifact(image,"png:compression-strategy");
11588 value=GetImageOption(image_info,"png:compression-strategy");
11592 if (LocaleCompare(value,"0") == 0)
11593 mng_info->write_png_compression_strategy = Z_DEFAULT_STRATEGY+1;
11595 else if (LocaleCompare(value,"1") == 0)
11596 mng_info->write_png_compression_strategy = Z_FILTERED+1;
11598 else if (LocaleCompare(value,"2") == 0)
11599 mng_info->write_png_compression_strategy = Z_HUFFMAN_ONLY+1;
11601 else if (LocaleCompare(value,"3") == 0)
11602 #ifdef Z_RLE /* Z_RLE was added to zlib-1.2.0 */
11603 mng_info->write_png_compression_strategy = Z_RLE+1;
11605 mng_info->write_png_compression_strategy = Z_DEFAULT_STRATEGY+1;
11608 else if (LocaleCompare(value,"4") == 0)
11609 #ifdef Z_FIXED /* Z_FIXED was added to zlib-1.2.2.2 */
11610 mng_info->write_png_compression_strategy = Z_FIXED+1;
11612 mng_info->write_png_compression_strategy = Z_DEFAULT_STRATEGY+1;
11616 (void) ThrowMagickException(exception,
11617 GetMagickModule(),CoderWarning,
11618 "ignoring invalid defined png:compression-strategy",
11622 value=GetImageArtifact(image,"png:compression-filter");
11624 value=GetImageOption(image_info,"png:compression-filter");
11628 /* To do: combinations of filters allowed by libpng
11629 * masks 0x08 through 0xf8
11631 * Implement this as a comma-separated list of 0,1,2,3,4,5
11632 * where 5 is a special case meaning PNG_ALL_FILTERS.
11635 if (LocaleCompare(value,"0") == 0)
11636 mng_info->write_png_compression_filter = 1;
11638 else if (LocaleCompare(value,"1") == 0)
11639 mng_info->write_png_compression_filter = 2;
11641 else if (LocaleCompare(value,"2") == 0)
11642 mng_info->write_png_compression_filter = 3;
11644 else if (LocaleCompare(value,"3") == 0)
11645 mng_info->write_png_compression_filter = 4;
11647 else if (LocaleCompare(value,"4") == 0)
11648 mng_info->write_png_compression_filter = 5;
11650 else if (LocaleCompare(value,"5") == 0)
11651 mng_info->write_png_compression_filter = 6;
11654 (void) ThrowMagickException(exception,
11655 GetMagickModule(),CoderWarning,
11656 "ignoring invalid defined png:compression-filter",
11660 excluding=MagickFalse;
11662 for (source=0; source<1; source++)
11666 value=GetImageArtifact(image,"png:exclude-chunk");
11669 value=GetImageArtifact(image,"png:exclude-chunks");
11673 value=GetImageOption(image_info,"png:exclude-chunk");
11676 value=GetImageOption(image_info,"png:exclude-chunks");
11685 excluding=MagickTrue;
11687 if (logging != MagickFalse)
11690 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11691 " png:exclude-chunk=%s found in image artifacts.\n", value);
11693 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11694 " png:exclude-chunk=%s found in image properties.\n", value);
11697 last=strlen(value);
11699 for (i=0; i<(int) last; i+=5)
11702 if (LocaleNCompare(value+i,"all",3) == 0)
11704 mng_info->ping_exclude_bKGD=MagickTrue;
11705 mng_info->ping_exclude_cHRM=MagickTrue;
11706 mng_info->ping_exclude_date=MagickTrue;
11707 mng_info->ping_exclude_EXIF=MagickTrue;
11708 mng_info->ping_exclude_gAMA=MagickTrue;
11709 mng_info->ping_exclude_iCCP=MagickTrue;
11710 /* mng_info->ping_exclude_iTXt=MagickTrue; */
11711 mng_info->ping_exclude_oFFs=MagickTrue;
11712 mng_info->ping_exclude_pHYs=MagickTrue;
11713 mng_info->ping_exclude_sRGB=MagickTrue;
11714 mng_info->ping_exclude_tEXt=MagickTrue;
11715 mng_info->ping_exclude_tRNS=MagickTrue;
11716 mng_info->ping_exclude_vpAg=MagickTrue;
11717 mng_info->ping_exclude_zCCP=MagickTrue;
11718 mng_info->ping_exclude_zTXt=MagickTrue;
11722 if (LocaleNCompare(value+i,"none",4) == 0)
11724 mng_info->ping_exclude_bKGD=MagickFalse;
11725 mng_info->ping_exclude_cHRM=MagickFalse;
11726 mng_info->ping_exclude_date=MagickFalse;
11727 mng_info->ping_exclude_EXIF=MagickFalse;
11728 mng_info->ping_exclude_gAMA=MagickFalse;
11729 mng_info->ping_exclude_iCCP=MagickFalse;
11730 /* mng_info->ping_exclude_iTXt=MagickFalse; */
11731 mng_info->ping_exclude_oFFs=MagickFalse;
11732 mng_info->ping_exclude_pHYs=MagickFalse;
11733 mng_info->ping_exclude_sRGB=MagickFalse;
11734 mng_info->ping_exclude_tEXt=MagickFalse;
11735 mng_info->ping_exclude_tRNS=MagickFalse;
11736 mng_info->ping_exclude_vpAg=MagickFalse;
11737 mng_info->ping_exclude_zCCP=MagickFalse;
11738 mng_info->ping_exclude_zTXt=MagickFalse;
11741 if (LocaleNCompare(value+i,"bkgd",4) == 0)
11742 mng_info->ping_exclude_bKGD=MagickTrue;
11744 if (LocaleNCompare(value+i,"chrm",4) == 0)
11745 mng_info->ping_exclude_cHRM=MagickTrue;
11747 if (LocaleNCompare(value+i,"date",4) == 0)
11748 mng_info->ping_exclude_date=MagickTrue;
11750 if (LocaleNCompare(value+i,"exif",4) == 0)
11751 mng_info->ping_exclude_EXIF=MagickTrue;
11753 if (LocaleNCompare(value+i,"gama",4) == 0)
11754 mng_info->ping_exclude_gAMA=MagickTrue;
11756 if (LocaleNCompare(value+i,"iccp",4) == 0)
11757 mng_info->ping_exclude_iCCP=MagickTrue;
11760 if (LocaleNCompare(value+i,"itxt",4) == 0)
11761 mng_info->ping_exclude_iTXt=MagickTrue;
11764 if (LocaleNCompare(value+i,"gama",4) == 0)
11765 mng_info->ping_exclude_gAMA=MagickTrue;
11767 if (LocaleNCompare(value+i,"offs",4) == 0)
11768 mng_info->ping_exclude_oFFs=MagickTrue;
11770 if (LocaleNCompare(value+i,"phys",4) == 0)
11771 mng_info->ping_exclude_pHYs=MagickTrue;
11773 if (LocaleNCompare(value+i,"srgb",4) == 0)
11774 mng_info->ping_exclude_sRGB=MagickTrue;
11776 if (LocaleNCompare(value+i,"text",4) == 0)
11777 mng_info->ping_exclude_tEXt=MagickTrue;
11779 if (LocaleNCompare(value+i,"trns",4) == 0)
11780 mng_info->ping_exclude_tRNS=MagickTrue;
11782 if (LocaleNCompare(value+i,"vpag",4) == 0)
11783 mng_info->ping_exclude_vpAg=MagickTrue;
11785 if (LocaleNCompare(value+i,"zccp",4) == 0)
11786 mng_info->ping_exclude_zCCP=MagickTrue;
11788 if (LocaleNCompare(value+i,"ztxt",4) == 0)
11789 mng_info->ping_exclude_zTXt=MagickTrue;
11795 for (source=0; source<1; source++)
11799 value=GetImageArtifact(image,"png:include-chunk");
11802 value=GetImageArtifact(image,"png:include-chunks");
11806 value=GetImageOption(image_info,"png:include-chunk");
11809 value=GetImageOption(image_info,"png:include-chunks");
11817 excluding=MagickTrue;
11819 if (logging != MagickFalse)
11822 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11823 " png:include-chunk=%s found in image artifacts.\n", value);
11825 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11826 " png:include-chunk=%s found in image properties.\n", value);
11829 last=strlen(value);
11831 for (i=0; i<(int) last; i+=5)
11833 if (LocaleNCompare(value+i,"all",3) == 0)
11835 mng_info->ping_exclude_bKGD=MagickFalse;
11836 mng_info->ping_exclude_cHRM=MagickFalse;
11837 mng_info->ping_exclude_date=MagickFalse;
11838 mng_info->ping_exclude_EXIF=MagickFalse;
11839 mng_info->ping_exclude_gAMA=MagickFalse;
11840 mng_info->ping_exclude_iCCP=MagickFalse;
11841 /* mng_info->ping_exclude_iTXt=MagickFalse; */
11842 mng_info->ping_exclude_oFFs=MagickFalse;
11843 mng_info->ping_exclude_pHYs=MagickFalse;
11844 mng_info->ping_exclude_sRGB=MagickFalse;
11845 mng_info->ping_exclude_tEXt=MagickFalse;
11846 mng_info->ping_exclude_tRNS=MagickFalse;
11847 mng_info->ping_exclude_vpAg=MagickFalse;
11848 mng_info->ping_exclude_zCCP=MagickFalse;
11849 mng_info->ping_exclude_zTXt=MagickFalse;
11853 if (LocaleNCompare(value+i,"none",4) == 0)
11855 mng_info->ping_exclude_bKGD=MagickTrue;
11856 mng_info->ping_exclude_cHRM=MagickTrue;
11857 mng_info->ping_exclude_date=MagickTrue;
11858 mng_info->ping_exclude_EXIF=MagickTrue;
11859 mng_info->ping_exclude_gAMA=MagickTrue;
11860 mng_info->ping_exclude_iCCP=MagickTrue;
11861 /* mng_info->ping_exclude_iTXt=MagickTrue; */
11862 mng_info->ping_exclude_oFFs=MagickTrue;
11863 mng_info->ping_exclude_pHYs=MagickTrue;
11864 mng_info->ping_exclude_sRGB=MagickTrue;
11865 mng_info->ping_exclude_tEXt=MagickTrue;
11866 mng_info->ping_exclude_tRNS=MagickTrue;
11867 mng_info->ping_exclude_vpAg=MagickTrue;
11868 mng_info->ping_exclude_zCCP=MagickTrue;
11869 mng_info->ping_exclude_zTXt=MagickTrue;
11872 if (LocaleNCompare(value+i,"bkgd",4) == 0)
11873 mng_info->ping_exclude_bKGD=MagickFalse;
11875 if (LocaleNCompare(value+i,"chrm",4) == 0)
11876 mng_info->ping_exclude_cHRM=MagickFalse;
11878 if (LocaleNCompare(value+i,"date",4) == 0)
11879 mng_info->ping_exclude_date=MagickFalse;
11881 if (LocaleNCompare(value+i,"exif",4) == 0)
11882 mng_info->ping_exclude_EXIF=MagickFalse;
11884 if (LocaleNCompare(value+i,"gama",4) == 0)
11885 mng_info->ping_exclude_gAMA=MagickFalse;
11887 if (LocaleNCompare(value+i,"iccp",4) == 0)
11888 mng_info->ping_exclude_iCCP=MagickFalse;
11891 if (LocaleNCompare(value+i,"itxt",4) == 0)
11892 mng_info->ping_exclude_iTXt=MagickFalse;
11895 if (LocaleNCompare(value+i,"gama",4) == 0)
11896 mng_info->ping_exclude_gAMA=MagickFalse;
11898 if (LocaleNCompare(value+i,"offs",4) == 0)
11899 mng_info->ping_exclude_oFFs=MagickFalse;
11901 if (LocaleNCompare(value+i,"phys",4) == 0)
11902 mng_info->ping_exclude_pHYs=MagickFalse;
11904 if (LocaleNCompare(value+i,"srgb",4) == 0)
11905 mng_info->ping_exclude_sRGB=MagickFalse;
11907 if (LocaleNCompare(value+i,"text",4) == 0)
11908 mng_info->ping_exclude_tEXt=MagickFalse;
11910 if (LocaleNCompare(value+i,"trns",4) == 0)
11911 mng_info->ping_exclude_tRNS=MagickFalse;
11913 if (LocaleNCompare(value+i,"vpag",4) == 0)
11914 mng_info->ping_exclude_vpAg=MagickFalse;
11916 if (LocaleNCompare(value+i,"zccp",4) == 0)
11917 mng_info->ping_exclude_zCCP=MagickFalse;
11919 if (LocaleNCompare(value+i,"ztxt",4) == 0)
11920 mng_info->ping_exclude_zTXt=MagickFalse;
11926 if (excluding != MagickFalse && logging != MagickFalse)
11928 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11929 " Chunks to be excluded from the output png:");
11930 if (mng_info->ping_exclude_bKGD != MagickFalse)
11931 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11933 if (mng_info->ping_exclude_cHRM != MagickFalse)
11934 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11936 if (mng_info->ping_exclude_date != MagickFalse)
11937 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11939 if (mng_info->ping_exclude_EXIF != MagickFalse)
11940 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11942 if (mng_info->ping_exclude_gAMA != MagickFalse)
11943 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11945 if (mng_info->ping_exclude_iCCP != MagickFalse)
11946 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11949 if (mng_info->ping_exclude_iTXt != MagickFalse)
11950 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11953 if (mng_info->ping_exclude_oFFs != MagickFalse)
11954 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11956 if (mng_info->ping_exclude_pHYs != MagickFalse)
11957 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11959 if (mng_info->ping_exclude_sRGB != MagickFalse)
11960 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11962 if (mng_info->ping_exclude_tEXt != MagickFalse)
11963 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11965 if (mng_info->ping_exclude_tRNS != MagickFalse)
11966 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11968 if (mng_info->ping_exclude_vpAg != MagickFalse)
11969 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11971 if (mng_info->ping_exclude_zCCP != MagickFalse)
11972 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11974 if (mng_info->ping_exclude_zTXt != MagickFalse)
11975 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11979 mng_info->need_blob = MagickTrue;
11981 status=WriteOnePNGImage(mng_info,image_info,image,exception);
11983 MngInfoFreeStruct(mng_info,&have_mng_structure);
11985 if (logging != MagickFalse)
11986 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit WritePNGImage()");
11991 #if defined(JNG_SUPPORTED)
11993 /* Write one JNG image */
11994 static MagickBooleanType WriteOneJNGImage(MngInfo *mng_info,
11995 const ImageInfo *image_info,Image *image,ExceptionInfo *exception)
12016 jng_alpha_compression_method,
12017 jng_alpha_sample_depth,
12025 logging=LogMagickEvent(CoderEvent,GetMagickModule(),
12026 " Enter WriteOneJNGImage()");
12028 blob=(unsigned char *) NULL;
12029 jpeg_image=(Image *) NULL;
12030 jpeg_image_info=(ImageInfo *) NULL;
12033 transparent=image_info->type==GrayscaleMatteType ||
12034 image_info->type==TrueColorMatteType || image->alpha_trait == BlendPixelTrait;
12036 jng_quality=image_info->quality == 0UL ? 75UL : image_info->quality%1000;
12038 jng_alpha_compression_method=image->compression==JPEGCompression? 8 : 0;
12040 jng_alpha_quality=image_info->quality == 0UL ? 75UL :
12041 image_info->quality;
12043 if (jng_alpha_quality >= 1000)
12044 jng_alpha_quality /= 1000;
12050 /* Create JPEG blob, image, and image_info */
12051 if (logging != MagickFalse)
12052 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12053 " Creating jpeg_image_info for alpha.");
12055 jpeg_image_info=(ImageInfo *) CloneImageInfo(image_info);
12057 if (jpeg_image_info == (ImageInfo *) NULL)
12058 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
12060 if (logging != MagickFalse)
12061 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12062 " Creating jpeg_image.");
12064 jpeg_image=SeparateImage(image,AlphaChannel,exception);
12065 if (jpeg_image == (Image *) NULL)
12066 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
12067 (void) CopyMagickString(jpeg_image->magick,"JPEG",MaxTextExtent);
12068 jpeg_image->alpha_trait=UndefinedPixelTrait;
12069 jpeg_image->quality=jng_alpha_quality;
12070 jpeg_image_info->type=GrayscaleType;
12071 (void) SetImageType(jpeg_image,GrayscaleType,exception);
12072 (void) AcquireUniqueFilename(jpeg_image->filename);
12073 (void) FormatLocaleString(jpeg_image_info->filename,MaxTextExtent,
12074 "%s",jpeg_image->filename);
12078 jng_alpha_compression_method=0;
12080 jng_alpha_sample_depth=0;
12083 /* To do: check bit depth of PNG alpha channel */
12085 /* Check if image is grayscale. */
12086 if (image_info->type != TrueColorMatteType && image_info->type !=
12087 TrueColorType && IsImageGray(image,exception))
12090 if (logging != MagickFalse)
12092 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12093 " JNG Quality = %d",(int) jng_quality);
12094 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12095 " JNG Color Type = %d",jng_color_type);
12098 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12099 " JNG Alpha Compression = %d",jng_alpha_compression_method);
12100 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12101 " JNG Alpha Depth = %d",jng_alpha_sample_depth);
12102 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12103 " JNG Alpha Quality = %d",(int) jng_alpha_quality);
12109 if (jng_alpha_compression_method==0)
12114 /* Encode alpha as a grayscale PNG blob */
12115 status=OpenBlob(jpeg_image_info,jpeg_image,WriteBinaryBlobMode,
12117 if (logging != MagickFalse)
12118 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12119 " Creating PNG blob.");
12122 (void) CopyMagickString(jpeg_image_info->magick,"PNG",MaxTextExtent);
12123 (void) CopyMagickString(jpeg_image->magick,"PNG",MaxTextExtent);
12124 jpeg_image_info->interlace=NoInterlace;
12126 /* Exclude all ancillary chunks */
12127 (void) SetImageArtifact(jpeg_image,"png:exclude-chunks","all");
12129 blob=ImageToBlob(jpeg_image_info,jpeg_image,&length,
12132 /* Retrieve sample depth used */
12133 value=GetImageProperty(jpeg_image,"png:bit-depth-written",exception);
12134 if (value != (char *) NULL)
12135 jng_alpha_sample_depth= (unsigned int) value[0];
12139 /* Encode alpha as a grayscale JPEG blob */
12141 status=OpenBlob(jpeg_image_info,jpeg_image,WriteBinaryBlobMode,
12144 (void) CopyMagickString(jpeg_image_info->magick,"JPEG",MaxTextExtent);
12145 (void) CopyMagickString(jpeg_image->magick,"JPEG",MaxTextExtent);
12146 jpeg_image_info->interlace=NoInterlace;
12147 if (logging != MagickFalse)
12148 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12149 " Creating blob.");
12150 blob=ImageToBlob(jpeg_image_info,jpeg_image,&length,
12152 jng_alpha_sample_depth=8;
12154 if (logging != MagickFalse)
12155 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12156 " Successfully read jpeg_image into a blob, length=%.20g.",
12160 /* Destroy JPEG image and image_info */
12161 jpeg_image=DestroyImage(jpeg_image);
12162 (void) RelinquishUniqueFileResource(jpeg_image_info->filename);
12163 jpeg_image_info=DestroyImageInfo(jpeg_image_info);
12166 /* Write JHDR chunk */
12167 (void) WriteBlobMSBULong(image,16L); /* chunk data length=16 */
12168 PNGType(chunk,mng_JHDR);
12169 LogPNGChunk(logging,mng_JHDR,16L);
12170 PNGLong(chunk+4,(png_uint_32) image->columns);
12171 PNGLong(chunk+8,(png_uint_32) image->rows);
12172 chunk[12]=jng_color_type;
12173 chunk[13]=8; /* sample depth */
12174 chunk[14]=8; /*jng_image_compression_method */
12175 chunk[15]=(unsigned char) (image_info->interlace == NoInterlace ? 0 : 8);
12176 chunk[16]=jng_alpha_sample_depth;
12177 chunk[17]=jng_alpha_compression_method;
12178 chunk[18]=0; /*jng_alpha_filter_method */
12179 chunk[19]=0; /*jng_alpha_interlace_method */
12180 (void) WriteBlob(image,20,chunk);
12181 (void) WriteBlobMSBULong(image,crc32(0,chunk,20));
12182 if (logging != MagickFalse)
12184 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12185 " JNG width:%15lu",(unsigned long) image->columns);
12187 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12188 " JNG height:%14lu",(unsigned long) image->rows);
12190 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12191 " JNG color type:%10d",jng_color_type);
12193 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12194 " JNG sample depth:%8d",8);
12196 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12197 " JNG compression:%9d",8);
12199 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12200 " JNG interlace:%11d",0);
12202 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12203 " JNG alpha depth:%9d",jng_alpha_sample_depth);
12205 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12206 " JNG alpha compression:%3d",jng_alpha_compression_method);
12208 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12209 " JNG alpha filter:%8d",0);
12211 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12212 " JNG alpha interlace:%5d",0);
12215 /* Write any JNG-chunk-b profiles */
12216 (void) Magick_png_write_chunk_from_profile(image,"JNG-chunk-b",logging);
12219 Write leading ancillary chunks
12225 Write JNG bKGD chunk
12236 if (jng_color_type == 8 || jng_color_type == 12)
12240 (void) WriteBlobMSBULong(image,(size_t) (num_bytes-4L));
12241 PNGType(chunk,mng_bKGD);
12242 LogPNGChunk(logging,mng_bKGD,(size_t) (num_bytes-4L));
12243 red=ScaleQuantumToChar(image->background_color.red);
12244 green=ScaleQuantumToChar(image->background_color.green);
12245 blue=ScaleQuantumToChar(image->background_color.blue);
12252 (void) WriteBlob(image,(size_t) num_bytes,chunk);
12253 (void) WriteBlobMSBULong(image,crc32(0,chunk,(uInt) num_bytes));
12256 if ((image->colorspace == sRGBColorspace || image->rendering_intent))
12259 Write JNG sRGB chunk
12261 (void) WriteBlobMSBULong(image,1L);
12262 PNGType(chunk,mng_sRGB);
12263 LogPNGChunk(logging,mng_sRGB,1L);
12265 if (image->rendering_intent != UndefinedIntent)
12266 chunk[4]=(unsigned char)
12267 Magick_RenderingIntent_to_PNG_RenderingIntent(
12268 (image->rendering_intent));
12271 chunk[4]=(unsigned char)
12272 Magick_RenderingIntent_to_PNG_RenderingIntent(
12273 (PerceptualIntent));
12275 (void) WriteBlob(image,5,chunk);
12276 (void) WriteBlobMSBULong(image,crc32(0,chunk,5));
12280 if (image->gamma != 0.0)
12283 Write JNG gAMA chunk
12285 (void) WriteBlobMSBULong(image,4L);
12286 PNGType(chunk,mng_gAMA);
12287 LogPNGChunk(logging,mng_gAMA,4L);
12288 PNGLong(chunk+4,(png_uint_32) (100000*image->gamma+0.5));
12289 (void) WriteBlob(image,8,chunk);
12290 (void) WriteBlobMSBULong(image,crc32(0,chunk,8));
12293 if ((mng_info->equal_chrms == MagickFalse) &&
12294 (image->chromaticity.red_primary.x != 0.0))
12300 Write JNG cHRM chunk
12302 (void) WriteBlobMSBULong(image,32L);
12303 PNGType(chunk,mng_cHRM);
12304 LogPNGChunk(logging,mng_cHRM,32L);
12305 primary=image->chromaticity.white_point;
12306 PNGLong(chunk+4,(png_uint_32) (100000*primary.x+0.5));
12307 PNGLong(chunk+8,(png_uint_32) (100000*primary.y+0.5));
12308 primary=image->chromaticity.red_primary;
12309 PNGLong(chunk+12,(png_uint_32) (100000*primary.x+0.5));
12310 PNGLong(chunk+16,(png_uint_32) (100000*primary.y+0.5));
12311 primary=image->chromaticity.green_primary;
12312 PNGLong(chunk+20,(png_uint_32) (100000*primary.x+0.5));
12313 PNGLong(chunk+24,(png_uint_32) (100000*primary.y+0.5));
12314 primary=image->chromaticity.blue_primary;
12315 PNGLong(chunk+28,(png_uint_32) (100000*primary.x+0.5));
12316 PNGLong(chunk+32,(png_uint_32) (100000*primary.y+0.5));
12317 (void) WriteBlob(image,36,chunk);
12318 (void) WriteBlobMSBULong(image,crc32(0,chunk,36));
12322 if (image->resolution.x && image->resolution.y && !mng_info->equal_physs)
12325 Write JNG pHYs chunk
12327 (void) WriteBlobMSBULong(image,9L);
12328 PNGType(chunk,mng_pHYs);
12329 LogPNGChunk(logging,mng_pHYs,9L);
12330 if (image->units == PixelsPerInchResolution)
12332 PNGLong(chunk+4,(png_uint_32)
12333 (image->resolution.x*100.0/2.54+0.5));
12335 PNGLong(chunk+8,(png_uint_32)
12336 (image->resolution.y*100.0/2.54+0.5));
12343 if (image->units == PixelsPerCentimeterResolution)
12345 PNGLong(chunk+4,(png_uint_32)
12346 (image->resolution.x*100.0+0.5));
12348 PNGLong(chunk+8,(png_uint_32)
12349 (image->resolution.y*100.0+0.5));
12356 PNGLong(chunk+4,(png_uint_32) (image->resolution.x+0.5));
12357 PNGLong(chunk+8,(png_uint_32) (image->resolution.y+0.5));
12361 (void) WriteBlob(image,13,chunk);
12362 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
12365 if (mng_info->write_mng == 0 && (image->page.x || image->page.y))
12368 Write JNG oFFs chunk
12370 (void) WriteBlobMSBULong(image,9L);
12371 PNGType(chunk,mng_oFFs);
12372 LogPNGChunk(logging,mng_oFFs,9L);
12373 PNGsLong(chunk+4,(ssize_t) (image->page.x));
12374 PNGsLong(chunk+8,(ssize_t) (image->page.y));
12376 (void) WriteBlob(image,13,chunk);
12377 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
12379 if (mng_info->write_mng == 0 && (image->page.width || image->page.height))
12381 (void) WriteBlobMSBULong(image,9L); /* data length=8 */
12382 PNGType(chunk,mng_vpAg);
12383 LogPNGChunk(logging,mng_vpAg,9L);
12384 PNGLong(chunk+4,(png_uint_32) image->page.width);
12385 PNGLong(chunk+8,(png_uint_32) image->page.height);
12386 chunk[12]=0; /* unit = pixels */
12387 (void) WriteBlob(image,13,chunk);
12388 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
12394 if (jng_alpha_compression_method==0)
12402 /* Write IDAT chunk header */
12403 if (logging != MagickFalse)
12404 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12405 " Write IDAT chunks from blob, length=%.20g.",(double)
12408 /* Copy IDAT chunks */
12411 for (i=8; i<(ssize_t) length; i+=len+12)
12413 len=(*p<<24)|((*(p+1))<<16)|((*(p+2))<<8)|(*(p+3));
12416 if (*(p)==73 && *(p+1)==68 && *(p+2)==65 && *(p+3)==84) /* IDAT */
12418 /* Found an IDAT chunk. */
12419 (void) WriteBlobMSBULong(image,(size_t) len);
12420 LogPNGChunk(logging,mng_IDAT,(size_t) len);
12421 (void) WriteBlob(image,(size_t) len+4,p);
12422 (void) WriteBlobMSBULong(image,
12423 crc32(0,p,(uInt) len+4));
12428 if (logging != MagickFalse)
12429 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12430 " Skipping %c%c%c%c chunk, length=%.20g.",
12431 *(p),*(p+1),*(p+2),*(p+3),(double) len);
12438 /* Write JDAA chunk header */
12439 if (logging != MagickFalse)
12440 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12441 " Write JDAA chunk, length=%.20g.",(double) length);
12442 (void) WriteBlobMSBULong(image,(size_t) length);
12443 PNGType(chunk,mng_JDAA);
12444 LogPNGChunk(logging,mng_JDAA,length);
12445 /* Write JDAT chunk(s) data */
12446 (void) WriteBlob(image,4,chunk);
12447 (void) WriteBlob(image,length,blob);
12448 (void) WriteBlobMSBULong(image,crc32(crc32(0,chunk,4),blob,
12451 blob=(unsigned char *) RelinquishMagickMemory(blob);
12454 /* Encode image as a JPEG blob */
12455 if (logging != MagickFalse)
12456 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12457 " Creating jpeg_image_info.");
12458 jpeg_image_info=(ImageInfo *) CloneImageInfo(image_info);
12459 if (jpeg_image_info == (ImageInfo *) NULL)
12460 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
12462 if (logging != MagickFalse)
12463 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12464 " Creating jpeg_image.");
12466 jpeg_image=CloneImage(image,0,0,MagickTrue,exception);
12467 if (jpeg_image == (Image *) NULL)
12468 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
12469 (void) CopyMagickString(jpeg_image->magick,"JPEG",MaxTextExtent);
12471 (void) AcquireUniqueFilename(jpeg_image->filename);
12472 (void) FormatLocaleString(jpeg_image_info->filename,MaxTextExtent,"%s",
12473 jpeg_image->filename);
12475 status=OpenBlob(jpeg_image_info,jpeg_image,WriteBinaryBlobMode,
12478 if (logging != MagickFalse)
12479 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12480 " Created jpeg_image, %.20g x %.20g.",(double) jpeg_image->columns,
12481 (double) jpeg_image->rows);
12483 if (jng_color_type == 8 || jng_color_type == 12)
12484 jpeg_image_info->type=GrayscaleType;
12486 jpeg_image_info->quality=jng_quality;
12487 jpeg_image->quality=jng_quality;
12488 (void) CopyMagickString(jpeg_image_info->magick,"JPEG",MaxTextExtent);
12489 (void) CopyMagickString(jpeg_image->magick,"JPEG",MaxTextExtent);
12491 if (logging != MagickFalse)
12492 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12493 " Creating blob.");
12495 blob=ImageToBlob(jpeg_image_info,jpeg_image,&length,exception);
12497 if (logging != MagickFalse)
12499 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12500 " Successfully read jpeg_image into a blob, length=%.20g.",
12503 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12504 " Write JDAT chunk, length=%.20g.",(double) length);
12507 /* Write JDAT chunk(s) */
12508 (void) WriteBlobMSBULong(image,(size_t) length);
12509 PNGType(chunk,mng_JDAT);
12510 LogPNGChunk(logging,mng_JDAT,length);
12511 (void) WriteBlob(image,4,chunk);
12512 (void) WriteBlob(image,length,blob);
12513 (void) WriteBlobMSBULong(image,crc32(crc32(0,chunk,4),blob,(uInt) length));
12515 jpeg_image=DestroyImage(jpeg_image);
12516 (void) RelinquishUniqueFileResource(jpeg_image_info->filename);
12517 jpeg_image_info=DestroyImageInfo(jpeg_image_info);
12518 blob=(unsigned char *) RelinquishMagickMemory(blob);
12520 /* Write any JNG-chunk-e profiles */
12521 (void) Magick_png_write_chunk_from_profile(image,"JNG-chunk-e",logging);
12523 /* Write IEND chunk */
12524 (void) WriteBlobMSBULong(image,0L);
12525 PNGType(chunk,mng_IEND);
12526 LogPNGChunk(logging,mng_IEND,0);
12527 (void) WriteBlob(image,4,chunk);
12528 (void) WriteBlobMSBULong(image,crc32(0,chunk,4));
12530 if (logging != MagickFalse)
12531 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12532 " exit WriteOneJNGImage()");
12539 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12543 % W r i t e J N G I m a g e %
12547 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12549 % WriteJNGImage() writes a JPEG Network Graphics (JNG) image file.
12551 % JNG support written by Glenn Randers-Pehrson, glennrp@image...
12553 % The format of the WriteJNGImage method is:
12555 % MagickBooleanType WriteJNGImage(const ImageInfo *image_info,
12556 % Image *image,ExceptionInfo *exception)
12558 % A description of each parameter follows:
12560 % o image_info: the image info.
12562 % o image: The image.
12564 % o exception: return any errors or warnings in this structure.
12566 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12568 static MagickBooleanType WriteJNGImage(const ImageInfo *image_info,Image *image,
12569 ExceptionInfo *exception)
12572 have_mng_structure,
12582 assert(image_info != (const ImageInfo *) NULL);
12583 assert(image_info->signature == MagickSignature);
12584 assert(image != (Image *) NULL);
12585 assert(image->signature == MagickSignature);
12586 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
12587 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter WriteJNGImage()");
12588 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
12589 if (status == MagickFalse)
12593 Allocate a MngInfo structure.
12595 have_mng_structure=MagickFalse;
12596 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
12597 if (mng_info == (MngInfo *) NULL)
12598 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
12600 Initialize members of the MngInfo structure.
12602 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
12603 mng_info->image=image;
12604 have_mng_structure=MagickTrue;
12606 (void) WriteBlob(image,8,(const unsigned char *) "\213JNG\r\n\032\n");
12608 status=WriteOneJNGImage(mng_info,image_info,image,exception);
12609 (void) CloseBlob(image);
12611 (void) CatchImageException(image);
12612 MngInfoFreeStruct(mng_info,&have_mng_structure);
12613 if (logging != MagickFalse)
12614 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit WriteJNGImage()");
12619 static MagickBooleanType WriteMNGImage(const ImageInfo *image_info,Image *image,
12620 ExceptionInfo *exception)
12629 have_mng_structure,
12632 volatile MagickBooleanType
12644 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
12645 defined(PNG_MNG_FEATURES_SUPPORTED)
12648 all_images_are_gray,
12658 volatile unsigned int
12669 #if (PNG_LIBPNG_VER < 10200)
12670 if (image_info->verbose)
12671 printf("Your PNG library (libpng-%s) is rather old.\n",
12672 PNG_LIBPNG_VER_STRING);
12678 assert(image_info != (const ImageInfo *) NULL);
12679 assert(image_info->signature == MagickSignature);
12680 assert(image != (Image *) NULL);
12681 assert(image->signature == MagickSignature);
12682 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
12683 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter WriteMNGImage()");
12684 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
12685 if (status == MagickFalse)
12689 Allocate a MngInfo structure.
12691 have_mng_structure=MagickFalse;
12692 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
12693 if (mng_info == (MngInfo *) NULL)
12694 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
12696 Initialize members of the MngInfo structure.
12698 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
12699 mng_info->image=image;
12700 have_mng_structure=MagickTrue;
12701 write_mng=LocaleCompare(image_info->magick,"MNG") == 0;
12704 * See if user has requested a specific PNG subformat to be used
12705 * for all of the PNGs in the MNG being written, e.g.,
12707 * convert *.png png8:animation.mng
12709 * To do: check -define png:bit_depth and png:color_type as well,
12710 * or perhaps use mng:bit_depth and mng:color_type instead for
12714 mng_info->write_png8=LocaleCompare(image_info->magick,"PNG8") == 0;
12715 mng_info->write_png24=LocaleCompare(image_info->magick,"PNG24") == 0;
12716 mng_info->write_png32=LocaleCompare(image_info->magick,"PNG32") == 0;
12718 write_jng=MagickFalse;
12719 if (image_info->compression == JPEGCompression)
12720 write_jng=MagickTrue;
12722 mng_info->adjoin=image_info->adjoin &&
12723 (GetNextImageInList(image) != (Image *) NULL) && write_mng;
12725 if (logging != MagickFalse)
12727 /* Log some info about the input */
12731 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12732 " Checking input image(s)");
12734 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12735 " Image_info depth: %.20g",(double) image_info->depth);
12737 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12738 " Type: %d",image_info->type);
12741 for (p=image; p != (Image *) NULL; p=GetNextImageInList(p))
12743 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12744 " Scene: %.20g",(double) scene++);
12746 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12747 " Image depth: %.20g",(double) p->depth);
12749 if (p->alpha_trait)
12750 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12754 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12757 if (p->storage_class == PseudoClass)
12758 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12759 " Storage class: PseudoClass");
12762 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12763 " Storage class: DirectClass");
12766 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12767 " Number of colors: %.20g",(double) p->colors);
12770 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12771 " Number of colors: unspecified");
12773 if (mng_info->adjoin == MagickFalse)
12778 use_global_plte=MagickFalse;
12779 all_images_are_gray=MagickFalse;
12780 #ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
12781 need_local_plte=MagickTrue;
12783 need_defi=MagickFalse;
12784 need_matte=MagickFalse;
12785 mng_info->framing_mode=1;
12786 mng_info->old_framing_mode=1;
12789 if (image_info->page != (char *) NULL)
12792 Determine image bounding box.
12794 SetGeometry(image,&mng_info->page);
12795 (void) ParseMetaGeometry(image_info->page,&mng_info->page.x,
12796 &mng_info->page.y,&mng_info->page.width,&mng_info->page.height);
12808 mng_info->page=image->page;
12809 need_geom=MagickTrue;
12810 if (mng_info->page.width || mng_info->page.height)
12811 need_geom=MagickFalse;
12813 Check all the scenes.
12815 initial_delay=image->delay;
12816 need_iterations=MagickFalse;
12817 mng_info->equal_chrms=image->chromaticity.red_primary.x != 0.0;
12818 mng_info->equal_physs=MagickTrue,
12819 mng_info->equal_gammas=MagickTrue;
12820 mng_info->equal_srgbs=MagickTrue;
12821 mng_info->equal_backgrounds=MagickTrue;
12823 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
12824 defined(PNG_MNG_FEATURES_SUPPORTED)
12825 all_images_are_gray=MagickTrue;
12826 mng_info->equal_palettes=MagickFalse;
12827 need_local_plte=MagickFalse;
12829 for (next_image=image; next_image != (Image *) NULL; )
12833 if ((next_image->columns+next_image->page.x) > mng_info->page.width)
12834 mng_info->page.width=next_image->columns+next_image->page.x;
12836 if ((next_image->rows+next_image->page.y) > mng_info->page.height)
12837 mng_info->page.height=next_image->rows+next_image->page.y;
12840 if (next_image->page.x || next_image->page.y)
12841 need_defi=MagickTrue;
12843 if (next_image->alpha_trait)
12844 need_matte=MagickTrue;
12846 if ((int) next_image->dispose >= BackgroundDispose)
12847 if (next_image->alpha_trait || next_image->page.x || next_image->page.y ||
12848 ((next_image->columns < mng_info->page.width) &&
12849 (next_image->rows < mng_info->page.height)))
12850 mng_info->need_fram=MagickTrue;
12852 if (next_image->iterations)
12853 need_iterations=MagickTrue;
12855 final_delay=next_image->delay;
12857 if (final_delay != initial_delay || final_delay > 1UL*
12858 next_image->ticks_per_second)
12859 mng_info->need_fram=1;
12861 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
12862 defined(PNG_MNG_FEATURES_SUPPORTED)
12864 check for global palette possibility.
12866 if (image->alpha_trait == BlendPixelTrait)
12867 need_local_plte=MagickTrue;
12869 if (need_local_plte == 0)
12871 if (IsImageGray(image,exception) == MagickFalse)
12872 all_images_are_gray=MagickFalse;
12873 mng_info->equal_palettes=PalettesAreEqual(image,next_image);
12874 if (use_global_plte == 0)
12875 use_global_plte=mng_info->equal_palettes;
12876 need_local_plte=!mng_info->equal_palettes;
12879 if (GetNextImageInList(next_image) != (Image *) NULL)
12881 if (next_image->background_color.red !=
12882 next_image->next->background_color.red ||
12883 next_image->background_color.green !=
12884 next_image->next->background_color.green ||
12885 next_image->background_color.blue !=
12886 next_image->next->background_color.blue)
12887 mng_info->equal_backgrounds=MagickFalse;
12889 if (next_image->gamma != next_image->next->gamma)
12890 mng_info->equal_gammas=MagickFalse;
12892 if (next_image->rendering_intent !=
12893 next_image->next->rendering_intent)
12894 mng_info->equal_srgbs=MagickFalse;
12896 if ((next_image->units != next_image->next->units) ||
12897 (next_image->resolution.x != next_image->next->resolution.x) ||
12898 (next_image->resolution.y != next_image->next->resolution.y))
12899 mng_info->equal_physs=MagickFalse;
12901 if (mng_info->equal_chrms)
12903 if (next_image->chromaticity.red_primary.x !=
12904 next_image->next->chromaticity.red_primary.x ||
12905 next_image->chromaticity.red_primary.y !=
12906 next_image->next->chromaticity.red_primary.y ||
12907 next_image->chromaticity.green_primary.x !=
12908 next_image->next->chromaticity.green_primary.x ||
12909 next_image->chromaticity.green_primary.y !=
12910 next_image->next->chromaticity.green_primary.y ||
12911 next_image->chromaticity.blue_primary.x !=
12912 next_image->next->chromaticity.blue_primary.x ||
12913 next_image->chromaticity.blue_primary.y !=
12914 next_image->next->chromaticity.blue_primary.y ||
12915 next_image->chromaticity.white_point.x !=
12916 next_image->next->chromaticity.white_point.x ||
12917 next_image->chromaticity.white_point.y !=
12918 next_image->next->chromaticity.white_point.y)
12919 mng_info->equal_chrms=MagickFalse;
12923 next_image=GetNextImageInList(next_image);
12925 if (image_count < 2)
12927 mng_info->equal_backgrounds=MagickFalse;
12928 mng_info->equal_chrms=MagickFalse;
12929 mng_info->equal_gammas=MagickFalse;
12930 mng_info->equal_srgbs=MagickFalse;
12931 mng_info->equal_physs=MagickFalse;
12932 use_global_plte=MagickFalse;
12933 #ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
12934 need_local_plte=MagickTrue;
12936 need_iterations=MagickFalse;
12939 if (mng_info->need_fram == MagickFalse)
12942 Only certain framing rates 100/n are exactly representable without
12943 the FRAM chunk but we'll allow some slop in VLC files
12945 if (final_delay == 0)
12947 if (need_iterations != MagickFalse)
12950 It's probably a GIF with loop; don't run it *too* fast.
12952 if (mng_info->adjoin)
12955 (void) ThrowMagickException(exception,GetMagickModule(),
12957 "input has zero delay between all frames; assuming",
12962 mng_info->ticks_per_second=0;
12964 if (final_delay != 0)
12965 mng_info->ticks_per_second=(png_uint_32)
12966 (image->ticks_per_second/final_delay);
12967 if (final_delay > 50)
12968 mng_info->ticks_per_second=2;
12970 if (final_delay > 75)
12971 mng_info->ticks_per_second=1;
12973 if (final_delay > 125)
12974 mng_info->need_fram=MagickTrue;
12976 if (need_defi && final_delay > 2 && (final_delay != 4) &&
12977 (final_delay != 5) && (final_delay != 10) && (final_delay != 20) &&
12978 (final_delay != 25) && (final_delay != 50) && (final_delay !=
12979 1UL*image->ticks_per_second))
12980 mng_info->need_fram=MagickTrue; /* make it exact; cannot be VLC */
12983 if (mng_info->need_fram != MagickFalse)
12984 mng_info->ticks_per_second=1UL*image->ticks_per_second;
12986 If pseudocolor, we should also check to see if all the
12987 palettes are identical and write a global PLTE if they are.
12991 Write the MNG version 1.0 signature and MHDR chunk.
12993 (void) WriteBlob(image,8,(const unsigned char *) "\212MNG\r\n\032\n");
12994 (void) WriteBlobMSBULong(image,28L); /* chunk data length=28 */
12995 PNGType(chunk,mng_MHDR);
12996 LogPNGChunk(logging,mng_MHDR,28L);
12997 PNGLong(chunk+4,(png_uint_32) mng_info->page.width);
12998 PNGLong(chunk+8,(png_uint_32) mng_info->page.height);
12999 PNGLong(chunk+12,mng_info->ticks_per_second);
13000 PNGLong(chunk+16,0L); /* layer count=unknown */
13001 PNGLong(chunk+20,0L); /* frame count=unknown */
13002 PNGLong(chunk+24,0L); /* play time=unknown */
13007 if (need_defi || mng_info->need_fram || use_global_plte)
13008 PNGLong(chunk+28,27L); /* simplicity=LC+JNG */
13011 PNGLong(chunk+28,25L); /* simplicity=VLC+JNG */
13016 if (need_defi || mng_info->need_fram || use_global_plte)
13017 PNGLong(chunk+28,19L); /* simplicity=LC+JNG, no transparency */
13020 PNGLong(chunk+28,17L); /* simplicity=VLC+JNG, no transparency */
13028 if (need_defi || mng_info->need_fram || use_global_plte)
13029 PNGLong(chunk+28,11L); /* simplicity=LC */
13032 PNGLong(chunk+28,9L); /* simplicity=VLC */
13037 if (need_defi || mng_info->need_fram || use_global_plte)
13038 PNGLong(chunk+28,3L); /* simplicity=LC, no transparency */
13041 PNGLong(chunk+28,1L); /* simplicity=VLC, no transparency */
13044 (void) WriteBlob(image,32,chunk);
13045 (void) WriteBlobMSBULong(image,crc32(0,chunk,32));
13046 option=GetImageOption(image_info,"mng:need-cacheoff");
13047 if (option != (const char *) NULL)
13053 Write "nEED CACHEOFF" to turn playback caching off for streaming MNG.
13055 PNGType(chunk,mng_nEED);
13056 length=CopyMagickString((char *) chunk+4,"CACHEOFF",20);
13057 (void) WriteBlobMSBULong(image,(size_t) length);
13058 LogPNGChunk(logging,mng_nEED,(size_t) length);
13060 (void) WriteBlob(image,length,chunk);
13061 (void) WriteBlobMSBULong(image,crc32(0,chunk,(uInt) length));
13063 if ((GetPreviousImageInList(image) == (Image *) NULL) &&
13064 (GetNextImageInList(image) != (Image *) NULL) &&
13065 (image->iterations != 1))
13068 Write MNG TERM chunk
13070 (void) WriteBlobMSBULong(image,10L); /* data length=10 */
13071 PNGType(chunk,mng_TERM);
13072 LogPNGChunk(logging,mng_TERM,10L);
13073 chunk[4]=3; /* repeat animation */
13074 chunk[5]=0; /* show last frame when done */
13075 PNGLong(chunk+6,(png_uint_32) (mng_info->ticks_per_second*
13076 final_delay/MagickMax(image->ticks_per_second,1)));
13078 if (image->iterations == 0)
13079 PNGLong(chunk+10,PNG_UINT_31_MAX);
13082 PNGLong(chunk+10,(png_uint_32) image->iterations);
13084 if (logging != MagickFalse)
13086 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
13087 " TERM delay: %.20g",(double) (mng_info->ticks_per_second*
13088 final_delay/MagickMax(image->ticks_per_second,1)));
13090 if (image->iterations == 0)
13091 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
13092 " TERM iterations: %.20g",(double) PNG_UINT_31_MAX);
13095 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
13096 " Image iterations: %.20g",(double) image->iterations);
13098 (void) WriteBlob(image,14,chunk);
13099 (void) WriteBlobMSBULong(image,crc32(0,chunk,14));
13102 To do: check for cHRM+gAMA == sRGB, and write sRGB instead.
13104 if ((image->colorspace == sRGBColorspace || image->rendering_intent) &&
13105 mng_info->equal_srgbs)
13108 Write MNG sRGB chunk
13110 (void) WriteBlobMSBULong(image,1L);
13111 PNGType(chunk,mng_sRGB);
13112 LogPNGChunk(logging,mng_sRGB,1L);
13114 if (image->rendering_intent != UndefinedIntent)
13115 chunk[4]=(unsigned char)
13116 Magick_RenderingIntent_to_PNG_RenderingIntent(
13117 (image->rendering_intent));
13120 chunk[4]=(unsigned char)
13121 Magick_RenderingIntent_to_PNG_RenderingIntent(
13122 (PerceptualIntent));
13124 (void) WriteBlob(image,5,chunk);
13125 (void) WriteBlobMSBULong(image,crc32(0,chunk,5));
13126 mng_info->have_write_global_srgb=MagickTrue;
13131 if (image->gamma && mng_info->equal_gammas)
13134 Write MNG gAMA chunk
13136 (void) WriteBlobMSBULong(image,4L);
13137 PNGType(chunk,mng_gAMA);
13138 LogPNGChunk(logging,mng_gAMA,4L);
13139 PNGLong(chunk+4,(png_uint_32) (100000*image->gamma+0.5));
13140 (void) WriteBlob(image,8,chunk);
13141 (void) WriteBlobMSBULong(image,crc32(0,chunk,8));
13142 mng_info->have_write_global_gama=MagickTrue;
13144 if (mng_info->equal_chrms)
13150 Write MNG cHRM chunk
13152 (void) WriteBlobMSBULong(image,32L);
13153 PNGType(chunk,mng_cHRM);
13154 LogPNGChunk(logging,mng_cHRM,32L);
13155 primary=image->chromaticity.white_point;
13156 PNGLong(chunk+4,(png_uint_32) (100000*primary.x+0.5));
13157 PNGLong(chunk+8,(png_uint_32) (100000*primary.y+0.5));
13158 primary=image->chromaticity.red_primary;
13159 PNGLong(chunk+12,(png_uint_32) (100000*primary.x+0.5));
13160 PNGLong(chunk+16,(png_uint_32) (100000*primary.y+0.5));
13161 primary=image->chromaticity.green_primary;
13162 PNGLong(chunk+20,(png_uint_32) (100000*primary.x+0.5));
13163 PNGLong(chunk+24,(png_uint_32) (100000*primary.y+0.5));
13164 primary=image->chromaticity.blue_primary;
13165 PNGLong(chunk+28,(png_uint_32) (100000*primary.x+0.5));
13166 PNGLong(chunk+32,(png_uint_32) (100000*primary.y+0.5));
13167 (void) WriteBlob(image,36,chunk);
13168 (void) WriteBlobMSBULong(image,crc32(0,chunk,36));
13169 mng_info->have_write_global_chrm=MagickTrue;
13172 if (image->resolution.x && image->resolution.y && mng_info->equal_physs)
13175 Write MNG pHYs chunk
13177 (void) WriteBlobMSBULong(image,9L);
13178 PNGType(chunk,mng_pHYs);
13179 LogPNGChunk(logging,mng_pHYs,9L);
13181 if (image->units == PixelsPerInchResolution)
13183 PNGLong(chunk+4,(png_uint_32)
13184 (image->resolution.x*100.0/2.54+0.5));
13186 PNGLong(chunk+8,(png_uint_32)
13187 (image->resolution.y*100.0/2.54+0.5));
13194 if (image->units == PixelsPerCentimeterResolution)
13196 PNGLong(chunk+4,(png_uint_32)
13197 (image->resolution.x*100.0+0.5));
13199 PNGLong(chunk+8,(png_uint_32)
13200 (image->resolution.y*100.0+0.5));
13207 PNGLong(chunk+4,(png_uint_32) (image->resolution.x+0.5));
13208 PNGLong(chunk+8,(png_uint_32) (image->resolution.y+0.5));
13212 (void) WriteBlob(image,13,chunk);
13213 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
13216 Write MNG BACK chunk and global bKGD chunk, if the image is transparent
13217 or does not cover the entire frame.
13219 if (write_mng && (image->alpha_trait || image->page.x > 0 ||
13220 image->page.y > 0 || (image->page.width &&
13221 (image->page.width+image->page.x < mng_info->page.width))
13222 || (image->page.height && (image->page.height+image->page.y
13223 < mng_info->page.height))))
13225 (void) WriteBlobMSBULong(image,6L);
13226 PNGType(chunk,mng_BACK);
13227 LogPNGChunk(logging,mng_BACK,6L);
13228 red=ScaleQuantumToShort(image->background_color.red);
13229 green=ScaleQuantumToShort(image->background_color.green);
13230 blue=ScaleQuantumToShort(image->background_color.blue);
13231 PNGShort(chunk+4,red);
13232 PNGShort(chunk+6,green);
13233 PNGShort(chunk+8,blue);
13234 (void) WriteBlob(image,10,chunk);
13235 (void) WriteBlobMSBULong(image,crc32(0,chunk,10));
13236 if (mng_info->equal_backgrounds)
13238 (void) WriteBlobMSBULong(image,6L);
13239 PNGType(chunk,mng_bKGD);
13240 LogPNGChunk(logging,mng_bKGD,6L);
13241 (void) WriteBlob(image,10,chunk);
13242 (void) WriteBlobMSBULong(image,crc32(0,chunk,10));
13246 #ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
13247 if ((need_local_plte == MagickFalse) &&
13248 (image->storage_class == PseudoClass) &&
13249 (all_images_are_gray == MagickFalse))
13255 Write MNG PLTE chunk
13257 data_length=3*image->colors;
13258 (void) WriteBlobMSBULong(image,data_length);
13259 PNGType(chunk,mng_PLTE);
13260 LogPNGChunk(logging,mng_PLTE,data_length);
13262 for (i=0; i < (ssize_t) image->colors; i++)
13264 chunk[4+i*3]=(unsigned char) (ScaleQuantumToChar(
13265 image->colormap[i].red) & 0xff);
13266 chunk[5+i*3]=(unsigned char) (ScaleQuantumToChar(
13267 image->colormap[i].green) & 0xff);
13268 chunk[6+i*3]=(unsigned char) (ScaleQuantumToChar(
13269 image->colormap[i].blue) & 0xff);
13272 (void) WriteBlob(image,data_length+4,chunk);
13273 (void) WriteBlobMSBULong(image,crc32(0,chunk,(uInt) (data_length+4)));
13274 mng_info->have_write_global_plte=MagickTrue;
13280 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
13281 defined(PNG_MNG_FEATURES_SUPPORTED)
13282 mng_info->equal_palettes=MagickFalse;
13286 if (mng_info->adjoin)
13288 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
13289 defined(PNG_MNG_FEATURES_SUPPORTED)
13291 If we aren't using a global palette for the entire MNG, check to
13292 see if we can use one for two or more consecutive images.
13294 if (need_local_plte && use_global_plte && !all_images_are_gray)
13296 if (mng_info->IsPalette)
13299 When equal_palettes is true, this image has the same palette
13300 as the previous PseudoClass image
13302 mng_info->have_write_global_plte=mng_info->equal_palettes;
13303 mng_info->equal_palettes=PalettesAreEqual(image,image->next);
13304 if (mng_info->equal_palettes && !mng_info->have_write_global_plte)
13307 Write MNG PLTE chunk
13312 data_length=3*image->colors;
13313 (void) WriteBlobMSBULong(image,data_length);
13314 PNGType(chunk,mng_PLTE);
13315 LogPNGChunk(logging,mng_PLTE,data_length);
13317 for (i=0; i < (ssize_t) image->colors; i++)
13319 chunk[4+i*3]=ScaleQuantumToChar(image->colormap[i].red);
13320 chunk[5+i*3]=ScaleQuantumToChar(image->colormap[i].green);
13321 chunk[6+i*3]=ScaleQuantumToChar(image->colormap[i].blue);
13324 (void) WriteBlob(image,data_length+4,chunk);
13325 (void) WriteBlobMSBULong(image,crc32(0,chunk,
13326 (uInt) (data_length+4)));
13327 mng_info->have_write_global_plte=MagickTrue;
13331 mng_info->have_write_global_plte=MagickFalse;
13342 previous_x=mng_info->page.x;
13343 previous_y=mng_info->page.y;
13350 mng_info->page=image->page;
13351 if ((mng_info->page.x != previous_x) ||
13352 (mng_info->page.y != previous_y))
13354 (void) WriteBlobMSBULong(image,12L); /* data length=12 */
13355 PNGType(chunk,mng_DEFI);
13356 LogPNGChunk(logging,mng_DEFI,12L);
13357 chunk[4]=0; /* object 0 MSB */
13358 chunk[5]=0; /* object 0 LSB */
13359 chunk[6]=0; /* visible */
13360 chunk[7]=0; /* abstract */
13361 PNGLong(chunk+8,(png_uint_32) mng_info->page.x);
13362 PNGLong(chunk+12,(png_uint_32) mng_info->page.y);
13363 (void) WriteBlob(image,16,chunk);
13364 (void) WriteBlobMSBULong(image,crc32(0,chunk,16));
13369 mng_info->write_mng=write_mng;
13371 if ((int) image->dispose >= 3)
13372 mng_info->framing_mode=3;
13374 if (mng_info->need_fram && mng_info->adjoin &&
13375 ((image->delay != mng_info->delay) ||
13376 (mng_info->framing_mode != mng_info->old_framing_mode)))
13378 if (image->delay == mng_info->delay)
13381 Write a MNG FRAM chunk with the new framing mode.
13383 (void) WriteBlobMSBULong(image,1L); /* data length=1 */
13384 PNGType(chunk,mng_FRAM);
13385 LogPNGChunk(logging,mng_FRAM,1L);
13386 chunk[4]=(unsigned char) mng_info->framing_mode;
13387 (void) WriteBlob(image,5,chunk);
13388 (void) WriteBlobMSBULong(image,crc32(0,chunk,5));
13393 Write a MNG FRAM chunk with the delay.
13395 (void) WriteBlobMSBULong(image,10L); /* data length=10 */
13396 PNGType(chunk,mng_FRAM);
13397 LogPNGChunk(logging,mng_FRAM,10L);
13398 chunk[4]=(unsigned char) mng_info->framing_mode;
13399 chunk[5]=0; /* frame name separator (no name) */
13400 chunk[6]=2; /* flag for changing default delay */
13401 chunk[7]=0; /* flag for changing frame timeout */
13402 chunk[8]=0; /* flag for changing frame clipping */
13403 chunk[9]=0; /* flag for changing frame sync_id */
13404 PNGLong(chunk+10,(png_uint_32)
13405 ((mng_info->ticks_per_second*
13406 image->delay)/MagickMax(image->ticks_per_second,1)));
13407 (void) WriteBlob(image,14,chunk);
13408 (void) WriteBlobMSBULong(image,crc32(0,chunk,14));
13409 mng_info->delay=(png_uint_32) image->delay;
13411 mng_info->old_framing_mode=mng_info->framing_mode;
13414 #if defined(JNG_SUPPORTED)
13415 if (image_info->compression == JPEGCompression)
13420 if (logging != MagickFalse)
13421 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
13422 " Writing JNG object.");
13423 /* To do: specify the desired alpha compression method. */
13424 write_info=CloneImageInfo(image_info);
13425 write_info->compression=UndefinedCompression;
13426 status=WriteOneJNGImage(mng_info,write_info,image,exception);
13427 write_info=DestroyImageInfo(write_info);
13432 if (logging != MagickFalse)
13433 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
13434 " Writing PNG object.");
13436 mng_info->need_blob = MagickFalse;
13437 mng_info->ping_preserve_colormap = MagickFalse;
13439 /* We don't want any ancillary chunks written */
13440 mng_info->ping_exclude_bKGD=MagickTrue;
13441 mng_info->ping_exclude_cHRM=MagickTrue;
13442 mng_info->ping_exclude_date=MagickTrue;
13443 mng_info->ping_exclude_EXIF=MagickTrue;
13444 mng_info->ping_exclude_gAMA=MagickTrue;
13445 mng_info->ping_exclude_iCCP=MagickTrue;
13446 /* mng_info->ping_exclude_iTXt=MagickTrue; */
13447 mng_info->ping_exclude_oFFs=MagickTrue;
13448 mng_info->ping_exclude_pHYs=MagickTrue;
13449 mng_info->ping_exclude_sRGB=MagickTrue;
13450 mng_info->ping_exclude_tEXt=MagickTrue;
13451 mng_info->ping_exclude_tRNS=MagickTrue;
13452 mng_info->ping_exclude_vpAg=MagickTrue;
13453 mng_info->ping_exclude_zCCP=MagickTrue;
13454 mng_info->ping_exclude_zTXt=MagickTrue;
13456 status=WriteOnePNGImage(mng_info,image_info,image,exception);
13459 if (status == MagickFalse)
13461 MngInfoFreeStruct(mng_info,&have_mng_structure);
13462 (void) CloseBlob(image);
13463 return(MagickFalse);
13465 (void) CatchImageException(image);
13466 if (GetNextImageInList(image) == (Image *) NULL)
13468 image=SyncNextImageInList(image);
13469 status=SetImageProgress(image,SaveImagesTag,scene++,
13470 GetImageListLength(image));
13472 if (status == MagickFalse)
13475 } while (mng_info->adjoin);
13479 while (GetPreviousImageInList(image) != (Image *) NULL)
13480 image=GetPreviousImageInList(image);
13482 Write the MEND chunk.
13484 (void) WriteBlobMSBULong(image,0x00000000L);
13485 PNGType(chunk,mng_MEND);
13486 LogPNGChunk(logging,mng_MEND,0L);
13487 (void) WriteBlob(image,4,chunk);
13488 (void) WriteBlobMSBULong(image,crc32(0,chunk,4));
13491 Relinquish resources.
13493 (void) CloseBlob(image);
13494 MngInfoFreeStruct(mng_info,&have_mng_structure);
13496 if (logging != MagickFalse)
13497 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit WriteMNGImage()");
13499 return(MagickTrue);
13501 #else /* PNG_LIBPNG_VER > 10011 */
13503 static MagickBooleanType WritePNGImage(const ImageInfo *image_info,Image *image)
13506 printf("Your PNG library is too old: You have libpng-%s\n",
13507 PNG_LIBPNG_VER_STRING);
13509 ThrowBinaryException(CoderError,"PNG library is too old",
13510 image_info->filename);
13513 static MagickBooleanType WriteMNGImage(const ImageInfo *image_info,Image *image)
13515 return(WritePNGImage(image_info,image));
13517 #endif /* PNG_LIBPNG_VER > 10011 */