2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13 % Read/Write Portable Network Graphics Image Format %
17 % Glenn Randers-Pehrson %
21 % Copyright 1999-2014 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 /* Table of recognized sRGB ICC profiles */
133 struct sRGB_info_struct
140 const struct sRGB_info_struct sRGB_info[] =
142 /* ICC v2 perceptual sRGB_IEC61966-2-1_black_scaled.icc */
143 { 3048, 0x3b8772b9UL, 0},
145 /* ICC v2 relative sRGB_IEC61966-2-1_no_black_scaling.icc */
146 { 3052, 0x427ebb21UL, 1},
148 /* ICC v4 perceptual sRGB_v4_ICC_preference_displayclass.icc */
149 {60988, 0x306fd8aeUL, 0},
151 /* ICC v4 perceptual sRGB_v4_ICC_preference.icc perceptual */
152 {60960, 0xbbef7812UL, 0},
154 /* HP? sRGB v2 media-relative sRGB_IEC61966-2-1_noBPC.icc */
155 { 3024, 0x5d5129ceUL, 1},
157 /* HP-Microsoft sRGB v2 perceptual */
158 { 3144, 0x182ea552UL, 0},
160 /* HP-Microsoft sRGB v2 media-relative */
161 { 3144, 0xf29e526dUL, 1},
163 /* Facebook's "2012/01/25 03:41:57", 524, "TINYsRGB.icc" */
164 { 524, 0xd4938c39UL, 0},
166 /* "2012/11/28 22:35:21", 3212, "Argyll_sRGB.icm") */
167 { 3212, 0x034af5a1UL, 0},
170 { 0, 0x00000000UL, 0},
173 /* Macros for left-bit-replication to ensure that pixels
174 * and PixelInfos all have the same image->depth, and for use
175 * in PNG8 quantization.
178 /* LBR01: Replicate top bit */
180 #define LBR01PacketRed(pixelpacket) \
181 (pixelpacket).red=(ScaleQuantumToChar((pixelpacket).red) < 0x10 ? \
184 #define LBR01PacketGreen(pixelpacket) \
185 (pixelpacket).green=(ScaleQuantumToChar((pixelpacket).green) < 0x10 ? \
188 #define LBR01PacketBlue(pixelpacket) \
189 (pixelpacket).blue=(ScaleQuantumToChar((pixelpacket).blue) < 0x10 ? \
192 #define LBR01PacketAlpha(pixelpacket) \
193 (pixelpacket).alpha=(ScaleQuantumToChar((pixelpacket).alpha) < 0x10 ? \
196 #define LBR01PacketRGB(pixelpacket) \
198 LBR01PacketRed((pixelpacket)); \
199 LBR01PacketGreen((pixelpacket)); \
200 LBR01PacketBlue((pixelpacket)); \
203 #define LBR01PacketRGBO(pixelpacket) \
205 LBR01PacketRGB((pixelpacket)); \
206 LBR01PacketAlpha((pixelpacket)); \
209 #define LBR01PixelRed(pixel) \
210 (SetPixelRed(image, \
211 ScaleQuantumToChar(GetPixelRed(image,(pixel))) < 0x10 ? \
212 0 : QuantumRange,(pixel)));
214 #define LBR01PixelGreen(pixel) \
215 (SetPixelGreen(image, \
216 ScaleQuantumToChar(GetPixelGreen(image,(pixel))) < 0x10 ? \
217 0 : QuantumRange,(pixel)));
219 #define LBR01PixelBlue(pixel) \
220 (SetPixelBlue(image, \
221 ScaleQuantumToChar(GetPixelBlue(image,(pixel))) < 0x10 ? \
222 0 : QuantumRange,(pixel)));
224 #define LBR01PixelAlpha(pixel) \
225 (SetPixelAlpha(image, \
226 ScaleQuantumToChar(GetPixelAlpha(image,(pixel))) < 0x10 ? \
227 0 : QuantumRange,(pixel)));
229 #define LBR01PixelRGB(pixel) \
231 LBR01PixelRed((pixel)); \
232 LBR01PixelGreen((pixel)); \
233 LBR01PixelBlue((pixel)); \
236 #define LBR01PixelRGBA(pixel) \
238 LBR01PixelRGB((pixel)); \
239 LBR01PixelAlpha((pixel)); \
242 /* LBR02: Replicate top 2 bits */
244 #define LBR02PacketRed(pixelpacket) \
246 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).red) & 0xc0; \
247 (pixelpacket).red=ScaleCharToQuantum( \
248 (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))); \
250 #define LBR02PacketGreen(pixelpacket) \
252 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).green) & 0xc0; \
253 (pixelpacket).green=ScaleCharToQuantum( \
254 (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))); \
256 #define LBR02PacketBlue(pixelpacket) \
258 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).blue) & 0xc0; \
259 (pixelpacket).blue=ScaleCharToQuantum( \
260 (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))); \
262 #define LBR02PacketAlpha(pixelpacket) \
264 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).alpha) & 0xc0; \
265 (pixelpacket).alpha=ScaleCharToQuantum( \
266 (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))); \
269 #define LBR02PacketRGB(pixelpacket) \
271 LBR02PacketRed((pixelpacket)); \
272 LBR02PacketGreen((pixelpacket)); \
273 LBR02PacketBlue((pixelpacket)); \
276 #define LBR02PacketRGBO(pixelpacket) \
278 LBR02PacketRGB((pixelpacket)); \
279 LBR02PacketAlpha((pixelpacket)); \
282 #define LBR02PixelRed(pixel) \
284 unsigned char lbr_bits=ScaleQuantumToChar(GetPixelRed(image,(pixel))) \
286 SetPixelRed(image, ScaleCharToQuantum( \
287 (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))), \
290 #define LBR02PixelGreen(pixel) \
292 unsigned char lbr_bits=ScaleQuantumToChar(GetPixelGreen(image,(pixel)))\
294 SetPixelGreen(image, ScaleCharToQuantum( \
295 (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))), \
298 #define LBR02PixelBlue(pixel) \
300 unsigned char lbr_bits= \
301 ScaleQuantumToChar(GetPixelBlue(image,(pixel))) & 0xc0; \
302 SetPixelBlue(image, ScaleCharToQuantum( \
303 (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))), \
306 #define LBR02PixelAlpha(pixel) \
308 unsigned char lbr_bits= \
309 ScaleQuantumToChar(GetPixelAlpha(image,(pixel))) & 0xc0; \
310 SetPixelAlpha(image, ScaleCharToQuantum( \
311 (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))), \
315 #define LBR02PixelRGB(pixel) \
317 LBR02PixelRed((pixel)); \
318 LBR02PixelGreen((pixel)); \
319 LBR02PixelBlue((pixel)); \
322 #define LBR02PixelRGBA(pixel) \
324 LBR02PixelRGB((pixel)); \
325 LBR02PixelAlpha((pixel)); \
328 /* LBR03: Replicate top 3 bits (only used with opaque pixels during
329 PNG8 quantization) */
331 #define LBR03PacketRed(pixelpacket) \
333 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).red) & 0xe0; \
334 (pixelpacket).red=ScaleCharToQuantum( \
335 (lbr_bits | (lbr_bits >> 3) | (lbr_bits >> 6))); \
337 #define LBR03PacketGreen(pixelpacket) \
339 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).green) & 0xe0; \
340 (pixelpacket).green=ScaleCharToQuantum( \
341 (lbr_bits | (lbr_bits >> 3) | (lbr_bits >> 6))); \
343 #define LBR03PacketBlue(pixelpacket) \
345 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).blue) & 0xe0; \
346 (pixelpacket).blue=ScaleCharToQuantum( \
347 (lbr_bits | (lbr_bits >> 3) | (lbr_bits >> 6))); \
350 #define LBR03PacketRGB(pixelpacket) \
352 LBR03PacketRed((pixelpacket)); \
353 LBR03PacketGreen((pixelpacket)); \
354 LBR03PacketBlue((pixelpacket)); \
357 #define LBR03PixelRed(pixel) \
359 unsigned char lbr_bits=ScaleQuantumToChar(GetPixelRed(image,(pixel))) \
361 SetPixelRed(image, ScaleCharToQuantum( \
362 (lbr_bits | (lbr_bits >> 3) | (lbr_bits >> 6))), (pixel)); \
364 #define LBR03Green(pixel) \
366 unsigned char lbr_bits=ScaleQuantumToChar(GetPixelGreen(image,(pixel)))\
368 SetPixelGreen(image, ScaleCharToQuantum( \
369 (lbr_bits | (lbr_bits >> 3) | (lbr_bits >> 6))), (pixel)); \
371 #define LBR03Blue(pixel) \
373 unsigned char lbr_bits=ScaleQuantumToChar(GetPixelBlue(image,(pixel))) \
375 SetPixelBlue(image, ScaleCharToQuantum( \
376 (lbr_bits | (lbr_bits >> 3) | (lbr_bits >> 6))), (pixel)); \
379 #define LBR03RGB(pixel) \
381 LBR03PixelRed((pixel)); \
382 LBR03Green((pixel)); \
383 LBR03Blue((pixel)); \
386 /* LBR04: Replicate top 4 bits */
388 #define LBR04PacketRed(pixelpacket) \
390 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).red) & 0xf0; \
391 (pixelpacket).red=ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))); \
393 #define LBR04PacketGreen(pixelpacket) \
395 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).green) & 0xf0; \
396 (pixelpacket).green=ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))); \
398 #define LBR04PacketBlue(pixelpacket) \
400 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).blue) & 0xf0; \
401 (pixelpacket).blue=ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))); \
403 #define LBR04PacketAlpha(pixelpacket) \
405 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).alpha) & 0xf0; \
406 (pixelpacket).alpha=ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))); \
409 #define LBR04PacketRGB(pixelpacket) \
411 LBR04PacketRed((pixelpacket)); \
412 LBR04PacketGreen((pixelpacket)); \
413 LBR04PacketBlue((pixelpacket)); \
416 #define LBR04PacketRGBO(pixelpacket) \
418 LBR04PacketRGB((pixelpacket)); \
419 LBR04PacketAlpha((pixelpacket)); \
422 #define LBR04PixelRed(pixel) \
424 unsigned char lbr_bits=ScaleQuantumToChar(GetPixelRed(image,(pixel))) \
427 ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))), (pixel)); \
429 #define LBR04PixelGreen(pixel) \
431 unsigned char lbr_bits=ScaleQuantumToChar(GetPixelGreen(image,(pixel)))\
433 SetPixelGreen(image,\
434 ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))), (pixel)); \
436 #define LBR04PixelBlue(pixel) \
438 unsigned char lbr_bits= \
439 ScaleQuantumToChar(GetPixelBlue(image,(pixel))) & 0xf0; \
441 ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))), (pixel)); \
443 #define LBR04PixelAlpha(pixel) \
445 unsigned char lbr_bits= \
446 ScaleQuantumToChar(GetPixelAlpha(image,(pixel))) & 0xf0; \
447 SetPixelAlpha(image,\
448 ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))), (pixel)); \
451 #define LBR04PixelRGB(pixel) \
453 LBR04PixelRed((pixel)); \
454 LBR04PixelGreen((pixel)); \
455 LBR04PixelBlue((pixel)); \
458 #define LBR04PixelRGBA(pixel) \
460 LBR04PixelRGB((pixel)); \
461 LBR04PixelAlpha((pixel)); \
465 #if MAGICKCORE_QUANTUM_DEPTH > 8
466 /* LBR08: Replicate top 8 bits */
468 #define LBR08PacketRed(pixelpacket) \
470 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).red); \
471 (pixelpacket).red=ScaleCharToQuantum((lbr_bits)); \
473 #define LBR08PacketGreen(pixelpacket) \
475 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).green); \
476 (pixelpacket).green=ScaleCharToQuantum((lbr_bits)); \
478 #define LBR08PacketBlue(pixelpacket) \
480 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).blue); \
481 (pixelpacket).blue=ScaleCharToQuantum((lbr_bits)); \
483 #define LBR08PacketAlpha(pixelpacket) \
485 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).alpha); \
486 (pixelpacket).alpha=ScaleCharToQuantum((lbr_bits)); \
489 #define LBR08PacketRGB(pixelpacket) \
491 LBR08PacketRed((pixelpacket)); \
492 LBR08PacketGreen((pixelpacket)); \
493 LBR08PacketBlue((pixelpacket)); \
496 #define LBR08PacketRGBO(pixelpacket) \
498 LBR08PacketRGB((pixelpacket)); \
499 LBR08PacketAlpha((pixelpacket)); \
502 #define LBR08PixelRed(pixel) \
504 unsigned char lbr_bits= \
505 ScaleQuantumToChar(GetPixelRed(image,(pixel))); \
507 ScaleCharToQuantum((lbr_bits)), (pixel)); \
509 #define LBR08PixelGreen(pixel) \
511 unsigned char lbr_bits= \
512 ScaleQuantumToChar(GetPixelGreen(image,(pixel))); \
513 SetPixelGreen(image,\
514 ScaleCharToQuantum((lbr_bits)), (pixel)); \
516 #define LBR08PixelBlue(pixel) \
518 unsigned char lbr_bits= \
519 ScaleQuantumToChar(GetPixelBlue(image,(pixel))); \
521 ScaleCharToQuantum((lbr_bits)), (pixel)); \
523 #define LBR08PixelAlpha(pixel) \
525 unsigned char lbr_bits= \
526 ScaleQuantumToChar(GetPixelAlpha(image,(pixel))); \
527 SetPixelAlpha(image,\
528 ScaleCharToQuantum((lbr_bits)), (pixel)); \
531 #define LBR08PixelRGB(pixel) \
533 LBR08PixelRed((pixel)); \
534 LBR08PixelGreen((pixel)); \
535 LBR08PixelBlue((pixel)); \
538 #define LBR08PixelRGBA(pixel) \
540 LBR08PixelRGB((pixel)); \
541 LBR08PixelAlpha((pixel)); \
543 #endif /* MAGICKCORE_QUANTUM_DEPTH > 8 */
546 #if MAGICKCORE_QUANTUM_DEPTH > 16
547 /* LBR16: Replicate top 16 bits */
549 #define LBR16PacketRed(pixelpacket) \
551 unsigned short lbr_bits=ScaleQuantumToShort((pixelpacket).red); \
552 (pixelpacket).red=ScaleShortToQuantum((lbr_bits)); \
554 #define LBR16PacketGreen(pixelpacket) \
556 unsigned short lbr_bits=ScaleQuantumToShort((pixelpacket).green); \
557 (pixelpacket).green=ScaleShortToQuantum((lbr_bits)); \
559 #define LBR16PacketBlue(pixelpacket) \
561 unsigned short lbr_bits=ScaleQuantumToShort((pixelpacket).blue); \
562 (pixelpacket).blue=ScaleShortToQuantum((lbr_bits)); \
564 #define LBR16PacketAlpha(pixelpacket) \
566 unsigned short lbr_bits=ScaleQuantumToShort((pixelpacket).alpha); \
567 (pixelpacket).alpha=ScaleShortToQuantum((lbr_bits)); \
570 #define LBR16PacketRGB(pixelpacket) \
572 LBR16PacketRed((pixelpacket)); \
573 LBR16PacketGreen((pixelpacket)); \
574 LBR16PacketBlue((pixelpacket)); \
577 #define LBR16PacketRGBO(pixelpacket) \
579 LBR16PacketRGB((pixelpacket)); \
580 LBR16PacketAlpha((pixelpacket)); \
583 #define LBR16PixelRed(pixel) \
585 unsigned short lbr_bits= \
586 ScaleQuantumToShort(GetPixelRed(image,(pixel))); \
588 ScaleShortToQuantum((lbr_bits)),(pixel)); \
590 #define LBR16PixelGreen(pixel) \
592 unsigned short lbr_bits= \
593 ScaleQuantumToShort(GetPixelGreen(image,(pixel))); \
594 SetPixelGreen(image,\
595 ScaleShortToQuantum((lbr_bits)),(pixel)); \
597 #define LBR16PixelBlue(pixel) \
599 unsigned short lbr_bits= \
600 ScaleQuantumToShort(GetPixelBlue(image,(pixel))); \
602 ScaleShortToQuantum((lbr_bits)),(pixel)); \
604 #define LBR16PixelAlpha(pixel) \
606 unsigned short lbr_bits= \
607 ScaleQuantumToShort(GetPixelAlpha(image,(pixel))); \
608 SetPixelAlpha(image,\
609 ScaleShortToQuantum((lbr_bits)),(pixel)); \
612 #define LBR16PixelRGB(pixel) \
614 LBR16PixelRed((pixel)); \
615 LBR16PixelGreen((pixel)); \
616 LBR16PixelBlue((pixel)); \
619 #define LBR16PixelRGBA(pixel) \
621 LBR16PixelRGB((pixel)); \
622 LBR16PixelAlpha((pixel)); \
624 #endif /* MAGICKCORE_QUANTUM_DEPTH > 16 */
627 Establish thread safety.
628 setjmp/longjmp is claimed to be safe on these platforms:
629 setjmp/longjmp is alleged to be unsafe on these platforms:
631 #ifdef PNG_SETJMP_SUPPORTED
632 # ifndef IMPNG_SETJMP_IS_THREAD_SAFE
633 # define IMPNG_SETJMP_NOT_THREAD_SAFE
636 # ifdef IMPNG_SETJMP_NOT_THREAD_SAFE
638 *ping_semaphore = (SemaphoreInfo *) NULL;
643 This temporary until I set up malloc'ed object attributes array.
644 Recompile with MNG_MAX_OBJECTS=65536L to avoid this limit but
647 #define MNG_MAX_OBJECTS 256
650 If this not defined, spec is interpreted strictly. If it is
651 defined, an attempt will be made to recover from some errors,
653 o global PLTE too short
658 Don't try to define PNG_MNG_FEATURES_SUPPORTED here. Make sure
659 it's defined in libpng/pngconf.h, version 1.0.9 or later. It won't work
660 with earlier versions of libpng. From libpng-1.0.3a to libpng-1.0.8,
661 PNG_READ|WRITE_EMPTY_PLTE were used but those have been deprecated in
662 libpng in favor of PNG_MNG_FEATURES_SUPPORTED, so we set them here.
663 PNG_MNG_FEATURES_SUPPORTED is disabled by default in libpng-1.0.9 and
664 will be enabled by default in libpng-1.2.0.
666 #ifdef PNG_MNG_FEATURES_SUPPORTED
667 # ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
668 # define PNG_READ_EMPTY_PLTE_SUPPORTED
670 # ifndef PNG_WRITE_EMPTY_PLTE_SUPPORTED
671 # define PNG_WRITE_EMPTY_PLTE_SUPPORTED
676 Maximum valid size_t in PNG/MNG chunks is (2^31)-1
677 This macro is only defined in libpng-1.0.3 and later.
678 Previously it was PNG_MAX_UINT but that was deprecated in libpng-1.2.6
680 #ifndef PNG_UINT_31_MAX
681 #define PNG_UINT_31_MAX (png_uint_32) 0x7fffffffL
685 Constant strings for known chunk types. If you need to add a chunk,
686 add a string holding the name here. To make the code more
687 portable, we use ASCII numbers like this, not characters.
690 static png_byte mng_MHDR[5]={ 77, 72, 68, 82, (png_byte) '\0'};
691 static png_byte mng_BACK[5]={ 66, 65, 67, 75, (png_byte) '\0'};
692 static png_byte mng_BASI[5]={ 66, 65, 83, 73, (png_byte) '\0'};
693 static png_byte mng_CLIP[5]={ 67, 76, 73, 80, (png_byte) '\0'};
694 static png_byte mng_CLON[5]={ 67, 76, 79, 78, (png_byte) '\0'};
695 static png_byte mng_DEFI[5]={ 68, 69, 70, 73, (png_byte) '\0'};
696 static png_byte mng_DHDR[5]={ 68, 72, 68, 82, (png_byte) '\0'};
697 static png_byte mng_DISC[5]={ 68, 73, 83, 67, (png_byte) '\0'};
698 static png_byte mng_ENDL[5]={ 69, 78, 68, 76, (png_byte) '\0'};
699 static png_byte mng_FRAM[5]={ 70, 82, 65, 77, (png_byte) '\0'};
700 static png_byte mng_IEND[5]={ 73, 69, 78, 68, (png_byte) '\0'};
701 static png_byte mng_IHDR[5]={ 73, 72, 68, 82, (png_byte) '\0'};
702 static png_byte mng_JHDR[5]={ 74, 72, 68, 82, (png_byte) '\0'};
703 static png_byte mng_LOOP[5]={ 76, 79, 79, 80, (png_byte) '\0'};
704 static png_byte mng_MAGN[5]={ 77, 65, 71, 78, (png_byte) '\0'};
705 static png_byte mng_MEND[5]={ 77, 69, 78, 68, (png_byte) '\0'};
706 static png_byte mng_MOVE[5]={ 77, 79, 86, 69, (png_byte) '\0'};
707 static png_byte mng_PAST[5]={ 80, 65, 83, 84, (png_byte) '\0'};
708 static png_byte mng_PLTE[5]={ 80, 76, 84, 69, (png_byte) '\0'};
709 static png_byte mng_SAVE[5]={ 83, 65, 86, 69, (png_byte) '\0'};
710 static png_byte mng_SEEK[5]={ 83, 69, 69, 75, (png_byte) '\0'};
711 static png_byte mng_SHOW[5]={ 83, 72, 79, 87, (png_byte) '\0'};
712 static png_byte mng_TERM[5]={ 84, 69, 82, 77, (png_byte) '\0'};
713 static png_byte mng_bKGD[5]={ 98, 75, 71, 68, (png_byte) '\0'};
714 static png_byte mng_cHRM[5]={ 99, 72, 82, 77, (png_byte) '\0'};
715 static png_byte mng_gAMA[5]={103, 65, 77, 65, (png_byte) '\0'};
716 static png_byte mng_iCCP[5]={105, 67, 67, 80, (png_byte) '\0'};
717 static png_byte mng_nEED[5]={110, 69, 69, 68, (png_byte) '\0'};
718 static png_byte mng_pHYg[5]={112, 72, 89, 103, (png_byte) '\0'};
719 static png_byte mng_vpAg[5]={118, 112, 65, 103, (png_byte) '\0'};
720 static png_byte mng_pHYs[5]={112, 72, 89, 115, (png_byte) '\0'};
721 static png_byte mng_sBIT[5]={115, 66, 73, 84, (png_byte) '\0'};
722 static png_byte mng_sRGB[5]={115, 82, 71, 66, (png_byte) '\0'};
723 static png_byte mng_tRNS[5]={116, 82, 78, 83, (png_byte) '\0'};
725 #if defined(JNG_SUPPORTED)
726 static png_byte mng_IDAT[5]={ 73, 68, 65, 84, (png_byte) '\0'};
727 static png_byte mng_JDAT[5]={ 74, 68, 65, 84, (png_byte) '\0'};
728 static png_byte mng_JDAA[5]={ 74, 68, 65, 65, (png_byte) '\0'};
729 static png_byte mng_JdAA[5]={ 74, 100, 65, 65, (png_byte) '\0'};
730 static png_byte mng_JSEP[5]={ 74, 83, 69, 80, (png_byte) '\0'};
731 static png_byte mng_oFFs[5]={111, 70, 70, 115, (png_byte) '\0'};
735 Other known chunks that are not yet supported by ImageMagick:
736 static png_byte mng_hIST[5]={104, 73, 83, 84, (png_byte) '\0'};
737 static png_byte mng_iCCP[5]={105, 67, 67, 80, (png_byte) '\0'};
738 static png_byte mng_iTXt[5]={105, 84, 88, 116, (png_byte) '\0'};
739 static png_byte mng_sPLT[5]={115, 80, 76, 84, (png_byte) '\0'};
740 static png_byte mng_sTER[5]={115, 84, 69, 82, (png_byte) '\0'};
741 static png_byte mng_tEXt[5]={116, 69, 88, 116, (png_byte) '\0'};
742 static png_byte mng_tIME[5]={116, 73, 77, 69, (png_byte) '\0'};
743 static png_byte mng_zTXt[5]={122, 84, 88, 116, (png_byte) '\0'};
746 typedef struct _MngBox
755 typedef struct _MngPair
762 #ifdef MNG_OBJECT_BUFFERS
763 typedef struct _MngBuffer
795 typedef struct _MngInfo
798 #ifdef MNG_OBJECT_BUFFERS
800 *ob[MNG_MAX_OBJECTS];
811 #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
812 bytes_in_read_buffer,
818 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
819 defined(PNG_MNG_FEATURES_SUPPORTED)
831 have_saved_bkgd_index,
832 have_write_global_chrm,
833 have_write_global_gama,
834 have_write_global_plte,
835 have_write_global_srgb,
849 x_off[MNG_MAX_OBJECTS],
850 y_off[MNG_MAX_OBJECTS];
856 object_clip[MNG_MAX_OBJECTS];
859 /* These flags could be combined into one byte */
860 exists[MNG_MAX_OBJECTS],
861 frozen[MNG_MAX_OBJECTS],
863 invisible[MNG_MAX_OBJECTS],
864 viewable[MNG_MAX_OBJECTS];
876 #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
894 global_x_pixels_per_unit,
895 global_y_pixels_per_unit,
905 global_phys_unit_type,
920 write_png_compression_level,
921 write_png_compression_strategy,
922 write_png_compression_filter,
929 #ifdef MNG_BASI_SUPPORTED
937 basi_compression_method,
939 basi_interlace_method,
962 /* Added at version 6.6.6-7 */
970 /* ping_exclude_iTXt, */
977 ping_exclude_zCCP, /* hex-encoded iCCP */
979 ping_preserve_colormap,
980 /* Added at version 6.8.5-7 */
987 Forward declarations.
989 static MagickBooleanType
990 WritePNGImage(const ImageInfo *,Image *,ExceptionInfo *);
992 static MagickBooleanType
993 WriteMNGImage(const ImageInfo *,Image *,ExceptionInfo *);
995 #if defined(JNG_SUPPORTED)
996 static MagickBooleanType
997 WriteJNGImage(const ImageInfo *,Image *,ExceptionInfo *);
1000 #if PNG_LIBPNG_VER > 10011
1003 #if (MAGICKCORE_QUANTUM_DEPTH >= 16)
1004 static MagickBooleanType
1005 LosslessReduceDepthOK(Image *image,ExceptionInfo *exception)
1007 /* Reduce bit depth if it can be reduced losslessly from 16+ to 8.
1009 * This is true if the high byte and the next highest byte of
1010 * each sample of the image, the colormap, and the background color
1011 * are equal to each other. We check this by seeing if the samples
1012 * are unchanged when we scale them down to 8 and back up to Quantum.
1014 * We don't use the method GetImageDepth() because it doesn't check
1015 * background and doesn't handle PseudoClass specially.
1018 #define QuantumToCharToQuantumEqQuantum(quantum) \
1019 ((ScaleCharToQuantum((unsigned char) ScaleQuantumToChar(quantum))) == quantum)
1022 ok_to_reduce=MagickFalse;
1024 if (image->depth >= 16)
1031 QuantumToCharToQuantumEqQuantum(image->background_color.red) &&
1032 QuantumToCharToQuantumEqQuantum(image->background_color.green) &&
1033 QuantumToCharToQuantumEqQuantum(image->background_color.blue) ?
1034 MagickTrue : MagickFalse;
1036 if (ok_to_reduce != MagickFalse && image->storage_class == PseudoClass)
1040 for (indx=0; indx < (ssize_t) image->colors; indx++)
1043 QuantumToCharToQuantumEqQuantum(
1044 image->colormap[indx].red) &&
1045 QuantumToCharToQuantumEqQuantum(
1046 image->colormap[indx].green) &&
1047 QuantumToCharToQuantumEqQuantum(
1048 image->colormap[indx].blue)) ?
1049 MagickTrue : MagickFalse;
1051 if (ok_to_reduce == MagickFalse)
1056 if ((ok_to_reduce != MagickFalse) &&
1057 (image->storage_class != PseudoClass))
1065 for (y=0; y < (ssize_t) image->rows; y++)
1067 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1069 if (p == (const Quantum *) NULL)
1071 ok_to_reduce = MagickFalse;
1075 for (x=(ssize_t) image->columns-1; x >= 0; x--)
1078 QuantumToCharToQuantumEqQuantum(GetPixelRed(image,p)) &&
1079 QuantumToCharToQuantumEqQuantum(GetPixelGreen(image,p)) &&
1080 QuantumToCharToQuantumEqQuantum(GetPixelBlue(image,p)) ?
1081 MagickTrue : MagickFalse;
1083 if (ok_to_reduce == MagickFalse)
1086 p+=GetPixelChannels(image);
1093 if (ok_to_reduce != MagickFalse)
1095 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1096 " OK to reduce PNG bit depth to 8 without loss of info");
1100 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1101 " Not OK to reduce PNG bit depth to 8 without loss of info");
1105 return ok_to_reduce;
1107 #endif /* MAGICKCORE_QUANTUM_DEPTH >= 16 */
1109 static const char* PngColorTypeToString(const unsigned int color_type)
1112 *result = "Unknown";
1116 case PNG_COLOR_TYPE_GRAY:
1119 case PNG_COLOR_TYPE_GRAY_ALPHA:
1120 result = "Gray+Alpha";
1122 case PNG_COLOR_TYPE_PALETTE:
1125 case PNG_COLOR_TYPE_RGB:
1128 case PNG_COLOR_TYPE_RGB_ALPHA:
1129 result = "RGB+Alpha";
1137 Magick_RenderingIntent_to_PNG_RenderingIntent(const RenderingIntent intent)
1141 case PerceptualIntent:
1144 case RelativeIntent:
1147 case SaturationIntent:
1150 case AbsoluteIntent:
1158 static RenderingIntent
1159 Magick_RenderingIntent_from_PNG_RenderingIntent(const int ping_intent)
1161 switch (ping_intent)
1164 return PerceptualIntent;
1167 return RelativeIntent;
1170 return SaturationIntent;
1173 return AbsoluteIntent;
1176 return UndefinedIntent;
1181 Magick_RenderingIntentString_from_PNG_RenderingIntent(const int ping_intent)
1183 switch (ping_intent)
1186 return "Perceptual Intent";
1189 return "Relative Intent";
1192 return "Saturation Intent";
1195 return "Absolute Intent";
1198 return "Undefined Intent";
1202 static inline ssize_t MagickMax(const ssize_t x,const ssize_t y)
1211 Magick_ColorType_from_PNG_ColorType(const int ping_colortype)
1213 switch (ping_colortype)
1231 return "UndefinedColorType";
1236 static inline ssize_t MagickMin(const ssize_t x,const ssize_t y)
1243 #endif /* PNG_LIBPNG_VER > 10011 */
1244 #endif /* MAGICKCORE_PNG_DELEGATE */
1247 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1255 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1257 % IsMNG() returns MagickTrue if the image format type, identified by the
1258 % magick string, is MNG.
1260 % The format of the IsMNG method is:
1262 % MagickBooleanType IsMNG(const unsigned char *magick,const size_t length)
1264 % A description of each parameter follows:
1266 % o magick: compare image format pattern against these bytes.
1268 % o length: Specifies the length of the magick string.
1272 static MagickBooleanType IsMNG(const unsigned char *magick,const size_t length)
1275 return(MagickFalse);
1277 if (memcmp(magick,"\212MNG\r\n\032\n",8) == 0)
1280 return(MagickFalse);
1284 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1292 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1294 % IsJNG() returns MagickTrue if the image format type, identified by the
1295 % magick string, is JNG.
1297 % The format of the IsJNG method is:
1299 % MagickBooleanType IsJNG(const unsigned char *magick,const size_t length)
1301 % A description of each parameter follows:
1303 % o magick: compare image format pattern against these bytes.
1305 % o length: Specifies the length of the magick string.
1309 static MagickBooleanType IsJNG(const unsigned char *magick,const size_t length)
1312 return(MagickFalse);
1314 if (memcmp(magick,"\213JNG\r\n\032\n",8) == 0)
1317 return(MagickFalse);
1321 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1329 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1331 % IsPNG() returns MagickTrue if the image format type, identified by the
1332 % magick string, is PNG.
1334 % The format of the IsPNG method is:
1336 % MagickBooleanType IsPNG(const unsigned char *magick,const size_t length)
1338 % A description of each parameter follows:
1340 % o magick: compare image format pattern against these bytes.
1342 % o length: Specifies the length of the magick string.
1345 static MagickBooleanType IsPNG(const unsigned char *magick,const size_t length)
1348 return(MagickFalse);
1350 if (memcmp(magick,"\211PNG\r\n\032\n",8) == 0)
1353 return(MagickFalse);
1356 #if defined(MAGICKCORE_PNG_DELEGATE)
1357 #if defined(__cplusplus) || defined(c_plusplus)
1361 #if (PNG_LIBPNG_VER > 10011)
1362 static size_t WriteBlobMSBULong(Image *image,const size_t value)
1367 assert(image != (Image *) NULL);
1368 assert(image->signature == MagickSignature);
1369 buffer[0]=(unsigned char) (value >> 24);
1370 buffer[1]=(unsigned char) (value >> 16);
1371 buffer[2]=(unsigned char) (value >> 8);
1372 buffer[3]=(unsigned char) value;
1373 return((size_t) WriteBlob(image,4,buffer));
1376 static void PNGLong(png_bytep p,png_uint_32 value)
1378 *p++=(png_byte) ((value >> 24) & 0xff);
1379 *p++=(png_byte) ((value >> 16) & 0xff);
1380 *p++=(png_byte) ((value >> 8) & 0xff);
1381 *p++=(png_byte) (value & 0xff);
1384 #if defined(JNG_SUPPORTED)
1385 static void PNGsLong(png_bytep p,png_int_32 value)
1387 *p++=(png_byte) ((value >> 24) & 0xff);
1388 *p++=(png_byte) ((value >> 16) & 0xff);
1389 *p++=(png_byte) ((value >> 8) & 0xff);
1390 *p++=(png_byte) (value & 0xff);
1394 static void PNGShort(png_bytep p,png_uint_16 value)
1396 *p++=(png_byte) ((value >> 8) & 0xff);
1397 *p++=(png_byte) (value & 0xff);
1400 static void PNGType(png_bytep p,png_bytep type)
1402 (void) CopyMagickMemory(p,type,4*sizeof(png_byte));
1405 static void LogPNGChunk(MagickBooleanType logging, png_bytep type,
1408 if (logging != MagickFalse)
1409 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1410 " Writing %c%c%c%c chunk, length: %.20g",
1411 type[0],type[1],type[2],type[3],(double) length);
1413 #endif /* PNG_LIBPNG_VER > 10011 */
1415 #if defined(__cplusplus) || defined(c_plusplus)
1419 #if PNG_LIBPNG_VER > 10011
1421 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1425 % R e a d P N G I m a g e %
1429 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1431 % ReadPNGImage() reads a Portable Network Graphics (PNG) or
1432 % Multiple-image Network Graphics (MNG) image file and returns it. It
1433 % allocates the memory necessary for the new Image structure and returns a
1434 % pointer to the new image or set of images.
1436 % MNG support written by Glenn Randers-Pehrson, glennrp@image...
1438 % The format of the ReadPNGImage method is:
1440 % Image *ReadPNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
1442 % A description of each parameter follows:
1444 % o image_info: the image info.
1446 % o exception: return any errors or warnings in this structure.
1448 % To do, more or less in chronological order (as of version 5.5.2,
1449 % November 26, 2002 -- glennrp -- see also "To do" under WriteMNGImage):
1451 % Get 16-bit cheap transparency working.
1453 % (At this point, PNG decoding is supposed to be in full MNG-LC compliance)
1455 % Preserve all unknown and not-yet-handled known chunks found in input
1456 % PNG file and copy them into output PNG files according to the PNG
1459 % (At this point, PNG encoding should be in full MNG compliance)
1461 % Provide options for choice of background to use when the MNG BACK
1462 % chunk is not present or is not mandatory (i.e., leave transparent,
1463 % user specified, MNG BACK, PNG bKGD)
1465 % Implement LOOP/ENDL [done, but could do discretionary loops more
1466 % efficiently by linking in the duplicate frames.].
1468 % Decode and act on the MHDR simplicity profile (offer option to reject
1469 % files or attempt to process them anyway when the profile isn't LC or VLC).
1471 % Upgrade to full MNG without Delta-PNG.
1473 % o BACK [done a while ago except for background image ID]
1474 % o MOVE [done 15 May 1999]
1475 % o CLIP [done 15 May 1999]
1476 % o DISC [done 19 May 1999]
1477 % o SAVE [partially done 19 May 1999 (marks objects frozen)]
1478 % o SEEK [partially done 19 May 1999 (discard function only)]
1482 % o MNG-level tEXt/iTXt/zTXt
1487 % o iTXt (wait for libpng implementation).
1489 % Use the scene signature to discover when an identical scene is
1490 % being reused, and just point to the original image->exception instead
1491 % of storing another set of pixels. This not specific to MNG
1492 % but could be applied generally.
1494 % Upgrade to full MNG with Delta-PNG.
1496 % JNG tEXt/iTXt/zTXt
1498 % We will not attempt to read files containing the CgBI chunk.
1499 % They are really Xcode files meant for display on the iPhone.
1500 % These are not valid PNG files and it is impossible to recover
1501 % the original PNG from files that have been converted to Xcode-PNG,
1502 % since irretrievable loss of color data has occurred due to the
1503 % use of premultiplied alpha.
1506 #if defined(__cplusplus) || defined(c_plusplus)
1511 This the function that does the actual reading of data. It is
1512 the same as the one supplied in libpng, except that it receives the
1513 datastream from the ReadBlob() function instead of standard input.
1515 static void png_get_data(png_structp png_ptr,png_bytep data,png_size_t length)
1520 image=(Image *) png_get_io_ptr(png_ptr);
1526 check=(png_size_t) ReadBlob(image,(size_t) length,data);
1527 if (check != length)
1532 (void) FormatLocaleString(msg,MaxTextExtent,
1533 "Expected %.20g bytes; found %.20g bytes",(double) length,
1535 png_warning(png_ptr,msg);
1536 png_error(png_ptr,"Read Exception");
1541 #if !defined(PNG_READ_EMPTY_PLTE_SUPPORTED) && \
1542 !defined(PNG_MNG_FEATURES_SUPPORTED)
1543 /* We use mng_get_data() instead of png_get_data() if we have a libpng
1544 * older than libpng-1.0.3a, which was the first to allow the empty
1545 * PLTE, or a newer libpng in which PNG_MNG_FEATURES_SUPPORTED was
1546 * ifdef'ed out. Earlier versions would crash if the bKGD chunk was
1547 * encountered after an empty PLTE, so we have to look ahead for bKGD
1548 * chunks and remove them from the datastream that is passed to libpng,
1549 * and store their contents for later use.
1551 static void mng_get_data(png_structp png_ptr,png_bytep data,png_size_t length)
1566 mng_info=(MngInfo *) png_get_io_ptr(png_ptr);
1567 image=(Image *) mng_info->image;
1568 while (mng_info->bytes_in_read_buffer && length)
1570 data[i]=mng_info->read_buffer[i];
1571 mng_info->bytes_in_read_buffer--;
1577 check=(png_size_t) ReadBlob(image,(size_t) length,(char *) data);
1579 if (check != length)
1580 png_error(png_ptr,"Read Exception");
1584 if ((data[0] == 0) && (data[1] == 0) && (data[2] == 0) &&
1587 check=(png_size_t) ReadBlob(image,(size_t) length,
1588 (char *) mng_info->read_buffer);
1589 mng_info->read_buffer[4]=0;
1590 mng_info->bytes_in_read_buffer=4;
1591 if (memcmp(mng_info->read_buffer,mng_PLTE,4) == 0)
1592 mng_info->found_empty_plte=MagickTrue;
1593 if (memcmp(mng_info->read_buffer,mng_IEND,4) == 0)
1595 mng_info->found_empty_plte=MagickFalse;
1596 mng_info->have_saved_bkgd_index=MagickFalse;
1600 if ((data[0] == 0) && (data[1] == 0) && (data[2] == 0) &&
1603 check=(png_size_t) ReadBlob(image,(size_t) length,
1604 (char *) mng_info->read_buffer);
1605 mng_info->read_buffer[4]=0;
1606 mng_info->bytes_in_read_buffer=4;
1607 if (memcmp(mng_info->read_buffer,mng_bKGD,4) == 0)
1608 if (mng_info->found_empty_plte)
1611 Skip the bKGD data byte and CRC.
1614 ReadBlob(image,5,(char *) mng_info->read_buffer);
1615 check=(png_size_t) ReadBlob(image,(size_t) length,
1616 (char *) mng_info->read_buffer);
1617 mng_info->saved_bkgd_index=mng_info->read_buffer[0];
1618 mng_info->have_saved_bkgd_index=MagickTrue;
1619 mng_info->bytes_in_read_buffer=0;
1627 static void png_put_data(png_structp png_ptr,png_bytep data,png_size_t length)
1632 image=(Image *) png_get_io_ptr(png_ptr);
1638 check=(png_size_t) WriteBlob(image,(size_t) length,data);
1640 if (check != length)
1641 png_error(png_ptr,"WriteBlob Failed");
1645 static void png_flush_data(png_structp png_ptr)
1650 #ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
1651 static int PalettesAreEqual(Image *a,Image *b)
1656 if ((a == (Image *) NULL) || (b == (Image *) NULL))
1657 return((int) MagickFalse);
1659 if (a->storage_class != PseudoClass || b->storage_class != PseudoClass)
1660 return((int) MagickFalse);
1662 if (a->colors != b->colors)
1663 return((int) MagickFalse);
1665 for (i=0; i < (ssize_t) a->colors; i++)
1667 if ((a->colormap[i].red != b->colormap[i].red) ||
1668 (a->colormap[i].green != b->colormap[i].green) ||
1669 (a->colormap[i].blue != b->colormap[i].blue))
1670 return((int) MagickFalse);
1673 return((int) MagickTrue);
1677 static void MngInfoDiscardObject(MngInfo *mng_info,int i)
1679 if (i && (i < MNG_MAX_OBJECTS) && (mng_info != (MngInfo *) NULL) &&
1680 mng_info->exists[i] && !mng_info->frozen[i])
1682 #ifdef MNG_OBJECT_BUFFERS
1683 if (mng_info->ob[i] != (MngBuffer *) NULL)
1685 if (mng_info->ob[i]->reference_count > 0)
1686 mng_info->ob[i]->reference_count--;
1688 if (mng_info->ob[i]->reference_count == 0)
1690 if (mng_info->ob[i]->image != (Image *) NULL)
1691 mng_info->ob[i]->image=DestroyImage(mng_info->ob[i]->image);
1693 mng_info->ob[i]=DestroyString(mng_info->ob[i]);
1696 mng_info->ob[i]=(MngBuffer *) NULL;
1698 mng_info->exists[i]=MagickFalse;
1699 mng_info->invisible[i]=MagickFalse;
1700 mng_info->viewable[i]=MagickFalse;
1701 mng_info->frozen[i]=MagickFalse;
1702 mng_info->x_off[i]=0;
1703 mng_info->y_off[i]=0;
1704 mng_info->object_clip[i].left=0;
1705 mng_info->object_clip[i].right=(ssize_t) PNG_UINT_31_MAX;
1706 mng_info->object_clip[i].top=0;
1707 mng_info->object_clip[i].bottom=(ssize_t) PNG_UINT_31_MAX;
1711 static void MngInfoFreeStruct(MngInfo *mng_info,
1712 MagickBooleanType *have_mng_structure)
1714 if (*have_mng_structure != MagickFalse && (mng_info != (MngInfo *) NULL))
1719 for (i=1; i < MNG_MAX_OBJECTS; i++)
1720 MngInfoDiscardObject(mng_info,i);
1722 if (mng_info->global_plte != (png_colorp) NULL)
1723 mng_info->global_plte=(png_colorp)
1724 RelinquishMagickMemory(mng_info->global_plte);
1726 mng_info=(MngInfo *) RelinquishMagickMemory(mng_info);
1727 *have_mng_structure=MagickFalse;
1731 static MngBox mng_minimum_box(MngBox box1,MngBox box2)
1737 if (box.left < box2.left)
1740 if (box.top < box2.top)
1743 if (box.right > box2.right)
1744 box.right=box2.right;
1746 if (box.bottom > box2.bottom)
1747 box.bottom=box2.bottom;
1752 static MngBox mng_read_box(MngBox previous_box,char delta_type,unsigned char *p)
1758 Read clipping boundaries from DEFI, CLIP, FRAM, or PAST chunk.
1760 box.left=(ssize_t) ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]);
1761 box.right=(ssize_t) ((p[4] << 24) | (p[5] << 16) | (p[6] << 8) | p[7]);
1762 box.top=(ssize_t) ((p[8] << 24) | (p[9] << 16) | (p[10] << 8) | p[11]);
1763 box.bottom=(ssize_t) ((p[12] << 24) | (p[13] << 16) | (p[14] << 8) | p[15]);
1764 if (delta_type != 0)
1766 box.left+=previous_box.left;
1767 box.right+=previous_box.right;
1768 box.top+=previous_box.top;
1769 box.bottom+=previous_box.bottom;
1775 static MngPair mng_read_pair(MngPair previous_pair,int delta_type,
1781 Read two ssize_ts from CLON, MOVE or PAST chunk
1783 pair.a=(long) ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]);
1784 pair.b=(long) ((p[4] << 24) | (p[5] << 16) | (p[6] << 8) | p[7]);
1786 if (delta_type != 0)
1788 pair.a+=previous_pair.a;
1789 pair.b+=previous_pair.b;
1795 static long mng_get_long(unsigned char *p)
1797 return((long) ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]));
1800 typedef struct _PNGErrorInfo
1809 static void MagickPNGErrorHandler(png_struct *ping,png_const_charp message)
1820 error_info=(PNGErrorInfo *) png_get_error_ptr(ping);
1821 image=error_info->image;
1822 exception=error_info->exception;
1824 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1825 " libpng-%s error: %s", PNG_LIBPNG_VER_STRING,message);
1827 (void) ThrowMagickException(exception,GetMagickModule(),CoderError,message,
1828 "`%s'",image->filename);
1830 #if (PNG_LIBPNG_VER < 10500)
1831 /* A warning about deprecated use of jmpbuf here is unavoidable if you
1832 * are building with libpng-1.4.x and can be ignored.
1834 longjmp(ping->jmpbuf,1);
1836 png_longjmp(ping,1);
1840 static void MagickPNGWarningHandler(png_struct *ping,png_const_charp message)
1851 if (LocaleCompare(message, "Missing PLTE before tRNS") == 0)
1852 png_error(ping, message);
1854 error_info=(PNGErrorInfo *) png_get_error_ptr(ping);
1855 image=error_info->image;
1856 exception=error_info->exception;
1857 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1858 " libpng-%s warning: %s", PNG_LIBPNG_VER_STRING,message);
1860 (void) ThrowMagickException(exception,GetMagickModule(),CoderWarning,
1861 message,"`%s'",image->filename);
1864 #ifdef PNG_USER_MEM_SUPPORTED
1865 #if PNG_LIBPNG_VER >= 10400
1866 static png_voidp Magick_png_malloc(png_structp png_ptr,png_alloc_size_t size)
1868 static png_voidp Magick_png_malloc(png_structp png_ptr,png_size_t size)
1872 return((png_voidp) AcquireMagickMemory((size_t) size));
1876 Free a pointer. It is removed from the list at the same time.
1878 static png_free_ptr Magick_png_free(png_structp png_ptr,png_voidp ptr)
1881 ptr=RelinquishMagickMemory(ptr);
1882 return((png_free_ptr) NULL);
1886 #if defined(__cplusplus) || defined(c_plusplus)
1891 Magick_png_read_raw_profile(png_struct *ping,Image *image,
1892 const ImageInfo *image_info, png_textp text,int ii,ExceptionInfo *exception)
1897 register unsigned char
1911 unhex[103]={0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,
1912 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,
1913 0,0,0,0,0,0,0,0,0,1, 2,3,4,5,6,7,8,9,0,0,
1914 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,
1915 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,10,11,12,
1919 /* look for newline */
1923 /* look for length */
1924 while (*sp == '\0' || *sp == ' ' || *sp == '\n')
1927 length=(png_uint_32) StringToLong(sp);
1929 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1930 " length: %lu",(unsigned long) length);
1932 while (*sp != ' ' && *sp != '\n')
1935 /* allocate space */
1938 png_warning(ping,"invalid profile length");
1939 return(MagickFalse);
1942 profile=BlobToStringInfo((const void *) NULL,length);
1944 if (profile == (StringInfo *) NULL)
1946 png_warning(ping, "unable to copy profile");
1947 return(MagickFalse);
1950 /* copy profile, skipping white space and column 1 "=" signs */
1951 dp=GetStringInfoDatum(profile);
1954 for (i=0; i < (ssize_t) nibbles; i++)
1956 while (*sp < '0' || (*sp > '9' && *sp < 'a') || *sp > 'f')
1960 png_warning(ping, "ran out of profile data");
1961 profile=DestroyStringInfo(profile);
1962 return(MagickFalse);
1968 *dp=(unsigned char) (16*unhex[(int) *sp++]);
1971 (*dp++)+=unhex[(int) *sp++];
1974 We have already read "Raw profile type.
1976 (void) SetImageProfile(image,&text[ii].key[17],profile,exception);
1977 profile=DestroyStringInfo(profile);
1979 if (image_info->verbose)
1980 (void) printf(" Found a generic profile, type %s\n",&text[ii].key[17]);
1985 #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
1986 static int read_vpag_chunk_callback(png_struct *ping, png_unknown_chunkp chunk)
1992 /* The unknown chunk structure contains the chunk data:
1997 Note that libpng has already taken care of the CRC handling.
2000 LogMagickEvent(CoderEvent,GetMagickModule(),
2001 " read_vpag_chunk: found %c%c%c%c chunk",
2002 chunk->name[0],chunk->name[1],chunk->name[2],chunk->name[3]);
2004 if (chunk->name[0] != 118 || chunk->name[1] != 112 ||
2005 chunk->name[2] != 65 ||chunk-> name[3] != 103)
2006 return(0); /* Did not recognize */
2008 /* recognized vpAg */
2010 if (chunk->size != 9)
2011 return(-1); /* Error return */
2013 if (chunk->data[8] != 0)
2014 return(0); /* ImageMagick requires pixel units */
2016 image=(Image *) png_get_user_chunk_ptr(ping);
2018 image->page.width=(size_t) ((chunk->data[0] << 24) |
2019 (chunk->data[1] << 16) | (chunk->data[2] << 8) | chunk->data[3]);
2021 image->page.height=(size_t) ((chunk->data[4] << 24) |
2022 (chunk->data[5] << 16) | (chunk->data[6] << 8) | chunk->data[7]);
2024 /* Return one of the following: */
2025 /* return(-n); chunk had an error */
2026 /* return(0); did not recognize */
2027 /* return(n); success */
2035 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2039 % R e a d O n e P N G I m a g e %
2043 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2045 % ReadOnePNGImage() reads a Portable Network Graphics (PNG) image file
2046 % (minus the 8-byte signature) and returns it. It allocates the memory
2047 % necessary for the new Image structure and returns a pointer to the new
2050 % The format of the ReadOnePNGImage method is:
2052 % Image *ReadOnePNGImage(MngInfo *mng_info, const ImageInfo *image_info,
2053 % ExceptionInfo *exception)
2055 % A description of each parameter follows:
2057 % o mng_info: Specifies a pointer to a MngInfo structure.
2059 % o image_info: the image info.
2061 % o exception: return any errors or warnings in this structure.
2064 static Image *ReadOnePNGImage(MngInfo *mng_info,
2065 const ImageInfo *image_info, ExceptionInfo *exception)
2067 /* Read one PNG image */
2069 /* To do: Read the tIME chunk into the date:modify property */
2070 /* To do: Read the tEXt/Creation Time chunk into the date:create property */
2083 intent, /* "PNG Rendering intent", which is ICC intent + 1 */
2093 ping_interlace_method,
2094 ping_compression_method,
2108 ping_found_sRGB_cHRM,
2113 *volatile pixel_info;
2151 register unsigned char
2171 #ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED
2172 png_byte unused_chunks[]=
2174 104, 73, 83, 84, (png_byte) '\0', /* hIST */
2175 105, 84, 88, 116, (png_byte) '\0', /* iTXt */
2176 112, 67, 65, 76, (png_byte) '\0', /* pCAL */
2177 115, 67, 65, 76, (png_byte) '\0', /* sCAL */
2178 115, 80, 76, 84, (png_byte) '\0', /* sPLT */
2179 116, 73, 77, 69, (png_byte) '\0', /* tIME */
2180 #ifdef PNG_APNG_SUPPORTED /* libpng was built with APNG patch; */
2181 /* ignore the APNG chunks */
2182 97, 99, 84, 76, (png_byte) '\0', /* acTL */
2183 102, 99, 84, 76, (png_byte) '\0', /* fcTL */
2184 102, 100, 65, 84, (png_byte) '\0', /* fdAT */
2189 logging=LogMagickEvent(CoderEvent,GetMagickModule(),
2190 " Enter ReadOnePNGImage()");
2192 /* Define these outside of the following "if logging()" block so they will
2193 * show in debuggers.
2196 (void) ConcatenateMagickString(im_vers,
2197 MagickLibVersionText,32);
2198 (void) ConcatenateMagickString(im_vers,
2199 MagickLibAddendum,32);
2202 (void) ConcatenateMagickString(libpng_vers,
2203 PNG_LIBPNG_VER_STRING,32);
2205 (void) ConcatenateMagickString(libpng_runv,
2206 png_get_libpng_ver(NULL),32);
2209 (void) ConcatenateMagickString(zlib_vers,
2212 (void) ConcatenateMagickString(zlib_runv,
2217 LogMagickEvent(CoderEvent,GetMagickModule()," IM version = %s",
2219 LogMagickEvent(CoderEvent,GetMagickModule()," Libpng version = %s",
2221 if (LocaleCompare(libpng_vers,libpng_runv) != 0)
2223 LogMagickEvent(CoderEvent,GetMagickModule()," running with %s",
2226 LogMagickEvent(CoderEvent,GetMagickModule()," Zlib version = %s",
2228 if (LocaleCompare(zlib_vers,zlib_runv) != 0)
2230 LogMagickEvent(CoderEvent,GetMagickModule()," running with %s",
2235 #if (PNG_LIBPNG_VER < 10200)
2236 if (image_info->verbose)
2237 printf("Your PNG library (libpng-%s) is rather old.\n",
2238 PNG_LIBPNG_VER_STRING);
2241 #if (PNG_LIBPNG_VER >= 10400)
2242 # ifndef PNG_TRANSFORM_GRAY_TO_RGB /* Added at libpng-1.4.0beta67 */
2243 if (image_info->verbose)
2245 printf("Your PNG library (libpng-%s) is an old beta version.\n",
2246 PNG_LIBPNG_VER_STRING);
2247 printf("Please update it.\n");
2253 quantum_info = (QuantumInfo *) NULL;
2254 image=mng_info->image;
2256 if (logging != MagickFalse)
2258 (void)LogMagickEvent(CoderEvent,GetMagickModule(),
2259 " Before reading:");
2261 (void)LogMagickEvent(CoderEvent,GetMagickModule(),
2262 " image->alpha_trait=%d",(int) image->alpha_trait);
2264 (void)LogMagickEvent(CoderEvent,GetMagickModule(),
2265 " image->rendering_intent=%d",(int) image->rendering_intent);
2267 (void)LogMagickEvent(CoderEvent,GetMagickModule(),
2268 " image->colorspace=%d",(int) image->colorspace);
2270 (void)LogMagickEvent(CoderEvent,GetMagickModule(),
2271 " image->gamma=%f", image->gamma);
2273 intent=Magick_RenderingIntent_to_PNG_RenderingIntent(image->rendering_intent);
2275 /* Set to an out-of-range color unless tRNS chunk is present */
2276 transparent_color.red=65537;
2277 transparent_color.green=65537;
2278 transparent_color.blue=65537;
2279 transparent_color.alpha=65537;
2284 num_raw_profiles = 0;
2286 ping_found_cHRM = MagickFalse;
2287 ping_found_gAMA = MagickFalse;
2288 ping_found_iCCP = MagickFalse;
2289 ping_found_sRGB = MagickFalse;
2290 ping_found_sRGB_cHRM = MagickFalse;
2291 ping_preserve_iCCP = MagickFalse;
2297 value=GetImageOption(image_info,"png:preserve-iCCP");
2300 value=GetImageArtifact(image,"png:preserve-iCCP");
2303 ping_preserve_iCCP=MagickTrue;
2307 Allocate the PNG structures
2309 #ifdef PNG_USER_MEM_SUPPORTED
2310 error_info.image=image;
2311 error_info.exception=exception;
2312 ping=png_create_read_struct_2(PNG_LIBPNG_VER_STRING,&error_info,
2313 MagickPNGErrorHandler,MagickPNGWarningHandler, NULL,
2314 (png_malloc_ptr) Magick_png_malloc,(png_free_ptr) Magick_png_free);
2316 ping=png_create_read_struct(PNG_LIBPNG_VER_STRING,&error_info,
2317 MagickPNGErrorHandler,MagickPNGWarningHandler);
2319 if (ping == (png_struct *) NULL)
2320 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2322 ping_info=png_create_info_struct(ping);
2324 if (ping_info == (png_info *) NULL)
2326 png_destroy_read_struct(&ping,(png_info **) NULL,(png_info **) NULL);
2327 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2330 end_info=png_create_info_struct(ping);
2332 if (end_info == (png_info *) NULL)
2334 png_destroy_read_struct(&ping,&ping_info,(png_info **) NULL);
2335 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2338 pixel_info=(MemoryInfo *) NULL;
2340 if (setjmp(png_jmpbuf(ping)))
2343 PNG image is corrupt.
2345 png_destroy_read_struct(&ping,&ping_info,&end_info);
2347 #ifdef IMPNG_SETJMP_NOT_THREAD_SAFE
2348 UnlockSemaphoreInfo(ping_semaphore);
2351 if (pixel_info != (MemoryInfo *) NULL)
2352 pixel_info=RelinquishVirtualMemory(pixel_info);
2354 if (logging != MagickFalse)
2355 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2356 " exit ReadOnePNGImage() with error.");
2358 if (image != (Image *) NULL)
2360 InheritException(exception,exception);
2364 return(GetFirstImageInList(image));
2367 /* { For navigation to end of SETJMP-protected block. Within this
2368 * block, use png_error() instead of Throwing an Exception, to ensure
2369 * that libpng is able to clean up, and that the semaphore is unlocked.
2372 #ifdef IMPNG_SETJMP_NOT_THREAD_SAFE
2373 LockSemaphoreInfo(ping_semaphore);
2376 #ifdef PNG_BENIGN_ERRORS_SUPPORTED
2377 /* Allow benign errors */
2378 png_set_benign_errors(ping, 1);
2382 Prepare PNG for reading.
2385 mng_info->image_found++;
2386 png_set_sig_bytes(ping,8);
2388 if (LocaleCompare(image_info->magick,"MNG") == 0)
2390 #if defined(PNG_MNG_FEATURES_SUPPORTED)
2391 (void) png_permit_mng_features(ping,PNG_ALL_MNG_FEATURES);
2392 png_set_read_fn(ping,image,png_get_data);
2394 #if defined(PNG_READ_EMPTY_PLTE_SUPPORTED)
2395 png_permit_empty_plte(ping,MagickTrue);
2396 png_set_read_fn(ping,image,png_get_data);
2398 mng_info->image=image;
2399 mng_info->bytes_in_read_buffer=0;
2400 mng_info->found_empty_plte=MagickFalse;
2401 mng_info->have_saved_bkgd_index=MagickFalse;
2402 png_set_read_fn(ping,mng_info,mng_get_data);
2408 png_set_read_fn(ping,image,png_get_data);
2410 #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
2411 /* Ignore unused chunks and all unknown chunks except for vpAg */
2412 #if PNG_LIBPNG_VER < 10700 /* Avoid libpng16 warning */
2413 png_set_keep_unknown_chunks(ping, 2, NULL, 0);
2415 png_set_keep_unknown_chunks(ping, 1, NULL, 0);
2417 png_set_keep_unknown_chunks(ping, 2, mng_vpAg, 1);
2418 png_set_keep_unknown_chunks(ping, 1, unused_chunks,
2419 (int)sizeof(unused_chunks)/5);
2420 /* Callback for other unknown chunks */
2421 png_set_read_user_chunk_fn(ping, image, read_vpag_chunk_callback);
2424 #ifdef PNG_SET_USER_LIMITS_SUPPORTED
2425 # if (PNG_LIBPNG_VER >= 10400)
2426 /* Limit the size of the chunk storage cache used for sPLT, text,
2427 * and unknown chunks.
2429 png_set_chunk_cache_max(ping, 32767);
2433 #ifdef PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED
2434 /* Disable new libpng-1.5.10 feature */
2435 png_set_check_for_invalid_index (ping, 0);
2438 #if (PNG_LIBPNG_VER < 10400)
2439 # if defined(PNG_USE_PNGGCCRD) && defined(PNG_ASSEMBLER_CODE_SUPPORTED) && \
2440 (PNG_LIBPNG_VER >= 10200) && (PNG_LIBPNG_VER < 10220) && defined(__i386__)
2441 /* Disable thread-unsafe features of pnggccrd */
2442 if (png_access_version_number() >= 10200)
2444 png_uint_32 mmx_disable_mask=0;
2445 png_uint_32 asm_flags;
2447 mmx_disable_mask |= ( PNG_ASM_FLAG_MMX_READ_COMBINE_ROW \
2448 | PNG_ASM_FLAG_MMX_READ_FILTER_SUB \
2449 | PNG_ASM_FLAG_MMX_READ_FILTER_AVG \
2450 | PNG_ASM_FLAG_MMX_READ_FILTER_PAETH );
2451 asm_flags=png_get_asm_flags(ping);
2452 png_set_asm_flags(ping, asm_flags & ~mmx_disable_mask);
2457 png_read_info(ping,ping_info);
2459 png_get_IHDR(ping,ping_info,&ping_width,&ping_height,
2460 &ping_bit_depth,&ping_color_type,
2461 &ping_interlace_method,&ping_compression_method,
2462 &ping_filter_method);
2464 ping_file_depth = ping_bit_depth;
2466 /* Swap bytes if requested */
2467 if (ping_file_depth == 16)
2472 value=GetImageOption(image_info,"png:swap-bytes");
2475 value=GetImageArtifact(image,"png:swap-bytes");
2481 /* Save bit-depth and color-type in case we later want to write a PNG00 */
2486 (void) FormatLocaleString(msg,MaxTextExtent,"%d",(int) ping_color_type);
2487 (void) SetImageProperty(image,"png:IHDR.color-type-orig",msg,exception);
2489 (void) FormatLocaleString(msg,MaxTextExtent,"%d",(int) ping_bit_depth);
2490 (void) SetImageProperty(image,"png:IHDR.bit-depth-orig",msg,exception);
2493 (void) png_get_tRNS(ping, ping_info, &ping_trans_alpha, &ping_num_trans,
2496 (void) png_get_bKGD(ping, ping_info, &ping_background);
2498 if (ping_bit_depth < 8)
2500 png_set_packing(ping);
2504 image->depth=ping_bit_depth;
2505 image->depth=GetImageQuantumDepth(image,MagickFalse);
2506 image->interlace=ping_interlace_method != 0 ? PNGInterlace : NoInterlace;
2508 if (((int) ping_color_type == PNG_COLOR_TYPE_GRAY) ||
2509 ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA))
2511 image->rendering_intent=UndefinedIntent;
2512 intent=Magick_RenderingIntent_to_PNG_RenderingIntent(UndefinedIntent);
2514 (void) ResetMagickMemory(&image->chromaticity,0,
2515 sizeof(image->chromaticity));
2518 if (logging != MagickFalse)
2520 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2521 " PNG width: %.20g, height: %.20g",
2522 (double) ping_width, (double) ping_height);
2524 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2525 " PNG color_type: %d, bit_depth: %d",
2526 ping_color_type, ping_bit_depth);
2528 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2529 " PNG compression_method: %d",
2530 ping_compression_method);
2532 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2533 " PNG interlace_method: %d, filter_method: %d",
2534 ping_interlace_method,ping_filter_method);
2537 if (png_get_valid(ping,ping_info, PNG_INFO_iCCP))
2539 ping_found_iCCP=MagickTrue;
2540 if (logging != MagickFalse)
2541 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2542 " Found PNG iCCP chunk.");
2545 if (png_get_valid(ping,ping_info,PNG_INFO_gAMA))
2547 ping_found_gAMA=MagickTrue;
2548 if (logging != MagickFalse)
2549 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2550 " Found PNG gAMA chunk.");
2553 if (png_get_valid(ping,ping_info,PNG_INFO_cHRM))
2555 ping_found_cHRM=MagickTrue;
2556 if (logging != MagickFalse)
2557 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2558 " Found PNG cHRM chunk.");
2561 if (ping_found_iCCP != MagickTrue && png_get_valid(ping,ping_info,
2564 ping_found_sRGB=MagickTrue;
2565 if (logging != MagickFalse)
2566 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2567 " Found PNG sRGB chunk.");
2570 #ifdef PNG_READ_iCCP_SUPPORTED
2571 if (ping_found_iCCP !=MagickTrue &&
2572 ping_found_sRGB != MagickTrue &&
2573 png_get_valid(ping,ping_info, PNG_INFO_iCCP))
2575 ping_found_iCCP=MagickTrue;
2576 if (logging != MagickFalse)
2577 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2578 " Found PNG iCCP chunk.");
2581 if (png_get_valid(ping,ping_info,PNG_INFO_iCCP))
2586 #if (PNG_LIBPNG_VER < 10500)
2600 (void) png_get_iCCP(ping,ping_info,&name,(int *) &compression,&info,
2603 if (profile_length != 0)
2608 if (logging != MagickFalse)
2609 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2610 " Reading PNG iCCP chunk.");
2612 profile=BlobToStringInfo(info,profile_length);
2614 if (profile == (StringInfo *) NULL)
2616 png_warning(ping, "ICC profile is NULL");
2617 profile=DestroyStringInfo(profile);
2621 if (ping_preserve_iCCP == MagickFalse)
2635 length=(png_uint_32) GetStringInfoLength(profile);
2637 for (icheck=0; sRGB_info[icheck].len > 0; icheck++)
2639 if (length == sRGB_info[icheck].len)
2643 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2644 " Got a %lu-byte ICC profile (potentially sRGB)",
2645 (unsigned long) length);
2647 data=GetStringInfoDatum(profile);
2648 profile_crc=crc32(0,data,length);
2650 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2651 " with crc=%8x",(unsigned int) profile_crc);
2655 if (profile_crc == sRGB_info[icheck].crc)
2657 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2658 " It is sRGB with rendering intent = %s",
2659 Magick_RenderingIntentString_from_PNG_RenderingIntent(
2660 sRGB_info[icheck].intent));
2661 if (image->rendering_intent==UndefinedIntent)
2663 image->rendering_intent=
2664 Magick_RenderingIntent_from_PNG_RenderingIntent(
2665 sRGB_info[icheck].intent);
2671 if (sRGB_info[icheck].len == 0)
2673 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2674 " Got a %lu-byte ICC profile not recognized as sRGB",
2675 (unsigned long) length);
2676 (void) SetImageProfile(image,"icc",profile,exception);
2679 else /* Preserve-iCCP */
2681 (void) SetImageProfile(image,"icc",profile,exception);
2684 profile=DestroyStringInfo(profile);
2690 #if defined(PNG_READ_sRGB_SUPPORTED)
2692 if (ping_found_iCCP==MagickFalse && png_get_valid(ping,ping_info,
2695 if (png_get_sRGB(ping,ping_info,&intent))
2697 if (image->rendering_intent == UndefinedIntent)
2698 image->rendering_intent=
2699 Magick_RenderingIntent_from_PNG_RenderingIntent (intent);
2701 if (logging != MagickFalse)
2702 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2703 " Reading PNG sRGB chunk: rendering_intent: %d",intent);
2707 else if (mng_info->have_global_srgb)
2709 if (image->rendering_intent == UndefinedIntent)
2710 image->rendering_intent=
2711 Magick_RenderingIntent_from_PNG_RenderingIntent
2712 (mng_info->global_srgb_intent);
2719 if (!png_get_gAMA(ping,ping_info,&file_gamma))
2720 if (mng_info->have_global_gama)
2721 png_set_gAMA(ping,ping_info,mng_info->global_gamma);
2723 if (png_get_gAMA(ping,ping_info,&file_gamma))
2725 image->gamma=(float) file_gamma;
2726 if (logging != MagickFalse)
2727 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2728 " Reading PNG gAMA chunk: gamma: %f",file_gamma);
2732 if (!png_get_valid(ping,ping_info,PNG_INFO_cHRM))
2734 if (mng_info->have_global_chrm != MagickFalse)
2736 (void) png_set_cHRM(ping,ping_info,
2737 mng_info->global_chrm.white_point.x,
2738 mng_info->global_chrm.white_point.y,
2739 mng_info->global_chrm.red_primary.x,
2740 mng_info->global_chrm.red_primary.y,
2741 mng_info->global_chrm.green_primary.x,
2742 mng_info->global_chrm.green_primary.y,
2743 mng_info->global_chrm.blue_primary.x,
2744 mng_info->global_chrm.blue_primary.y);
2748 if (png_get_valid(ping,ping_info,PNG_INFO_cHRM))
2750 (void) png_get_cHRM(ping,ping_info,
2751 &image->chromaticity.white_point.x,
2752 &image->chromaticity.white_point.y,
2753 &image->chromaticity.red_primary.x,
2754 &image->chromaticity.red_primary.y,
2755 &image->chromaticity.green_primary.x,
2756 &image->chromaticity.green_primary.y,
2757 &image->chromaticity.blue_primary.x,
2758 &image->chromaticity.blue_primary.y);
2760 ping_found_cHRM=MagickTrue;
2762 if (image->chromaticity.red_primary.x>0.6399f &&
2763 image->chromaticity.red_primary.x<0.6401f &&
2764 image->chromaticity.red_primary.y>0.3299f &&
2765 image->chromaticity.red_primary.y<0.3301f &&
2766 image->chromaticity.green_primary.x>0.2999f &&
2767 image->chromaticity.green_primary.x<0.3001f &&
2768 image->chromaticity.green_primary.y>0.5999f &&
2769 image->chromaticity.green_primary.y<0.6001f &&
2770 image->chromaticity.blue_primary.x>0.1499f &&
2771 image->chromaticity.blue_primary.x<0.1501f &&
2772 image->chromaticity.blue_primary.y>0.0599f &&
2773 image->chromaticity.blue_primary.y<0.0601f &&
2774 image->chromaticity.white_point.x>0.3126f &&
2775 image->chromaticity.white_point.x<0.3128f &&
2776 image->chromaticity.white_point.y>0.3289f &&
2777 image->chromaticity.white_point.y<0.3291f)
2778 ping_found_sRGB_cHRM=MagickTrue;
2781 if (image->rendering_intent != UndefinedIntent)
2783 if (ping_found_sRGB != MagickTrue &&
2784 (ping_found_gAMA != MagickTrue ||
2785 (image->gamma > .45 && image->gamma < .46)) &&
2786 (ping_found_cHRM != MagickTrue ||
2787 ping_found_sRGB_cHRM != MagickFalse) &&
2788 ping_found_iCCP != MagickTrue)
2790 png_set_sRGB(ping,ping_info,
2791 Magick_RenderingIntent_to_PNG_RenderingIntent
2792 (image->rendering_intent));
2793 file_gamma=1.000f/2.200f;
2794 ping_found_sRGB=MagickTrue;
2795 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2796 " Setting sRGB as if in input");
2800 #if defined(PNG_oFFs_SUPPORTED)
2801 if (png_get_valid(ping,ping_info,PNG_INFO_oFFs))
2803 image->page.x=(ssize_t) png_get_x_offset_pixels(ping, ping_info);
2804 image->page.y=(ssize_t) png_get_y_offset_pixels(ping, ping_info);
2806 if (logging != MagickFalse)
2807 if (image->page.x || image->page.y)
2808 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2809 " Reading PNG oFFs chunk: x: %.20g, y: %.20g.",(double)
2810 image->page.x,(double) image->page.y);
2813 #if defined(PNG_pHYs_SUPPORTED)
2814 if (!png_get_valid(ping,ping_info,PNG_INFO_pHYs))
2816 if (mng_info->have_global_phys)
2818 png_set_pHYs(ping,ping_info,
2819 mng_info->global_x_pixels_per_unit,
2820 mng_info->global_y_pixels_per_unit,
2821 mng_info->global_phys_unit_type);
2828 if (png_get_valid(ping,ping_info,PNG_INFO_pHYs))
2831 Set image resolution.
2833 (void) png_get_pHYs(ping,ping_info,&x_resolution,&y_resolution,
2835 image->resolution.x=(double) x_resolution;
2836 image->resolution.y=(double) y_resolution;
2838 if (unit_type == PNG_RESOLUTION_METER)
2840 image->units=PixelsPerCentimeterResolution;
2841 image->resolution.x=(double) x_resolution/100.0;
2842 image->resolution.y=(double) y_resolution/100.0;
2845 if (logging != MagickFalse)
2846 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2847 " Reading PNG pHYs chunk: xres: %.20g, yres: %.20g, units: %d.",
2848 (double) x_resolution,(double) y_resolution,unit_type);
2852 if (png_get_valid(ping,ping_info,PNG_INFO_PLTE))
2857 (void) png_get_PLTE(ping,ping_info,&palette,&number_colors);
2859 if ((number_colors == 0) &&
2860 ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE))
2862 if (mng_info->global_plte_length)
2864 png_set_PLTE(ping,ping_info,mng_info->global_plte,
2865 (int) mng_info->global_plte_length);
2867 if (!png_get_valid(ping,ping_info,PNG_INFO_tRNS))
2869 if (mng_info->global_trns_length)
2872 "global tRNS has more entries than global PLTE");
2876 png_set_tRNS(ping,ping_info,mng_info->global_trns,
2877 (int) mng_info->global_trns_length,NULL);
2880 #ifdef PNG_READ_bKGD_SUPPORTED
2882 #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
2883 mng_info->have_saved_bkgd_index ||
2885 png_get_valid(ping,ping_info,PNG_INFO_bKGD))
2890 #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
2891 if (mng_info->have_saved_bkgd_index)
2892 background.index=mng_info->saved_bkgd_index;
2894 if (png_get_valid(ping, ping_info, PNG_INFO_bKGD))
2895 background.index=ping_background->index;
2897 background.red=(png_uint_16)
2898 mng_info->global_plte[background.index].red;
2900 background.green=(png_uint_16)
2901 mng_info->global_plte[background.index].green;
2903 background.blue=(png_uint_16)
2904 mng_info->global_plte[background.index].blue;
2906 background.gray=(png_uint_16)
2907 mng_info->global_plte[background.index].green;
2909 png_set_bKGD(ping,ping_info,&background);
2914 png_error(ping,"No global PLTE in file");
2918 #ifdef PNG_READ_bKGD_SUPPORTED
2919 if (mng_info->have_global_bkgd &&
2920 (!png_get_valid(ping,ping_info,PNG_INFO_bKGD)))
2921 image->background_color=mng_info->mng_global_bkgd;
2923 if (png_get_valid(ping,ping_info,PNG_INFO_bKGD))
2929 Set image background color.
2931 if (logging != MagickFalse)
2932 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2933 " Reading PNG bKGD chunk.");
2935 /* Scale background components to 16-bit, then scale
2938 if (logging != MagickFalse)
2939 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2940 " raw ping_background=(%d,%d,%d).",ping_background->red,
2941 ping_background->green,ping_background->blue);
2945 if (ping_file_depth == 1)
2948 else if (ping_file_depth == 2)
2951 else if (ping_file_depth == 4)
2954 if (ping_file_depth <= 8)
2957 ping_background->red *= bkgd_scale;
2958 ping_background->green *= bkgd_scale;
2959 ping_background->blue *= bkgd_scale;
2961 if (logging != MagickFalse)
2963 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2964 " bkgd_scale=%d.",bkgd_scale);
2966 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2967 " ping_background=(%d,%d,%d).",ping_background->red,
2968 ping_background->green,ping_background->blue);
2971 image->background_color.red=
2972 ScaleShortToQuantum(ping_background->red);
2974 image->background_color.green=
2975 ScaleShortToQuantum(ping_background->green);
2977 image->background_color.blue=
2978 ScaleShortToQuantum(ping_background->blue);
2980 image->background_color.alpha=OpaqueAlpha;
2982 if (logging != MagickFalse)
2983 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2984 " image->background_color=(%.20g,%.20g,%.20g).",
2985 (double) image->background_color.red,
2986 (double) image->background_color.green,
2987 (double) image->background_color.blue);
2989 #endif /* PNG_READ_bKGD_SUPPORTED */
2991 if (png_get_valid(ping,ping_info,PNG_INFO_tRNS))
2994 Image has a tRNS chunk.
3002 if (logging != MagickFalse)
3003 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3004 " Reading PNG tRNS chunk.");
3006 max_sample = (int) ((one << ping_file_depth) - 1);
3008 if ((ping_color_type == PNG_COLOR_TYPE_GRAY &&
3009 (int)ping_trans_color->gray > max_sample) ||
3010 (ping_color_type == PNG_COLOR_TYPE_RGB &&
3011 ((int)ping_trans_color->red > max_sample ||
3012 (int)ping_trans_color->green > max_sample ||
3013 (int)ping_trans_color->blue > max_sample)))
3015 if (logging != MagickFalse)
3016 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3017 " Ignoring PNG tRNS chunk with out-of-range sample.");
3018 png_free_data(ping, ping_info, PNG_FREE_TRNS, 0);
3019 png_set_invalid(ping,ping_info,PNG_INFO_tRNS);
3020 image->alpha_trait=UndefinedPixelTrait;
3027 scale_to_short = 65535L/((1UL << ping_file_depth)-1);
3029 /* Scale transparent_color to short */
3030 transparent_color.red= scale_to_short*ping_trans_color->red;
3031 transparent_color.green= scale_to_short*ping_trans_color->green;
3032 transparent_color.blue= scale_to_short*ping_trans_color->blue;
3033 transparent_color.alpha= scale_to_short*ping_trans_color->gray;
3035 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
3037 if (logging != MagickFalse)
3039 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3040 " Raw tRNS graylevel is %d.",ping_trans_color->gray);
3042 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3043 " scaled graylevel is %.20g.",transparent_color.alpha);
3045 transparent_color.red=transparent_color.alpha;
3046 transparent_color.green=transparent_color.alpha;
3047 transparent_color.blue=transparent_color.alpha;
3051 #if defined(PNG_READ_sBIT_SUPPORTED)
3052 if (mng_info->have_global_sbit)
3054 if (!png_get_valid(ping,ping_info,PNG_INFO_sBIT))
3055 png_set_sBIT(ping,ping_info,&mng_info->global_sbit);
3058 num_passes=png_set_interlace_handling(ping);
3060 png_read_update_info(ping,ping_info);
3062 ping_rowbytes=png_get_rowbytes(ping,ping_info);
3065 Initialize image structure.
3067 mng_info->image_box.left=0;
3068 mng_info->image_box.right=(ssize_t) ping_width;
3069 mng_info->image_box.top=0;
3070 mng_info->image_box.bottom=(ssize_t) ping_height;
3071 if (mng_info->mng_type == 0)
3073 mng_info->mng_width=ping_width;
3074 mng_info->mng_height=ping_height;
3075 mng_info->frame=mng_info->image_box;
3076 mng_info->clip=mng_info->image_box;
3081 image->page.y=mng_info->y_off[mng_info->object_id];
3084 image->compression=ZipCompression;
3085 image->columns=ping_width;
3086 image->rows=ping_height;
3088 if (((int) ping_color_type == PNG_COLOR_TYPE_GRAY) ||
3089 ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA))
3092 image_gamma = image->gamma;
3094 (void)LogMagickEvent(CoderEvent,GetMagickModule(),
3095 " image->gamma=%f",(float) image_gamma);
3097 if (image_gamma > 0.75)
3099 /* Set image->rendering_intent to Undefined,
3100 * image->colorspace to GRAY, and reset image->chromaticity.
3102 image->intensity = Rec709LuminancePixelIntensityMethod;
3103 SetImageColorspace(image,GRAYColorspace,exception);
3104 image->gamma = image_gamma;
3108 (void)LogMagickEvent(CoderEvent,GetMagickModule(),
3109 " image->colorspace=%d",(int) image->colorspace);
3111 if (((int) ping_color_type == PNG_COLOR_TYPE_PALETTE) ||
3112 ((int) ping_bit_depth < 16 &&
3113 (int) ping_color_type == PNG_COLOR_TYPE_GRAY))
3118 image->storage_class=PseudoClass;
3120 image->colors=one << ping_file_depth;
3121 #if (MAGICKCORE_QUANTUM_DEPTH == 8)
3122 if (image->colors > 256)
3125 if (image->colors > 65536L)
3126 image->colors=65536L;
3128 if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
3133 (void) png_get_PLTE(ping,ping_info,&palette,&number_colors);
3134 image->colors=(size_t) number_colors;
3136 if (logging != MagickFalse)
3137 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3138 " Reading PNG PLTE chunk: number_colors: %d.",number_colors);
3142 if (image->storage_class == PseudoClass)
3145 Initialize image colormap.
3147 if (AcquireImageColormap(image,image->colors,exception) == MagickFalse)
3148 png_error(ping,"Memory allocation failed");
3150 if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
3155 (void) png_get_PLTE(ping,ping_info,&palette,&number_colors);
3157 for (i=0; i < (ssize_t) number_colors; i++)
3159 image->colormap[i].red=ScaleCharToQuantum(palette[i].red);
3160 image->colormap[i].green=ScaleCharToQuantum(palette[i].green);
3161 image->colormap[i].blue=ScaleCharToQuantum(palette[i].blue);
3164 for ( ; i < (ssize_t) image->colors; i++)
3166 image->colormap[i].red=0;
3167 image->colormap[i].green=0;
3168 image->colormap[i].blue=0;
3177 scale=(QuantumRange/((1UL << ping_file_depth)-1));
3182 for (i=0; i < (ssize_t) image->colors; i++)
3184 image->colormap[i].red=(Quantum) (i*scale);
3185 image->colormap[i].green=(Quantum) (i*scale);
3186 image->colormap[i].blue=(Quantum) (i*scale);
3191 /* Set some properties for reporting by "identify" */
3196 /* encode ping_width, ping_height, ping_file_depth, ping_color_type,
3197 ping_interlace_method in value */
3199 (void) FormatLocaleString(msg,MaxTextExtent,
3200 "%d, %d",(int) ping_width, (int) ping_height);
3201 (void) SetImageProperty(image,"png:IHDR.width,height",msg,exception);
3203 (void) FormatLocaleString(msg,MaxTextExtent,"%d",(int) ping_file_depth);
3204 (void) SetImageProperty(image,"png:IHDR.bit_depth",msg,exception);
3206 (void) FormatLocaleString(msg,MaxTextExtent,"%d (%s)",
3207 (int) ping_color_type,
3208 Magick_ColorType_from_PNG_ColorType((int)ping_color_type));
3209 (void) SetImageProperty(image,"png:IHDR.color_type",msg,exception);
3211 if (ping_interlace_method == 0)
3213 (void) FormatLocaleString(msg,MaxTextExtent,"%d (Not interlaced)",
3214 (int) ping_interlace_method);
3216 else if (ping_interlace_method == 1)
3218 (void) FormatLocaleString(msg,MaxTextExtent,"%d (Adam7 method)",
3219 (int) ping_interlace_method);
3223 (void) FormatLocaleString(msg,MaxTextExtent,"%d (Unknown method)",
3224 (int) ping_interlace_method);
3226 (void) SetImageProperty(image,"png:IHDR.interlace_method",msg,exception);
3228 if (number_colors != 0)
3230 (void) FormatLocaleString(msg,MaxTextExtent,"%d",
3231 (int) number_colors);
3232 (void) SetImageProperty(image,"png:PLTE.number_colors",msg,
3238 Read image scanlines.
3240 if (image->delay != 0)
3241 mng_info->scenes_found++;
3243 if ((mng_info->mng_type == 0 && (image->ping != MagickFalse)) || (
3244 (image_info->number_scenes != 0) && (mng_info->scenes_found > (ssize_t)
3245 (image_info->first_scene+image_info->number_scenes))))
3247 /* This happens later in non-ping decodes */
3248 if (png_get_valid(ping,ping_info,PNG_INFO_tRNS))
3249 image->storage_class=DirectClass;
3251 if (logging != MagickFalse)
3252 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3253 " Skipping PNG image data for scene %.20g",(double)
3254 mng_info->scenes_found-1);
3255 png_destroy_read_struct(&ping,&ping_info,&end_info);
3257 #ifdef IMPNG_SETJMP_NOT_THREAD_SAFE
3258 UnlockSemaphoreInfo(ping_semaphore);
3261 if (logging != MagickFalse)
3262 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3263 " exit ReadOnePNGImage().");
3268 if (logging != MagickFalse)
3269 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3270 " Reading PNG IDAT chunk(s)");
3273 pixel_info=AcquireVirtualMemory(image->rows,ping_rowbytes*
3274 sizeof(*ping_pixels));
3276 pixel_info=AcquireVirtualMemory(ping_rowbytes,sizeof(*ping_pixels));
3278 if (pixel_info == (MemoryInfo *) NULL)
3279 png_error(ping,"Memory allocation failed");
3280 ping_pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
3282 if (logging != MagickFalse)
3283 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3284 " Converting PNG pixels to pixel packets");
3286 Convert PNG pixels to pixel packets.
3288 quantum_info=AcquireQuantumInfo(image_info,image);
3290 if (quantum_info == (QuantumInfo *) NULL)
3291 png_error(ping,"Failed to allocate quantum_info");
3293 (void) SetQuantumEndian(image,quantum_info,MSBEndian);
3298 found_transparent_pixel;
3300 found_transparent_pixel=MagickFalse;
3302 if (image->storage_class == DirectClass)
3304 for (pass=0; pass < num_passes; pass++)
3307 Convert image to DirectClass pixel packets.
3309 image->alpha_trait=(((int) ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA) ||
3310 ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) ||
3311 (png_get_valid(ping,ping_info,PNG_INFO_tRNS))) ?
3312 BlendPixelTrait : UndefinedPixelTrait;
3314 for (y=0; y < (ssize_t) image->rows; y++)
3317 row_offset=ping_rowbytes*y;
3322 png_read_row(ping,ping_pixels+row_offset,NULL);
3324 if (pass < num_passes-1)
3327 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
3329 if (q == (Quantum *) NULL)
3332 if ((int) ping_color_type == PNG_COLOR_TYPE_GRAY)
3333 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
3334 GrayQuantum,ping_pixels+row_offset,exception);
3336 else if ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
3337 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
3338 GrayAlphaQuantum,ping_pixels+row_offset,exception);
3340 else if ((int) ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA)
3341 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
3342 RGBAQuantum,ping_pixels+row_offset,exception);
3344 else if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
3345 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
3346 IndexQuantum,ping_pixels+row_offset,exception);
3348 else /* ping_color_type == PNG_COLOR_TYPE_RGB */
3349 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
3350 RGBQuantum,ping_pixels+row_offset,exception);
3352 if (found_transparent_pixel == MagickFalse)
3354 /* Is there a transparent pixel in the row? */
3355 if (y== 0 && logging != MagickFalse)
3356 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3357 " Looking for cheap transparent pixel");
3359 for (x=(ssize_t) image->columns-1; x >= 0; x--)
3361 if ((ping_color_type == PNG_COLOR_TYPE_RGBA ||
3362 ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) &&
3363 (GetPixelAlpha(image,q) != OpaqueAlpha))
3365 if (logging != MagickFalse)
3366 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3369 found_transparent_pixel = MagickTrue;
3372 if ((ping_color_type == PNG_COLOR_TYPE_RGB ||
3373 ping_color_type == PNG_COLOR_TYPE_GRAY) &&
3374 (ScaleQuantumToShort(GetPixelRed(image,q)) ==
3375 transparent_color.red &&
3376 ScaleQuantumToShort(GetPixelGreen(image,q)) ==
3377 transparent_color.green &&
3378 ScaleQuantumToShort(GetPixelBlue(image,q)) ==
3379 transparent_color.blue))
3381 if (logging != MagickFalse)
3382 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3384 found_transparent_pixel = MagickTrue;
3387 q+=GetPixelChannels(image);
3391 if ((image->previous == (Image *) NULL) && (num_passes == 1))
3393 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
3396 if (status == MagickFalse)
3399 if (SyncAuthenticPixels(image,exception) == MagickFalse)
3403 if ((image->previous == (Image *) NULL) && (num_passes != 1))
3405 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
3406 if (status == MagickFalse)
3412 else /* image->storage_class != DirectClass */
3414 for (pass=0; pass < num_passes; pass++)
3423 Convert grayscale image to PseudoClass pixel packets.
3425 if (logging != MagickFalse)
3426 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3427 " Converting grayscale pixels to pixel packets");
3429 image->alpha_trait=ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA ?
3430 BlendPixelTrait : UndefinedPixelTrait;
3432 quantum_scanline=(Quantum *) AcquireQuantumMemory(image->columns,
3433 (image->alpha_trait == BlendPixelTrait? 2 : 1)*
3434 sizeof(*quantum_scanline));
3436 if (quantum_scanline == (Quantum *) NULL)
3437 png_error(ping,"Memory allocation failed");
3439 for (y=0; y < (ssize_t) image->rows; y++)
3445 row_offset=ping_rowbytes*y;
3450 png_read_row(ping,ping_pixels+row_offset,NULL);
3452 if (pass < num_passes-1)
3455 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
3457 if (q == (Quantum *) NULL)
3460 p=ping_pixels+row_offset;
3463 switch (ping_bit_depth)
3468 if (ping_color_type == 4)
3469 for (x=(ssize_t) image->columns-1; x >= 0; x--)
3473 alpha=ScaleCharToQuantum((unsigned char)*p++);
3475 SetPixelAlpha(image,alpha,q);
3477 if (alpha != OpaqueAlpha)
3478 found_transparent_pixel = MagickTrue;
3480 q+=GetPixelChannels(image);
3484 for (x=(ssize_t) image->columns-1; x >= 0; x--)
3492 for (x=(ssize_t) image->columns-1; x >= 0; x--)
3494 #if (MAGICKCORE_QUANTUM_DEPTH == 16) || (MAGICKCORE_QUANTUM_DEPTH == 32)
3498 if (image->colors > 256)
3499 quantum=((*p++) << 8);
3505 *r=ScaleShortToQuantum(quantum);
3508 if (ping_color_type == 4)
3510 if (image->colors > 256)
3511 quantum=((*p++) << 8);
3517 alpha=ScaleShortToQuantum(quantum);
3518 SetPixelAlpha(image,alpha,q);
3520 if (alpha != OpaqueAlpha)
3521 found_transparent_pixel = MagickTrue;
3523 q+=GetPixelChannels(image);
3526 #else /* MAGICKCORE_QUANTUM_DEPTH == 8 */
3528 p++; /* strip low byte */
3530 if (ping_color_type == 4)
3532 SetPixelAlpha(image,*p++,q);
3534 if (GetPixelAlpha(image,q) != OpaqueAlpha)
3535 found_transparent_pixel = MagickTrue;
3538 q+=GetPixelChannels(image);
3551 Transfer image scanline.
3555 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
3557 if (q == (Quantum *) NULL)
3559 for (x=0; x < (ssize_t) image->columns; x++)
3561 SetPixelIndex(image,*r++,q);
3562 q+=GetPixelChannels(image);
3565 if (SyncAuthenticPixels(image,exception) == MagickFalse)
3568 if ((image->previous == (Image *) NULL) && (num_passes == 1))
3570 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
3573 if (status == MagickFalse)
3578 if ((image->previous == (Image *) NULL) && (num_passes != 1))
3580 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
3582 if (status == MagickFalse)
3586 quantum_scanline=(Quantum *) RelinquishMagickMemory(quantum_scanline);
3589 image->alpha_trait=found_transparent_pixel ? BlendPixelTrait :
3590 UndefinedPixelTrait;
3592 if (logging != MagickFalse)
3594 if (found_transparent_pixel != MagickFalse)
3595 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3596 " Found transparent pixel");
3599 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3600 " No transparent pixel was found");
3602 ping_color_type&=0x03;
3607 if (quantum_info != (QuantumInfo *) NULL)
3608 quantum_info=DestroyQuantumInfo(quantum_info);
3610 if (image->storage_class == PseudoClass)
3615 alpha_trait=image->alpha_trait;
3616 image->alpha_trait=UndefinedPixelTrait;
3617 (void) SyncImage(image,exception);
3618 image->alpha_trait=alpha_trait;
3621 png_read_end(ping,end_info);
3623 if (image_info->number_scenes != 0 && mng_info->scenes_found-1 <
3624 (ssize_t) image_info->first_scene && image->delay != 0)
3626 png_destroy_read_struct(&ping,&ping_info,&end_info);
3627 pixel_info=RelinquishVirtualMemory(pixel_info);
3629 (void) SetImageBackgroundColor(image,exception);
3630 #ifdef IMPNG_SETJMP_NOT_THREAD_SAFE
3631 UnlockSemaphoreInfo(ping_semaphore);
3633 if (logging != MagickFalse)
3634 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3635 " exit ReadOnePNGImage() early.");
3639 if (png_get_valid(ping,ping_info,PNG_INFO_tRNS))
3645 Image has a transparent background.
3647 storage_class=image->storage_class;
3648 image->alpha_trait=BlendPixelTrait;
3650 /* Balfour fix from imagemagick discourse server, 5 Feb 2010 */
3652 if (storage_class == PseudoClass)
3654 if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
3656 for (x=0; x < ping_num_trans; x++)
3658 image->colormap[x].alpha_trait=BlendPixelTrait;
3659 image->colormap[x].alpha =
3660 ScaleCharToQuantum((unsigned char)ping_trans_alpha[x]);
3664 else if (ping_color_type == PNG_COLOR_TYPE_GRAY)
3666 for (x=0; x < (int) image->colors; x++)
3668 if (ScaleQuantumToShort(image->colormap[x].red) ==
3669 transparent_color.alpha)
3671 image->colormap[x].alpha_trait=BlendPixelTrait;
3672 image->colormap[x].alpha = (Quantum) TransparentAlpha;
3676 (void) SyncImage(image,exception);
3679 #if 1 /* Should have already been done above, but glennrp problem P10
3684 for (y=0; y < (ssize_t) image->rows; y++)
3686 image->storage_class=storage_class;
3687 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
3689 if (q == (Quantum *) NULL)
3693 /* Caution: on a Q8 build, this does not distinguish between
3694 * 16-bit colors that differ only in the low byte
3696 for (x=(ssize_t) image->columns-1; x >= 0; x--)
3698 if (ScaleQuantumToShort(GetPixelRed(image,q)) ==
3699 transparent_color.red &&
3700 ScaleQuantumToShort(GetPixelGreen(image,q)) ==
3701 transparent_color.green &&
3702 ScaleQuantumToShort(GetPixelBlue(image,q)) ==
3703 transparent_color.blue)
3705 SetPixelAlpha(image,TransparentAlpha,q);
3708 #if 0 /* I have not found a case where this is needed. */
3711 SetPixelAlpha(image,q)=(Quantum) OpaqueAlpha;
3715 q+=GetPixelChannels(image);
3718 if (SyncAuthenticPixels(image,exception) == MagickFalse)
3724 image->storage_class=DirectClass;
3727 for (j = 0; j < 2; j++)
3730 status = png_get_text(ping,ping_info,&text,&num_text) != 0 ?
3731 MagickTrue : MagickFalse;
3733 status = png_get_text(ping,end_info,&text,&num_text) != 0 ?
3734 MagickTrue : MagickFalse;
3736 if (status != MagickFalse)
3737 for (i=0; i < (ssize_t) num_text; i++)
3739 /* Check for a profile */
3741 if (logging != MagickFalse)
3742 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3743 " Reading PNG text chunk");
3745 if (memcmp(text[i].key, "Raw profile type ",17) == 0)
3747 (void) Magick_png_read_raw_profile(ping,image,image_info,text,
3757 length=text[i].text_length;
3758 value=(char *) AcquireQuantumMemory(length+MaxTextExtent,
3760 if (value == (char *) NULL)
3762 png_error(ping,"Memory allocation failed");
3766 (void) ConcatenateMagickString(value,text[i].text,length+2);
3768 /* Don't save "density" or "units" property if we have a pHYs
3771 if (!png_get_valid(ping,ping_info,PNG_INFO_pHYs) ||
3772 (LocaleCompare(text[i].key,"density") != 0 &&
3773 LocaleCompare(text[i].key,"units") != 0))
3774 (void) SetImageProperty(image,text[i].key,value,exception);
3776 if (logging != MagickFalse)
3778 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3779 " length: %lu",(unsigned long) length);
3780 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3781 " Keyword: %s",text[i].key);
3784 value=DestroyString(value);
3787 num_text_total += num_text;
3790 #ifdef MNG_OBJECT_BUFFERS
3792 Store the object if necessary.
3794 if (object_id && !mng_info->frozen[object_id])
3796 if (mng_info->ob[object_id] == (MngBuffer *) NULL)
3799 create a new object buffer.
3801 mng_info->ob[object_id]=(MngBuffer *)
3802 AcquireMagickMemory(sizeof(MngBuffer));
3804 if (mng_info->ob[object_id] != (MngBuffer *) NULL)
3806 mng_info->ob[object_id]->image=(Image *) NULL;
3807 mng_info->ob[object_id]->reference_count=1;
3811 if ((mng_info->ob[object_id] == (MngBuffer *) NULL) ||
3812 mng_info->ob[object_id]->frozen)
3814 if (mng_info->ob[object_id] == (MngBuffer *) NULL)
3815 png_error(ping,"Memory allocation failed");
3817 if (mng_info->ob[object_id]->frozen)
3818 png_error(ping,"Cannot overwrite frozen MNG object buffer");
3824 if (mng_info->ob[object_id]->image != (Image *) NULL)
3825 mng_info->ob[object_id]->image=DestroyImage
3826 (mng_info->ob[object_id]->image);
3828 mng_info->ob[object_id]->image=CloneImage(image,0,0,MagickTrue,
3831 if (mng_info->ob[object_id]->image != (Image *) NULL)
3832 mng_info->ob[object_id]->image->file=(FILE *) NULL;
3835 png_error(ping, "Cloning image for object buffer failed");
3837 if (ping_width > 250000L || ping_height > 250000L)
3838 png_error(ping,"PNG Image dimensions are too large.");
3840 mng_info->ob[object_id]->width=ping_width;
3841 mng_info->ob[object_id]->height=ping_height;
3842 mng_info->ob[object_id]->color_type=ping_color_type;
3843 mng_info->ob[object_id]->sample_depth=ping_bit_depth;
3844 mng_info->ob[object_id]->interlace_method=ping_interlace_method;
3845 mng_info->ob[object_id]->compression_method=
3846 ping_compression_method;
3847 mng_info->ob[object_id]->filter_method=ping_filter_method;
3849 if (png_get_valid(ping,ping_info,PNG_INFO_PLTE))
3855 Copy the PLTE to the object buffer.
3857 png_get_PLTE(ping,ping_info,&plte,&number_colors);
3858 mng_info->ob[object_id]->plte_length=number_colors;
3860 for (i=0; i < number_colors; i++)
3862 mng_info->ob[object_id]->plte[i]=plte[i];
3867 mng_info->ob[object_id]->plte_length=0;
3872 /* Set image->alpha_trait to MagickTrue if the input colortype supports
3873 * alpha or if a valid tRNS chunk is present, no matter whether there
3874 * is actual transparency present.
3876 image->alpha_trait=(((int) ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA) ||
3877 ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) ||
3878 (png_get_valid(ping,ping_info,PNG_INFO_tRNS))) ?
3879 BlendPixelTrait : UndefinedPixelTrait;
3881 #if 0 /* I'm not sure what's wrong here but it does not work. */
3882 if (image->alpha_trait == BlendPixelTrait)
3884 if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
3885 (void) SetImageType(image,GrayscaleMatteType,exception);
3887 else if (ping_color_type == PNG_COLOR_TYPE_PALETTE)
3888 (void) SetImageType(image,PaletteMatteType,exception);
3891 (void) SetImageType(image,TrueColorMatteType,exception);
3896 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
3897 (void) SetImageType(image,GrayscaleType,exception);
3899 else if (ping_color_type == PNG_COLOR_TYPE_PALETTE)
3900 (void) SetImageType(image,PaletteType,exception);
3903 (void) SetImageType(image,TrueColorType,exception);
3907 /* Set more properties for identify to retrieve */
3912 if (num_text_total != 0)
3914 /* libpng doesn't tell us whether they were tEXt, zTXt, or iTXt */
3915 (void) FormatLocaleString(msg,MaxTextExtent,
3916 "%d tEXt/zTXt/iTXt chunks were found", num_text_total);
3917 (void) SetImageProperty(image,"png:text",msg,
3921 if (num_raw_profiles != 0)
3923 (void) FormatLocaleString(msg,MaxTextExtent,
3924 "%d were found", num_raw_profiles);
3925 (void) SetImageProperty(image,"png:text-encoded profiles",msg,
3929 if (ping_found_cHRM != MagickFalse)
3931 (void) FormatLocaleString(msg,MaxTextExtent,"%s",
3932 "chunk was found (see Chromaticity, above)");
3933 (void) SetImageProperty(image,"png:cHRM",msg,
3937 if (png_get_valid(ping,ping_info,PNG_INFO_bKGD))
3939 (void) FormatLocaleString(msg,MaxTextExtent,"%s",
3940 "chunk was found (see Background color, above)");
3941 (void) SetImageProperty(image,"png:bKGD",msg,
3945 (void) FormatLocaleString(msg,MaxTextExtent,"%s",
3948 #if defined(PNG_iCCP_SUPPORTED)
3949 if (ping_found_iCCP != MagickFalse)
3950 (void) SetImageProperty(image,"png:iCCP",msg,
3954 if (png_get_valid(ping,ping_info,PNG_INFO_tRNS))
3955 (void) SetImageProperty(image,"png:tRNS",msg,
3958 #if defined(PNG_sRGB_SUPPORTED)
3959 if (ping_found_sRGB != MagickFalse)
3961 (void) FormatLocaleString(msg,MaxTextExtent,
3964 Magick_RenderingIntentString_from_PNG_RenderingIntent(intent));
3965 (void) SetImageProperty(image,"png:sRGB",msg,
3970 if (ping_found_gAMA != MagickFalse)
3972 (void) FormatLocaleString(msg,MaxTextExtent,
3973 "gamma=%.8g (See Gamma, above)",
3975 (void) SetImageProperty(image,"png:gAMA",msg,
3979 #if defined(PNG_pHYs_SUPPORTED)
3980 if (png_get_valid(ping,ping_info,PNG_INFO_pHYs))
3982 (void) FormatLocaleString(msg,MaxTextExtent,
3983 "x_res=%.10g, y_res=%.10g, units=%d",
3984 (double) x_resolution,(double) y_resolution, unit_type);
3985 (void) SetImageProperty(image,"png:pHYs",msg,
3990 #if defined(PNG_oFFs_SUPPORTED)
3991 if (png_get_valid(ping,ping_info,PNG_INFO_oFFs))
3993 (void) FormatLocaleString(msg,MaxTextExtent,"x_off=%.20g, y_off=%.20g",
3994 (double) image->page.x,(double) image->page.y);
3995 (void) SetImageProperty(image,"png:oFFs",msg,
4000 if ((image->page.width != 0 && image->page.width != image->columns) ||
4001 (image->page.height != 0 && image->page.height != image->rows))
4003 (void) FormatLocaleString(msg,MaxTextExtent,
4004 "width=%.20g, height=%.20g",
4005 (double) image->page.width,(double) image->page.height);
4006 (void) SetImageProperty(image,"png:vpAg",msg,
4012 Relinquish resources.
4014 png_destroy_read_struct(&ping,&ping_info,&end_info);
4016 pixel_info=RelinquishVirtualMemory(pixel_info);
4018 if (logging != MagickFalse)
4019 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4020 " exit ReadOnePNGImage()");
4022 #ifdef IMPNG_SETJMP_NOT_THREAD_SAFE
4023 UnlockSemaphoreInfo(ping_semaphore);
4026 /* } for navigation to beginning of SETJMP-protected block, revert to
4027 * Throwing an Exception when an error occurs.
4032 /* end of reading one PNG image */
4035 static Image *ReadPNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
4050 magic_number[MaxTextExtent];
4058 assert(image_info != (const ImageInfo *) NULL);
4059 assert(image_info->signature == MagickSignature);
4061 if (image_info->debug != MagickFalse)
4062 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4063 image_info->filename);
4065 assert(exception != (ExceptionInfo *) NULL);
4066 assert(exception->signature == MagickSignature);
4067 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter ReadPNGImage()");
4068 image=AcquireImage(image_info,exception);
4069 mng_info=(MngInfo *) NULL;
4070 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
4072 if (status == MagickFalse)
4073 ThrowReaderException(FileOpenError,"UnableToOpenFile");
4076 Verify PNG signature.
4078 count=ReadBlob(image,8,(unsigned char *) magic_number);
4080 if (count < 8 || memcmp(magic_number,"\211PNG\r\n\032\n",8) != 0)
4081 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
4084 Allocate a MngInfo structure.
4086 have_mng_structure=MagickFalse;
4087 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
4089 if (mng_info == (MngInfo *) NULL)
4090 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
4093 Initialize members of the MngInfo structure.
4095 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
4096 mng_info->image=image;
4097 have_mng_structure=MagickTrue;
4100 image=ReadOnePNGImage(mng_info,image_info,exception);
4101 MngInfoFreeStruct(mng_info,&have_mng_structure);
4103 if (image == (Image *) NULL)
4105 if (previous != (Image *) NULL)
4107 if (previous->signature != MagickSignature)
4108 ThrowReaderException(CorruptImageError,"CorruptImage");
4110 (void) CloseBlob(previous);
4111 (void) DestroyImageList(previous);
4114 if (logging != MagickFalse)
4115 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4116 "exit ReadPNGImage() with error");
4118 return((Image *) NULL);
4121 (void) CloseBlob(image);
4123 if ((image->columns == 0) || (image->rows == 0))
4125 if (logging != MagickFalse)
4126 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4127 "exit ReadPNGImage() with error.");
4129 ThrowReaderException(CorruptImageError,"CorruptImage");
4132 if ((IssRGBColorspace(image->colorspace) != MagickFalse) &&
4133 ((image->gamma < .45) || (image->gamma > .46)) &&
4134 !(image->chromaticity.red_primary.x>0.6399f &&
4135 image->chromaticity.red_primary.x<0.6401f &&
4136 image->chromaticity.red_primary.y>0.3299f &&
4137 image->chromaticity.red_primary.y<0.3301f &&
4138 image->chromaticity.green_primary.x>0.2999f &&
4139 image->chromaticity.green_primary.x<0.3001f &&
4140 image->chromaticity.green_primary.y>0.5999f &&
4141 image->chromaticity.green_primary.y<0.6001f &&
4142 image->chromaticity.blue_primary.x>0.1499f &&
4143 image->chromaticity.blue_primary.x<0.1501f &&
4144 image->chromaticity.blue_primary.y>0.0599f &&
4145 image->chromaticity.blue_primary.y<0.0601f &&
4146 image->chromaticity.white_point.x>0.3126f &&
4147 image->chromaticity.white_point.x<0.3128f &&
4148 image->chromaticity.white_point.y>0.3289f &&
4149 image->chromaticity.white_point.y<0.3291f))
4150 SetImageColorspace(image,RGBColorspace,exception);
4152 if (logging != MagickFalse)
4153 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4154 " page.w: %.20g, page.h: %.20g,page.x: %.20g, page.y: %.20g.",
4155 (double) image->page.width,(double) image->page.height,
4156 (double) image->page.x,(double) image->page.y);
4158 if (logging != MagickFalse)
4159 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit ReadPNGImage()");
4166 #if defined(JNG_SUPPORTED)
4168 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4172 % R e a d O n e J N G I m a g e %
4176 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4178 % ReadOneJNGImage() reads a JPEG Network Graphics (JNG) image file
4179 % (minus the 8-byte signature) and returns it. It allocates the memory
4180 % necessary for the new Image structure and returns a pointer to the new
4183 % JNG support written by Glenn Randers-Pehrson, glennrp@image...
4185 % The format of the ReadOneJNGImage method is:
4187 % Image *ReadOneJNGImage(MngInfo *mng_info, const ImageInfo *image_info,
4188 % ExceptionInfo *exception)
4190 % A description of each parameter follows:
4192 % o mng_info: Specifies a pointer to a MngInfo structure.
4194 % o image_info: the image info.
4196 % o exception: return any errors or warnings in this structure.
4199 static Image *ReadOneJNGImage(MngInfo *mng_info,
4200 const ImageInfo *image_info, ExceptionInfo *exception)
4227 jng_image_sample_depth,
4228 jng_image_compression_method,
4229 jng_image_interlace_method,
4230 jng_alpha_sample_depth,
4231 jng_alpha_compression_method,
4232 jng_alpha_filter_method,
4233 jng_alpha_interlace_method;
4235 register const Quantum
4245 register unsigned char
4256 jng_alpha_compression_method=0;
4257 jng_alpha_sample_depth=8;
4261 alpha_image=(Image *) NULL;
4262 color_image=(Image *) NULL;
4263 alpha_image_info=(ImageInfo *) NULL;
4264 color_image_info=(ImageInfo *) NULL;
4266 logging=LogMagickEvent(CoderEvent,GetMagickModule(),
4267 " Enter ReadOneJNGImage()");
4269 image=mng_info->image;
4271 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
4274 Allocate next image structure.
4276 if (logging != MagickFalse)
4277 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4278 " AcquireNextImage()");
4280 AcquireNextImage(image_info,image,exception);
4282 if (GetNextImageInList(image) == (Image *) NULL)
4283 return((Image *) NULL);
4285 image=SyncNextImageInList(image);
4287 mng_info->image=image;
4290 Signature bytes have already been read.
4293 read_JSEP=MagickFalse;
4294 reading_idat=MagickFalse;
4295 skip_to_iend=MagickFalse;
4299 type[MaxTextExtent];
4308 Read a new JNG chunk.
4310 status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
4311 2*GetBlobSize(image));
4313 if (status == MagickFalse)
4317 (void) ConcatenateMagickString(type,"errr",MaxTextExtent);
4318 length=ReadBlobMSBLong(image);
4319 count=(unsigned int) ReadBlob(image,4,(unsigned char *) type);
4321 if (logging != MagickFalse)
4322 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4323 " Reading JNG chunk type %c%c%c%c, length: %.20g",
4324 type[0],type[1],type[2],type[3],(double) length);
4326 if (length > PNG_UINT_31_MAX || count == 0)
4327 ThrowReaderException(CorruptImageError,"CorruptImage");
4330 chunk=(unsigned char *) NULL;
4334 chunk=(unsigned char *) AcquireQuantumMemory(length,sizeof(*chunk));
4336 if (chunk == (unsigned char *) NULL)
4337 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
4339 for (i=0; i < (ssize_t) length; i++)
4340 chunk[i]=(unsigned char) ReadBlobByte(image);
4345 (void) ReadBlobMSBLong(image); /* read crc word */
4350 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4355 if (memcmp(type,mng_JHDR,4) == 0)
4359 jng_width=(size_t) ((p[0] << 24) | (p[1] << 16) |
4360 (p[2] << 8) | p[3]);
4361 jng_height=(size_t) ((p[4] << 24) | (p[5] << 16) |
4362 (p[6] << 8) | p[7]);
4363 jng_color_type=p[8];
4364 jng_image_sample_depth=p[9];
4365 jng_image_compression_method=p[10];
4366 jng_image_interlace_method=p[11];
4368 image->interlace=jng_image_interlace_method != 0 ? PNGInterlace :
4371 jng_alpha_sample_depth=p[12];
4372 jng_alpha_compression_method=p[13];
4373 jng_alpha_filter_method=p[14];
4374 jng_alpha_interlace_method=p[15];
4376 if (logging != MagickFalse)
4378 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4379 " jng_width: %16lu",(unsigned long) jng_width);
4381 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4382 " jng_width: %16lu",(unsigned long) jng_height);
4384 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4385 " jng_color_type: %16d",jng_color_type);
4387 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4388 " jng_image_sample_depth: %3d",
4389 jng_image_sample_depth);
4391 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4392 " jng_image_compression_method:%3d",
4393 jng_image_compression_method);
4395 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4396 " jng_image_interlace_method: %3d",
4397 jng_image_interlace_method);
4399 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4400 " jng_alpha_sample_depth: %3d",
4401 jng_alpha_sample_depth);
4403 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4404 " jng_alpha_compression_method:%3d",
4405 jng_alpha_compression_method);
4407 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4408 " jng_alpha_filter_method: %3d",
4409 jng_alpha_filter_method);
4411 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4412 " jng_alpha_interlace_method: %3d",
4413 jng_alpha_interlace_method);
4418 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4424 if ((reading_idat == MagickFalse) && (read_JSEP == MagickFalse) &&
4425 ((memcmp(type,mng_JDAT,4) == 0) || (memcmp(type,mng_JdAA,4) == 0) ||
4426 (memcmp(type,mng_IDAT,4) == 0) || (memcmp(type,mng_JDAA,4) == 0)))
4429 o create color_image
4430 o open color_blob, attached to color_image
4431 o if (color type has alpha)
4432 open alpha_blob, attached to alpha_image
4435 color_image_info=(ImageInfo *)AcquireMagickMemory(sizeof(ImageInfo));
4437 if (color_image_info == (ImageInfo *) NULL)
4438 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
4440 GetImageInfo(color_image_info);
4441 color_image=AcquireImage(color_image_info,exception);
4443 if (color_image == (Image *) NULL)
4444 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
4446 if (logging != MagickFalse)
4447 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4448 " Creating color_blob.");
4450 (void) AcquireUniqueFilename(color_image->filename);
4451 status=OpenBlob(color_image_info,color_image,WriteBinaryBlobMode,
4454 if (status == MagickFalse)
4455 return((Image *) NULL);
4457 if ((image_info->ping == MagickFalse) && (jng_color_type >= 12))
4459 alpha_image_info=(ImageInfo *)
4460 AcquireMagickMemory(sizeof(ImageInfo));
4462 if (alpha_image_info == (ImageInfo *) NULL)
4463 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
4465 GetImageInfo(alpha_image_info);
4466 alpha_image=AcquireImage(alpha_image_info,exception);
4468 if (alpha_image == (Image *) NULL)
4470 alpha_image=DestroyImage(alpha_image);
4471 ThrowReaderException(ResourceLimitError,
4472 "MemoryAllocationFailed");
4475 if (logging != MagickFalse)
4476 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4477 " Creating alpha_blob.");
4479 (void) AcquireUniqueFilename(alpha_image->filename);
4480 status=OpenBlob(alpha_image_info,alpha_image,WriteBinaryBlobMode,
4483 if (status == MagickFalse)
4484 return((Image *) NULL);
4486 if (jng_alpha_compression_method == 0)
4491 if (logging != MagickFalse)
4492 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4493 " Writing IHDR chunk to alpha_blob.");
4495 (void) WriteBlob(alpha_image,8,(const unsigned char *)
4496 "\211PNG\r\n\032\n");
4498 (void) WriteBlobMSBULong(alpha_image,13L);
4499 PNGType(data,mng_IHDR);
4500 LogPNGChunk(logging,mng_IHDR,13L);
4501 PNGLong(data+4,jng_width);
4502 PNGLong(data+8,jng_height);
4503 data[12]=jng_alpha_sample_depth;
4504 data[13]=0; /* color_type gray */
4505 data[14]=0; /* compression method 0 */
4506 data[15]=0; /* filter_method 0 */
4507 data[16]=0; /* interlace_method 0 */
4508 (void) WriteBlob(alpha_image,17,data);
4509 (void) WriteBlobMSBULong(alpha_image,crc32(0,data,17));
4512 reading_idat=MagickTrue;
4515 if (memcmp(type,mng_JDAT,4) == 0)
4517 /* Copy chunk to color_image->blob */
4519 if (logging != MagickFalse)
4520 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4521 " Copying JDAT chunk data to color_blob.");
4523 (void) WriteBlob(color_image,length,chunk);
4526 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4531 if (memcmp(type,mng_IDAT,4) == 0)
4536 /* Copy IDAT header and chunk data to alpha_image->blob */
4538 if (image_info->ping == MagickFalse)
4540 if (logging != MagickFalse)
4541 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4542 " Copying IDAT chunk data to alpha_blob.");
4544 (void) WriteBlobMSBULong(alpha_image,(size_t) length);
4545 PNGType(data,mng_IDAT);
4546 LogPNGChunk(logging,mng_IDAT,length);
4547 (void) WriteBlob(alpha_image,4,data);
4548 (void) WriteBlob(alpha_image,length,chunk);
4549 (void) WriteBlobMSBULong(alpha_image,
4550 crc32(crc32(0,data,4),chunk,(uInt) length));
4554 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4559 if ((memcmp(type,mng_JDAA,4) == 0) || (memcmp(type,mng_JdAA,4) == 0))
4561 /* Copy chunk data to alpha_image->blob */
4563 if (image_info->ping == MagickFalse)
4565 if (logging != MagickFalse)
4566 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4567 " Copying JDAA chunk data to alpha_blob.");
4569 (void) WriteBlob(alpha_image,length,chunk);
4573 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4578 if (memcmp(type,mng_JSEP,4) == 0)
4580 read_JSEP=MagickTrue;
4583 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4588 if (memcmp(type,mng_bKGD,4) == 0)
4592 image->background_color.red=ScaleCharToQuantum(p[1]);
4593 image->background_color.green=image->background_color.red;
4594 image->background_color.blue=image->background_color.red;
4599 image->background_color.red=ScaleCharToQuantum(p[1]);
4600 image->background_color.green=ScaleCharToQuantum(p[3]);
4601 image->background_color.blue=ScaleCharToQuantum(p[5]);
4604 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4608 if (memcmp(type,mng_gAMA,4) == 0)
4611 image->gamma=((float) mng_get_long(p))*0.00001;
4613 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4617 if (memcmp(type,mng_cHRM,4) == 0)
4621 image->chromaticity.white_point.x=0.00001*mng_get_long(p);
4622 image->chromaticity.white_point.y=0.00001*mng_get_long(&p[4]);
4623 image->chromaticity.red_primary.x=0.00001*mng_get_long(&p[8]);
4624 image->chromaticity.red_primary.y=0.00001*mng_get_long(&p[12]);
4625 image->chromaticity.green_primary.x=0.00001*mng_get_long(&p[16]);
4626 image->chromaticity.green_primary.y=0.00001*mng_get_long(&p[20]);
4627 image->chromaticity.blue_primary.x=0.00001*mng_get_long(&p[24]);
4628 image->chromaticity.blue_primary.y=0.00001*mng_get_long(&p[28]);
4631 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4635 if (memcmp(type,mng_sRGB,4) == 0)
4639 image->rendering_intent=
4640 Magick_RenderingIntent_from_PNG_RenderingIntent(p[0]);
4641 image->gamma=1.000f/2.200f;
4642 image->chromaticity.red_primary.x=0.6400f;
4643 image->chromaticity.red_primary.y=0.3300f;
4644 image->chromaticity.green_primary.x=0.3000f;
4645 image->chromaticity.green_primary.y=0.6000f;
4646 image->chromaticity.blue_primary.x=0.1500f;
4647 image->chromaticity.blue_primary.y=0.0600f;
4648 image->chromaticity.white_point.x=0.3127f;
4649 image->chromaticity.white_point.y=0.3290f;
4652 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4656 if (memcmp(type,mng_oFFs,4) == 0)
4660 image->page.x=(ssize_t) mng_get_long(p);
4661 image->page.y=(ssize_t) mng_get_long(&p[4]);
4663 if ((int) p[8] != 0)
4665 image->page.x/=10000;
4666 image->page.y/=10000;
4671 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4676 if (memcmp(type,mng_pHYs,4) == 0)
4680 image->resolution.x=(double) mng_get_long(p);
4681 image->resolution.y=(double) mng_get_long(&p[4]);
4682 if ((int) p[8] == PNG_RESOLUTION_METER)
4684 image->units=PixelsPerCentimeterResolution;
4685 image->resolution.x=image->resolution.x/100.0f;
4686 image->resolution.y=image->resolution.y/100.0f;
4690 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4695 if (memcmp(type,mng_iCCP,4) == 0)
4699 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4706 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4708 if (memcmp(type,mng_IEND,4))
4718 Finish up reading image data:
4720 o read main image from color_blob.
4724 o if (color_type has alpha)
4725 if alpha_encoding is PNG
4726 read secondary image from alpha_blob via ReadPNG
4727 if alpha_encoding is JPEG
4728 read secondary image from alpha_blob via ReadJPEG
4732 o copy intensity of secondary image into
4733 alpha samples of main image.
4735 o destroy the secondary image.
4738 (void) CloseBlob(color_image);
4740 if (logging != MagickFalse)
4741 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4742 " Reading jng_image from color_blob.");
4744 assert(color_image_info != (ImageInfo *) NULL);
4745 (void) FormatLocaleString(color_image_info->filename,MaxTextExtent,"%s",
4746 color_image->filename);
4748 color_image_info->ping=MagickFalse; /* To do: avoid this */
4749 jng_image=ReadImage(color_image_info,exception);
4751 if (jng_image == (Image *) NULL)
4752 return((Image *) NULL);
4754 (void) RelinquishUniqueFileResource(color_image->filename);
4755 color_image=DestroyImage(color_image);
4756 color_image_info=DestroyImageInfo(color_image_info);
4758 if (jng_image == (Image *) NULL)
4759 return((Image *) NULL);
4761 if (logging != MagickFalse)
4762 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4763 " Copying jng_image pixels to main image.");
4765 image->rows=jng_height;
4766 image->columns=jng_width;
4768 for (y=0; y < (ssize_t) image->rows; y++)
4770 s=GetVirtualPixels(jng_image,0,y,image->columns,1,exception);
4771 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
4772 for (x=(ssize_t) image->columns; x != 0; x--)
4774 SetPixelRed(image,GetPixelRed(jng_image,s),q);
4775 SetPixelGreen(image,GetPixelGreen(jng_image,s),q);
4776 SetPixelBlue(image,GetPixelBlue(jng_image,s),q);
4777 q+=GetPixelChannels(image);
4778 s+=GetPixelChannels(jng_image);
4781 if (SyncAuthenticPixels(image,exception) == MagickFalse)
4785 jng_image=DestroyImage(jng_image);
4787 if (image_info->ping == MagickFalse)
4789 if (jng_color_type >= 12)
4791 if (jng_alpha_compression_method == 0)
4795 (void) WriteBlobMSBULong(alpha_image,0x00000000L);
4796 PNGType(data,mng_IEND);
4797 LogPNGChunk(logging,mng_IEND,0L);
4798 (void) WriteBlob(alpha_image,4,data);
4799 (void) WriteBlobMSBULong(alpha_image,crc32(0,data,4));
4802 (void) CloseBlob(alpha_image);
4804 if (logging != MagickFalse)
4805 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4806 " Reading alpha from alpha_blob.");
4808 (void) FormatLocaleString(alpha_image_info->filename,MaxTextExtent,
4809 "%s",alpha_image->filename);
4811 jng_image=ReadImage(alpha_image_info,exception);
4813 if (jng_image != (Image *) NULL)
4814 for (y=0; y < (ssize_t) image->rows; y++)
4816 s=GetVirtualPixels(jng_image,0,y,image->columns,1,
4818 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
4820 if (image->alpha_trait == BlendPixelTrait)
4821 for (x=(ssize_t) image->columns; x != 0; x--)
4823 SetPixelAlpha(image,GetPixelRed(jng_image,s),q);
4824 q+=GetPixelChannels(image);
4825 s+=GetPixelChannels(jng_image);
4829 for (x=(ssize_t) image->columns; x != 0; x--)
4831 SetPixelAlpha(image,GetPixelRed(jng_image,s),q);
4832 if (GetPixelAlpha(image,q) != OpaqueAlpha)
4833 image->alpha_trait=BlendPixelTrait;
4834 q+=GetPixelChannels(image);
4835 s+=GetPixelChannels(jng_image);
4838 if (SyncAuthenticPixels(image,exception) == MagickFalse)
4841 (void) RelinquishUniqueFileResource(alpha_image->filename);
4842 alpha_image=DestroyImage(alpha_image);
4843 alpha_image_info=DestroyImageInfo(alpha_image_info);
4844 if (jng_image != (Image *) NULL)
4845 jng_image=DestroyImage(jng_image);
4849 /* Read the JNG image. */
4851 if (mng_info->mng_type == 0)
4853 mng_info->mng_width=jng_width;
4854 mng_info->mng_height=jng_height;
4857 if (image->page.width == 0 && image->page.height == 0)
4859 image->page.width=jng_width;
4860 image->page.height=jng_height;
4863 if (image->page.x == 0 && image->page.y == 0)
4865 image->page.x=mng_info->x_off[mng_info->object_id];
4866 image->page.y=mng_info->y_off[mng_info->object_id];
4871 image->page.y=mng_info->y_off[mng_info->object_id];
4874 mng_info->image_found++;
4875 status=SetImageProgress(image,LoadImagesTag,2*TellBlob(image),
4876 2*GetBlobSize(image));
4878 if (logging != MagickFalse)
4879 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4880 " exit ReadOneJNGImage()");
4886 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4890 % R e a d J N G I m a g e %
4894 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4896 % ReadJNGImage() reads a JPEG Network Graphics (JNG) image file
4897 % (including the 8-byte signature) and returns it. It allocates the memory
4898 % necessary for the new Image structure and returns a pointer to the new
4901 % JNG support written by Glenn Randers-Pehrson, glennrp@image...
4903 % The format of the ReadJNGImage method is:
4905 % Image *ReadJNGImage(const ImageInfo *image_info, ExceptionInfo
4908 % A description of each parameter follows:
4910 % o image_info: the image info.
4912 % o exception: return any errors or warnings in this structure.
4916 static Image *ReadJNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
4931 magic_number[MaxTextExtent];
4939 assert(image_info != (const ImageInfo *) NULL);
4940 assert(image_info->signature == MagickSignature);
4941 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image_info->filename);
4942 assert(exception != (ExceptionInfo *) NULL);
4943 assert(exception->signature == MagickSignature);
4944 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter ReadJNGImage()");
4945 image=AcquireImage(image_info,exception);
4946 mng_info=(MngInfo *) NULL;
4947 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
4949 if (status == MagickFalse)
4950 return((Image *) NULL);
4952 if (LocaleCompare(image_info->magick,"JNG") != 0)
4953 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
4955 /* Verify JNG signature. */
4957 count=(size_t) ReadBlob(image,8,(unsigned char *) magic_number);
4959 if (count < 8 || memcmp(magic_number,"\213JNG\r\n\032\n",8) != 0)
4960 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
4962 /* Allocate a MngInfo structure. */
4964 have_mng_structure=MagickFalse;
4965 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(*mng_info));
4967 if (mng_info == (MngInfo *) NULL)
4968 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
4970 /* Initialize members of the MngInfo structure. */
4972 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
4973 have_mng_structure=MagickTrue;
4975 mng_info->image=image;
4977 image=ReadOneJNGImage(mng_info,image_info,exception);
4978 MngInfoFreeStruct(mng_info,&have_mng_structure);
4980 if (image == (Image *) NULL)
4982 if (IsImageObject(previous) != MagickFalse)
4984 (void) CloseBlob(previous);
4985 (void) DestroyImageList(previous);
4988 if (logging != MagickFalse)
4989 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4990 "exit ReadJNGImage() with error");
4992 return((Image *) NULL);
4994 (void) CloseBlob(image);
4996 if (image->columns == 0 || image->rows == 0)
4998 if (logging != MagickFalse)
4999 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5000 "exit ReadJNGImage() with error");
5002 ThrowReaderException(CorruptImageError,"CorruptImage");
5005 if (logging != MagickFalse)
5006 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit ReadJNGImage()");
5012 static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
5015 page_geometry[MaxTextExtent];
5048 #if defined(MNG_INSERT_LAYERS)
5050 mng_background_color;
5053 register unsigned char
5068 #if defined(MNG_INSERT_LAYERS)
5073 volatile unsigned int
5074 #ifdef MNG_OBJECT_BUFFERS
5075 mng_background_object=0,
5077 mng_type=0; /* 0: PNG or JNG; 1: MNG; 2: MNG-LC; 3: MNG-VLC */
5080 default_frame_timeout,
5082 #if defined(MNG_INSERT_LAYERS)
5088 /* These delays are all measured in image ticks_per_second,
5089 * not in MNG ticks_per_second
5092 default_frame_delay,
5096 #if defined(MNG_INSERT_LAYERS)
5105 previous_fb.bottom=0;
5107 previous_fb.right=0;
5109 default_fb.bottom=0;
5113 /* Open image file. */
5115 assert(image_info != (const ImageInfo *) NULL);
5116 assert(image_info->signature == MagickSignature);
5117 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image_info->filename);
5118 assert(exception != (ExceptionInfo *) NULL);
5119 assert(exception->signature == MagickSignature);
5120 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter ReadMNGImage()");
5121 image=AcquireImage(image_info,exception);
5122 mng_info=(MngInfo *) NULL;
5123 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
5125 if (status == MagickFalse)
5126 return((Image *) NULL);
5128 first_mng_object=MagickFalse;
5130 have_mng_structure=MagickFalse;
5132 /* Allocate a MngInfo structure. */
5134 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
5136 if (mng_info == (MngInfo *) NULL)
5137 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
5139 /* Initialize members of the MngInfo structure. */
5141 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
5142 mng_info->image=image;
5143 have_mng_structure=MagickTrue;
5145 if (LocaleCompare(image_info->magick,"MNG") == 0)
5148 magic_number[MaxTextExtent];
5150 /* Verify MNG signature. */
5151 count=(size_t) ReadBlob(image,8,(unsigned char *) magic_number);
5152 if (memcmp(magic_number,"\212MNG\r\n\032\n",8) != 0)
5153 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
5155 /* Initialize some nonzero members of the MngInfo structure. */
5156 for (i=0; i < MNG_MAX_OBJECTS; i++)
5158 mng_info->object_clip[i].right=(ssize_t) PNG_UINT_31_MAX;
5159 mng_info->object_clip[i].bottom=(ssize_t) PNG_UINT_31_MAX;
5161 mng_info->exists[0]=MagickTrue;
5164 first_mng_object=MagickTrue;
5166 #if defined(MNG_INSERT_LAYERS)
5167 insert_layers=MagickFalse; /* should be False when converting or mogrifying */
5169 default_frame_delay=0;
5170 default_frame_timeout=0;
5173 mng_info->ticks_per_second=1UL*image->ticks_per_second;
5175 skip_to_iend=MagickFalse;
5176 term_chunk_found=MagickFalse;
5177 mng_info->framing_mode=1;
5178 #if defined(MNG_INSERT_LAYERS)
5179 mandatory_back=MagickFalse;
5181 #if defined(MNG_INSERT_LAYERS)
5182 mng_background_color=image->background_color;
5184 default_fb=mng_info->frame;
5185 previous_fb=mng_info->frame;
5189 type[MaxTextExtent];
5191 if (LocaleCompare(image_info->magick,"MNG") == 0)
5200 (void) ConcatenateMagickString(type,"errr",MaxTextExtent);
5201 length=ReadBlobMSBLong(image);
5202 count=(size_t) ReadBlob(image,4,(unsigned char *) type);
5204 if (logging != MagickFalse)
5205 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5206 " Reading MNG chunk type %c%c%c%c, length: %.20g",
5207 type[0],type[1],type[2],type[3],(double) length);
5209 if (length > PNG_UINT_31_MAX)
5213 ThrowReaderException(CorruptImageError,"CorruptImage");
5216 chunk=(unsigned char *) NULL;
5220 chunk=(unsigned char *) AcquireQuantumMemory(length,sizeof(*chunk));
5222 if (chunk == (unsigned char *) NULL)
5223 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
5225 for (i=0; i < (ssize_t) length; i++)
5226 chunk[i]=(unsigned char) ReadBlobByte(image);
5231 (void) ReadBlobMSBLong(image); /* read crc word */
5233 #if !defined(JNG_SUPPORTED)
5234 if (memcmp(type,mng_JHDR,4) == 0)
5236 skip_to_iend=MagickTrue;
5238 if (mng_info->jhdr_warning == 0)
5239 (void) ThrowMagickException(exception,GetMagickModule(),
5240 CoderError,"JNGCompressNotSupported","`%s'",image->filename);
5242 mng_info->jhdr_warning++;
5245 if (memcmp(type,mng_DHDR,4) == 0)
5247 skip_to_iend=MagickTrue;
5249 if (mng_info->dhdr_warning == 0)
5250 (void) ThrowMagickException(exception,GetMagickModule(),
5251 CoderError,"DeltaPNGNotSupported","`%s'",image->filename);
5253 mng_info->dhdr_warning++;
5255 if (memcmp(type,mng_MEND,4) == 0)
5260 if (memcmp(type,mng_IEND,4) == 0)
5261 skip_to_iend=MagickFalse;
5264 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5266 if (logging != MagickFalse)
5267 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5273 if (memcmp(type,mng_MHDR,4) == 0)
5275 mng_info->mng_width=(size_t) ((p[0] << 24) | (p[1] << 16) |
5276 (p[2] << 8) | p[3]);
5278 mng_info->mng_height=(size_t) ((p[4] << 24) | (p[5] << 16) |
5279 (p[6] << 8) | p[7]);
5281 if (logging != MagickFalse)
5283 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5284 " MNG width: %.20g",(double) mng_info->mng_width);
5285 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5286 " MNG height: %.20g",(double) mng_info->mng_height);
5290 mng_info->ticks_per_second=(size_t) mng_get_long(p);
5292 if (mng_info->ticks_per_second == 0)
5293 default_frame_delay=0;
5296 default_frame_delay=1UL*image->ticks_per_second/
5297 mng_info->ticks_per_second;
5299 frame_delay=default_frame_delay;
5305 simplicity=(size_t) mng_get_long(p);
5308 mng_type=1; /* Full MNG */
5310 if ((simplicity != 0) && ((simplicity | 11) == 11))
5311 mng_type=2; /* LC */
5313 if ((simplicity != 0) && ((simplicity | 9) == 9))
5314 mng_type=3; /* VLC */
5316 #if defined(MNG_INSERT_LAYERS)
5318 insert_layers=MagickTrue;
5320 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
5322 /* Allocate next image structure. */
5323 AcquireNextImage(image_info,image,exception);
5325 if (GetNextImageInList(image) == (Image *) NULL)
5326 return((Image *) NULL);
5328 image=SyncNextImageInList(image);
5329 mng_info->image=image;
5332 if ((mng_info->mng_width > 65535L) ||
5333 (mng_info->mng_height > 65535L))
5334 ThrowReaderException(ImageError,"WidthOrHeightExceedsLimit");
5336 (void) FormatLocaleString(page_geometry,MaxTextExtent,
5337 "%.20gx%.20g+0+0",(double) mng_info->mng_width,(double)
5338 mng_info->mng_height);
5340 mng_info->frame.left=0;
5341 mng_info->frame.right=(ssize_t) mng_info->mng_width;
5342 mng_info->frame.top=0;
5343 mng_info->frame.bottom=(ssize_t) mng_info->mng_height;
5344 mng_info->clip=default_fb=previous_fb=mng_info->frame;
5346 for (i=0; i < MNG_MAX_OBJECTS; i++)
5347 mng_info->object_clip[i]=mng_info->frame;
5349 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5353 if (memcmp(type,mng_TERM,4) == 0)
5364 final_delay=(png_uint_32) mng_get_long(&p[2]);
5365 mng_iterations=(png_uint_32) mng_get_long(&p[6]);
5367 if (mng_iterations == PNG_UINT_31_MAX)
5370 image->iterations=mng_iterations;
5371 term_chunk_found=MagickTrue;
5374 if (logging != MagickFalse)
5376 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5377 " repeat=%d",repeat);
5379 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5380 " final_delay=%.20g",(double) final_delay);
5382 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5383 " image->iterations=%.20g",(double) image->iterations);
5386 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5389 if (memcmp(type,mng_DEFI,4) == 0)
5392 (void) ThrowMagickException(exception,GetMagickModule(),
5393 CoderError,"DEFI chunk found in MNG-VLC datastream","`%s'",
5396 object_id=(p[0] << 8) | p[1];
5398 if (mng_type == 2 && object_id != 0)
5399 (void) ThrowMagickException(exception,GetMagickModule(),
5400 CoderError,"Nonzero object_id in MNG-LC datastream","`%s'",
5403 if (object_id > MNG_MAX_OBJECTS)
5406 Instead of using a warning we should allocate a larger
5407 MngInfo structure and continue.
5409 (void) ThrowMagickException(exception,GetMagickModule(),
5410 CoderError,"object id too large","`%s'",image->filename);
5411 object_id=MNG_MAX_OBJECTS;
5414 if (mng_info->exists[object_id])
5415 if (mng_info->frozen[object_id])
5417 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5418 (void) ThrowMagickException(exception,
5419 GetMagickModule(),CoderError,
5420 "DEFI cannot redefine a frozen MNG object","`%s'",
5425 mng_info->exists[object_id]=MagickTrue;
5428 mng_info->invisible[object_id]=p[2];
5431 Extract object offset info.
5435 mng_info->x_off[object_id]=(ssize_t) ((p[4] << 24) |
5436 (p[5] << 16) | (p[6] << 8) | p[7]);
5438 mng_info->y_off[object_id]=(ssize_t) ((p[8] << 24) |
5439 (p[9] << 16) | (p[10] << 8) | p[11]);
5441 if (logging != MagickFalse)
5443 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5444 " x_off[%d]: %.20g",object_id,(double)
5445 mng_info->x_off[object_id]);
5447 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5448 " y_off[%d]: %.20g",object_id,(double)
5449 mng_info->y_off[object_id]);
5454 Extract object clipping info.
5457 mng_info->object_clip[object_id]=mng_read_box(mng_info->frame,0,
5460 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5463 if (memcmp(type,mng_bKGD,4) == 0)
5465 mng_info->have_global_bkgd=MagickFalse;
5469 mng_info->mng_global_bkgd.red=
5470 ScaleShortToQuantum((unsigned short) ((p[0] << 8) | p[1]));
5472 mng_info->mng_global_bkgd.green=
5473 ScaleShortToQuantum((unsigned short) ((p[2] << 8) | p[3]));
5475 mng_info->mng_global_bkgd.blue=
5476 ScaleShortToQuantum((unsigned short) ((p[4] << 8) | p[5]));
5478 mng_info->have_global_bkgd=MagickTrue;
5481 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5484 if (memcmp(type,mng_BACK,4) == 0)
5486 #if defined(MNG_INSERT_LAYERS)
5488 mandatory_back=p[6];
5493 if (mandatory_back && length > 5)
5495 mng_background_color.red=
5496 ScaleShortToQuantum((unsigned short) ((p[0] << 8) | p[1]));
5498 mng_background_color.green=
5499 ScaleShortToQuantum((unsigned short) ((p[2] << 8) | p[3]));
5501 mng_background_color.blue=
5502 ScaleShortToQuantum((unsigned short) ((p[4] << 8) | p[5]));
5504 mng_background_color.alpha=OpaqueAlpha;
5507 #ifdef MNG_OBJECT_BUFFERS
5509 mng_background_object=(p[7] << 8) | p[8];
5512 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5516 if (memcmp(type,mng_PLTE,4) == 0)
5518 /* Read global PLTE. */
5520 if (length && (length < 769))
5522 if (mng_info->global_plte == (png_colorp) NULL)
5523 mng_info->global_plte=(png_colorp) AcquireQuantumMemory(256,
5524 sizeof(*mng_info->global_plte));
5526 for (i=0; i < (ssize_t) (length/3); i++)
5528 mng_info->global_plte[i].red=p[3*i];
5529 mng_info->global_plte[i].green=p[3*i+1];
5530 mng_info->global_plte[i].blue=p[3*i+2];
5533 mng_info->global_plte_length=(unsigned int) (length/3);
5536 for ( ; i < 256; i++)
5538 mng_info->global_plte[i].red=i;
5539 mng_info->global_plte[i].green=i;
5540 mng_info->global_plte[i].blue=i;
5544 mng_info->global_plte_length=256;
5547 mng_info->global_plte_length=0;
5549 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5553 if (memcmp(type,mng_tRNS,4) == 0)
5555 /* read global tRNS */
5558 for (i=0; i < (ssize_t) length; i++)
5559 mng_info->global_trns[i]=p[i];
5562 for ( ; i < 256; i++)
5563 mng_info->global_trns[i]=255;
5565 mng_info->global_trns_length=(unsigned int) length;
5566 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5569 if (memcmp(type,mng_gAMA,4) == 0)
5576 igamma=mng_get_long(p);
5577 mng_info->global_gamma=((float) igamma)*0.00001;
5578 mng_info->have_global_gama=MagickTrue;
5582 mng_info->have_global_gama=MagickFalse;
5584 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5588 if (memcmp(type,mng_cHRM,4) == 0)
5590 /* Read global cHRM */
5594 mng_info->global_chrm.white_point.x=0.00001*mng_get_long(p);
5595 mng_info->global_chrm.white_point.y=0.00001*mng_get_long(&p[4]);
5596 mng_info->global_chrm.red_primary.x=0.00001*mng_get_long(&p[8]);
5597 mng_info->global_chrm.red_primary.y=0.00001*
5598 mng_get_long(&p[12]);
5599 mng_info->global_chrm.green_primary.x=0.00001*
5600 mng_get_long(&p[16]);
5601 mng_info->global_chrm.green_primary.y=0.00001*
5602 mng_get_long(&p[20]);
5603 mng_info->global_chrm.blue_primary.x=0.00001*
5604 mng_get_long(&p[24]);
5605 mng_info->global_chrm.blue_primary.y=0.00001*
5606 mng_get_long(&p[28]);
5607 mng_info->have_global_chrm=MagickTrue;
5610 mng_info->have_global_chrm=MagickFalse;
5612 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5616 if (memcmp(type,mng_sRGB,4) == 0)
5623 mng_info->global_srgb_intent=
5624 Magick_RenderingIntent_from_PNG_RenderingIntent(p[0]);
5625 mng_info->have_global_srgb=MagickTrue;
5628 mng_info->have_global_srgb=MagickFalse;
5630 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5634 if (memcmp(type,mng_iCCP,4) == 0)
5642 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5647 if (memcmp(type,mng_FRAM,4) == 0)
5650 (void) ThrowMagickException(exception,GetMagickModule(),
5651 CoderError,"FRAM chunk found in MNG-VLC datastream","`%s'",
5654 if ((mng_info->framing_mode == 2) || (mng_info->framing_mode == 4))
5655 image->delay=frame_delay;
5657 frame_delay=default_frame_delay;
5658 frame_timeout=default_frame_timeout;
5663 mng_info->framing_mode=p[0];
5665 if (logging != MagickFalse)
5666 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5667 " Framing_mode=%d",mng_info->framing_mode);
5671 /* Note the delay and frame clipping boundaries. */
5673 p++; /* framing mode */
5675 while (*p && ((p-chunk) < (ssize_t) length))
5676 p++; /* frame name */
5678 p++; /* frame name terminator */
5680 if ((p-chunk) < (ssize_t) (length-4))
5687 change_delay=(*p++);
5688 change_timeout=(*p++);
5689 change_clipping=(*p++);
5690 p++; /* change_sync */
5694 frame_delay=1UL*image->ticks_per_second*
5697 if (mng_info->ticks_per_second != 0)
5698 frame_delay/=mng_info->ticks_per_second;
5701 frame_delay=PNG_UINT_31_MAX;
5703 if (change_delay == 2)
5704 default_frame_delay=frame_delay;
5708 if (logging != MagickFalse)
5709 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5710 " Framing_delay=%.20g",(double) frame_delay);
5715 frame_timeout=1UL*image->ticks_per_second*
5718 if (mng_info->ticks_per_second != 0)
5719 frame_timeout/=mng_info->ticks_per_second;
5722 frame_timeout=PNG_UINT_31_MAX;
5724 if (change_delay == 2)
5725 default_frame_timeout=frame_timeout;
5729 if (logging != MagickFalse)
5730 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5731 " Framing_timeout=%.20g",(double) frame_timeout);
5734 if (change_clipping)
5736 fb=mng_read_box(previous_fb,(char) p[0],&p[1]);
5740 if (logging != MagickFalse)
5741 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5742 " Frame_clip: L=%.20g R=%.20g T=%.20g B=%.20g",
5743 (double) fb.left,(double) fb.right,(double) fb.top,
5744 (double) fb.bottom);
5746 if (change_clipping == 2)
5752 mng_info->clip=mng_minimum_box(fb,mng_info->frame);
5754 subframe_width=(size_t) (mng_info->clip.right
5755 -mng_info->clip.left);
5757 subframe_height=(size_t) (mng_info->clip.bottom
5758 -mng_info->clip.top);
5760 Insert a background layer behind the frame if framing_mode is 4.
5762 #if defined(MNG_INSERT_LAYERS)
5763 if (logging != MagickFalse)
5764 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5765 " subframe_width=%.20g, subframe_height=%.20g",(double)
5766 subframe_width,(double) subframe_height);
5768 if (insert_layers && (mng_info->framing_mode == 4) &&
5769 (subframe_width) && (subframe_height))
5771 /* Allocate next image structure. */
5772 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
5774 AcquireNextImage(image_info,image,exception);
5776 if (GetNextImageInList(image) == (Image *) NULL)
5778 image=DestroyImageList(image);
5779 MngInfoFreeStruct(mng_info,&have_mng_structure);
5780 return((Image *) NULL);
5783 image=SyncNextImageInList(image);
5786 mng_info->image=image;
5788 if (term_chunk_found)
5790 image->start_loop=MagickTrue;
5791 image->iterations=mng_iterations;
5792 term_chunk_found=MagickFalse;
5796 image->start_loop=MagickFalse;
5798 image->columns=subframe_width;
5799 image->rows=subframe_height;
5800 image->page.width=subframe_width;
5801 image->page.height=subframe_height;
5802 image->page.x=mng_info->clip.left;
5803 image->page.y=mng_info->clip.top;
5804 image->background_color=mng_background_color;
5805 image->alpha_trait=UndefinedPixelTrait;
5807 (void) SetImageBackgroundColor(image,exception);
5809 if (logging != MagickFalse)
5810 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5811 " Insert backgd layer, L=%.20g, R=%.20g T=%.20g, B=%.20g",
5812 (double) mng_info->clip.left,(double) mng_info->clip.right,
5813 (double) mng_info->clip.top,(double) mng_info->clip.bottom);
5816 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5819 if (memcmp(type,mng_CLIP,4) == 0)
5828 first_object=(p[0] << 8) | p[1];
5829 last_object=(p[2] << 8) | p[3];
5831 for (i=(int) first_object; i <= (int) last_object; i++)
5833 if (mng_info->exists[i] && !mng_info->frozen[i])
5838 box=mng_info->object_clip[i];
5839 mng_info->object_clip[i]=mng_read_box(box,(char) p[4],&p[5]);
5843 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5846 if (memcmp(type,mng_SAVE,4) == 0)
5848 for (i=1; i < MNG_MAX_OBJECTS; i++)
5849 if (mng_info->exists[i])
5851 mng_info->frozen[i]=MagickTrue;
5852 #ifdef MNG_OBJECT_BUFFERS
5853 if (mng_info->ob[i] != (MngBuffer *) NULL)
5854 mng_info->ob[i]->frozen=MagickTrue;
5859 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5864 if ((memcmp(type,mng_DISC,4) == 0) || (memcmp(type,mng_SEEK,4) == 0))
5866 /* Read DISC or SEEK. */
5868 if ((length == 0) || !memcmp(type,mng_SEEK,4))
5870 for (i=1; i < MNG_MAX_OBJECTS; i++)
5871 MngInfoDiscardObject(mng_info,i);
5879 for (j=0; j < (ssize_t) length; j+=2)
5881 i=p[j] << 8 | p[j+1];
5882 MngInfoDiscardObject(mng_info,i);
5887 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5892 if (memcmp(type,mng_MOVE,4) == 0)
5900 first_object=(p[0] << 8) | p[1];
5901 last_object=(p[2] << 8) | p[3];
5902 for (i=(ssize_t) first_object; i <= (ssize_t) last_object; i++)
5904 if (mng_info->exists[i] && !mng_info->frozen[i])
5912 old_pair.a=mng_info->x_off[i];
5913 old_pair.b=mng_info->y_off[i];
5914 new_pair=mng_read_pair(old_pair,(int) p[4],&p[5]);
5915 mng_info->x_off[i]=new_pair.a;
5916 mng_info->y_off[i]=new_pair.b;
5920 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5924 if (memcmp(type,mng_LOOP,4) == 0)
5926 ssize_t loop_iters=1;
5927 loop_level=chunk[0];
5928 mng_info->loop_active[loop_level]=1; /* mark loop active */
5930 /* Record starting point. */
5931 loop_iters=mng_get_long(&chunk[1]);
5933 if (logging != MagickFalse)
5934 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5935 " LOOP level %.20g has %.20g iterations ",(double) loop_level,
5936 (double) loop_iters);
5938 if (loop_iters == 0)
5939 skipping_loop=loop_level;
5943 mng_info->loop_jump[loop_level]=TellBlob(image);
5944 mng_info->loop_count[loop_level]=loop_iters;
5947 mng_info->loop_iteration[loop_level]=0;
5948 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5952 if (memcmp(type,mng_ENDL,4) == 0)
5954 loop_level=chunk[0];
5956 if (skipping_loop > 0)
5958 if (skipping_loop == loop_level)
5961 Found end of zero-iteration loop.
5964 mng_info->loop_active[loop_level]=0;
5970 if (mng_info->loop_active[loop_level] == 1)
5972 mng_info->loop_count[loop_level]--;
5973 mng_info->loop_iteration[loop_level]++;
5975 if (logging != MagickFalse)
5976 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5977 " ENDL: LOOP level %.20g has %.20g remaining iters ",
5978 (double) loop_level,(double)
5979 mng_info->loop_count[loop_level]);
5981 if (mng_info->loop_count[loop_level] != 0)
5983 offset=SeekBlob(image,mng_info->loop_jump[loop_level],
5987 ThrowReaderException(CorruptImageError,
5988 "ImproperImageHeader");
5999 mng_info->loop_active[loop_level]=0;
6001 for (i=0; i < loop_level; i++)
6002 if (mng_info->loop_active[i] == 1)
6003 last_level=(short) i;
6004 loop_level=last_level;
6009 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
6013 if (memcmp(type,mng_CLON,4) == 0)
6015 if (mng_info->clon_warning == 0)
6016 (void) ThrowMagickException(exception,GetMagickModule(),
6017 CoderError,"CLON is not implemented yet","`%s'",
6020 mng_info->clon_warning++;
6023 if (memcmp(type,mng_MAGN,4) == 0)
6038 magn_first=(p[0] << 8) | p[1];
6044 magn_last=(p[2] << 8) | p[3];
6047 magn_last=magn_first;
6048 #ifndef MNG_OBJECT_BUFFERS
6049 if (magn_first || magn_last)
6050 if (mng_info->magn_warning == 0)
6052 (void) ThrowMagickException(exception,
6053 GetMagickModule(),CoderError,
6054 "MAGN is not implemented yet for nonzero objects",
6055 "`%s'",image->filename);
6057 mng_info->magn_warning++;
6067 magn_mx=(p[5] << 8) | p[6];
6076 magn_my=(p[7] << 8) | p[8];
6085 magn_ml=(p[9] << 8) | p[10];
6094 magn_mr=(p[11] << 8) | p[12];
6103 magn_mt=(p[13] << 8) | p[14];
6112 magn_mb=(p[15] << 8) | p[16];
6124 magn_methy=magn_methx;
6127 if (magn_methx > 5 || magn_methy > 5)
6128 if (mng_info->magn_warning == 0)
6130 (void) ThrowMagickException(exception,
6131 GetMagickModule(),CoderError,
6132 "Unknown MAGN method in MNG datastream","`%s'",
6135 mng_info->magn_warning++;
6137 #ifdef MNG_OBJECT_BUFFERS
6138 /* Magnify existing objects in the range magn_first to magn_last */
6140 if (magn_first == 0 || magn_last == 0)
6142 /* Save the magnification factors for object 0 */
6143 mng_info->magn_mb=magn_mb;
6144 mng_info->magn_ml=magn_ml;
6145 mng_info->magn_mr=magn_mr;
6146 mng_info->magn_mt=magn_mt;
6147 mng_info->magn_mx=magn_mx;
6148 mng_info->magn_my=magn_my;
6149 mng_info->magn_methx=magn_methx;
6150 mng_info->magn_methy=magn_methy;
6154 if (memcmp(type,mng_PAST,4) == 0)
6156 if (mng_info->past_warning == 0)
6157 (void) ThrowMagickException(exception,GetMagickModule(),
6158 CoderError,"PAST is not implemented yet","`%s'",
6161 mng_info->past_warning++;
6164 if (memcmp(type,mng_SHOW,4) == 0)
6166 if (mng_info->show_warning == 0)
6167 (void) ThrowMagickException(exception,GetMagickModule(),
6168 CoderError,"SHOW is not implemented yet","`%s'",
6171 mng_info->show_warning++;
6174 if (memcmp(type,mng_sBIT,4) == 0)
6177 mng_info->have_global_sbit=MagickFalse;
6181 mng_info->global_sbit.gray=p[0];
6182 mng_info->global_sbit.red=p[0];
6183 mng_info->global_sbit.green=p[1];
6184 mng_info->global_sbit.blue=p[2];
6185 mng_info->global_sbit.alpha=p[3];
6186 mng_info->have_global_sbit=MagickTrue;
6189 if (memcmp(type,mng_pHYs,4) == 0)
6193 mng_info->global_x_pixels_per_unit=
6194 (size_t) mng_get_long(p);
6195 mng_info->global_y_pixels_per_unit=
6196 (size_t) mng_get_long(&p[4]);
6197 mng_info->global_phys_unit_type=p[8];
6198 mng_info->have_global_phys=MagickTrue;
6202 mng_info->have_global_phys=MagickFalse;
6204 if (memcmp(type,mng_pHYg,4) == 0)
6206 if (mng_info->phyg_warning == 0)
6207 (void) ThrowMagickException(exception,GetMagickModule(),
6208 CoderError,"pHYg is not implemented.","`%s'",image->filename);
6210 mng_info->phyg_warning++;
6212 if (memcmp(type,mng_BASI,4) == 0)
6214 skip_to_iend=MagickTrue;
6216 if (mng_info->basi_warning == 0)
6217 (void) ThrowMagickException(exception,GetMagickModule(),
6218 CoderError,"BASI is not implemented yet","`%s'",
6221 mng_info->basi_warning++;
6222 #ifdef MNG_BASI_SUPPORTED
6223 basi_width=(size_t) ((p[0] << 24) | (p[1] << 16) |
6224 (p[2] << 8) | p[3]);
6225 basi_height=(size_t) ((p[4] << 24) | (p[5] << 16) |
6226 (p[6] << 8) | p[7]);
6227 basi_color_type=p[8];
6228 basi_compression_method=p[9];
6229 basi_filter_type=p[10];
6230 basi_interlace_method=p[11];
6232 basi_red=(p[12] << 8) & p[13];
6238 basi_green=(p[14] << 8) & p[15];
6244 basi_blue=(p[16] << 8) & p[17];
6250 basi_alpha=(p[18] << 8) & p[19];
6254 if (basi_sample_depth == 16)
6261 basi_viewable=p[20];
6267 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
6271 if (memcmp(type,mng_IHDR,4)
6272 #if defined(JNG_SUPPORTED)
6273 && memcmp(type,mng_JHDR,4)
6277 /* Not an IHDR or JHDR chunk */
6279 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
6284 if (logging != MagickFalse)
6285 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6286 " Processing %c%c%c%c chunk",type[0],type[1],type[2],type[3]);
6288 mng_info->exists[object_id]=MagickTrue;
6289 mng_info->viewable[object_id]=MagickTrue;
6291 if (mng_info->invisible[object_id])
6293 if (logging != MagickFalse)
6294 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6295 " Skipping invisible object");
6297 skip_to_iend=MagickTrue;
6298 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
6301 #if defined(MNG_INSERT_LAYERS)
6303 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
6305 image_width=(size_t) mng_get_long(p);
6306 image_height=(size_t) mng_get_long(&p[4]);
6308 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
6311 Insert a transparent background layer behind the entire animation
6312 if it is not full screen.
6314 #if defined(MNG_INSERT_LAYERS)
6315 if (insert_layers && mng_type && first_mng_object)
6317 if ((mng_info->clip.left > 0) || (mng_info->clip.top > 0) ||
6318 (image_width < mng_info->mng_width) ||
6319 (mng_info->clip.right < (ssize_t) mng_info->mng_width) ||
6320 (image_height < mng_info->mng_height) ||
6321 (mng_info->clip.bottom < (ssize_t) mng_info->mng_height))
6323 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
6326 Allocate next image structure.
6328 AcquireNextImage(image_info,image,exception);
6330 if (GetNextImageInList(image) == (Image *) NULL)
6332 image=DestroyImageList(image);
6333 MngInfoFreeStruct(mng_info,&have_mng_structure);
6334 return((Image *) NULL);
6337 image=SyncNextImageInList(image);
6339 mng_info->image=image;
6341 if (term_chunk_found)
6343 image->start_loop=MagickTrue;
6344 image->iterations=mng_iterations;
6345 term_chunk_found=MagickFalse;
6349 image->start_loop=MagickFalse;
6351 /* Make a background rectangle. */
6354 image->columns=mng_info->mng_width;
6355 image->rows=mng_info->mng_height;
6356 image->page.width=mng_info->mng_width;
6357 image->page.height=mng_info->mng_height;
6360 image->background_color=mng_background_color;
6361 (void) SetImageBackgroundColor(image,exception);
6362 if (logging != MagickFalse)
6363 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6364 " Inserted transparent background layer, W=%.20g, H=%.20g",
6365 (double) mng_info->mng_width,(double) mng_info->mng_height);
6369 Insert a background layer behind the upcoming image if
6370 framing_mode is 3, and we haven't already inserted one.
6372 if (insert_layers && (mng_info->framing_mode == 3) &&
6373 (subframe_width) && (subframe_height) && (simplicity == 0 ||
6374 (simplicity & 0x08)))
6376 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
6379 Allocate next image structure.
6381 AcquireNextImage(image_info,image,exception);
6383 if (GetNextImageInList(image) == (Image *) NULL)
6385 image=DestroyImageList(image);
6386 MngInfoFreeStruct(mng_info,&have_mng_structure);
6387 return((Image *) NULL);
6390 image=SyncNextImageInList(image);
6393 mng_info->image=image;
6395 if (term_chunk_found)
6397 image->start_loop=MagickTrue;
6398 image->iterations=mng_iterations;
6399 term_chunk_found=MagickFalse;
6403 image->start_loop=MagickFalse;
6406 image->columns=subframe_width;
6407 image->rows=subframe_height;
6408 image->page.width=subframe_width;
6409 image->page.height=subframe_height;
6410 image->page.x=mng_info->clip.left;
6411 image->page.y=mng_info->clip.top;
6412 image->background_color=mng_background_color;
6413 image->alpha_trait=UndefinedPixelTrait;
6414 (void) SetImageBackgroundColor(image,exception);
6416 if (logging != MagickFalse)
6417 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6418 " Insert background layer, L=%.20g, R=%.20g T=%.20g, B=%.20g",
6419 (double) mng_info->clip.left,(double) mng_info->clip.right,
6420 (double) mng_info->clip.top,(double) mng_info->clip.bottom);
6422 #endif /* MNG_INSERT_LAYERS */
6423 first_mng_object=MagickFalse;
6425 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
6428 Allocate next image structure.
6430 AcquireNextImage(image_info,image,exception);
6432 if (GetNextImageInList(image) == (Image *) NULL)
6434 image=DestroyImageList(image);
6435 MngInfoFreeStruct(mng_info,&have_mng_structure);
6436 return((Image *) NULL);
6439 image=SyncNextImageInList(image);
6441 mng_info->image=image;
6442 status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
6443 GetBlobSize(image));
6445 if (status == MagickFalse)
6448 if (term_chunk_found)
6450 image->start_loop=MagickTrue;
6451 term_chunk_found=MagickFalse;
6455 image->start_loop=MagickFalse;
6457 if (mng_info->framing_mode == 1 || mng_info->framing_mode == 3)
6459 image->delay=frame_delay;
6460 frame_delay=default_frame_delay;
6466 image->page.width=mng_info->mng_width;
6467 image->page.height=mng_info->mng_height;
6468 image->page.x=mng_info->x_off[object_id];
6469 image->page.y=mng_info->y_off[object_id];
6470 image->iterations=mng_iterations;
6473 Seek back to the beginning of the IHDR or JHDR chunk's length field.
6476 if (logging != MagickFalse)
6477 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6478 " Seeking back to beginning of %c%c%c%c chunk",type[0],type[1],
6481 offset=SeekBlob(image,-((ssize_t) length+12),SEEK_CUR);
6484 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
6488 mng_info->image=image;
6489 mng_info->mng_type=mng_type;
6490 mng_info->object_id=object_id;
6492 if (memcmp(type,mng_IHDR,4) == 0)
6493 image=ReadOnePNGImage(mng_info,image_info,exception);
6495 #if defined(JNG_SUPPORTED)
6497 image=ReadOneJNGImage(mng_info,image_info,exception);
6500 if (image == (Image *) NULL)
6502 if (IsImageObject(previous) != MagickFalse)
6504 (void) DestroyImageList(previous);
6505 (void) CloseBlob(previous);
6508 MngInfoFreeStruct(mng_info,&have_mng_structure);
6509 return((Image *) NULL);
6512 if (image->columns == 0 || image->rows == 0)
6514 (void) CloseBlob(image);
6515 image=DestroyImageList(image);
6516 MngInfoFreeStruct(mng_info,&have_mng_structure);
6517 return((Image *) NULL);
6520 mng_info->image=image;
6527 if (mng_info->magn_methx || mng_info->magn_methy)
6533 if (logging != MagickFalse)
6534 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6535 " Processing MNG MAGN chunk");
6537 if (mng_info->magn_methx == 1)
6539 magnified_width=mng_info->magn_ml;
6541 if (image->columns > 1)
6542 magnified_width += mng_info->magn_mr;
6544 if (image->columns > 2)
6545 magnified_width += (png_uint_32)
6546 ((image->columns-2)*(mng_info->magn_mx));
6551 magnified_width=(png_uint_32) image->columns;
6553 if (image->columns > 1)
6554 magnified_width += mng_info->magn_ml-1;
6556 if (image->columns > 2)
6557 magnified_width += mng_info->magn_mr-1;
6559 if (image->columns > 3)
6560 magnified_width += (png_uint_32)
6561 ((image->columns-3)*(mng_info->magn_mx-1));
6564 if (mng_info->magn_methy == 1)
6566 magnified_height=mng_info->magn_mt;
6568 if (image->rows > 1)
6569 magnified_height += mng_info->magn_mb;
6571 if (image->rows > 2)
6572 magnified_height += (png_uint_32)
6573 ((image->rows-2)*(mng_info->magn_my));
6578 magnified_height=(png_uint_32) image->rows;
6580 if (image->rows > 1)
6581 magnified_height += mng_info->magn_mt-1;
6583 if (image->rows > 2)
6584 magnified_height += mng_info->magn_mb-1;
6586 if (image->rows > 3)
6587 magnified_height += (png_uint_32)
6588 ((image->rows-3)*(mng_info->magn_my-1));
6591 if (magnified_height > image->rows ||
6592 magnified_width > image->columns)
6619 /* Allocate next image structure. */
6621 if (logging != MagickFalse)
6622 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6623 " Allocate magnified image");
6625 AcquireNextImage(image_info,image,exception);
6627 if (GetNextImageInList(image) == (Image *) NULL)
6629 image=DestroyImageList(image);
6630 MngInfoFreeStruct(mng_info,&have_mng_structure);
6631 return((Image *) NULL);
6634 large_image=SyncNextImageInList(image);
6636 large_image->columns=magnified_width;
6637 large_image->rows=magnified_height;
6639 magn_methx=mng_info->magn_methx;
6640 magn_methy=mng_info->magn_methy;
6642 #if (MAGICKCORE_QUANTUM_DEPTH > 16)
6643 #define QM unsigned short
6644 if (magn_methx != 1 || magn_methy != 1)
6647 Scale pixels to unsigned shorts to prevent
6648 overflow of intermediate values of interpolations
6650 for (y=0; y < (ssize_t) image->rows; y++)
6652 q=GetAuthenticPixels(image,0,y,image->columns,1,
6655 for (x=(ssize_t) image->columns-1; x >= 0; x--)
6657 SetPixelRed(image,ScaleQuantumToShort(
6658 GetPixelRed(image,q)),q);
6659 SetPixelGreen(image,ScaleQuantumToShort(
6660 GetPixelGreen(image,q)),q);
6661 SetPixelBlue(image,ScaleQuantumToShort(
6662 GetPixelBlue(image,q)),q);
6663 SetPixelAlpha(image,ScaleQuantumToShort(
6664 GetPixelAlpha(image,q)),q);
6665 q+=GetPixelChannels(image);
6668 if (SyncAuthenticPixels(image,exception) == MagickFalse)
6676 if (image->alpha_trait == BlendPixelTrait)
6677 (void) SetImageBackgroundColor(large_image,exception);
6681 large_image->background_color.alpha=OpaqueAlpha;
6682 (void) SetImageBackgroundColor(large_image,exception);
6684 if (magn_methx == 4)
6687 if (magn_methx == 5)
6690 if (magn_methy == 4)
6693 if (magn_methy == 5)
6697 /* magnify the rows into the right side of the large image */
6699 if (logging != MagickFalse)
6700 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6701 " Magnify the rows to %.20g",(double) large_image->rows);
6702 m=(ssize_t) mng_info->magn_mt;
6704 length=(size_t) image->columns*GetPixelChannels(image);
6705 next=(Quantum *) AcquireQuantumMemory(length,sizeof(*next));
6706 prev=(Quantum *) AcquireQuantumMemory(length,sizeof(*prev));
6708 if ((prev == (Quantum *) NULL) ||
6709 (next == (Quantum *) NULL))
6711 image=DestroyImageList(image);
6712 MngInfoFreeStruct(mng_info,&have_mng_structure);
6713 ThrowReaderException(ResourceLimitError,
6714 "MemoryAllocationFailed");
6717 n=GetAuthenticPixels(image,0,0,image->columns,1,exception);
6718 (void) CopyMagickMemory(next,n,length);
6720 for (y=0; y < (ssize_t) image->rows; y++)
6723 m=(ssize_t) mng_info->magn_mt;
6725 else if (magn_methy > 1 && y == (ssize_t) image->rows-2)
6726 m=(ssize_t) mng_info->magn_mb;
6728 else if (magn_methy <= 1 && y == (ssize_t) image->rows-1)
6729 m=(ssize_t) mng_info->magn_mb;
6731 else if (magn_methy > 1 && y == (ssize_t) image->rows-1)
6735 m=(ssize_t) mng_info->magn_my;
6741 if (y < (ssize_t) image->rows-1)
6743 n=GetAuthenticPixels(image,0,y+1,image->columns,1,
6745 (void) CopyMagickMemory(next,n,length);
6748 for (i=0; i < m; i++, yy++)
6753 assert(yy < (ssize_t) large_image->rows);
6756 q=GetAuthenticPixels(large_image,0,yy,large_image->columns,
6758 q+=(large_image->columns-image->columns)*
6759 GetPixelChannels(large_image);
6761 for (x=(ssize_t) image->columns-1; x >= 0; x--)
6763 /* To do: get color as function of indexes[x] */
6765 if (image->storage_class == PseudoClass)
6770 if (magn_methy <= 1)
6772 /* replicate previous */
6773 SetPixelRed(large_image,GetPixelRed(image,pixels),q);
6774 SetPixelGreen(large_image,GetPixelGreen(image,
6776 SetPixelBlue(large_image,GetPixelBlue(image,
6778 SetPixelAlpha(large_image,GetPixelAlpha(image,
6782 else if (magn_methy == 2 || magn_methy == 4)
6786 SetPixelRed(large_image,GetPixelRed(image,
6788 SetPixelGreen(large_image,GetPixelGreen(image,
6790 SetPixelBlue(large_image,GetPixelBlue(image,
6792 SetPixelAlpha(large_image,GetPixelAlpha(image,
6799 SetPixelRed(large_image,((QM) (((ssize_t)
6800 (2*i*(GetPixelRed(image,n)
6801 -GetPixelRed(image,pixels)+m))/
6803 +GetPixelRed(image,pixels)))),q);
6804 SetPixelGreen(large_image,((QM) (((ssize_t)
6805 (2*i*(GetPixelGreen(image,n)
6806 -GetPixelGreen(image,pixels)+m))/
6808 +GetPixelGreen(image,pixels)))),q);
6809 SetPixelBlue(large_image,((QM) (((ssize_t)
6810 (2*i*(GetPixelBlue(image,n)
6811 -GetPixelBlue(image,pixels)+m))/
6813 +GetPixelBlue(image,pixels)))),q);
6815 if (image->alpha_trait == BlendPixelTrait)
6816 SetPixelAlpha(large_image, ((QM) (((ssize_t)
6817 (2*i*(GetPixelAlpha(image,n)
6818 -GetPixelAlpha(image,pixels)+m))
6820 GetPixelAlpha(image,pixels)))),q);
6823 if (magn_methy == 4)
6825 /* Replicate nearest */
6826 if (i <= ((m+1) << 1))
6827 SetPixelAlpha(large_image,GetPixelAlpha(image,
6830 SetPixelAlpha(large_image,GetPixelAlpha(image,
6835 else /* if (magn_methy == 3 || magn_methy == 5) */
6837 /* Replicate nearest */
6838 if (i <= ((m+1) << 1))
6840 SetPixelRed(large_image,GetPixelRed(image,
6842 SetPixelGreen(large_image,GetPixelGreen(image,
6844 SetPixelBlue(large_image,GetPixelBlue(image,
6846 SetPixelAlpha(large_image,GetPixelAlpha(image,
6852 SetPixelRed(large_image,GetPixelRed(image,n),q);
6853 SetPixelGreen(large_image,GetPixelGreen(image,n),
6855 SetPixelBlue(large_image,GetPixelBlue(image,n),
6857 SetPixelAlpha(large_image,GetPixelAlpha(image,n),
6861 if (magn_methy == 5)
6863 SetPixelAlpha(large_image,(QM) (((ssize_t) (2*i*
6864 (GetPixelAlpha(image,n)
6865 -GetPixelAlpha(image,pixels))
6866 +m))/((ssize_t) (m*2))
6867 +GetPixelAlpha(image,pixels)),q);
6870 n+=GetPixelChannels(image);
6871 q+=GetPixelChannels(large_image);
6872 pixels+=GetPixelChannels(image);
6875 if (SyncAuthenticPixels(large_image,exception) == 0)
6881 prev=(Quantum *) RelinquishMagickMemory(prev);
6882 next=(Quantum *) RelinquishMagickMemory(next);
6884 length=image->columns;
6886 if (logging != MagickFalse)
6887 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6888 " Delete original image");
6890 DeleteImageFromList(&image);
6894 mng_info->image=image;
6896 /* magnify the columns */
6897 if (logging != MagickFalse)
6898 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6899 " Magnify the columns to %.20g",(double) image->columns);
6901 for (y=0; y < (ssize_t) image->rows; y++)
6906 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
6907 pixels=q+(image->columns-length)*GetPixelChannels(image);
6908 n=pixels+GetPixelChannels(image);
6910 for (x=(ssize_t) (image->columns-length);
6911 x < (ssize_t) image->columns; x++)
6913 /* To do: Rewrite using Get/Set***PixelChannel() */
6915 if (x == (ssize_t) (image->columns-length))
6916 m=(ssize_t) mng_info->magn_ml;
6918 else if (magn_methx > 1 && x == (ssize_t) image->columns-2)
6919 m=(ssize_t) mng_info->magn_mr;
6921 else if (magn_methx <= 1 && x == (ssize_t) image->columns-1)
6922 m=(ssize_t) mng_info->magn_mr;
6924 else if (magn_methx > 1 && x == (ssize_t) image->columns-1)
6928 m=(ssize_t) mng_info->magn_mx;
6930 for (i=0; i < m; i++)
6932 if (magn_methx <= 1)
6934 /* replicate previous */
6935 SetPixelRed(image,GetPixelRed(image,pixels),q);
6936 SetPixelGreen(image,GetPixelGreen(image,pixels),q);
6937 SetPixelBlue(image,GetPixelBlue(image,pixels),q);
6938 SetPixelAlpha(image,GetPixelAlpha(image,pixels),q);
6941 else if (magn_methx == 2 || magn_methx == 4)
6945 SetPixelRed(image,GetPixelRed(image,pixels),q);
6946 SetPixelGreen(image,GetPixelGreen(image,pixels),q);
6947 SetPixelBlue(image,GetPixelBlue(image,pixels),q);
6948 SetPixelAlpha(image,GetPixelAlpha(image,pixels),q);
6951 /* To do: Rewrite using Get/Set***PixelChannel() */
6955 SetPixelRed(image,(QM) ((2*i*(
6956 GetPixelRed(image,n)
6957 -GetPixelRed(image,pixels))+m)
6959 GetPixelRed(image,pixels)),q);
6961 SetPixelGreen(image,(QM) ((2*i*(
6962 GetPixelGreen(image,n)
6963 -GetPixelGreen(image,pixels))+m)
6965 GetPixelGreen(image,pixels)),q);
6967 SetPixelBlue(image,(QM) ((2*i*(
6968 GetPixelBlue(image,n)
6969 -GetPixelBlue(image,pixels))+m)
6971 GetPixelBlue(image,pixels)),q);
6972 if (image->alpha_trait == BlendPixelTrait)
6973 SetPixelAlpha(image,(QM) ((2*i*(
6974 GetPixelAlpha(image,n)
6975 -GetPixelAlpha(image,pixels))+m)
6977 GetPixelAlpha(image,pixels)),q);
6980 if (magn_methx == 4)
6982 /* Replicate nearest */
6983 if (i <= ((m+1) << 1))
6985 SetPixelAlpha(image,
6986 GetPixelAlpha(image,pixels)+0,q);
6990 SetPixelAlpha(image,
6991 GetPixelAlpha(image,n)+0,q);
6996 else /* if (magn_methx == 3 || magn_methx == 5) */
6998 /* Replicate nearest */
6999 if (i <= ((m+1) << 1))
7001 SetPixelRed(image,GetPixelRed(image,pixels),q);
7002 SetPixelGreen(image,GetPixelGreen(image,pixels),q);
7003 SetPixelBlue(image,GetPixelBlue(image,pixels),q);
7004 SetPixelAlpha(image,GetPixelAlpha(image,pixels),q);
7009 SetPixelRed(image,GetPixelRed(image,n),q);
7010 SetPixelGreen(image,GetPixelGreen(image,n),q);
7011 SetPixelBlue(image,GetPixelBlue(image,n),q);
7012 SetPixelAlpha(image,GetPixelAlpha(image,n),q);
7015 if (magn_methx == 5)
7018 SetPixelAlpha(image,
7019 (QM) ((2*i*( GetPixelAlpha(image,n)
7020 -GetPixelAlpha(image,pixels))+m)/
7022 +GetPixelAlpha(image,pixels)),q);
7025 q+=GetPixelChannels(image);
7027 n+=GetPixelChannels(image);
7030 if (SyncAuthenticPixels(image,exception) == MagickFalse)
7033 #if (MAGICKCORE_QUANTUM_DEPTH > 16)
7034 if (magn_methx != 1 || magn_methy != 1)
7037 Rescale pixels to Quantum
7039 for (y=0; y < (ssize_t) image->rows; y++)
7041 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
7043 for (x=(ssize_t) image->columns-1; x >= 0; x--)
7045 SetPixelRed(image,ScaleShortToQuantum(
7046 GetPixelRed(image,q)),q);
7047 SetPixelGreen(image,ScaleShortToQuantum(
7048 GetPixelGreen(image,q)),q);
7049 SetPixelBlue(image,ScaleShortToQuantum(
7050 GetPixelBlue(image,q)),q);
7051 SetPixelAlpha(image,ScaleShortToQuantum(
7052 GetPixelAlpha(image,q)),q);
7053 q+=GetPixelChannels(image);
7056 if (SyncAuthenticPixels(image,exception) == MagickFalse)
7061 if (logging != MagickFalse)
7062 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7063 " Finished MAGN processing");
7068 Crop_box is with respect to the upper left corner of the MNG.
7070 crop_box.left=mng_info->image_box.left+mng_info->x_off[object_id];
7071 crop_box.right=mng_info->image_box.right+mng_info->x_off[object_id];
7072 crop_box.top=mng_info->image_box.top+mng_info->y_off[object_id];
7073 crop_box.bottom=mng_info->image_box.bottom+mng_info->y_off[object_id];
7074 crop_box=mng_minimum_box(crop_box,mng_info->clip);
7075 crop_box=mng_minimum_box(crop_box,mng_info->frame);
7076 crop_box=mng_minimum_box(crop_box,mng_info->object_clip[object_id]);
7077 if ((crop_box.left != (mng_info->image_box.left
7078 +mng_info->x_off[object_id])) ||
7079 (crop_box.right != (mng_info->image_box.right
7080 +mng_info->x_off[object_id])) ||
7081 (crop_box.top != (mng_info->image_box.top
7082 +mng_info->y_off[object_id])) ||
7083 (crop_box.bottom != (mng_info->image_box.bottom
7084 +mng_info->y_off[object_id])))
7086 if (logging != MagickFalse)
7087 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7088 " Crop the PNG image");
7090 if ((crop_box.left < crop_box.right) &&
7091 (crop_box.top < crop_box.bottom))
7100 Crop_info is with respect to the upper left corner of
7103 crop_info.x=(crop_box.left-mng_info->x_off[object_id]);
7104 crop_info.y=(crop_box.top-mng_info->y_off[object_id]);
7105 crop_info.width=(size_t) (crop_box.right-crop_box.left);
7106 crop_info.height=(size_t) (crop_box.bottom-crop_box.top);
7107 image->page.width=image->columns;
7108 image->page.height=image->rows;
7111 im=CropImage(image,&crop_info,exception);
7113 if (im != (Image *) NULL)
7115 image->columns=im->columns;
7116 image->rows=im->rows;
7117 im=DestroyImage(im);
7118 image->page.width=image->columns;
7119 image->page.height=image->rows;
7120 image->page.x=crop_box.left;
7121 image->page.y=crop_box.top;
7128 No pixels in crop area. The MNG spec still requires
7129 a layer, though, so make a single transparent pixel in
7130 the top left corner.
7135 (void) SetImageBackgroundColor(image,exception);
7136 image->page.width=1;
7137 image->page.height=1;
7142 #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
7143 image=mng_info->image;
7147 #if (MAGICKCORE_QUANTUM_DEPTH > 16)
7148 /* PNG does not handle depths greater than 16 so reduce it even
7151 if (image->depth > 16)
7155 #if (MAGICKCORE_QUANTUM_DEPTH > 8)
7156 if (image->depth > 8)
7158 /* To do: fill low byte properly */
7162 if (LosslessReduceDepthOK(image,exception) != MagickFalse)
7166 if (image_info->number_scenes != 0)
7168 if (mng_info->scenes_found >
7169 (ssize_t) (image_info->first_scene+image_info->number_scenes))
7173 if (logging != MagickFalse)
7174 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7175 " Finished reading image datastream.");
7177 } while (LocaleCompare(image_info->magick,"MNG") == 0);
7179 (void) CloseBlob(image);
7181 if (logging != MagickFalse)
7182 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7183 " Finished reading all image datastreams.");
7185 #if defined(MNG_INSERT_LAYERS)
7186 if (insert_layers && !mng_info->image_found && (mng_info->mng_width) &&
7187 (mng_info->mng_height))
7190 Insert a background layer if nothing else was found.
7192 if (logging != MagickFalse)
7193 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7194 " No images found. Inserting a background layer.");
7196 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
7199 Allocate next image structure.
7201 AcquireNextImage(image_info,image,exception);
7202 if (GetNextImageInList(image) == (Image *) NULL)
7204 image=DestroyImageList(image);
7205 MngInfoFreeStruct(mng_info,&have_mng_structure);
7207 if (logging != MagickFalse)
7208 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7209 " Allocation failed, returning NULL.");
7211 return((Image *) NULL);
7213 image=SyncNextImageInList(image);
7215 image->columns=mng_info->mng_width;
7216 image->rows=mng_info->mng_height;
7217 image->page.width=mng_info->mng_width;
7218 image->page.height=mng_info->mng_height;
7221 image->background_color=mng_background_color;
7222 image->alpha_trait=UndefinedPixelTrait;
7224 if (image_info->ping == MagickFalse)
7225 (void) SetImageBackgroundColor(image,exception);
7227 mng_info->image_found++;
7230 image->iterations=mng_iterations;
7232 if (mng_iterations == 1)
7233 image->start_loop=MagickTrue;
7235 while (GetPreviousImageInList(image) != (Image *) NULL)
7238 if (image_count > 10*mng_info->image_found)
7240 if (logging != MagickFalse)
7241 (void) LogMagickEvent(CoderEvent,GetMagickModule()," No beginning");
7243 (void) ThrowMagickException(exception,GetMagickModule(),
7244 CoderError,"Linked list is corrupted, beginning of list not found",
7245 "`%s'",image_info->filename);
7247 return((Image *) NULL);
7250 image=GetPreviousImageInList(image);
7252 if (GetNextImageInList(image) == (Image *) NULL)
7254 if (logging != MagickFalse)
7255 (void) LogMagickEvent(CoderEvent,GetMagickModule()," Corrupt list");
7257 (void) ThrowMagickException(exception,GetMagickModule(),
7258 CoderError,"Linked list is corrupted; next_image is NULL","`%s'",
7259 image_info->filename);
7263 if (mng_info->ticks_per_second && mng_info->image_found > 1 &&
7264 GetNextImageInList(image) ==
7267 if (logging != MagickFalse)
7268 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7269 " First image null");
7271 (void) ThrowMagickException(exception,GetMagickModule(),
7272 CoderError,"image->next for first image is NULL but shouldn't be.",
7273 "`%s'",image_info->filename);
7276 if (mng_info->image_found == 0)
7278 if (logging != MagickFalse)
7279 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7280 " No visible images found.");
7282 (void) ThrowMagickException(exception,GetMagickModule(),
7283 CoderError,"No visible images in file","`%s'",image_info->filename);
7285 if (image != (Image *) NULL)
7286 image=DestroyImageList(image);
7288 MngInfoFreeStruct(mng_info,&have_mng_structure);
7289 return((Image *) NULL);
7292 if (mng_info->ticks_per_second)
7293 final_delay=1UL*MagickMax(image->ticks_per_second,1L)*
7294 final_delay/mng_info->ticks_per_second;
7297 image->start_loop=MagickTrue;
7299 /* Find final nonzero image delay */
7300 final_image_delay=0;
7302 while (GetNextImageInList(image) != (Image *) NULL)
7305 final_image_delay=image->delay;
7307 image=GetNextImageInList(image);
7310 if (final_delay < final_image_delay)
7311 final_delay=final_image_delay;
7313 image->delay=final_delay;
7315 if (logging != MagickFalse)
7316 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7317 " image->delay=%.20g, final_delay=%.20g",(double) image->delay,
7318 (double) final_delay);
7320 if (logging != MagickFalse)
7326 image=GetFirstImageInList(image);
7328 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7329 " Before coalesce:");
7331 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7332 " scene 0 delay=%.20g",(double) image->delay);
7334 while (GetNextImageInList(image) != (Image *) NULL)
7336 image=GetNextImageInList(image);
7337 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7338 " scene %.20g delay=%.20g",(double) scene++,(double) image->delay);
7342 image=GetFirstImageInList(image);
7343 #ifdef MNG_COALESCE_LAYERS
7353 if (logging != MagickFalse)
7354 (void) LogMagickEvent(CoderEvent,GetMagickModule()," Coalesce Images");
7357 next_image=CoalesceImages(image,exception);
7359 if (next_image == (Image *) NULL)
7360 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
7362 image=DestroyImageList(image);
7365 for (next=image; next != (Image *) NULL; next=next_image)
7367 next->page.width=mng_info->mng_width;
7368 next->page.height=mng_info->mng_height;
7371 next->scene=scene++;
7372 next_image=GetNextImageInList(next);
7374 if (next_image == (Image *) NULL)
7377 if (next->delay == 0)
7380 next_image->previous=GetPreviousImageInList(next);
7381 if (GetPreviousImageInList(next) == (Image *) NULL)
7384 next->previous->next=next_image;
7385 next=DestroyImage(next);
7391 while (GetNextImageInList(image) != (Image *) NULL)
7392 image=GetNextImageInList(image);
7394 image->dispose=BackgroundDispose;
7396 if (logging != MagickFalse)
7402 image=GetFirstImageInList(image);
7404 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7405 " After coalesce:");
7407 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7408 " scene 0 delay=%.20g dispose=%.20g",(double) image->delay,
7409 (double) image->dispose);
7411 while (GetNextImageInList(image) != (Image *) NULL)
7413 image=GetNextImageInList(image);
7415 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7416 " scene %.20g delay=%.20g dispose=%.20g",(double) scene++,
7417 (double) image->delay,(double) image->dispose);
7421 image=GetFirstImageInList(image);
7422 MngInfoFreeStruct(mng_info,&have_mng_structure);
7423 have_mng_structure=MagickFalse;
7425 if (logging != MagickFalse)
7426 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit ReadMNGImage()");
7428 return(GetFirstImageInList(image));
7430 #else /* PNG_LIBPNG_VER > 10011 */
7431 static Image *ReadPNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
7433 printf("Your PNG library is too old: You have libpng-%s\n",
7434 PNG_LIBPNG_VER_STRING);
7436 (void) ThrowMagickException(exception,GetMagickModule(),CoderError,
7437 "PNG library is too old","`%s'",image_info->filename);
7439 return(Image *) NULL;
7442 static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
7444 return(ReadPNGImage(image_info,exception));
7446 #endif /* PNG_LIBPNG_VER > 10011 */
7450 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7454 % R e g i s t e r P N G I m a g e %
7458 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7460 % RegisterPNGImage() adds properties for the PNG image format to
7461 % the list of supported formats. The properties include the image format
7462 % tag, a method to read and/or write the format, whether the format
7463 % supports the saving of more than one frame to the same file or blob,
7464 % whether the format supports native in-memory I/O, and a brief
7465 % description of the format.
7467 % The format of the RegisterPNGImage method is:
7469 % size_t RegisterPNGImage(void)
7472 ModuleExport size_t RegisterPNGImage(void)
7475 version[MaxTextExtent];
7483 "See http://www.libpng.org/ for details about the PNG format."
7488 "See http://www.libpng.org/pub/mng/ for details about the JNG\n"
7494 "See http://www.libpng.org/pub/mng/ for details about the MNG\n"
7500 #if defined(PNG_LIBPNG_VER_STRING)
7501 (void) ConcatenateMagickString(version,"libpng ",MaxTextExtent);
7502 (void) ConcatenateMagickString(version,PNG_LIBPNG_VER_STRING,MaxTextExtent);
7504 if (LocaleCompare(PNG_LIBPNG_VER_STRING,png_get_header_ver(NULL)) != 0)
7506 (void) ConcatenateMagickString(version,",",MaxTextExtent);
7507 (void) ConcatenateMagickString(version,png_get_libpng_ver(NULL),
7512 entry=SetMagickInfo("MNG");
7513 entry->seekable_stream=MagickTrue; /* To do: eliminate this. */
7515 #if defined(MAGICKCORE_PNG_DELEGATE)
7516 entry->decoder=(DecodeImageHandler *) ReadMNGImage;
7517 entry->encoder=(EncodeImageHandler *) WriteMNGImage;
7520 entry->magick=(IsImageFormatHandler *) IsMNG;
7521 entry->description=ConstantString("Multiple-image Network Graphics");
7523 if (*version != '\0')
7524 entry->version=ConstantString(version);
7526 entry->mime_type=ConstantString("video/x-mng");
7527 entry->module=ConstantString("PNG");
7528 entry->note=ConstantString(MNGNote);
7529 (void) RegisterMagickInfo(entry);
7531 entry=SetMagickInfo("PNG");
7533 #if defined(MAGICKCORE_PNG_DELEGATE)
7534 entry->decoder=(DecodeImageHandler *) ReadPNGImage;
7535 entry->encoder=(EncodeImageHandler *) WritePNGImage;
7538 entry->magick=(IsImageFormatHandler *) IsPNG;
7539 entry->adjoin=MagickFalse;
7540 entry->description=ConstantString("Portable Network Graphics");
7541 entry->mime_type=ConstantString("image/png");
7542 entry->module=ConstantString("PNG");
7544 if (*version != '\0')
7545 entry->version=ConstantString(version);
7547 entry->note=ConstantString(PNGNote);
7548 (void) RegisterMagickInfo(entry);
7550 entry=SetMagickInfo("PNG8");
7552 #if defined(MAGICKCORE_PNG_DELEGATE)
7553 entry->decoder=(DecodeImageHandler *) ReadPNGImage;
7554 entry->encoder=(EncodeImageHandler *) WritePNGImage;
7557 entry->magick=(IsImageFormatHandler *) IsPNG;
7558 entry->adjoin=MagickFalse;
7559 entry->description=ConstantString(
7560 "8-bit indexed with optional binary transparency");
7561 entry->mime_type=ConstantString("image/png");
7562 entry->module=ConstantString("PNG");
7563 (void) RegisterMagickInfo(entry);
7565 entry=SetMagickInfo("PNG24");
7568 #if defined(ZLIB_VERSION)
7569 (void) ConcatenateMagickString(version,"zlib ",MaxTextExtent);
7570 (void) ConcatenateMagickString(version,ZLIB_VERSION,MaxTextExtent);
7572 if (LocaleCompare(ZLIB_VERSION,zlib_version) != 0)
7574 (void) ConcatenateMagickString(version,",",MaxTextExtent);
7575 (void) ConcatenateMagickString(version,zlib_version,MaxTextExtent);
7579 if (*version != '\0')
7580 entry->version=ConstantString(version);
7582 #if defined(MAGICKCORE_PNG_DELEGATE)
7583 entry->decoder=(DecodeImageHandler *) ReadPNGImage;
7584 entry->encoder=(EncodeImageHandler *) WritePNGImage;
7587 entry->magick=(IsImageFormatHandler *) IsPNG;
7588 entry->adjoin=MagickFalse;
7589 entry->description=ConstantString("opaque or binary transparent 24-bit RGB");
7590 entry->mime_type=ConstantString("image/png");
7591 entry->module=ConstantString("PNG");
7592 (void) RegisterMagickInfo(entry);
7594 entry=SetMagickInfo("PNG32");
7596 #if defined(MAGICKCORE_PNG_DELEGATE)
7597 entry->decoder=(DecodeImageHandler *) ReadPNGImage;
7598 entry->encoder=(EncodeImageHandler *) WritePNGImage;
7601 entry->magick=(IsImageFormatHandler *) IsPNG;
7602 entry->adjoin=MagickFalse;
7603 entry->description=ConstantString("opaque or transparent 32-bit RGBA");
7604 entry->mime_type=ConstantString("image/png");
7605 entry->module=ConstantString("PNG");
7606 (void) RegisterMagickInfo(entry);
7608 entry=SetMagickInfo("PNG48");
7610 #if defined(MAGICKCORE_PNG_DELEGATE)
7611 entry->decoder=(DecodeImageHandler *) ReadPNGImage;
7612 entry->encoder=(EncodeImageHandler *) WritePNGImage;
7615 entry->magick=(IsImageFormatHandler *) IsPNG;
7616 entry->adjoin=MagickFalse;
7617 entry->description=ConstantString("opaque or binary transparent 48-bit RGB");
7618 entry->mime_type=ConstantString("image/png");
7619 entry->module=ConstantString("PNG");
7620 (void) RegisterMagickInfo(entry);
7622 entry=SetMagickInfo("PNG64");
7624 #if defined(MAGICKCORE_PNG_DELEGATE)
7625 entry->decoder=(DecodeImageHandler *) ReadPNGImage;
7626 entry->encoder=(EncodeImageHandler *) WritePNGImage;
7629 entry->magick=(IsImageFormatHandler *) IsPNG;
7630 entry->adjoin=MagickFalse;
7631 entry->description=ConstantString("opaque or transparent 64-bit RGBA");
7632 entry->mime_type=ConstantString("image/png");
7633 entry->module=ConstantString("PNG");
7634 (void) RegisterMagickInfo(entry);
7636 entry=SetMagickInfo("PNG00");
7638 #if defined(MAGICKCORE_PNG_DELEGATE)
7639 entry->decoder=(DecodeImageHandler *) ReadPNGImage;
7640 entry->encoder=(EncodeImageHandler *) WritePNGImage;
7643 entry->magick=(IsImageFormatHandler *) IsPNG;
7644 entry->adjoin=MagickFalse;
7645 entry->description=ConstantString(
7646 "PNG inheriting bit-depth and color-type from original");
7647 entry->mime_type=ConstantString("image/png");
7648 entry->module=ConstantString("PNG");
7649 (void) RegisterMagickInfo(entry);
7651 entry=SetMagickInfo("JNG");
7653 #if defined(JNG_SUPPORTED)
7654 #if defined(MAGICKCORE_PNG_DELEGATE)
7655 entry->decoder=(DecodeImageHandler *) ReadJNGImage;
7656 entry->encoder=(EncodeImageHandler *) WriteJNGImage;
7660 entry->magick=(IsImageFormatHandler *) IsJNG;
7661 entry->adjoin=MagickFalse;
7662 entry->description=ConstantString("JPEG Network Graphics");
7663 entry->mime_type=ConstantString("image/x-jng");
7664 entry->module=ConstantString("PNG");
7665 entry->note=ConstantString(JNGNote);
7666 (void) RegisterMagickInfo(entry);
7668 #ifdef IMPNG_SETJMP_NOT_THREAD_SAFE
7669 ping_semaphore=AcquireSemaphoreInfo();
7672 return(MagickImageCoderSignature);
7676 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7680 % U n r e g i s t e r P N G I m a g e %
7684 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7686 % UnregisterPNGImage() removes format registrations made by the
7687 % PNG module from the list of supported formats.
7689 % The format of the UnregisterPNGImage method is:
7691 % UnregisterPNGImage(void)
7694 ModuleExport void UnregisterPNGImage(void)
7696 (void) UnregisterMagickInfo("MNG");
7697 (void) UnregisterMagickInfo("PNG");
7698 (void) UnregisterMagickInfo("PNG8");
7699 (void) UnregisterMagickInfo("PNG24");
7700 (void) UnregisterMagickInfo("PNG32");
7701 (void) UnregisterMagickInfo("PNG48");
7702 (void) UnregisterMagickInfo("PNG64");
7703 (void) UnregisterMagickInfo("PNG00");
7704 (void) UnregisterMagickInfo("JNG");
7706 #ifdef IMPNG_SETJMP_NOT_THREAD_SAFE
7707 if (ping_semaphore != (SemaphoreInfo *) NULL)
7708 RelinquishSemaphoreInfo(&ping_semaphore);
7712 #if defined(MAGICKCORE_PNG_DELEGATE)
7713 #if PNG_LIBPNG_VER > 10011
7715 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7719 % W r i t e M N G I m a g e %
7723 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7725 % WriteMNGImage() writes an image in the Portable Network Graphics
7726 % Group's "Multiple-image Network Graphics" encoded image format.
7728 % MNG support written by Glenn Randers-Pehrson, glennrp@image...
7730 % The format of the WriteMNGImage method is:
7732 % MagickBooleanType WriteMNGImage(const ImageInfo *image_info,
7733 % Image *image,ExceptionInfo *exception)
7735 % A description of each parameter follows.
7737 % o image_info: the image info.
7739 % o image: The image.
7741 % o exception: return any errors or warnings in this structure.
7743 % To do (as of version 5.5.2, November 26, 2002 -- glennrp -- see also
7744 % "To do" under ReadPNGImage):
7746 % Preserve all unknown and not-yet-handled known chunks found in input
7747 % PNG file and copy them into output PNG files according to the PNG
7750 % Write the iCCP chunk at MNG level when (icc profile length > 0)
7752 % Improve selection of color type (use indexed-colour or indexed-colour
7753 % with tRNS when 256 or fewer unique RGBA values are present).
7755 % Figure out what to do with "dispose=<restore-to-previous>" (dispose == 3)
7756 % This will be complicated if we limit ourselves to generating MNG-LC
7757 % files. For now we ignore disposal method 3 and simply overlay the next
7760 % Check for identical PLTE's or PLTE/tRNS combinations and use a
7761 % global MNG PLTE or PLTE/tRNS combination when appropriate.
7762 % [mostly done 15 June 1999 but still need to take care of tRNS]
7764 % Check for identical sRGB and replace with a global sRGB (and remove
7765 % gAMA/cHRM if sRGB is found; check for identical gAMA/cHRM and
7766 % replace with global gAMA/cHRM (or with sRGB if appropriate; replace
7767 % local gAMA/cHRM with local sRGB if appropriate).
7769 % Check for identical sBIT chunks and write global ones.
7771 % Provide option to skip writing the signature tEXt chunks.
7773 % Use signatures to detect identical objects and reuse the first
7774 % instance of such objects instead of writing duplicate objects.
7776 % Use a smaller-than-32k value of compression window size when
7779 % Encode JNG datastreams. Mostly done as of 5.5.2; need to write
7780 % ancillary text chunks and save profiles.
7782 % Provide an option to force LC files (to ensure exact framing rate)
7785 % Provide an option to force VLC files instead of LC, even when offsets
7786 % are present. This will involve expanding the embedded images with a
7787 % transparent region at the top and/or left.
7791 Magick_png_write_raw_profile(const ImageInfo *image_info,png_struct *ping,
7792 png_info *ping_info, unsigned char *profile_type, unsigned char
7793 *profile_description, unsigned char *profile_data, png_uint_32 length)
7812 hex[16]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
7814 if (LocaleNCompare((char *) profile_type+1, "ng-chunk-",9) == 0)
7817 if (image_info->verbose)
7819 (void) printf("writing raw profile: type=%s, length=%.20g\n",
7820 (char *) profile_type, (double) length);
7823 #if PNG_LIBPNG_VER >= 10400
7824 text=(png_textp) png_malloc(ping,(png_alloc_size_t) sizeof(png_text));
7826 text=(png_textp) png_malloc(ping,(png_size_t) sizeof(png_text));
7828 description_length=(png_uint_32) strlen((const char *) profile_description);
7829 allocated_length=(png_uint_32) (length*2 + (length >> 5) + 20
7830 + description_length);
7831 #if PNG_LIBPNG_VER >= 10400
7832 text[0].text=(png_charp) png_malloc(ping,
7833 (png_alloc_size_t) allocated_length);
7834 text[0].key=(png_charp) png_malloc(ping, (png_alloc_size_t) 80);
7836 text[0].text=(png_charp) png_malloc(ping, (png_size_t) allocated_length);
7837 text[0].key=(png_charp) png_malloc(ping, (png_size_t) 80);
7839 text[0].key[0]='\0';
7840 (void) ConcatenateMagickString(text[0].key,
7841 "Raw profile type ",MaxTextExtent);
7842 (void) ConcatenateMagickString(text[0].key,(const char *) profile_type,62);
7846 (void) CopyMagickString(dp,(const char *) profile_description,
7848 dp+=description_length;
7850 (void) FormatLocaleString(dp,allocated_length-
7851 (png_size_t) (dp-text[0].text),"%8lu ",(unsigned long) length);
7854 for (i=0; i < (ssize_t) length; i++)
7858 *(dp++)=(char) hex[((*sp >> 4) & 0x0f)];
7859 *(dp++)=(char) hex[((*sp++ ) & 0x0f)];
7864 text[0].text_length=(png_size_t) (dp-text[0].text);
7865 text[0].compression=image_info->compression == NoCompression ||
7866 (image_info->compression == UndefinedCompression &&
7867 text[0].text_length < 128) ? -1 : 0;
7869 if (text[0].text_length <= allocated_length)
7870 png_set_text(ping,ping_info,text,1);
7872 png_free(ping,text[0].text);
7873 png_free(ping,text[0].key);
7874 png_free(ping,text);
7877 static MagickBooleanType Magick_png_write_chunk_from_profile(Image *image,
7878 const char *string, MagickBooleanType logging)
7891 ResetImageProfileIterator(image);
7893 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
7895 profile=GetImageProfile(image,name);
7897 if (profile != (const StringInfo *) NULL)
7902 if (LocaleNCompare(name,string,11) == 0)
7904 if (logging != MagickFalse)
7905 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7906 " Found %s profile",name);
7908 ping_profile=CloneStringInfo(profile);
7909 data=GetStringInfoDatum(ping_profile),
7910 length=(png_uint_32) GetStringInfoLength(ping_profile);
7915 (void) WriteBlobMSBULong(image,length-5); /* data length */
7916 (void) WriteBlob(image,length-1,data+1);
7917 (void) WriteBlobMSBULong(image,crc32(0,data+1,(uInt) length-1));
7918 ping_profile=DestroyStringInfo(ping_profile);
7922 name=GetNextImageProfile(image);
7929 /* Write one PNG image */
7930 static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
7931 const ImageInfo *IMimage_info,Image *IMimage,ExceptionInfo *exception)
7962 ping_trans_alpha[256];
7990 ping_have_cheap_transparency,
8003 /* ping_exclude_EXIF, */
8006 /* ping_exclude_iTXt, */
8011 /* ping_exclude_tRNS, */
8013 ping_exclude_zCCP, /* hex-encoded iCCP */
8016 ping_preserve_colormap,
8018 ping_need_colortype_warning,
8026 *volatile pixel_info;
8045 ping_interlace_method,
8046 ping_compression_method,
8063 number_semitransparent,
8065 ping_pHYs_unit_type;
8068 ping_pHYs_x_resolution,
8069 ping_pHYs_y_resolution;
8071 logging=LogMagickEvent(CoderEvent,GetMagickModule(),
8072 " Enter WriteOnePNGImage()");
8074 image = CloneImage(IMimage,0,0,MagickFalse,exception);
8075 image_info=(ImageInfo *) CloneImageInfo(IMimage_info);
8076 if (image_info == (ImageInfo *) NULL)
8077 ThrowWriterException(ResourceLimitError, "MemoryAllocationFailed");
8079 /* Define these outside of the following "if logging()" block so they will
8080 * show in debuggers.
8083 (void) ConcatenateMagickString(im_vers,
8084 MagickLibVersionText,MaxTextExtent);
8085 (void) ConcatenateMagickString(im_vers,
8086 MagickLibAddendum,MaxTextExtent);
8089 (void) ConcatenateMagickString(libpng_vers,
8090 PNG_LIBPNG_VER_STRING,32);
8092 (void) ConcatenateMagickString(libpng_runv,
8093 png_get_libpng_ver(NULL),32);
8096 (void) ConcatenateMagickString(zlib_vers,
8099 (void) ConcatenateMagickString(zlib_runv,
8104 LogMagickEvent(CoderEvent,GetMagickModule()," IM version = %s",
8106 LogMagickEvent(CoderEvent,GetMagickModule()," Libpng version = %s",
8108 if (LocaleCompare(libpng_vers,libpng_runv) != 0)
8110 LogMagickEvent(CoderEvent,GetMagickModule()," running with %s",
8113 LogMagickEvent(CoderEvent,GetMagickModule()," Zlib version = %s",
8115 if (LocaleCompare(zlib_vers,zlib_runv) != 0)
8117 LogMagickEvent(CoderEvent,GetMagickModule()," running with %s",
8122 /* Initialize some stuff */
8125 ping_interlace_method=0,
8126 ping_compression_method=0,
8127 ping_filter_method=0,
8130 ping_background.red = 0;
8131 ping_background.green = 0;
8132 ping_background.blue = 0;
8133 ping_background.gray = 0;
8134 ping_background.index = 0;
8136 ping_trans_color.red=0;
8137 ping_trans_color.green=0;
8138 ping_trans_color.blue=0;
8139 ping_trans_color.gray=0;
8141 ping_pHYs_unit_type = 0;
8142 ping_pHYs_x_resolution = 0;
8143 ping_pHYs_y_resolution = 0;
8145 ping_have_blob=MagickFalse;
8146 ping_have_cheap_transparency=MagickFalse;
8147 ping_have_color=MagickTrue;
8148 ping_have_non_bw=MagickTrue;
8149 ping_have_PLTE=MagickFalse;
8150 ping_have_bKGD=MagickFalse;
8151 ping_have_iCCP=MagickFalse;
8152 ping_have_pHYs=MagickFalse;
8153 ping_have_sRGB=MagickFalse;
8154 ping_have_tRNS=MagickFalse;
8156 ping_exclude_bKGD=mng_info->ping_exclude_bKGD;
8157 ping_exclude_cHRM=mng_info->ping_exclude_cHRM;
8158 ping_exclude_date=mng_info->ping_exclude_date;
8159 /* ping_exclude_EXIF=mng_info->ping_exclude_EXIF; */
8160 ping_exclude_gAMA=mng_info->ping_exclude_gAMA;
8161 ping_exclude_iCCP=mng_info->ping_exclude_iCCP;
8162 /* ping_exclude_iTXt=mng_info->ping_exclude_iTXt; */
8163 ping_exclude_oFFs=mng_info->ping_exclude_oFFs;
8164 ping_exclude_pHYs=mng_info->ping_exclude_pHYs;
8165 ping_exclude_sRGB=mng_info->ping_exclude_sRGB;
8166 ping_exclude_tEXt=mng_info->ping_exclude_tEXt;
8167 /* ping_exclude_tRNS=mng_info->ping_exclude_tRNS; */
8168 ping_exclude_vpAg=mng_info->ping_exclude_vpAg;
8169 ping_exclude_zCCP=mng_info->ping_exclude_zCCP; /* hex-encoded iCCP in zTXt */
8170 ping_exclude_zTXt=mng_info->ping_exclude_zTXt;
8172 ping_preserve_colormap = mng_info->ping_preserve_colormap;
8173 ping_preserve_iCCP = mng_info->ping_preserve_iCCP;
8174 ping_need_colortype_warning = MagickFalse;
8176 /* Recognize the ICC sRGB profile and convert it to the sRGB chunk,
8177 * i.e., eliminate the ICC profile and set image->rendering_intent.
8178 * Note that this will not involve any changes to the actual pixels
8179 * but merely passes information to applications that read the resulting
8182 * To do: recognize other variants of the sRGB profile, using the CRC to
8183 * verify all recognized variants including the 7 already known.
8185 * Work around libpng16+ rejecting some "known invalid sRGB profiles".
8187 * Use something other than image->rendering_intent to record the fact
8188 * that the sRGB profile was found.
8190 * Record the ICC version (currently v2 or v4) of the incoming sRGB ICC
8191 * profile. Record the Blackpoint Compensation, if any.
8193 if (ping_exclude_sRGB == MagickFalse && ping_preserve_iCCP == MagickFalse)
8201 ResetImageProfileIterator(image);
8202 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
8204 profile=GetImageProfile(image,name);
8206 if (profile != (StringInfo *) NULL)
8208 if ((LocaleCompare(name,"ICC") == 0) ||
8209 (LocaleCompare(name,"ICM") == 0))
8224 length=(png_uint_32) GetStringInfoLength(profile);
8226 for (icheck=0; sRGB_info[icheck].len > 0; icheck++)
8228 if (length == sRGB_info[icheck].len)
8232 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8233 " Got a %lu-byte ICC profile (potentially sRGB)",
8234 (unsigned long) length);
8236 data=GetStringInfoDatum(profile);
8237 profile_crc=crc32(0,data,length);
8239 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8240 " with crc=%8x",(unsigned int) profile_crc);
8244 if (profile_crc == sRGB_info[icheck].crc)
8246 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8247 " It is sRGB with rendering intent = %s",
8248 Magick_RenderingIntentString_from_PNG_RenderingIntent(
8249 sRGB_info[icheck].intent));
8250 if (image->rendering_intent==UndefinedIntent)
8252 image->rendering_intent=
8253 Magick_RenderingIntent_from_PNG_RenderingIntent(
8254 sRGB_info[icheck].intent);
8256 ping_exclude_iCCP = MagickTrue;
8257 ping_exclude_zCCP = MagickTrue;
8258 ping_have_sRGB = MagickTrue;
8263 if (sRGB_info[icheck].len == 0)
8264 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8265 " Got a %lu-byte ICC profile not recognized as sRGB",
8266 (unsigned long) length);
8269 name=GetNextImageProfile(image);
8274 number_semitransparent = 0;
8275 number_transparent = 0;
8277 if (logging != MagickFalse)
8279 if (image->storage_class == UndefinedClass)
8280 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8281 " storage_class=UndefinedClass");
8282 if (image->storage_class == DirectClass)
8283 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8284 " storage_class=DirectClass");
8285 if (image->storage_class == PseudoClass)
8286 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8287 " storage_class=PseudoClass");
8290 if (image->storage_class == PseudoClass &&
8291 (mng_info->write_png8 || mng_info->write_png24 || mng_info->write_png32 ||
8292 mng_info->write_png48 || mng_info->write_png64 ||
8293 (mng_info->write_png_colortype != 1 &&
8294 mng_info->write_png_colortype != 5)))
8296 (void) SyncImage(image,exception);
8297 image->storage_class = DirectClass;
8300 if (ping_preserve_colormap == MagickFalse)
8302 if (image->storage_class != PseudoClass && image->colormap != NULL)
8304 /* Free the bogus colormap; it can cause trouble later */
8305 if (logging != MagickFalse)
8306 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8307 " Freeing bogus colormap");
8308 (void) RelinquishMagickMemory(image->colormap);
8309 image->colormap=NULL;
8313 if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
8314 (void) TransformImageColorspace(image,sRGBColorspace,exception);
8317 Sometimes we get PseudoClass images whose RGB values don't match
8318 the colors in the colormap. This code syncs the RGB values.
8320 if (image->depth <= 8 && image->taint && image->storage_class == PseudoClass)
8321 (void) SyncImage(image,exception);
8323 #if (MAGICKCORE_QUANTUM_DEPTH == 8)
8324 if (image->depth > 8)
8326 if (logging != MagickFalse)
8327 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8328 " Reducing PNG bit depth to 8 since this is a Q8 build.");
8334 /* Respect the -depth option */
8335 if (image->depth < MAGICKCORE_QUANTUM_DEPTH)
8340 if (image->depth > 8)
8342 #if MAGICKCORE_QUANTUM_DEPTH > 16
8343 /* Scale to 16-bit */
8344 LBR16PacketRGBO(image->background_color);
8346 for (y=0; y < (ssize_t) image->rows; y++)
8348 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8350 if (r == (Quantum *) NULL)
8353 for (x=0; x < (ssize_t) image->columns; x++)
8356 r+=GetPixelChannels(image);
8359 if (SyncAuthenticPixels(image,exception) == MagickFalse)
8363 if (image->storage_class == PseudoClass && image->colormap != NULL)
8365 for (i=0; i < (ssize_t) image->colors; i++)
8367 LBR16PacketRGBO(image->colormap[i]);
8370 #endif /* MAGICKCORE_QUANTUM_DEPTH > 16 */
8373 else if (image->depth > 4)
8375 #if MAGICKCORE_QUANTUM_DEPTH > 8
8376 /* Scale to 8-bit */
8377 LBR08PacketRGBO(image->background_color);
8379 for (y=0; y < (ssize_t) image->rows; y++)
8381 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8383 if (r == (Quantum *) NULL)
8386 for (x=0; x < (ssize_t) image->columns; x++)
8389 r+=GetPixelChannels(image);
8392 if (SyncAuthenticPixels(image,exception) == MagickFalse)
8396 if (image->storage_class == PseudoClass && image->colormap != NULL)
8398 for (i=0; i < (ssize_t) image->colors; i++)
8400 LBR08PacketRGBO(image->colormap[i]);
8403 #endif /* MAGICKCORE_QUANTUM_DEPTH > 8 */
8406 if (image->depth > 2)
8408 /* Scale to 4-bit */
8409 LBR04PacketRGBO(image->background_color);
8411 for (y=0; y < (ssize_t) image->rows; y++)
8413 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8415 if (r == (Quantum *) NULL)
8418 for (x=0; x < (ssize_t) image->columns; x++)
8421 r+=GetPixelChannels(image);
8424 if (SyncAuthenticPixels(image,exception) == MagickFalse)
8428 if (image->storage_class == PseudoClass && image->colormap != NULL)
8430 for (i=0; i < (ssize_t) image->colors; i++)
8432 LBR04PacketRGBO(image->colormap[i]);
8437 else if (image->depth > 1)
8439 /* Scale to 2-bit */
8440 LBR02PacketRGBO(image->background_color);
8442 for (y=0; y < (ssize_t) image->rows; y++)
8444 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8446 if (r == (Quantum *) NULL)
8449 for (x=0; x < (ssize_t) image->columns; x++)
8452 r+=GetPixelChannels(image);
8455 if (SyncAuthenticPixels(image,exception) == MagickFalse)
8459 if (image->storage_class == PseudoClass && image->colormap != NULL)
8461 for (i=0; i < (ssize_t) image->colors; i++)
8463 LBR02PacketRGBO(image->colormap[i]);
8469 /* Scale to 1-bit */
8470 LBR01PacketRGBO(image->background_color);
8472 for (y=0; y < (ssize_t) image->rows; y++)
8474 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8476 if (r == (Quantum *) NULL)
8479 for (x=0; x < (ssize_t) image->columns; x++)
8482 r+=GetPixelChannels(image);
8485 if (SyncAuthenticPixels(image,exception) == MagickFalse)
8489 if (image->storage_class == PseudoClass && image->colormap != NULL)
8491 for (i=0; i < (ssize_t) image->colors; i++)
8493 LBR01PacketRGBO(image->colormap[i]);
8499 /* To do: set to next higher multiple of 8 */
8500 if (image->depth < 8)
8503 #if (MAGICKCORE_QUANTUM_DEPTH > 16)
8504 /* PNG does not handle depths greater than 16 so reduce it even
8507 if (image->depth > 8)
8511 #if (MAGICKCORE_QUANTUM_DEPTH > 8)
8512 if (image->depth > 8)
8514 /* To do: fill low byte properly */
8518 if (image->depth == 16 && mng_info->write_png_depth != 16)
8519 if (mng_info->write_png8 || LosslessReduceDepthOK(image,exception) != MagickFalse)
8523 image_colors = (int) image->colors;
8524 number_opaque = (int) image->colors;
8525 number_transparent = 0;
8526 number_semitransparent = 0;
8528 if (image->storage_class != PseudoClass && mng_info->write_png_colortype &&
8529 (mng_info->write_png_colortype > 4 || (mng_info->write_png_depth >= 8 &&
8530 mng_info->write_png_colortype < 4 &&
8531 image->alpha_trait != BlendPixelTrait)))
8533 /* Avoid the expensive BUILD_PALETTE operation if we're sure that we
8534 * are not going to need the result.
8536 if (mng_info->write_png_colortype == 1 ||
8537 mng_info->write_png_colortype == 5)
8538 ping_have_color=MagickFalse;
8540 if (image->alpha_trait == BlendPixelTrait)
8542 number_transparent = 2;
8543 number_semitransparent = 1;
8551 * Normally we run this just once, but in the case of writing PNG8
8552 * we reduce the transparency to binary and run again, then if there
8553 * are still too many colors we reduce to a simple 4-4-4-1, then 3-3-3-1
8554 * RGBA palette and run again, and then to a simple 3-3-2-1 RGBA
8555 * palette. Then (To do) we take care of a final reduction that is only
8556 * needed if there are still 256 colors present and one of them has both
8557 * transparent and opaque instances.
8560 tried_332 = MagickFalse;
8561 tried_333 = MagickFalse;
8562 tried_444 = MagickFalse;
8567 * Sometimes we get DirectClass images that have 256 colors or fewer.
8568 * This code will build a colormap.
8570 * Also, sometimes we get PseudoClass images with an out-of-date
8571 * colormap. This code will replace the colormap with a new one.
8572 * Sometimes we get PseudoClass images that have more than 256 colors.
8573 * This code will delete the colormap and change the image to
8576 * If image->alpha_trait is MagickFalse, we ignore the alpha channel
8577 * even though it sometimes contains left-over non-opaque values.
8579 * Also we gather some information (number of opaque, transparent,
8580 * and semitransparent pixels, and whether the image has any non-gray
8581 * pixels or only black-and-white pixels) that we might need later.
8583 * Even if the user wants to force GrayAlpha or RGBA (colortype 4 or 6)
8584 * we need to check for bogus non-opaque values, at least.
8592 semitransparent[260],
8595 register const Quantum
8602 if (logging != MagickFalse)
8603 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8604 " Enter BUILD_PALETTE:");
8606 if (logging != MagickFalse)
8608 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8609 " image->columns=%.20g",(double) image->columns);
8610 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8611 " image->rows=%.20g",(double) image->rows);
8612 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8613 " image->alpha_trait=%.20g",(double) image->alpha_trait);
8614 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8615 " image->depth=%.20g",(double) image->depth);
8617 if (image->storage_class == PseudoClass && image->colormap != NULL)
8619 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8620 " Original colormap:");
8621 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8622 " i (red,green,blue,alpha)");
8624 for (i=0; i < 256; i++)
8626 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8627 " %d (%d,%d,%d,%d)",
8629 (int) image->colormap[i].red,
8630 (int) image->colormap[i].green,
8631 (int) image->colormap[i].blue,
8632 (int) image->colormap[i].alpha);
8635 for (i=image->colors - 10; i < (ssize_t) image->colors; i++)
8639 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8640 " %d (%d,%d,%d,%d)",
8642 (int) image->colormap[i].red,
8643 (int) image->colormap[i].green,
8644 (int) image->colormap[i].blue,
8645 (int) image->colormap[i].alpha);
8650 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8651 " image->colors=%d",(int) image->colors);
8653 if (image->colors == 0)
8654 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8655 " (zero means unknown)");
8657 if (ping_preserve_colormap == MagickFalse)
8658 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8659 " Regenerate the colormap");
8664 number_semitransparent = 0;
8665 number_transparent = 0;
8667 for (y=0; y < (ssize_t) image->rows; y++)
8669 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8671 if (q == (Quantum *) NULL)
8674 for (x=0; x < (ssize_t) image->columns; x++)
8676 if (image->alpha_trait != BlendPixelTrait ||
8677 GetPixelAlpha(image,q) == OpaqueAlpha)
8679 if (number_opaque < 259)
8681 if (number_opaque == 0)
8683 GetPixelInfoPixel(image, q, opaque);
8684 opaque[0].alpha=OpaqueAlpha;
8688 for (i=0; i< (ssize_t) number_opaque; i++)
8690 if (IsPixelEquivalent(image,q, opaque+i))
8694 if (i == (ssize_t) number_opaque && number_opaque < 259)
8697 GetPixelInfoPixel(image, q, opaque+i);
8698 opaque[i].alpha=OpaqueAlpha;
8702 else if (GetPixelAlpha(image,q) == TransparentAlpha)
8704 if (number_transparent < 259)
8706 if (number_transparent == 0)
8708 GetPixelInfoPixel(image, q, transparent);
8709 ping_trans_color.red=(unsigned short)
8710 GetPixelRed(image,q);
8711 ping_trans_color.green=(unsigned short)
8712 GetPixelGreen(image,q);
8713 ping_trans_color.blue=(unsigned short)
8714 GetPixelBlue(image,q);
8715 ping_trans_color.gray=(unsigned short)
8716 GetPixelGray(image,q);
8717 number_transparent = 1;
8720 for (i=0; i< (ssize_t) number_transparent; i++)
8722 if (IsPixelEquivalent(image,q, transparent+i))
8726 if (i == (ssize_t) number_transparent &&
8727 number_transparent < 259)
8729 number_transparent++;
8730 GetPixelInfoPixel(image,q,transparent+i);
8736 if (number_semitransparent < 259)
8738 if (number_semitransparent == 0)
8740 GetPixelInfoPixel(image,q,semitransparent);
8741 number_semitransparent = 1;
8744 for (i=0; i< (ssize_t) number_semitransparent; i++)
8746 if (IsPixelEquivalent(image,q, semitransparent+i)
8747 && GetPixelAlpha(image,q) ==
8748 semitransparent[i].alpha)
8752 if (i == (ssize_t) number_semitransparent &&
8753 number_semitransparent < 259)
8755 number_semitransparent++;
8756 GetPixelInfoPixel(image, q, semitransparent+i);
8760 q+=GetPixelChannels(image);
8764 if (mng_info->write_png8 == MagickFalse &&
8765 ping_exclude_bKGD == MagickFalse)
8767 /* Add the background color to the palette, if it
8768 * isn't already there.
8770 if (logging != MagickFalse)
8772 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8773 " Check colormap for background (%d,%d,%d)",
8774 (int) image->background_color.red,
8775 (int) image->background_color.green,
8776 (int) image->background_color.blue);
8778 for (i=0; i<number_opaque; i++)
8780 if (opaque[i].red == image->background_color.red &&
8781 opaque[i].green == image->background_color.green &&
8782 opaque[i].blue == image->background_color.blue)
8785 if (number_opaque < 259 && i == number_opaque)
8787 opaque[i] = image->background_color;
8788 ping_background.index = i;
8790 if (logging != MagickFalse)
8792 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8793 " background_color index is %d",(int) i);
8797 else if (logging != MagickFalse)
8798 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8799 " No room in the colormap to add background color");
8802 image_colors=number_opaque+number_transparent+number_semitransparent;
8804 if (logging != MagickFalse)
8806 if (image_colors > 256)
8807 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8808 " image has more than 256 colors");
8811 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8812 " image has %d colors",image_colors);
8815 if (ping_preserve_colormap != MagickFalse)
8818 if (mng_info->write_png_colortype != 7) /* We won't need this info */
8820 ping_have_color=MagickFalse;
8821 ping_have_non_bw=MagickFalse;
8823 if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
8825 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8826 "incompatible colorspace");
8827 ping_have_color=MagickTrue;
8828 ping_have_non_bw=MagickTrue;
8831 if(image_colors > 256)
8833 for (y=0; y < (ssize_t) image->rows; y++)
8835 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8837 if (q == (Quantum *) NULL)
8841 for (x=0; x < (ssize_t) image->columns; x++)
8843 if (GetPixelRed(image,s) != GetPixelGreen(image,s) ||
8844 GetPixelRed(image,s) != GetPixelBlue(image,s))
8846 ping_have_color=MagickTrue;
8847 ping_have_non_bw=MagickTrue;
8850 s+=GetPixelChannels(image);
8853 if (ping_have_color != MagickFalse)
8856 /* Worst case is black-and-white; we are looking at every
8860 if (ping_have_non_bw == MagickFalse)
8863 for (x=0; x < (ssize_t) image->columns; x++)
8865 if (GetPixelRed(image,s) != 0 &&
8866 GetPixelRed(image,s) != QuantumRange)
8868 ping_have_non_bw=MagickTrue;
8871 s+=GetPixelChannels(image);
8878 if (image_colors < 257)
8884 * Initialize image colormap.
8887 if (logging != MagickFalse)
8888 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8889 " Sort the new colormap");
8891 /* Sort palette, transparent first */;
8895 for (i=0; i<number_transparent; i++)
8896 colormap[n++] = transparent[i];
8898 for (i=0; i<number_semitransparent; i++)
8899 colormap[n++] = semitransparent[i];
8901 for (i=0; i<number_opaque; i++)
8902 colormap[n++] = opaque[i];
8904 ping_background.index +=
8905 (number_transparent + number_semitransparent);
8907 /* image_colors < 257; search the colormap instead of the pixels
8908 * to get ping_have_color and ping_have_non_bw
8912 if (ping_have_color == MagickFalse)
8914 if (colormap[i].red != colormap[i].green ||
8915 colormap[i].red != colormap[i].blue)
8917 ping_have_color=MagickTrue;
8918 ping_have_non_bw=MagickTrue;
8923 if (ping_have_non_bw == MagickFalse)
8925 if (colormap[i].red != 0 && colormap[i].red != QuantumRange)
8926 ping_have_non_bw=MagickTrue;
8930 if ((mng_info->ping_exclude_tRNS == MagickFalse ||
8931 (number_transparent == 0 && number_semitransparent == 0)) &&
8932 (((mng_info->write_png_colortype-1) ==
8933 PNG_COLOR_TYPE_PALETTE) ||
8934 (mng_info->write_png_colortype == 0)))
8936 if (logging != MagickFalse)
8938 if (n != (ssize_t) image_colors)
8939 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8940 " image_colors (%d) and n (%d) don't match",
8943 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8944 " AcquireImageColormap");
8947 image->colors = image_colors;
8949 if (AcquireImageColormap(image,image_colors,exception) ==
8951 ThrowWriterException(ResourceLimitError,
8952 "MemoryAllocationFailed");
8954 for (i=0; i< (ssize_t) image_colors; i++)
8955 image->colormap[i] = colormap[i];
8957 if (logging != MagickFalse)
8959 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8960 " image->colors=%d (%d)",
8961 (int) image->colors, image_colors);
8963 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8964 " Update the pixel indexes");
8967 /* Sync the pixel indices with the new colormap */
8969 for (y=0; y < (ssize_t) image->rows; y++)
8971 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8973 if (q == (Quantum *) NULL)
8976 for (x=0; x < (ssize_t) image->columns; x++)
8978 for (i=0; i< (ssize_t) image_colors; i++)
8980 if ((image->alpha_trait != BlendPixelTrait ||
8981 image->colormap[i].alpha == GetPixelAlpha(image,q)) &&
8982 image->colormap[i].red == GetPixelRed(image,q) &&
8983 image->colormap[i].green == GetPixelGreen(image,q) &&
8984 image->colormap[i].blue == GetPixelBlue(image,q))
8986 SetPixelIndex(image,i,q);
8990 q+=GetPixelChannels(image);
8993 if (SyncAuthenticPixels(image,exception) == MagickFalse)
8999 if (logging != MagickFalse)
9001 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9002 " image->colors=%d", (int) image->colors);
9004 if (image->colormap != NULL)
9006 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9007 " i (red,green,blue,alpha)");
9009 for (i=0; i < (ssize_t) image->colors; i++)
9011 if (i < 300 || i >= (ssize_t) image->colors - 10)
9013 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9014 " %d (%d,%d,%d,%d)",
9016 (int) image->colormap[i].red,
9017 (int) image->colormap[i].green,
9018 (int) image->colormap[i].blue,
9019 (int) image->colormap[i].alpha);
9024 if (number_transparent < 257)
9025 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9026 " number_transparent = %d",
9027 number_transparent);
9030 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9031 " number_transparent > 256");
9033 if (number_opaque < 257)
9034 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9035 " number_opaque = %d",
9039 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9040 " number_opaque > 256");
9042 if (number_semitransparent < 257)
9043 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9044 " number_semitransparent = %d",
9045 number_semitransparent);
9048 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9049 " number_semitransparent > 256");
9051 if (ping_have_non_bw == MagickFalse)
9052 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9053 " All pixels and the background are black or white");
9055 else if (ping_have_color == MagickFalse)
9056 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9057 " All pixels and the background are gray");
9060 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9061 " At least one pixel or the background is non-gray");
9063 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9064 " Exit BUILD_PALETTE:");
9067 if (mng_info->write_png8 == MagickFalse)
9070 /* Make any reductions necessary for the PNG8 format */
9071 if (image_colors <= 256 &&
9072 image_colors != 0 && image->colormap != NULL &&
9073 number_semitransparent == 0 &&
9074 number_transparent <= 1)
9077 /* PNG8 can't have semitransparent colors so we threshold the
9078 * opacity to 0 or OpaqueOpacity, and PNG8 can only have one
9079 * transparent color so if more than one is transparent we merge
9080 * them into image->background_color.
9082 if (number_semitransparent != 0 || number_transparent > 1)
9084 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9085 " Thresholding the alpha channel to binary");
9087 for (y=0; y < (ssize_t) image->rows; y++)
9089 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
9091 if (r == (Quantum *) NULL)
9094 for (x=0; x < (ssize_t) image->columns; x++)
9096 if (GetPixelAlpha(image,r) < OpaqueAlpha/2)
9098 SetPixelInfoPixel(image,&image->background_color,r);
9099 SetPixelAlpha(image,TransparentAlpha,r);
9102 SetPixelAlpha(image,OpaqueAlpha,r);
9103 r+=GetPixelChannels(image);
9106 if (SyncAuthenticPixels(image,exception) == MagickFalse)
9109 if (image_colors != 0 && image_colors <= 256 &&
9110 image->colormap != NULL)
9111 for (i=0; i<image_colors; i++)
9112 image->colormap[i].alpha =
9113 (image->colormap[i].alpha > TransparentAlpha/2 ?
9114 TransparentAlpha : OpaqueAlpha);
9119 /* PNG8 can't have more than 256 colors so we quantize the pixels and
9120 * background color to the 4-4-4-1, 3-3-3-1 or 3-3-2-1 palette. If the
9121 * image is mostly gray, the 4-4-4-1 palette is likely to end up with 256
9124 if (tried_444 == MagickFalse && (image_colors == 0 || image_colors > 256))
9126 if (logging != MagickFalse)
9127 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9128 " Quantizing the background color to 4-4-4");
9130 tried_444 = MagickTrue;
9132 LBR04PacketRGB(image->background_color);
9134 if (logging != MagickFalse)
9135 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9136 " Quantizing the pixel colors to 4-4-4");
9138 if (image->colormap == NULL)
9140 for (y=0; y < (ssize_t) image->rows; y++)
9142 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
9144 if (r == (Quantum *) NULL)
9147 for (x=0; x < (ssize_t) image->columns; x++)
9149 if (GetPixelAlpha(image,r) == OpaqueAlpha)
9151 r+=GetPixelChannels(image);
9154 if (SyncAuthenticPixels(image,exception) == MagickFalse)
9159 else /* Should not reach this; colormap already exists and
9162 if (logging != MagickFalse)
9163 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9164 " Quantizing the colormap to 4-4-4");
9166 for (i=0; i<image_colors; i++)
9168 LBR04PacketRGB(image->colormap[i]);
9174 if (tried_333 == MagickFalse && (image_colors == 0 || image_colors > 256))
9176 if (logging != MagickFalse)
9177 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9178 " Quantizing the background color to 3-3-3");
9180 tried_333 = MagickTrue;
9182 LBR03PacketRGB(image->background_color);
9184 if (logging != MagickFalse)
9185 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9186 " Quantizing the pixel colors to 3-3-3-1");
9188 if (image->colormap == NULL)
9190 for (y=0; y < (ssize_t) image->rows; y++)
9192 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
9194 if (r == (Quantum *) NULL)
9197 for (x=0; x < (ssize_t) image->columns; x++)
9199 if (GetPixelAlpha(image,r) == OpaqueAlpha)
9201 r+=GetPixelChannels(image);
9204 if (SyncAuthenticPixels(image,exception) == MagickFalse)
9209 else /* Should not reach this; colormap already exists and
9212 if (logging != MagickFalse)
9213 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9214 " Quantizing the colormap to 3-3-3-1");
9215 for (i=0; i<image_colors; i++)
9217 LBR03PacketRGB(image->colormap[i]);
9223 if (tried_332 == MagickFalse && (image_colors == 0 || image_colors > 256))
9225 if (logging != MagickFalse)
9226 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9227 " Quantizing the background color to 3-3-2");
9229 tried_332 = MagickTrue;
9231 /* Red and green were already done so we only quantize the blue
9235 LBR02PacketBlue(image->background_color);
9237 if (logging != MagickFalse)
9238 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9239 " Quantizing the pixel colors to 3-3-2-1");
9241 if (image->colormap == NULL)
9243 for (y=0; y < (ssize_t) image->rows; y++)
9245 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
9247 if (r == (Quantum *) NULL)
9250 for (x=0; x < (ssize_t) image->columns; x++)
9252 if (GetPixelAlpha(image,r) == OpaqueAlpha)
9254 r+=GetPixelChannels(image);
9257 if (SyncAuthenticPixels(image,exception) == MagickFalse)
9262 else /* Should not reach this; colormap already exists and
9265 if (logging != MagickFalse)
9266 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9267 " Quantizing the colormap to 3-3-2-1");
9268 for (i=0; i<image_colors; i++)
9270 LBR02PacketBlue(image->colormap[i]);
9276 if (image_colors == 0 || image_colors > 256)
9278 /* Take care of special case with 256 opaque colors + 1 transparent
9279 * color. We don't need to quantize to 2-3-2-1; we only need to
9280 * eliminate one color, so we'll merge the two darkest red
9281 * colors (0x49, 0, 0) -> (0x24, 0, 0).
9283 if (logging != MagickFalse)
9284 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9285 " Merging two dark red background colors to 3-3-2-1");
9287 if (ScaleQuantumToChar(image->background_color.red) == 0x49 &&
9288 ScaleQuantumToChar(image->background_color.green) == 0x00 &&
9289 ScaleQuantumToChar(image->background_color.blue) == 0x00)
9291 image->background_color.red=ScaleCharToQuantum(0x24);
9294 if (logging != MagickFalse)
9295 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9296 " Merging two dark red pixel colors to 3-3-2-1");
9298 if (image->colormap == NULL)
9300 for (y=0; y < (ssize_t) image->rows; y++)
9302 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
9304 if (r == (Quantum *) NULL)
9307 for (x=0; x < (ssize_t) image->columns; x++)
9309 if (ScaleQuantumToChar(GetPixelRed(image,r)) == 0x49 &&
9310 ScaleQuantumToChar(GetPixelGreen(image,r)) == 0x00 &&
9311 ScaleQuantumToChar(GetPixelBlue(image,r)) == 0x00 &&
9312 GetPixelAlpha(image,r) == OpaqueAlpha)
9314 SetPixelRed(image,ScaleCharToQuantum(0x24),r);
9316 r+=GetPixelChannels(image);
9319 if (SyncAuthenticPixels(image,exception) == MagickFalse)
9327 for (i=0; i<image_colors; i++)
9329 if (ScaleQuantumToChar(image->colormap[i].red) == 0x49 &&
9330 ScaleQuantumToChar(image->colormap[i].green) == 0x00 &&
9331 ScaleQuantumToChar(image->colormap[i].blue) == 0x00)
9333 image->colormap[i].red=ScaleCharToQuantum(0x24);
9340 /* END OF BUILD_PALETTE */
9342 /* If we are excluding the tRNS chunk and there is transparency,
9343 * then we must write a Gray-Alpha (color-type 4) or RGBA (color-type 6)
9346 if (mng_info->ping_exclude_tRNS != MagickFalse &&
9347 (number_transparent != 0 || number_semitransparent != 0))
9349 unsigned int colortype=mng_info->write_png_colortype;
9351 if (ping_have_color == MagickFalse)
9352 mng_info->write_png_colortype = 5;
9355 mng_info->write_png_colortype = 7;
9357 if (colortype != 0 &&
9358 mng_info->write_png_colortype != colortype)
9359 ping_need_colortype_warning=MagickTrue;
9363 /* See if cheap transparency is possible. It is only possible
9364 * when there is a single transparent color, no semitransparent
9365 * color, and no opaque color that has the same RGB components
9366 * as the transparent color. We only need this information if
9367 * we are writing a PNG with colortype 0 or 2, and we have not
9368 * excluded the tRNS chunk.
9370 if (number_transparent == 1 &&
9371 mng_info->write_png_colortype < 4)
9373 ping_have_cheap_transparency = MagickTrue;
9375 if (number_semitransparent != 0)
9376 ping_have_cheap_transparency = MagickFalse;
9378 else if (image_colors == 0 || image_colors > 256 ||
9379 image->colormap == NULL)
9381 register const Quantum
9384 for (y=0; y < (ssize_t) image->rows; y++)
9386 q=GetVirtualPixels(image,0,y,image->columns,1, exception);
9388 if (q == (Quantum *) NULL)
9391 for (x=0; x < (ssize_t) image->columns; x++)
9393 if (GetPixelAlpha(image,q) != TransparentAlpha &&
9394 (unsigned short) GetPixelRed(image,q) ==
9395 ping_trans_color.red &&
9396 (unsigned short) GetPixelGreen(image,q) ==
9397 ping_trans_color.green &&
9398 (unsigned short) GetPixelBlue(image,q) ==
9399 ping_trans_color.blue)
9401 ping_have_cheap_transparency = MagickFalse;
9405 q+=GetPixelChannels(image);
9408 if (ping_have_cheap_transparency == MagickFalse)
9414 /* Assuming that image->colormap[0] is the one transparent color
9415 * and that all others are opaque.
9417 if (image_colors > 1)
9418 for (i=1; i<image_colors; i++)
9419 if (image->colormap[i].red == image->colormap[0].red &&
9420 image->colormap[i].green == image->colormap[0].green &&
9421 image->colormap[i].blue == image->colormap[0].blue)
9423 ping_have_cheap_transparency = MagickFalse;
9428 if (logging != MagickFalse)
9430 if (ping_have_cheap_transparency == MagickFalse)
9431 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9432 " Cheap transparency is not possible.");
9435 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9436 " Cheap transparency is possible.");
9440 ping_have_cheap_transparency = MagickFalse;
9442 image_depth=image->depth;
9444 quantum_info = (QuantumInfo *) NULL;
9446 image_colors=(int) image->colors;
9447 image_matte=image->alpha_trait == BlendPixelTrait ? MagickTrue : MagickFalse;
9449 mng_info->IsPalette=image->storage_class == PseudoClass &&
9450 image_colors <= 256 && image->colormap != NULL;
9452 if ((mng_info->write_png_colortype == 4 || mng_info->write_png8) &&
9453 (image->colors == 0 || image->colormap == NULL))
9455 image_info=DestroyImageInfo(image_info);
9456 image=DestroyImage(image);
9457 (void) ThrowMagickException(exception,GetMagickModule(),CoderError,
9458 "Cannot write PNG8 or color-type 3; colormap is NULL",
9459 "`%s'",IMimage->filename);
9460 return(MagickFalse);
9464 Allocate the PNG structures
9466 #ifdef PNG_USER_MEM_SUPPORTED
9467 error_info.image=image;
9468 error_info.exception=exception;
9469 ping=png_create_write_struct_2(PNG_LIBPNG_VER_STRING,&error_info,
9470 MagickPNGErrorHandler,MagickPNGWarningHandler,(void *) NULL,
9471 (png_malloc_ptr) Magick_png_malloc,(png_free_ptr) Magick_png_free);
9474 ping=png_create_write_struct(PNG_LIBPNG_VER_STRING,&error_info,
9475 MagickPNGErrorHandler,MagickPNGWarningHandler);
9478 if (ping == (png_struct *) NULL)
9479 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
9481 ping_info=png_create_info_struct(ping);
9483 if (ping_info == (png_info *) NULL)
9485 png_destroy_write_struct(&ping,(png_info **) NULL);
9486 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
9489 png_set_write_fn(ping,image,png_put_data,png_flush_data);
9490 pixel_info=(MemoryInfo *) NULL;
9492 if (setjmp(png_jmpbuf(ping)))
9498 if (image_info->verbose)
9499 (void) printf("PNG write has failed.\n");
9501 png_destroy_write_struct(&ping,&ping_info);
9502 #ifdef IMPNG_SETJMP_NOT_THREAD_SAFE
9503 UnlockSemaphoreInfo(ping_semaphore);
9506 if (pixel_info != (MemoryInfo *) NULL)
9507 pixel_info=RelinquishVirtualMemory(pixel_info);
9509 if (quantum_info != (QuantumInfo *) NULL)
9510 quantum_info=DestroyQuantumInfo(quantum_info);
9512 if (ping_have_blob != MagickFalse)
9513 (void) CloseBlob(image);
9514 image_info=DestroyImageInfo(image_info);
9515 image=DestroyImage(image);
9516 return(MagickFalse);
9519 /* { For navigation to end of SETJMP-protected block. Within this
9520 * block, use png_error() instead of Throwing an Exception, to ensure
9521 * that libpng is able to clean up, and that the semaphore is unlocked.
9524 #ifdef IMPNG_SETJMP_NOT_THREAD_SAFE
9525 LockSemaphoreInfo(ping_semaphore);
9528 #ifdef PNG_BENIGN_ERRORS_SUPPORTED
9529 /* Allow benign errors */
9530 png_set_benign_errors(ping, 1);
9534 Prepare PNG for writing.
9537 #if defined(PNG_MNG_FEATURES_SUPPORTED)
9538 if (mng_info->write_mng)
9540 (void) png_permit_mng_features(ping,PNG_ALL_MNG_FEATURES);
9541 # ifdef PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED
9542 /* Disable new libpng-1.5.10 feature when writing a MNG because
9543 * zero-length PLTE is OK
9545 png_set_check_for_invalid_index (ping, 0);
9550 # ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
9551 if (mng_info->write_mng)
9552 png_permit_empty_plte(ping,MagickTrue);
9559 ping_width=(png_uint_32) image->columns;
9560 ping_height=(png_uint_32) image->rows;
9562 if (mng_info->write_png8 || mng_info->write_png24 || mng_info->write_png32)
9565 if (mng_info->write_png48 || mng_info->write_png64)
9568 if (mng_info->write_png_depth != 0)
9569 image_depth=mng_info->write_png_depth;
9571 /* Adjust requested depth to next higher valid depth if necessary */
9572 if (image_depth > 8)
9575 if ((image_depth > 4) && (image_depth < 8))
9578 if (image_depth == 3)
9581 if (logging != MagickFalse)
9583 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9584 " width=%.20g",(double) ping_width);
9585 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9586 " height=%.20g",(double) ping_height);
9587 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9588 " image_matte=%.20g",(double) image->alpha_trait);
9589 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9590 " image->depth=%.20g",(double) image->depth);
9591 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9592 " Tentative ping_bit_depth=%.20g",(double) image_depth);
9595 save_image_depth=image_depth;
9596 ping_bit_depth=(png_byte) save_image_depth;
9599 #if defined(PNG_pHYs_SUPPORTED)
9600 if (ping_exclude_pHYs == MagickFalse)
9602 if ((image->resolution.x != 0) && (image->resolution.y != 0) &&
9603 (!mng_info->write_mng || !mng_info->equal_physs))
9605 if (logging != MagickFalse)
9606 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9607 " Setting up pHYs chunk");
9609 if (image->units == PixelsPerInchResolution)
9611 ping_pHYs_unit_type=PNG_RESOLUTION_METER;
9612 ping_pHYs_x_resolution=
9613 (png_uint_32) ((100.0*image->resolution.x+0.5)/2.54);
9614 ping_pHYs_y_resolution=
9615 (png_uint_32) ((100.0*image->resolution.y+0.5)/2.54);
9618 else if (image->units == PixelsPerCentimeterResolution)
9620 ping_pHYs_unit_type=PNG_RESOLUTION_METER;
9621 ping_pHYs_x_resolution=(png_uint_32) (100.0*image->resolution.x+0.5);
9622 ping_pHYs_y_resolution=(png_uint_32) (100.0*image->resolution.y+0.5);
9627 ping_pHYs_unit_type=PNG_RESOLUTION_UNKNOWN;
9628 ping_pHYs_x_resolution=(png_uint_32) image->resolution.x;
9629 ping_pHYs_y_resolution=(png_uint_32) image->resolution.y;
9632 if (logging != MagickFalse)
9633 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9634 " Set up PNG pHYs chunk: xres: %.20g, yres: %.20g, units: %d.",
9635 (double) ping_pHYs_x_resolution,(double) ping_pHYs_y_resolution,
9636 (int) ping_pHYs_unit_type);
9637 ping_have_pHYs = MagickTrue;
9642 if (ping_exclude_bKGD == MagickFalse)
9644 if ((!mng_info->adjoin || !mng_info->equal_backgrounds))
9650 if (ping_bit_depth == 8)
9653 if (ping_bit_depth == 4)
9656 if (ping_bit_depth == 2)
9659 if (ping_bit_depth == 1)
9662 ping_background.red=(png_uint_16)
9663 (ScaleQuantumToShort(image->background_color.red) & mask);
9665 ping_background.green=(png_uint_16)
9666 (ScaleQuantumToShort(image->background_color.green) & mask);
9668 ping_background.blue=(png_uint_16)
9669 (ScaleQuantumToShort(image->background_color.blue) & mask);
9671 ping_background.gray=(png_uint_16) ping_background.green;
9674 if (logging != MagickFalse)
9676 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9677 " Setting up bKGD chunk (1)");
9678 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9679 " background_color index is %d",
9680 (int) ping_background.index);
9682 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9683 " ping_bit_depth=%d",ping_bit_depth);
9686 ping_have_bKGD = MagickTrue;
9690 Select the color type.
9695 if (mng_info->IsPalette && mng_info->write_png8)
9697 /* To do: make this a function cause it's used twice, except
9698 for reducing the sample depth from 8. */
9700 number_colors=image_colors;
9702 ping_have_tRNS=MagickFalse;
9707 ping_color_type=(png_byte) PNG_COLOR_TYPE_PALETTE;
9709 if (logging != MagickFalse)
9710 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9711 " Setting up PLTE chunk with %d colors (%d)",
9712 number_colors, image_colors);
9714 for (i=0; i < (ssize_t) number_colors; i++)
9716 palette[i].red=ScaleQuantumToChar(image->colormap[i].red);
9717 palette[i].green=ScaleQuantumToChar(image->colormap[i].green);
9718 palette[i].blue=ScaleQuantumToChar(image->colormap[i].blue);
9719 if (logging != MagickFalse)
9720 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9721 #if MAGICKCORE_QUANTUM_DEPTH == 8
9722 " %3ld (%3d,%3d,%3d)",
9724 " %5ld (%5d,%5d,%5d)",
9726 (long) i,palette[i].red,palette[i].green,palette[i].blue);
9730 ping_have_PLTE=MagickTrue;
9731 image_depth=ping_bit_depth;
9734 if (matte != MagickFalse)
9737 Identify which colormap entry is transparent.
9739 assert(number_colors <= 256);
9740 assert(image->colormap != NULL);
9742 for (i=0; i < (ssize_t) number_transparent; i++)
9743 ping_trans_alpha[i]=0;
9746 ping_num_trans=(unsigned short) (number_transparent +
9747 number_semitransparent);
9749 if (ping_num_trans == 0)
9750 ping_have_tRNS=MagickFalse;
9753 ping_have_tRNS=MagickTrue;
9756 if (ping_exclude_bKGD == MagickFalse)
9759 * Identify which colormap entry is the background color.
9762 for (i=0; i < (ssize_t) MagickMax(1L*number_colors-1L,1L); i++)
9763 if (IsPNGColorEqual(ping_background,image->colormap[i]))
9766 ping_background.index=(png_byte) i;
9768 if (logging != MagickFalse)
9770 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9771 " background_color index is %d",
9772 (int) ping_background.index);
9775 } /* end of write_png8 */
9777 else if (mng_info->write_png_colortype == 1)
9779 image_matte=MagickFalse;
9780 ping_color_type=(png_byte) PNG_COLOR_TYPE_GRAY;
9783 else if (mng_info->write_png24 || mng_info->write_png48 ||
9784 mng_info->write_png_colortype == 3)
9786 image_matte=MagickFalse;
9787 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB;
9790 else if (mng_info->write_png32 || mng_info->write_png64 ||
9791 mng_info->write_png_colortype == 7)
9793 image_matte=MagickTrue;
9794 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB_ALPHA;
9797 else /* mng_info->write_pngNN not specified */
9799 image_depth=ping_bit_depth;
9801 if (mng_info->write_png_colortype != 0)
9803 ping_color_type=(png_byte) mng_info->write_png_colortype-1;
9805 if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA ||
9806 ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA)
9807 image_matte=MagickTrue;
9810 image_matte=MagickFalse;
9812 if (logging != MagickFalse)
9813 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9814 " PNG colortype %d was specified:",(int) ping_color_type);
9817 else /* write_png_colortype not specified */
9819 if (logging != MagickFalse)
9820 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9821 " Selecting PNG colortype:");
9823 ping_color_type=(png_byte) ((matte != MagickFalse)?
9824 PNG_COLOR_TYPE_RGB_ALPHA:PNG_COLOR_TYPE_RGB);
9826 if (image_info->type == TrueColorType)
9828 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB;
9829 image_matte=MagickFalse;
9832 if (image_info->type == TrueColorMatteType)
9834 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB_ALPHA;
9835 image_matte=MagickTrue;
9838 if (image_info->type == PaletteType ||
9839 image_info->type == PaletteMatteType)
9840 ping_color_type=(png_byte) PNG_COLOR_TYPE_PALETTE;
9842 if (mng_info->write_png_colortype == 0 &&
9843 (image_info->type == UndefinedType ||
9844 image_info->type == OptimizeType))
9846 if (ping_have_color == MagickFalse)
9848 if (image_matte == MagickFalse)
9850 ping_color_type=(png_byte) PNG_COLOR_TYPE_GRAY;
9851 image_matte=MagickFalse;
9856 ping_color_type=(png_byte) PNG_COLOR_TYPE_GRAY_ALPHA;
9857 image_matte=MagickTrue;
9862 if (image_matte == MagickFalse)
9864 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB;
9865 image_matte=MagickFalse;
9870 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGBA;
9871 image_matte=MagickTrue;
9878 if (logging != MagickFalse)
9879 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9880 " Selected PNG colortype=%d",ping_color_type);
9882 if (ping_bit_depth < 8)
9884 if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA ||
9885 ping_color_type == PNG_COLOR_TYPE_RGB ||
9886 ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA)
9890 old_bit_depth=ping_bit_depth;
9892 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
9894 if (image->alpha_trait != BlendPixelTrait && ping_have_non_bw == MagickFalse)
9898 if (ping_color_type == PNG_COLOR_TYPE_PALETTE)
9903 if (image->colors == 0)
9906 png_error(ping,"image has 0 colors");
9909 while ((int) (one << ping_bit_depth) < (ssize_t) image_colors)
9910 ping_bit_depth <<= 1;
9913 if (logging != MagickFalse)
9915 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9916 " Number of colors: %.20g",(double) image_colors);
9918 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9919 " Tentative PNG bit depth: %d",ping_bit_depth);
9922 if (ping_bit_depth < (int) mng_info->write_png_depth)
9923 ping_bit_depth = mng_info->write_png_depth;
9926 image_depth=ping_bit_depth;
9928 if (logging != MagickFalse)
9930 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9931 " Tentative PNG color type: %s (%.20g)",
9932 PngColorTypeToString(ping_color_type),
9933 (double) ping_color_type);
9935 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9936 " image_info->type: %.20g",(double) image_info->type);
9938 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9939 " image_depth: %.20g",(double) image_depth);
9941 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9943 " image->depth: %.20g",(double) image->depth);
9945 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9946 " ping_bit_depth: %.20g",(double) ping_bit_depth);
9949 if (matte != MagickFalse)
9951 if (mng_info->IsPalette)
9953 if (mng_info->write_png_colortype == 0)
9955 ping_color_type=PNG_COLOR_TYPE_GRAY_ALPHA;
9957 if (ping_have_color != MagickFalse)
9958 ping_color_type=PNG_COLOR_TYPE_RGBA;
9962 * Determine if there is any transparent color.
9964 if (number_transparent + number_semitransparent == 0)
9967 No transparent pixels are present. Change 4 or 6 to 0 or 2.
9970 image_matte=MagickFalse;
9972 if (mng_info->write_png_colortype == 0)
9973 ping_color_type&=0x03;
9983 if (ping_bit_depth == 8)
9986 if (ping_bit_depth == 4)
9989 if (ping_bit_depth == 2)
9992 if (ping_bit_depth == 1)
9995 ping_trans_color.red=(png_uint_16)
9996 (ScaleQuantumToShort(image->colormap[0].red) & mask);
9998 ping_trans_color.green=(png_uint_16)
9999 (ScaleQuantumToShort(image->colormap[0].green) & mask);
10001 ping_trans_color.blue=(png_uint_16)
10002 (ScaleQuantumToShort(image->colormap[0].blue) & mask);
10004 ping_trans_color.gray=(png_uint_16)
10005 (ScaleQuantumToShort(GetPixelInfoIntensity(
10006 image->colormap)) & mask);
10008 ping_trans_color.index=(png_byte) 0;
10010 ping_have_tRNS=MagickTrue;
10013 if (ping_have_tRNS != MagickFalse)
10016 * Determine if there is one and only one transparent color
10017 * and if so if it is fully transparent.
10019 if (ping_have_cheap_transparency == MagickFalse)
10020 ping_have_tRNS=MagickFalse;
10023 if (ping_have_tRNS != MagickFalse)
10025 if (mng_info->write_png_colortype == 0)
10026 ping_color_type &= 0x03; /* changes 4 or 6 to 0 or 2 */
10028 if (image_depth == 8)
10030 ping_trans_color.red&=0xff;
10031 ping_trans_color.green&=0xff;
10032 ping_trans_color.blue&=0xff;
10033 ping_trans_color.gray&=0xff;
10039 if (image_depth == 8)
10041 ping_trans_color.red&=0xff;
10042 ping_trans_color.green&=0xff;
10043 ping_trans_color.blue&=0xff;
10044 ping_trans_color.gray&=0xff;
10051 if (ping_have_tRNS != MagickFalse)
10052 image_matte=MagickFalse;
10054 if ((mng_info->IsPalette) &&
10055 mng_info->write_png_colortype-1 != PNG_COLOR_TYPE_PALETTE &&
10056 ping_have_color == MagickFalse &&
10057 (image_matte == MagickFalse || image_depth >= 8))
10061 if (image_matte != MagickFalse)
10062 ping_color_type=PNG_COLOR_TYPE_GRAY_ALPHA;
10064 else if (mng_info->write_png_colortype-1 != PNG_COLOR_TYPE_GRAY_ALPHA)
10066 ping_color_type=PNG_COLOR_TYPE_GRAY;
10068 if (save_image_depth == 16 && image_depth == 8)
10070 if (logging != MagickFalse)
10072 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10073 " Scaling ping_trans_color (0)");
10075 ping_trans_color.gray*=0x0101;
10079 if (image_depth > MAGICKCORE_QUANTUM_DEPTH)
10080 image_depth=MAGICKCORE_QUANTUM_DEPTH;
10082 if ((image_colors == 0) ||
10083 ((ssize_t) (image_colors-1) > (ssize_t) MaxColormapSize))
10084 image_colors=(int) (one << image_depth);
10086 if (image_depth > 8)
10092 if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
10094 if(!mng_info->write_png_depth)
10098 while ((int) (one << ping_bit_depth)
10099 < (ssize_t) image_colors)
10100 ping_bit_depth <<= 1;
10104 else if (ping_color_type ==
10105 PNG_COLOR_TYPE_GRAY && image_colors < 17 &&
10106 mng_info->IsPalette)
10108 /* Check if grayscale is reducible */
10111 depth_4_ok=MagickTrue,
10112 depth_2_ok=MagickTrue,
10113 depth_1_ok=MagickTrue;
10115 for (i=0; i < (ssize_t) image_colors; i++)
10120 intensity=ScaleQuantumToChar(image->colormap[i].red);
10122 if ((intensity & 0x0f) != ((intensity & 0xf0) >> 4))
10123 depth_4_ok=depth_2_ok=depth_1_ok=MagickFalse;
10124 else if ((intensity & 0x03) != ((intensity & 0x0c) >> 2))
10125 depth_2_ok=depth_1_ok=MagickFalse;
10126 else if ((intensity & 0x01) != ((intensity & 0x02) >> 1))
10127 depth_1_ok=MagickFalse;
10130 if (depth_1_ok && mng_info->write_png_depth <= 1)
10133 else if (depth_2_ok && mng_info->write_png_depth <= 2)
10136 else if (depth_4_ok && mng_info->write_png_depth <= 4)
10141 image_depth=ping_bit_depth;
10146 if (mng_info->IsPalette)
10148 number_colors=image_colors;
10150 if (image_depth <= 8)
10155 ping_color_type=(png_byte) PNG_COLOR_TYPE_PALETTE;
10157 if (!(mng_info->have_write_global_plte && matte == MagickFalse))
10159 for (i=0; i < (ssize_t) number_colors; i++)
10161 palette[i].red=ScaleQuantumToChar(image->colormap[i].red);
10162 palette[i].green=ScaleQuantumToChar(image->colormap[i].green);
10163 palette[i].blue=ScaleQuantumToChar(image->colormap[i].blue);
10166 if (logging != MagickFalse)
10167 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10168 " Setting up PLTE chunk with %d colors",
10171 ping_have_PLTE=MagickTrue;
10174 /* color_type is PNG_COLOR_TYPE_PALETTE */
10175 if (mng_info->write_png_depth == 0)
10183 while ((one << ping_bit_depth) < (size_t) number_colors)
10184 ping_bit_depth <<= 1;
10189 if (matte != MagickFalse)
10192 * Set up trans_colors array.
10194 assert(number_colors <= 256);
10196 ping_num_trans=(unsigned short) (number_transparent +
10197 number_semitransparent);
10199 if (ping_num_trans == 0)
10200 ping_have_tRNS=MagickFalse;
10204 if (logging != MagickFalse)
10206 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10207 " Scaling ping_trans_color (1)");
10209 ping_have_tRNS=MagickTrue;
10211 for (i=0; i < ping_num_trans; i++)
10213 ping_trans_alpha[i]= (png_byte)
10214 ScaleQuantumToChar(image->colormap[i].alpha);
10224 if (image_depth < 8)
10227 if ((save_image_depth == 16) && (image_depth == 8))
10229 if (logging != MagickFalse)
10231 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10232 " Scaling ping_trans_color from (%d,%d,%d)",
10233 (int) ping_trans_color.red,
10234 (int) ping_trans_color.green,
10235 (int) ping_trans_color.blue);
10238 ping_trans_color.red*=0x0101;
10239 ping_trans_color.green*=0x0101;
10240 ping_trans_color.blue*=0x0101;
10241 ping_trans_color.gray*=0x0101;
10243 if (logging != MagickFalse)
10245 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10247 (int) ping_trans_color.red,
10248 (int) ping_trans_color.green,
10249 (int) ping_trans_color.blue);
10254 if (ping_bit_depth < (ssize_t) mng_info->write_png_depth)
10255 ping_bit_depth = (ssize_t) mng_info->write_png_depth;
10258 Adjust background and transparency samples in sub-8-bit grayscale files.
10260 if (ping_bit_depth < 8 && ping_color_type ==
10261 PNG_COLOR_TYPE_GRAY)
10269 maxval=(png_uint_16) ((one << ping_bit_depth)-1);
10271 if (ping_exclude_bKGD == MagickFalse)
10274 ping_background.gray=(png_uint_16) ((maxval/65535.)*
10275 (ScaleQuantumToShort(((GetPixelInfoIntensity(
10276 &image->background_color))) +.5)));
10278 if (logging != MagickFalse)
10279 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10280 " Setting up bKGD chunk (2)");
10281 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10282 " background_color index is %d",
10283 (int) ping_background.index);
10285 ping_have_bKGD = MagickTrue;
10288 if (logging != MagickFalse)
10289 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10290 " Scaling ping_trans_color.gray from %d",
10291 (int)ping_trans_color.gray);
10293 ping_trans_color.gray=(png_uint_16) ((maxval/255.)*(
10294 ping_trans_color.gray)+.5);
10296 if (logging != MagickFalse)
10297 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10298 " to %d", (int)ping_trans_color.gray);
10301 if (ping_exclude_bKGD == MagickFalse)
10303 if (mng_info->IsPalette && (int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
10306 Identify which colormap entry is the background color.
10309 number_colors=image_colors;
10311 for (i=0; i < (ssize_t) MagickMax(1L*number_colors,1L); i++)
10312 if (IsPNGColorEqual(image->background_color,image->colormap[i]))
10315 ping_background.index=(png_byte) i;
10317 if (logging != MagickFalse)
10319 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10320 " Setting up bKGD chunk with index=%d",(int) i);
10323 if (i < (ssize_t) number_colors)
10325 ping_have_bKGD = MagickTrue;
10327 if (logging != MagickFalse)
10329 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10330 " background =(%d,%d,%d)",
10331 (int) ping_background.red,
10332 (int) ping_background.green,
10333 (int) ping_background.blue);
10337 else /* Can't happen */
10339 if (logging != MagickFalse)
10340 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10341 " No room in PLTE to add bKGD color");
10342 ping_have_bKGD = MagickFalse;
10347 if (logging != MagickFalse)
10348 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10349 " PNG color type: %s (%d)", PngColorTypeToString(ping_color_type),
10352 Initialize compression level and filtering.
10354 if (logging != MagickFalse)
10356 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10357 " Setting up deflate compression");
10359 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10360 " Compression buffer size: 32768");
10363 png_set_compression_buffer_size(ping,32768L);
10365 if (logging != MagickFalse)
10366 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10367 " Compression mem level: 9");
10369 png_set_compression_mem_level(ping, 9);
10371 /* Untangle the "-quality" setting:
10373 Undefined is 0; the default is used.
10378 0 or omitted: Use Z_HUFFMAN_ONLY strategy with the
10379 zlib default compression level
10381 1-9: the zlib compression level
10385 0-4: the PNG filter method
10387 5: libpng adaptive filtering if compression level > 5
10388 libpng filter type "none" if compression level <= 5
10389 or if image is grayscale or palette
10391 6: libpng adaptive filtering
10393 7: "LOCO" filtering (intrapixel differing) if writing
10394 a MNG, otherwise "none". Did not work in IM-6.7.0-9
10395 and earlier because of a missing "else".
10397 8: Z_RLE strategy (or Z_HUFFMAN_ONLY if quality < 10), adaptive
10398 filtering. Unused prior to IM-6.7.0-10, was same as 6
10400 9: Z_RLE strategy (or Z_HUFFMAN_ONLY if quality < 10), no PNG filters
10401 Unused prior to IM-6.7.0-10, was same as 6
10403 Note that using the -quality option, not all combinations of
10404 PNG filter type, zlib compression level, and zlib compression
10405 strategy are possible. This will be addressed soon in a
10406 release that accomodates "-define png:compression-strategy", etc.
10410 quality=image_info->quality == UndefinedCompressionQuality ? 75UL :
10411 image_info->quality;
10415 if (mng_info->write_png_compression_strategy == 0)
10416 mng_info->write_png_compression_strategy = Z_HUFFMAN_ONLY+1;
10419 else if (mng_info->write_png_compression_level == 0)
10424 level=(int) MagickMin((ssize_t) quality/10,9);
10426 mng_info->write_png_compression_level = level+1;
10429 if (mng_info->write_png_compression_strategy == 0)
10431 if ((quality %10) == 8 || (quality %10) == 9)
10432 #ifdef Z_RLE /* Z_RLE was added to zlib-1.2.0 */
10433 mng_info->write_png_compression_strategy=Z_RLE+1;
10435 mng_info->write_png_compression_strategy = Z_DEFAULT_STRATEGY+1;
10439 if (mng_info->write_png_compression_filter == 0)
10440 mng_info->write_png_compression_filter=((int) quality % 10) + 1;
10442 if (logging != MagickFalse)
10444 if (mng_info->write_png_compression_level)
10445 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10446 " Compression level: %d",
10447 (int) mng_info->write_png_compression_level-1);
10449 if (mng_info->write_png_compression_strategy)
10450 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10451 " Compression strategy: %d",
10452 (int) mng_info->write_png_compression_strategy-1);
10454 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10455 " Setting up filtering");
10457 if (mng_info->write_png_compression_filter == 6)
10458 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10459 " Base filter method: ADAPTIVE");
10460 else if (mng_info->write_png_compression_filter == 0 ||
10461 mng_info->write_png_compression_filter == 1)
10462 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10463 " Base filter method: NONE");
10465 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10466 " Base filter method: %d",
10467 (int) mng_info->write_png_compression_filter-1);
10470 if (mng_info->write_png_compression_level != 0)
10471 png_set_compression_level(ping,mng_info->write_png_compression_level-1);
10473 if (mng_info->write_png_compression_filter == 6)
10475 if (((int) ping_color_type == PNG_COLOR_TYPE_GRAY) ||
10476 ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE) ||
10478 png_set_filter(ping,PNG_FILTER_TYPE_BASE,PNG_NO_FILTERS);
10480 png_set_filter(ping,PNG_FILTER_TYPE_BASE,PNG_ALL_FILTERS);
10482 else if (mng_info->write_png_compression_filter == 7 ||
10483 mng_info->write_png_compression_filter == 10)
10484 png_set_filter(ping,PNG_FILTER_TYPE_BASE,PNG_ALL_FILTERS);
10486 else if (mng_info->write_png_compression_filter == 8)
10488 #if defined(PNG_MNG_FEATURES_SUPPORTED) && defined(PNG_INTRAPIXEL_DIFFERENCING)
10489 if (mng_info->write_mng)
10491 if (((int) ping_color_type == PNG_COLOR_TYPE_RGB) ||
10492 ((int) ping_color_type == PNG_COLOR_TYPE_RGBA))
10493 ping_filter_method=PNG_INTRAPIXEL_DIFFERENCING;
10496 png_set_filter(ping,PNG_FILTER_TYPE_BASE,PNG_NO_FILTERS);
10499 else if (mng_info->write_png_compression_filter == 9)
10500 png_set_filter(ping,PNG_FILTER_TYPE_BASE,PNG_NO_FILTERS);
10502 else if (mng_info->write_png_compression_filter != 0)
10503 png_set_filter(ping,PNG_FILTER_TYPE_BASE,
10504 mng_info->write_png_compression_filter-1);
10506 if (mng_info->write_png_compression_strategy != 0)
10507 png_set_compression_strategy(ping,
10508 mng_info->write_png_compression_strategy-1);
10510 ping_interlace_method=image_info->interlace != NoInterlace;
10512 if (mng_info->write_mng)
10513 png_set_sig_bytes(ping,8);
10515 /* Bail out if cannot meet defined png:bit-depth or png:color-type */
10517 if (mng_info->write_png_colortype != 0)
10519 if (mng_info->write_png_colortype-1 == PNG_COLOR_TYPE_GRAY)
10520 if (ping_have_color != MagickFalse)
10522 ping_color_type = PNG_COLOR_TYPE_RGB;
10524 if (ping_bit_depth < 8)
10528 if (mng_info->write_png_colortype-1 == PNG_COLOR_TYPE_GRAY_ALPHA)
10529 if (ping_have_color != MagickFalse)
10530 ping_color_type = PNG_COLOR_TYPE_RGB_ALPHA;
10533 if (ping_need_colortype_warning != MagickFalse ||
10534 ((mng_info->write_png_depth &&
10535 (int) mng_info->write_png_depth != ping_bit_depth) ||
10536 (mng_info->write_png_colortype &&
10537 ((int) mng_info->write_png_colortype-1 != ping_color_type &&
10538 mng_info->write_png_colortype != 7 &&
10539 !(mng_info->write_png_colortype == 5 && ping_color_type == 0)))))
10541 if (logging != MagickFalse)
10543 if (ping_need_colortype_warning != MagickFalse)
10545 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10546 " Image has transparency but tRNS chunk was excluded");
10549 if (mng_info->write_png_depth)
10551 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10552 " Defined png:bit-depth=%u, Computed depth=%u",
10553 mng_info->write_png_depth,
10557 if (mng_info->write_png_colortype)
10559 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10560 " Defined png:color-type=%u, Computed color type=%u",
10561 mng_info->write_png_colortype-1,
10567 "Cannot write image with defined png:bit-depth or png:color-type.");
10570 if (image_matte != MagickFalse && image->alpha_trait != BlendPixelTrait)
10572 /* Add an opaque matte channel */
10573 image->alpha_trait = BlendPixelTrait;
10574 (void) SetImageAlpha(image,OpaqueAlpha,exception);
10576 if (logging != MagickFalse)
10577 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10578 " Added an opaque matte channel");
10581 if (number_transparent != 0 || number_semitransparent != 0)
10583 if (ping_color_type < 4)
10585 ping_have_tRNS=MagickTrue;
10586 if (logging != MagickFalse)
10587 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10588 " Setting ping_have_tRNS=MagickTrue.");
10592 if (logging != MagickFalse)
10593 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10594 " Writing PNG header chunks");
10596 png_set_IHDR(ping,ping_info,ping_width,ping_height,
10597 ping_bit_depth,ping_color_type,
10598 ping_interlace_method,ping_compression_method,
10599 ping_filter_method);
10601 if (ping_color_type == 3 && ping_have_PLTE != MagickFalse)
10603 png_set_PLTE(ping,ping_info,palette,number_colors);
10605 if (logging != MagickFalse)
10607 for (i=0; i< (ssize_t) number_colors; i++)
10609 if (i < ping_num_trans)
10610 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10611 " PLTE[%d] = (%d,%d,%d), tRNS[%d] = (%d)",
10613 (int) palette[i].red,
10614 (int) palette[i].green,
10615 (int) palette[i].blue,
10617 (int) ping_trans_alpha[i]);
10619 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10620 " PLTE[%d] = (%d,%d,%d)",
10622 (int) palette[i].red,
10623 (int) palette[i].green,
10624 (int) palette[i].blue);
10629 /* Only write the iCCP chunk if we are not writing the sRGB chunk. */
10630 if (ping_exclude_sRGB != MagickFalse ||
10631 (!png_get_valid(ping,ping_info,PNG_INFO_sRGB)))
10633 if ((ping_exclude_tEXt == MagickFalse ||
10634 ping_exclude_zTXt == MagickFalse) &&
10635 (ping_exclude_iCCP == MagickFalse || ping_exclude_zCCP == MagickFalse))
10637 ResetImageProfileIterator(image);
10638 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
10640 profile=GetImageProfile(image,name);
10642 if (profile != (StringInfo *) NULL)
10644 #ifdef PNG_WRITE_iCCP_SUPPORTED
10645 if ((LocaleCompare(name,"ICC") == 0) ||
10646 (LocaleCompare(name,"ICM") == 0))
10649 if (ping_exclude_iCCP == MagickFalse)
10651 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10652 " Setting up iCCP chunk");
10654 png_set_iCCP(ping,ping_info,(png_charp) name,0,
10655 #if (PNG_LIBPNG_VER < 10500)
10656 (png_charp) GetStringInfoDatum(profile),
10658 (png_const_bytep) GetStringInfoDatum(profile),
10660 (png_uint_32) GetStringInfoLength(profile));
10661 ping_have_iCCP = MagickTrue;
10667 if (ping_exclude_zCCP == MagickFalse)
10669 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10670 " Setting up zTXT chunk with uuencoded ICC");
10671 Magick_png_write_raw_profile(image_info,ping,ping_info,
10672 (unsigned char *) name,(unsigned char *) name,
10673 GetStringInfoDatum(profile),
10674 (png_uint_32) GetStringInfoLength(profile));
10675 ping_have_iCCP = MagickTrue;
10679 if (logging != MagickFalse)
10680 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10681 " Setting up text chunk with %s profile",name);
10683 name=GetNextImageProfile(image);
10688 #if defined(PNG_WRITE_sRGB_SUPPORTED)
10689 if ((mng_info->have_write_global_srgb == 0) &&
10690 ping_have_iCCP != MagickTrue &&
10691 (ping_have_sRGB != MagickFalse ||
10692 png_get_valid(ping,ping_info,PNG_INFO_sRGB)))
10694 if (ping_exclude_sRGB == MagickFalse)
10697 Note image rendering intent.
10699 if (logging != MagickFalse)
10700 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10701 " Setting up sRGB chunk");
10703 (void) png_set_sRGB(ping,ping_info,(
10704 Magick_RenderingIntent_to_PNG_RenderingIntent(
10705 image->rendering_intent)));
10707 ping_have_sRGB = MagickTrue;
10711 if ((!mng_info->write_mng) || (!png_get_valid(ping,ping_info,PNG_INFO_sRGB)))
10714 if (ping_exclude_gAMA == MagickFalse &&
10715 ping_have_iCCP == MagickFalse &&
10716 ping_have_sRGB == MagickFalse &&
10717 (ping_exclude_sRGB == MagickFalse ||
10718 (image->gamma < .45 || image->gamma > .46)))
10720 if ((mng_info->have_write_global_gama == 0) && (image->gamma != 0.0))
10724 To do: check for cHRM+gAMA == sRGB, and write sRGB instead.
10726 if (logging != MagickFalse)
10727 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10728 " Setting up gAMA chunk");
10730 png_set_gAMA(ping,ping_info,image->gamma);
10734 if (ping_exclude_cHRM == MagickFalse && ping_have_sRGB == MagickFalse)
10736 if ((mng_info->have_write_global_chrm == 0) &&
10737 (image->chromaticity.red_primary.x != 0.0))
10740 Note image chromaticity.
10741 Note: if cHRM+gAMA == sRGB write sRGB instead.
10749 wp=image->chromaticity.white_point;
10750 rp=image->chromaticity.red_primary;
10751 gp=image->chromaticity.green_primary;
10752 bp=image->chromaticity.blue_primary;
10754 if (logging != MagickFalse)
10755 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10756 " Setting up cHRM chunk");
10758 png_set_cHRM(ping,ping_info,wp.x,wp.y,rp.x,rp.y,gp.x,gp.y,
10764 if (ping_exclude_bKGD == MagickFalse)
10766 if (ping_have_bKGD != MagickFalse)
10768 png_set_bKGD(ping,ping_info,&ping_background);
10771 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10772 " Setting up bKGD chunk");
10773 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10774 " background color = (%d,%d,%d)",
10775 (int) ping_background.red,
10776 (int) ping_background.green,
10777 (int) ping_background.blue);
10778 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10779 " index = %d, gray=%d",
10780 (int) ping_background.index,
10781 (int) ping_background.gray);
10786 if (ping_exclude_pHYs == MagickFalse)
10788 if (ping_have_pHYs != MagickFalse)
10790 png_set_pHYs(ping,ping_info,
10791 ping_pHYs_x_resolution,
10792 ping_pHYs_y_resolution,
10793 ping_pHYs_unit_type);
10797 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10798 " Setting up pHYs chunk");
10799 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10800 " x_resolution=%lu",
10801 (unsigned long) ping_pHYs_x_resolution);
10802 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10803 " y_resolution=%lu",
10804 (unsigned long) ping_pHYs_y_resolution);
10805 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10807 (unsigned long) ping_pHYs_unit_type);
10812 #if defined(PNG_oFFs_SUPPORTED)
10813 if (ping_exclude_oFFs == MagickFalse)
10815 if (image->page.x || image->page.y)
10817 png_set_oFFs(ping,ping_info,(png_int_32) image->page.x,
10818 (png_int_32) image->page.y, 0);
10820 if (logging != MagickFalse)
10821 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10822 " Setting up oFFs chunk with x=%d, y=%d, units=0",
10823 (int) image->page.x, (int) image->page.y);
10828 if (mng_info->need_blob != MagickFalse)
10830 if (OpenBlob(image_info,image,WriteBinaryBlobMode,exception) ==
10832 png_error(ping,"WriteBlob Failed");
10834 ping_have_blob=MagickTrue;
10837 png_write_info_before_PLTE(ping, ping_info);
10839 if (ping_have_tRNS != MagickFalse && ping_color_type < 4)
10841 if (logging != MagickFalse)
10843 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10844 " Calling png_set_tRNS with num_trans=%d",ping_num_trans);
10847 if (ping_color_type == 3)
10848 (void) png_set_tRNS(ping, ping_info,
10855 (void) png_set_tRNS(ping, ping_info,
10858 &ping_trans_color);
10860 if (logging != MagickFalse)
10862 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10863 " tRNS color =(%d,%d,%d)",
10864 (int) ping_trans_color.red,
10865 (int) ping_trans_color.green,
10866 (int) ping_trans_color.blue);
10871 /* write any png-chunk-b profiles */
10872 (void) Magick_png_write_chunk_from_profile(image,"PNG-chunk-b",logging);
10874 png_write_info(ping,ping_info);
10876 /* write any PNG-chunk-m profiles */
10877 (void) Magick_png_write_chunk_from_profile(image,"PNG-chunk-m",logging);
10879 if (ping_exclude_vpAg == MagickFalse)
10881 if ((image->page.width != 0 && image->page.width != image->columns) ||
10882 (image->page.height != 0 && image->page.height != image->rows))
10887 (void) WriteBlobMSBULong(image,9L); /* data length=8 */
10888 PNGType(chunk,mng_vpAg);
10889 LogPNGChunk(logging,mng_vpAg,9L);
10890 PNGLong(chunk+4,(png_uint_32) image->page.width);
10891 PNGLong(chunk+8,(png_uint_32) image->page.height);
10892 chunk[12]=0; /* unit = pixels */
10893 (void) WriteBlob(image,13,chunk);
10894 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
10898 #if (PNG_LIBPNG_VER == 10206)
10899 /* avoid libpng-1.2.6 bug by setting PNG_HAVE_IDAT flag */
10900 #define PNG_HAVE_IDAT 0x04
10901 ping->mode |= PNG_HAVE_IDAT;
10902 #undef PNG_HAVE_IDAT
10905 png_set_packing(ping);
10909 rowbytes=image->columns;
10910 if (image_depth > 8)
10912 switch (ping_color_type)
10914 case PNG_COLOR_TYPE_RGB:
10918 case PNG_COLOR_TYPE_GRAY_ALPHA:
10922 case PNG_COLOR_TYPE_RGBA:
10930 if (logging != MagickFalse)
10932 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10933 " Writing PNG image data");
10935 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10936 " Allocating %.20g bytes of memory for pixels",(double) rowbytes);
10938 pixel_info=AcquireVirtualMemory(rowbytes,sizeof(*ping_pixels));
10939 if (pixel_info == (MemoryInfo *) NULL)
10940 png_error(ping,"Allocation of memory for pixels failed");
10941 ping_pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
10944 Initialize image scanlines.
10946 quantum_info=AcquireQuantumInfo(image_info,image);
10947 if (quantum_info == (QuantumInfo *) NULL)
10948 png_error(ping,"Memory allocation for quantum_info failed");
10949 quantum_info->format=UndefinedQuantumFormat;
10950 quantum_info->depth=image_depth;
10951 (void) SetQuantumEndian(image,quantum_info,MSBEndian);
10952 num_passes=png_set_interlace_handling(ping);
10954 if ((!mng_info->write_png8 && !mng_info->write_png24 &&
10955 !mng_info->write_png48 && !mng_info->write_png64 &&
10956 !mng_info->write_png32) &&
10957 (mng_info->IsPalette ||
10958 (image_info->type == BilevelType)) &&
10959 image_matte == MagickFalse &&
10960 ping_have_non_bw == MagickFalse)
10962 /* Palette, Bilevel, or Opaque Monochrome */
10963 register const Quantum
10966 quantum_info->depth=8;
10967 for (pass=0; pass < num_passes; pass++)
10970 Convert PseudoClass image to a PNG monochrome image.
10972 for (y=0; y < (ssize_t) image->rows; y++)
10974 if (logging != MagickFalse && y == 0)
10975 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10976 " Writing row of pixels (0)");
10978 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
10980 if (p == (const Quantum *) NULL)
10983 if (mng_info->IsPalette)
10985 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10986 quantum_info,GrayQuantum,ping_pixels,exception);
10987 if (mng_info->write_png_colortype-1 == PNG_COLOR_TYPE_PALETTE &&
10988 mng_info->write_png_depth &&
10989 mng_info->write_png_depth != old_bit_depth)
10991 /* Undo pixel scaling */
10992 for (i=0; i < (ssize_t) image->columns; i++)
10993 *(ping_pixels+i)=(unsigned char) (*(ping_pixels+i)
10994 >> (8-old_bit_depth));
11000 (void) ExportQuantumPixels(image,(CacheView *) NULL,
11001 quantum_info,RedQuantum,ping_pixels,exception);
11004 if (mng_info->write_png_colortype-1 != PNG_COLOR_TYPE_PALETTE)
11005 for (i=0; i < (ssize_t) image->columns; i++)
11006 *(ping_pixels+i)=(unsigned char) ((*(ping_pixels+i) > 127) ?
11009 if (logging != MagickFalse && y == 0)
11010 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11011 " Writing row of pixels (1)");
11013 png_write_row(ping,ping_pixels);
11015 if (image->previous == (Image *) NULL)
11017 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
11018 if (status == MagickFalse)
11024 else /* Not Palette, Bilevel, or Opaque Monochrome */
11026 if ((!mng_info->write_png8 && !mng_info->write_png24 &&
11027 !mng_info->write_png48 && !mng_info->write_png64 &&
11028 !mng_info->write_png32) && (image_matte != MagickFalse ||
11029 (ping_bit_depth >= MAGICKCORE_QUANTUM_DEPTH)) &&
11030 (mng_info->IsPalette) && ping_have_color == MagickFalse)
11032 register const Quantum
11035 for (pass=0; pass < num_passes; pass++)
11038 for (y=0; y < (ssize_t) image->rows; y++)
11040 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
11042 if (p == (const Quantum *) NULL)
11045 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
11047 if (mng_info->IsPalette)
11048 (void) ExportQuantumPixels(image,(CacheView *) NULL,
11049 quantum_info,GrayQuantum,ping_pixels,exception);
11052 (void) ExportQuantumPixels(image,(CacheView *) NULL,
11053 quantum_info,RedQuantum,ping_pixels,exception);
11055 if (logging != MagickFalse && y == 0)
11056 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11057 " Writing GRAY PNG pixels (2)");
11060 else /* PNG_COLOR_TYPE_GRAY_ALPHA */
11062 if (logging != MagickFalse && y == 0)
11063 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11064 " Writing GRAY_ALPHA PNG pixels (2)");
11066 (void) ExportQuantumPixels(image,(CacheView *) NULL,
11067 quantum_info,GrayAlphaQuantum,ping_pixels,exception);
11070 if (logging != MagickFalse && y == 0)
11071 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11072 " Writing row of pixels (2)");
11074 png_write_row(ping,ping_pixels);
11077 if (image->previous == (Image *) NULL)
11079 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
11080 if (status == MagickFalse)
11088 register const Quantum
11091 for (pass=0; pass < num_passes; pass++)
11093 if ((image_depth > 8) ||
11094 mng_info->write_png24 ||
11095 mng_info->write_png32 ||
11096 mng_info->write_png48 ||
11097 mng_info->write_png64 ||
11098 (!mng_info->write_png8 && !mng_info->IsPalette))
11100 for (y=0; y < (ssize_t) image->rows; y++)
11102 p=GetVirtualPixels(image,0,y,image->columns,1, exception);
11104 if (p == (const Quantum *) NULL)
11107 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
11109 if (image->storage_class == DirectClass)
11110 (void) ExportQuantumPixels(image,(CacheView *) NULL,
11111 quantum_info,RedQuantum,ping_pixels,exception);
11114 (void) ExportQuantumPixels(image,(CacheView *) NULL,
11115 quantum_info,GrayQuantum,ping_pixels,exception);
11118 else if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
11120 (void) ExportQuantumPixels(image,(CacheView *) NULL,
11121 quantum_info,GrayAlphaQuantum,ping_pixels,
11124 if (logging != MagickFalse && y == 0)
11125 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11126 " Writing GRAY_ALPHA PNG pixels (3)");
11129 else if (image_matte != MagickFalse)
11130 (void) ExportQuantumPixels(image,(CacheView *) NULL,
11131 quantum_info,RGBAQuantum,ping_pixels,exception);
11134 (void) ExportQuantumPixels(image,(CacheView *) NULL,
11135 quantum_info,RGBQuantum,ping_pixels,exception);
11137 if (logging != MagickFalse && y == 0)
11138 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11139 " Writing row of pixels (3)");
11141 png_write_row(ping,ping_pixels);
11146 /* not ((image_depth > 8) ||
11147 mng_info->write_png24 || mng_info->write_png32 ||
11148 mng_info->write_png48 || mng_info->write_png64 ||
11149 (!mng_info->write_png8 && !mng_info->IsPalette))
11152 if ((ping_color_type != PNG_COLOR_TYPE_GRAY) &&
11153 (ping_color_type != PNG_COLOR_TYPE_GRAY_ALPHA))
11155 if (logging != MagickFalse)
11156 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11157 " pass %d, Image Is not GRAY or GRAY_ALPHA",pass);
11159 quantum_info->depth=8;
11163 for (y=0; y < (ssize_t) image->rows; y++)
11165 if (logging != MagickFalse && y == 0)
11166 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11167 " pass %d, Image Is RGB, 16-bit GRAY, or GRAY_ALPHA",pass);
11169 p=GetVirtualPixels(image,0,y,image->columns,1, exception);
11171 if (p == (const Quantum *) NULL)
11174 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
11176 quantum_info->depth=image->depth;
11178 (void) ExportQuantumPixels(image,(CacheView *) NULL,
11179 quantum_info,GrayQuantum,ping_pixels,exception);
11182 else if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
11184 if (logging != MagickFalse && y == 0)
11185 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11186 " Writing GRAY_ALPHA PNG pixels (4)");
11188 (void) ExportQuantumPixels(image,(CacheView *) NULL,
11189 quantum_info,GrayAlphaQuantum,ping_pixels,
11195 (void) ExportQuantumPixels(image,(CacheView *) NULL,
11196 quantum_info,IndexQuantum,ping_pixels,exception);
11198 if (logging != MagickFalse && y <= 2)
11200 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11201 " Writing row of non-gray pixels (4)");
11203 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11204 " ping_pixels[0]=%d,ping_pixels[1]=%d",
11205 (int)ping_pixels[0],(int)ping_pixels[1]);
11208 png_write_row(ping,ping_pixels);
11212 if (image->previous == (Image *) NULL)
11214 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
11215 if (status == MagickFalse)
11222 if (quantum_info != (QuantumInfo *) NULL)
11223 quantum_info=DestroyQuantumInfo(quantum_info);
11225 if (logging != MagickFalse)
11227 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11228 " Wrote PNG image data");
11230 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11231 " Width: %.20g",(double) ping_width);
11233 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11234 " Height: %.20g",(double) ping_height);
11236 if (mng_info->write_png_depth)
11238 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11239 " Defined png:bit-depth: %d",mng_info->write_png_depth);
11242 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11243 " PNG bit-depth written: %d",ping_bit_depth);
11245 if (mng_info->write_png_colortype)
11247 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11248 " Defined png:color-type: %d",mng_info->write_png_colortype-1);
11251 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11252 " PNG color-type written: %d",ping_color_type);
11254 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11255 " PNG Interlace method: %d",ping_interlace_method);
11258 Generate text chunks after IDAT.
11260 if (ping_exclude_tEXt == MagickFalse || ping_exclude_zTXt == MagickFalse)
11262 ResetImagePropertyIterator(image);
11263 property=GetNextImageProperty(image);
11264 while (property != (const char *) NULL)
11269 value=GetImageProperty(image,property,exception);
11271 /* Don't write any "png:" or "jpeg:" properties; those are just for
11272 * "identify" or for passing through to another JPEG
11274 if ((LocaleNCompare(property,"png:",4) != 0 &&
11275 LocaleNCompare(property,"jpeg:",5) != 0) &&
11278 /* Suppress density and units if we wrote a pHYs chunk */
11279 (ping_exclude_pHYs != MagickFalse ||
11280 LocaleCompare(property,"density") != 0 ||
11281 LocaleCompare(property,"units") != 0) &&
11283 /* Suppress the IM-generated Date:create and Date:modify */
11284 (ping_exclude_date == MagickFalse ||
11285 LocaleNCompare(property, "Date:",5) != 0))
11287 if (value != (const char *) NULL)
11290 #if PNG_LIBPNG_VER >= 10400
11291 text=(png_textp) png_malloc(ping,
11292 (png_alloc_size_t) sizeof(png_text));
11294 text=(png_textp) png_malloc(ping,(png_size_t) sizeof(png_text));
11296 text[0].key=(char *) property;
11297 text[0].text=(char *) value;
11298 text[0].text_length=strlen(value);
11300 if (ping_exclude_tEXt != MagickFalse)
11301 text[0].compression=PNG_TEXT_COMPRESSION_zTXt;
11303 else if (ping_exclude_zTXt != MagickFalse)
11304 text[0].compression=PNG_TEXT_COMPRESSION_NONE;
11308 text[0].compression=image_info->compression == NoCompression ||
11309 (image_info->compression == UndefinedCompression &&
11310 text[0].text_length < 128) ? PNG_TEXT_COMPRESSION_NONE :
11311 PNG_TEXT_COMPRESSION_zTXt ;
11314 if (logging != MagickFalse)
11316 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11317 " Setting up text chunk");
11319 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11320 " keyword: '%s'",text[0].key);
11323 png_set_text(ping,ping_info,text,1);
11324 png_free(ping,text);
11327 property=GetNextImageProperty(image);
11331 /* write any PNG-chunk-e profiles */
11332 (void) Magick_png_write_chunk_from_profile(image,"PNG-chunk-e",logging);
11334 if (logging != MagickFalse)
11335 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11336 " Writing PNG end info");
11338 png_write_end(ping,ping_info);
11340 if (mng_info->need_fram && (int) image->dispose == BackgroundDispose)
11342 if (mng_info->page.x || mng_info->page.y ||
11343 (ping_width != mng_info->page.width) ||
11344 (ping_height != mng_info->page.height))
11350 Write FRAM 4 with clipping boundaries followed by FRAM 1.
11352 (void) WriteBlobMSBULong(image,27L); /* data length=27 */
11353 PNGType(chunk,mng_FRAM);
11354 LogPNGChunk(logging,mng_FRAM,27L);
11356 chunk[5]=0; /* frame name separator (no name) */
11357 chunk[6]=1; /* flag for changing delay, for next frame only */
11358 chunk[7]=0; /* flag for changing frame timeout */
11359 chunk[8]=1; /* flag for changing frame clipping for next frame */
11360 chunk[9]=0; /* flag for changing frame sync_id */
11361 PNGLong(chunk+10,(png_uint_32) (0L)); /* temporary 0 delay */
11362 chunk[14]=0; /* clipping boundaries delta type */
11363 PNGLong(chunk+15,(png_uint_32) (mng_info->page.x)); /* left cb */
11365 (png_uint_32) (mng_info->page.x + ping_width));
11366 PNGLong(chunk+23,(png_uint_32) (mng_info->page.y)); /* top cb */
11368 (png_uint_32) (mng_info->page.y + ping_height));
11369 (void) WriteBlob(image,31,chunk);
11370 (void) WriteBlobMSBULong(image,crc32(0,chunk,31));
11371 mng_info->old_framing_mode=4;
11372 mng_info->framing_mode=1;
11376 mng_info->framing_mode=3;
11378 if (mng_info->write_mng && !mng_info->need_fram &&
11379 ((int) image->dispose == 3))
11380 png_error(ping, "Cannot convert GIF with disposal method 3 to MNG-LC");
11383 Free PNG resources.
11386 png_destroy_write_struct(&ping,&ping_info);
11388 pixel_info=RelinquishVirtualMemory(pixel_info);
11390 if (ping_have_blob != MagickFalse)
11391 (void) CloseBlob(image);
11393 image_info=DestroyImageInfo(image_info);
11394 image=DestroyImage(image);
11396 /* Store bit depth actually written */
11397 s[0]=(char) ping_bit_depth;
11400 (void) SetImageProperty(IMimage,"png:bit-depth-written",s,exception);
11402 if (logging != MagickFalse)
11403 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11404 " exit WriteOnePNGImage()");
11406 #ifdef IMPNG_SETJMP_NOT_THREAD_SAFE
11407 UnlockSemaphoreInfo(ping_semaphore);
11410 /* } for navigation to beginning of SETJMP-protected block. Revert to
11411 * Throwing an Exception when an error occurs.
11414 return(MagickTrue);
11415 /* End write one PNG image */
11420 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11424 % W r i t e P N G I m a g e %
11428 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11430 % WritePNGImage() writes a Portable Network Graphics (PNG) or
11431 % Multiple-image Network Graphics (MNG) image file.
11433 % MNG support written by Glenn Randers-Pehrson, glennrp@image...
11435 % The format of the WritePNGImage method is:
11437 % MagickBooleanType WritePNGImage(const ImageInfo *image_info,
11438 % Image *image,ExceptionInfo *exception)
11440 % A description of each parameter follows:
11442 % o image_info: the image info.
11444 % o image: The image.
11446 % o exception: return any errors or warnings in this structure.
11448 % Returns MagickTrue on success, MagickFalse on failure.
11450 % Communicating with the PNG encoder:
11452 % While the datastream written is always in PNG format and normally would
11453 % be given the "png" file extension, this method also writes the following
11454 % pseudo-formats which are subsets of png:
11456 % o PNG8: An 8-bit indexed PNG datastream is written. If the image has
11457 % a depth greater than 8, the depth is reduced. If transparency
11458 % is present, the tRNS chunk must only have values 0 and 255
11459 % (i.e., transparency is binary: fully opaque or fully
11460 % transparent). If other values are present they will be
11461 % 50%-thresholded to binary transparency. If more than 256
11462 % colors are present, they will be quantized to the 4-4-4-1,
11463 % 3-3-3-1, or 3-3-2-1 palette. The underlying RGB color
11464 % of any resulting fully-transparent pixels is changed to
11465 % the image's background color.
11467 % If you want better quantization or dithering of the colors
11468 % or alpha than that, you need to do it before calling the
11469 % PNG encoder. The pixels contain 8-bit indices even if
11470 % they could be represented with 1, 2, or 4 bits. Grayscale
11471 % images will be written as indexed PNG files even though the
11472 % PNG grayscale type might be slightly more efficient. Please
11473 % note that writing to the PNG8 format may result in loss
11474 % of color and alpha data.
11476 % o PNG24: An 8-bit per sample RGB PNG datastream is written. The tRNS
11477 % chunk can be present to convey binary transparency by naming
11478 % one of the colors as transparent. The only loss incurred
11479 % is reduction of sample depth to 8. If the image has more
11480 % than one transparent color, has semitransparent pixels, or
11481 % has an opaque pixel with the same RGB components as the
11482 % transparent color, an image is not written.
11484 % o PNG32: An 8-bit per sample RGBA PNG is written. Partial
11485 % transparency is permitted, i.e., the alpha sample for
11486 % each pixel can have any value from 0 to 255. The alpha
11487 % channel is present even if the image is fully opaque.
11488 % The only loss in data is the reduction of the sample depth
11491 % o PNG48: A 16-bit per sample RGB PNG datastream is written. The tRNS
11492 % chunk can be present to convey binary transparency by naming
11493 % one of the colors as transparent. If the image has more
11494 % than one transparent color, has semitransparent pixels, or
11495 % has an opaque pixel with the same RGB components as the
11496 % transparent color, an image is not written.
11498 % o PNG64: A 16-bit per sample RGBA PNG is written. Partial
11499 % transparency is permitted, i.e., the alpha sample for
11500 % each pixel can have any value from 0 to 65535. The alpha
11501 % channel is present even if the image is fully opaque.
11503 % o PNG00: A PNG that inherits its colortype and bit-depth from the input
11504 % image, if the input was a PNG, is written. If these values
11505 % cannot be found, then "PNG00" falls back to the regular "PNG"
11508 % o -define: For more precise control of the PNG output, you can use the
11509 % Image options "png:bit-depth" and "png:color-type". These
11510 % can be set from the commandline with "-define" and also
11511 % from the application programming interfaces. The options
11512 % are case-independent and are converted to lowercase before
11513 % being passed to this encoder.
11515 % png:color-type can be 0, 2, 3, 4, or 6.
11517 % When png:color-type is 0 (Grayscale), png:bit-depth can
11518 % be 1, 2, 4, 8, or 16.
11520 % When png:color-type is 2 (RGB), png:bit-depth can
11523 % When png:color-type is 3 (Indexed), png:bit-depth can
11524 % be 1, 2, 4, or 8. This refers to the number of bits
11525 % used to store the index. The color samples always have
11526 % bit-depth 8 in indexed PNG files.
11528 % When png:color-type is 4 (Gray-Matte) or 6 (RGB-Matte),
11529 % png:bit-depth can be 8 or 16.
11531 % If the image cannot be written without loss with the
11532 % requested bit-depth and color-type, a PNG file will not
11533 % be written, a warning will be issued, and the encoder will
11534 % return MagickFalse.
11536 % Since image encoders should not be responsible for the "heavy lifting",
11537 % the user should make sure that ImageMagick has already reduced the
11538 % image depth and number of colors and limit transparency to binary
11539 % transparency prior to attempting to write the image with depth, color,
11540 % or transparency limitations.
11542 % Note that another definition, "png:bit-depth-written" exists, but it
11543 % is not intended for external use. It is only used internally by the
11544 % PNG encoder to inform the JNG encoder of the depth of the alpha channel.
11546 % It is possible to request that the PNG encoder write previously-formatted
11547 % ancillary chunks in the output PNG file, using the "-profile" commandline
11548 % option as shown below or by setting the profile via a programming
11551 % -profile PNG-chunk-x:<file>
11553 % where x is a location flag and <file> is a file containing the chunk
11554 % name in the first 4 bytes, then a colon (":"), followed by the chunk data.
11555 % This encoder will compute the chunk length and CRC, so those must not
11556 % be included in the file.
11558 % "x" can be "b" (before PLTE), "m" (middle, i.e., between PLTE and IDAT),
11559 % or "e" (end, i.e., after IDAT). If you want to write multiple chunks
11560 % of the same type, then add a short unique string after the "x" to prevent
11561 % subsequent profiles from overwriting the preceding ones, e.g.,
11563 % -profile PNG-chunk-b01:file01 -profile PNG-chunk-b02:file02
11565 % As of version 6.6.6 the following optimizations are always done:
11567 % o 32-bit depth is reduced to 16.
11568 % o 16-bit depth is reduced to 8 if all pixels contain samples whose
11569 % high byte and low byte are identical.
11570 % o Palette is sorted to remove unused entries and to put a
11571 % transparent color first, if BUILD_PNG_PALETTE is defined.
11572 % o Opaque matte channel is removed when writing an indexed PNG.
11573 % o Grayscale images are reduced to 1, 2, or 4 bit depth if
11574 % this can be done without loss and a larger bit depth N was not
11575 % requested via the "-define png:bit-depth=N" option.
11576 % o If matte channel is present but only one transparent color is
11577 % present, RGB+tRNS is written instead of RGBA
11578 % o Opaque matte channel is removed (or added, if color-type 4 or 6
11579 % was requested when converting an opaque image).
11581 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11583 static MagickBooleanType WritePNGImage(const ImageInfo *image_info,
11584 Image *image,ExceptionInfo *exception)
11589 have_mng_structure,
11605 assert(image_info != (const ImageInfo *) NULL);
11606 assert(image_info->signature == MagickSignature);
11607 assert(image != (Image *) NULL);
11608 assert(image->signature == MagickSignature);
11609 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
11610 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter WritePNGImage()");
11612 Allocate a MngInfo structure.
11614 have_mng_structure=MagickFalse;
11615 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
11617 if (mng_info == (MngInfo *) NULL)
11618 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
11621 Initialize members of the MngInfo structure.
11623 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
11624 mng_info->image=image;
11625 mng_info->equal_backgrounds=MagickTrue;
11626 have_mng_structure=MagickTrue;
11628 /* See if user has requested a specific PNG subformat */
11630 mng_info->write_png8=LocaleCompare(image_info->magick,"PNG8") == 0;
11631 mng_info->write_png24=LocaleCompare(image_info->magick,"PNG24") == 0;
11632 mng_info->write_png32=LocaleCompare(image_info->magick,"PNG32") == 0;
11633 mng_info->write_png48=LocaleCompare(image_info->magick,"PNG48") == 0;
11634 mng_info->write_png64=LocaleCompare(image_info->magick,"PNG64") == 0;
11636 value=GetImageOption(image_info,"png:format");
11638 if (value != (char *) NULL)
11640 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11641 " Format=%s",value);
11643 mng_info->write_png8 = MagickFalse;
11644 mng_info->write_png24 = MagickFalse;
11645 mng_info->write_png32 = MagickFalse;
11646 mng_info->write_png48 = MagickFalse;
11647 mng_info->write_png64 = MagickFalse;
11649 if (LocaleCompare(value,"png8") == 0)
11650 mng_info->write_png8 = MagickTrue;
11652 else if (LocaleCompare(value,"png24") == 0)
11653 mng_info->write_png24 = MagickTrue;
11655 else if (LocaleCompare(value,"png32") == 0)
11656 mng_info->write_png32 = MagickTrue;
11658 else if (LocaleCompare(value,"png48") == 0)
11659 mng_info->write_png48 = MagickTrue;
11661 else if (LocaleCompare(value,"png64") == 0)
11662 mng_info->write_png64 = MagickTrue;
11664 else if (LocaleCompare(value,"png00") == 0)
11666 /* Retrieve png:IHDR.bit-depth-orig and png:IHDR.color-type-orig. */
11667 value=GetImageProperty(image,"png:IHDR.bit-depth-orig",exception);
11669 if (value != (char *) NULL)
11671 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11672 " png00 inherited bit depth=%s",value);
11674 if (LocaleCompare(value,"1") == 0)
11675 mng_info->write_png_depth = 1;
11677 else if (LocaleCompare(value,"1") == 0)
11678 mng_info->write_png_depth = 2;
11680 else if (LocaleCompare(value,"2") == 0)
11681 mng_info->write_png_depth = 4;
11683 else if (LocaleCompare(value,"8") == 0)
11684 mng_info->write_png_depth = 8;
11686 else if (LocaleCompare(value,"16") == 0)
11687 mng_info->write_png_depth = 16;
11690 value=GetImageProperty(image,"png:IHDR.color-type-orig",exception);
11692 if (value != (char *) NULL)
11694 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11695 " png00 inherited color type=%s",value);
11697 if (LocaleCompare(value,"0") == 0)
11698 mng_info->write_png_colortype = 1;
11700 else if (LocaleCompare(value,"2") == 0)
11701 mng_info->write_png_colortype = 3;
11703 else if (LocaleCompare(value,"3") == 0)
11704 mng_info->write_png_colortype = 4;
11706 else if (LocaleCompare(value,"4") == 0)
11707 mng_info->write_png_colortype = 5;
11709 else if (LocaleCompare(value,"6") == 0)
11710 mng_info->write_png_colortype = 7;
11715 if (mng_info->write_png8)
11717 mng_info->write_png_colortype = /* 3 */ 4;
11718 mng_info->write_png_depth = 8;
11722 if (mng_info->write_png24)
11724 mng_info->write_png_colortype = /* 2 */ 3;
11725 mng_info->write_png_depth = 8;
11728 if (image->alpha_trait == BlendPixelTrait)
11729 (void) SetImageType(image,TrueColorMatteType,exception);
11732 (void) SetImageType(image,TrueColorType,exception);
11734 (void) SyncImage(image,exception);
11737 if (mng_info->write_png32)
11739 mng_info->write_png_colortype = /* 6 */ 7;
11740 mng_info->write_png_depth = 8;
11743 if (image->alpha_trait == BlendPixelTrait)
11744 (void) SetImageType(image,TrueColorMatteType,exception);
11747 (void) SetImageType(image,TrueColorType,exception);
11749 (void) SyncImage(image,exception);
11752 if (mng_info->write_png48)
11754 mng_info->write_png_colortype = /* 2 */ 3;
11755 mng_info->write_png_depth = 16;
11758 if (image->alpha_trait == BlendPixelTrait)
11759 (void) SetImageType(image,TrueColorMatteType,exception);
11762 (void) SetImageType(image,TrueColorType,exception);
11764 (void) SyncImage(image,exception);
11767 if (mng_info->write_png64)
11769 mng_info->write_png_colortype = /* 6 */ 7;
11770 mng_info->write_png_depth = 16;
11773 if (image->alpha_trait == BlendPixelTrait)
11774 (void) SetImageType(image,TrueColorMatteType,exception);
11777 (void) SetImageType(image,TrueColorType,exception);
11779 (void) SyncImage(image,exception);
11782 value=GetImageOption(image_info,"png:bit-depth");
11784 if (value != (char *) NULL)
11786 if (LocaleCompare(value,"1") == 0)
11787 mng_info->write_png_depth = 1;
11789 else if (LocaleCompare(value,"2") == 0)
11790 mng_info->write_png_depth = 2;
11792 else if (LocaleCompare(value,"4") == 0)
11793 mng_info->write_png_depth = 4;
11795 else if (LocaleCompare(value,"8") == 0)
11796 mng_info->write_png_depth = 8;
11798 else if (LocaleCompare(value,"16") == 0)
11799 mng_info->write_png_depth = 16;
11802 (void) ThrowMagickException(exception,
11803 GetMagickModule(),CoderWarning,
11804 "ignoring invalid defined png:bit-depth",
11807 if (logging != MagickFalse)
11808 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11809 " png:bit-depth=%d was defined.\n",mng_info->write_png_depth);
11812 value=GetImageOption(image_info,"png:color-type");
11814 if (value != (char *) NULL)
11816 /* We must store colortype+1 because 0 is a valid colortype */
11817 if (LocaleCompare(value,"0") == 0)
11818 mng_info->write_png_colortype = 1;
11820 else if (LocaleCompare(value,"1") == 0)
11821 mng_info->write_png_colortype = 2;
11823 else if (LocaleCompare(value,"2") == 0)
11824 mng_info->write_png_colortype = 3;
11826 else if (LocaleCompare(value,"3") == 0)
11827 mng_info->write_png_colortype = 4;
11829 else if (LocaleCompare(value,"4") == 0)
11830 mng_info->write_png_colortype = 5;
11832 else if (LocaleCompare(value,"6") == 0)
11833 mng_info->write_png_colortype = 7;
11836 (void) ThrowMagickException(exception,
11837 GetMagickModule(),CoderWarning,
11838 "ignoring invalid defined png:color-type",
11841 if (logging != MagickFalse)
11842 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11843 " png:color-type=%d was defined.\n",mng_info->write_png_colortype-1);
11846 /* Check for chunks to be excluded:
11848 * The default is to not exclude any known chunks except for any
11849 * listed in the "unused_chunks" array, above.
11851 * Chunks can be listed for exclusion via a "png:exclude-chunk"
11852 * define (in the image properties or in the image artifacts)
11853 * or via a mng_info member. For convenience, in addition
11854 * to or instead of a comma-separated list of chunks, the
11855 * "exclude-chunk" string can be simply "all" or "none".
11857 * The exclude-chunk define takes priority over the mng_info.
11859 * A "png:include-chunk" define takes priority over both the
11860 * mng_info and the "png:exclude-chunk" define. Like the
11861 * "exclude-chunk" string, it can define "all" or "none" as
11862 * well as a comma-separated list. Chunks that are unknown to
11863 * ImageMagick are always excluded, regardless of their "copy-safe"
11864 * status according to the PNG specification, and even if they
11865 * appear in the "include-chunk" list. Such defines appearing among
11866 * the image options take priority over those found among the image
11869 * Finally, all chunks listed in the "unused_chunks" array are
11870 * automatically excluded, regardless of the other instructions
11873 * if you exclude sRGB but not gAMA (recommended), then sRGB chunk
11874 * will not be written and the gAMA chunk will only be written if it
11875 * is not between .45 and .46, or approximately (1.0/2.2).
11877 * If you exclude tRNS and the image has transparency, the colortype
11878 * is forced to be 4 or 6 (GRAY_ALPHA or RGB_ALPHA).
11880 * The -strip option causes StripImage() to set the png:include-chunk
11881 * artifact to "none,trns,gama".
11884 mng_info->ping_exclude_bKGD=MagickFalse;
11885 mng_info->ping_exclude_cHRM=MagickFalse;
11886 mng_info->ping_exclude_date=MagickFalse;
11887 mng_info->ping_exclude_EXIF=MagickFalse; /* hex-encoded EXIF in zTXt */
11888 mng_info->ping_exclude_gAMA=MagickFalse;
11889 mng_info->ping_exclude_iCCP=MagickFalse;
11890 /* mng_info->ping_exclude_iTXt=MagickFalse; */
11891 mng_info->ping_exclude_oFFs=MagickFalse;
11892 mng_info->ping_exclude_pHYs=MagickFalse;
11893 mng_info->ping_exclude_sRGB=MagickFalse;
11894 mng_info->ping_exclude_tEXt=MagickFalse;
11895 mng_info->ping_exclude_tRNS=MagickFalse;
11896 mng_info->ping_exclude_vpAg=MagickFalse;
11897 mng_info->ping_exclude_zCCP=MagickFalse; /* hex-encoded iCCP in zTXt */
11898 mng_info->ping_exclude_zTXt=MagickFalse;
11900 mng_info->ping_preserve_colormap=MagickFalse;
11902 value=GetImageOption(image_info,"png:preserve-colormap");
11904 value=GetImageArtifact(image,"png:preserve-colormap");
11906 mng_info->ping_preserve_colormap=MagickTrue;
11908 mng_info->ping_preserve_iCCP=MagickFalse;
11910 value=GetImageOption(image_info,"png:preserve-iCCP");
11912 value=GetImageArtifact(image,"png:preserve-iCCP");
11914 mng_info->ping_preserve_iCCP=MagickTrue;
11916 /* These compression-level, compression-strategy, and compression-filter
11917 * defines take precedence over values from the -quality option.
11919 value=GetImageOption(image_info,"png:compression-level");
11921 value=GetImageArtifact(image,"png:compression-level");
11924 /* We have to add 1 to everything because 0 is a valid input,
11925 * and we want to use 0 (the default) to mean undefined.
11927 if (LocaleCompare(value,"0") == 0)
11928 mng_info->write_png_compression_level = 1;
11930 else if (LocaleCompare(value,"1") == 0)
11931 mng_info->write_png_compression_level = 2;
11933 else if (LocaleCompare(value,"2") == 0)
11934 mng_info->write_png_compression_level = 3;
11936 else if (LocaleCompare(value,"3") == 0)
11937 mng_info->write_png_compression_level = 4;
11939 else if (LocaleCompare(value,"4") == 0)
11940 mng_info->write_png_compression_level = 5;
11942 else if (LocaleCompare(value,"5") == 0)
11943 mng_info->write_png_compression_level = 6;
11945 else if (LocaleCompare(value,"6") == 0)
11946 mng_info->write_png_compression_level = 7;
11948 else if (LocaleCompare(value,"7") == 0)
11949 mng_info->write_png_compression_level = 8;
11951 else if (LocaleCompare(value,"8") == 0)
11952 mng_info->write_png_compression_level = 9;
11954 else if (LocaleCompare(value,"9") == 0)
11955 mng_info->write_png_compression_level = 10;
11958 (void) ThrowMagickException(exception,
11959 GetMagickModule(),CoderWarning,
11960 "ignoring invalid defined png:compression-level",
11964 value=GetImageOption(image_info,"png:compression-strategy");
11966 value=GetImageArtifact(image,"png:compression-strategy");
11970 if (LocaleCompare(value,"0") == 0)
11971 mng_info->write_png_compression_strategy = Z_DEFAULT_STRATEGY+1;
11973 else if (LocaleCompare(value,"1") == 0)
11974 mng_info->write_png_compression_strategy = Z_FILTERED+1;
11976 else if (LocaleCompare(value,"2") == 0)
11977 mng_info->write_png_compression_strategy = Z_HUFFMAN_ONLY+1;
11979 else if (LocaleCompare(value,"3") == 0)
11980 #ifdef Z_RLE /* Z_RLE was added to zlib-1.2.0 */
11981 mng_info->write_png_compression_strategy = Z_RLE+1;
11983 mng_info->write_png_compression_strategy = Z_DEFAULT_STRATEGY+1;
11986 else if (LocaleCompare(value,"4") == 0)
11987 #ifdef Z_FIXED /* Z_FIXED was added to zlib-1.2.2.2 */
11988 mng_info->write_png_compression_strategy = Z_FIXED+1;
11990 mng_info->write_png_compression_strategy = Z_DEFAULT_STRATEGY+1;
11994 (void) ThrowMagickException(exception,
11995 GetMagickModule(),CoderWarning,
11996 "ignoring invalid defined png:compression-strategy",
12000 value=GetImageOption(image_info,"png:compression-filter");
12002 value=GetImageArtifact(image,"png:compression-filter");
12006 /* To do: combinations of filters allowed by libpng
12007 * masks 0x08 through 0xf8
12009 * Implement this as a comma-separated list of 0,1,2,3,4,5
12010 * where 5 is a special case meaning PNG_ALL_FILTERS.
12013 if (LocaleCompare(value,"0") == 0)
12014 mng_info->write_png_compression_filter = 1;
12016 else if (LocaleCompare(value,"1") == 0)
12017 mng_info->write_png_compression_filter = 2;
12019 else if (LocaleCompare(value,"2") == 0)
12020 mng_info->write_png_compression_filter = 3;
12022 else if (LocaleCompare(value,"3") == 0)
12023 mng_info->write_png_compression_filter = 4;
12025 else if (LocaleCompare(value,"4") == 0)
12026 mng_info->write_png_compression_filter = 5;
12028 else if (LocaleCompare(value,"5") == 0)
12029 mng_info->write_png_compression_filter = 6;
12032 (void) ThrowMagickException(exception,
12033 GetMagickModule(),CoderWarning,
12034 "ignoring invalid defined png:compression-filter",
12038 excluding=MagickFalse;
12040 for (source=0; source<1; source++)
12044 value=GetImageOption(image_info,"png:exclude-chunk");
12047 value=GetImageArtifact(image,"png:exclude-chunk");
12051 value=GetImageOption(image_info,"png:exclude-chunks");
12054 value=GetImageArtifact(image,"png:exclude-chunks");
12063 excluding=MagickTrue;
12065 if (logging != MagickFalse)
12068 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12069 " png:exclude-chunk=%s found in image artifacts.\n", value);
12071 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12072 " png:exclude-chunk=%s found in image properties.\n", value);
12075 last=strlen(value);
12077 for (i=0; i<(int) last; i+=5)
12080 if (LocaleNCompare(value+i,"none",4) == 0)
12082 mng_info->ping_exclude_bKGD=MagickFalse;
12083 mng_info->ping_exclude_cHRM=MagickFalse;
12084 mng_info->ping_exclude_date=MagickFalse;
12085 mng_info->ping_exclude_EXIF=MagickFalse;
12086 mng_info->ping_exclude_gAMA=MagickFalse;
12087 mng_info->ping_exclude_iCCP=MagickFalse;
12088 /* mng_info->ping_exclude_iTXt=MagickFalse; */
12089 mng_info->ping_exclude_oFFs=MagickFalse;
12090 mng_info->ping_exclude_pHYs=MagickFalse;
12091 mng_info->ping_exclude_sRGB=MagickFalse;
12092 mng_info->ping_exclude_tEXt=MagickFalse;
12093 mng_info->ping_exclude_tRNS=MagickFalse;
12094 mng_info->ping_exclude_vpAg=MagickFalse;
12095 mng_info->ping_exclude_zCCP=MagickFalse;
12096 mng_info->ping_exclude_zTXt=MagickFalse;
12099 if (LocaleNCompare(value+i,"bkgd",4) == 0)
12100 mng_info->ping_exclude_bKGD=MagickTrue;
12102 if (LocaleNCompare(value+i,"chrm",4) == 0)
12103 mng_info->ping_exclude_cHRM=MagickTrue;
12105 if (LocaleNCompare(value+i,"date",4) == 0)
12106 mng_info->ping_exclude_date=MagickTrue;
12108 if (LocaleNCompare(value+i,"exif",4) == 0)
12109 mng_info->ping_exclude_EXIF=MagickTrue;
12111 if (LocaleNCompare(value+i,"gama",4) == 0)
12112 mng_info->ping_exclude_gAMA=MagickTrue;
12114 if (LocaleNCompare(value+i,"iccp",4) == 0)
12115 mng_info->ping_exclude_iCCP=MagickTrue;
12118 if (LocaleNCompare(value+i,"itxt",4) == 0)
12119 mng_info->ping_exclude_iTXt=MagickTrue;
12122 if (LocaleNCompare(value+i,"gama",4) == 0)
12123 mng_info->ping_exclude_gAMA=MagickTrue;
12125 if (LocaleNCompare(value+i,"offs",4) == 0)
12126 mng_info->ping_exclude_oFFs=MagickTrue;
12128 if (LocaleNCompare(value+i,"phys",4) == 0)
12129 mng_info->ping_exclude_pHYs=MagickTrue;
12131 if (LocaleNCompare(value+i,"srgb",4) == 0)
12132 mng_info->ping_exclude_sRGB=MagickTrue;
12134 if (LocaleNCompare(value+i,"text",4) == 0)
12135 mng_info->ping_exclude_tEXt=MagickTrue;
12137 if (LocaleNCompare(value+i,"trns",4) == 0)
12138 mng_info->ping_exclude_tRNS=MagickTrue;
12140 if (LocaleNCompare(value+i,"vpag",4) == 0)
12141 mng_info->ping_exclude_vpAg=MagickTrue;
12143 if (LocaleNCompare(value+i,"zccp",4) == 0)
12144 mng_info->ping_exclude_zCCP=MagickTrue;
12146 if (LocaleNCompare(value+i,"ztxt",4) == 0)
12147 mng_info->ping_exclude_zTXt=MagickTrue;
12149 if (LocaleNCompare(value+i,"all",3) == 0)
12151 mng_info->ping_exclude_bKGD=MagickTrue;
12152 mng_info->ping_exclude_cHRM=MagickTrue;
12153 mng_info->ping_exclude_date=MagickTrue;
12154 mng_info->ping_exclude_EXIF=MagickTrue;
12155 mng_info->ping_exclude_gAMA=MagickTrue;
12156 mng_info->ping_exclude_iCCP=MagickTrue;
12157 /* mng_info->ping_exclude_iTXt=MagickTrue; */
12158 mng_info->ping_exclude_oFFs=MagickTrue;
12159 mng_info->ping_exclude_pHYs=MagickTrue;
12160 mng_info->ping_exclude_sRGB=MagickTrue;
12161 mng_info->ping_exclude_tEXt=MagickTrue;
12162 mng_info->ping_exclude_tRNS=MagickTrue;
12163 mng_info->ping_exclude_vpAg=MagickTrue;
12164 mng_info->ping_exclude_zCCP=MagickTrue;
12165 mng_info->ping_exclude_zTXt=MagickTrue;
12172 for (source=0; source<1; source++)
12176 value=GetImageOption(image_info,"png:include-chunk");
12179 value=GetImageArtifact(image,"png:include-chunk");
12183 value=GetImageOption(image_info,"png:include-chunks");
12186 value=GetImageArtifact(image,"png:include-chunks");
12194 excluding=MagickTrue;
12196 if (logging != MagickFalse)
12199 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12200 " png:include-chunk=%s found in image artifacts.\n", value);
12202 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12203 " png:include-chunk=%s found in image properties.\n", value);
12206 last=strlen(value);
12208 for (i=0; i<(int) last; i+=5)
12210 if (LocaleNCompare(value+i,"none",4) == 0)
12212 mng_info->ping_exclude_bKGD=MagickTrue;
12213 mng_info->ping_exclude_cHRM=MagickTrue;
12214 mng_info->ping_exclude_date=MagickTrue;
12215 mng_info->ping_exclude_EXIF=MagickTrue;
12216 mng_info->ping_exclude_gAMA=MagickTrue;
12217 mng_info->ping_exclude_iCCP=MagickTrue;
12218 /* mng_info->ping_exclude_iTXt=MagickTrue; */
12219 mng_info->ping_exclude_oFFs=MagickTrue;
12220 mng_info->ping_exclude_pHYs=MagickTrue;
12221 mng_info->ping_exclude_sRGB=MagickTrue;
12222 mng_info->ping_exclude_tEXt=MagickTrue;
12223 mng_info->ping_exclude_tRNS=MagickTrue;
12224 mng_info->ping_exclude_vpAg=MagickTrue;
12225 mng_info->ping_exclude_zCCP=MagickTrue;
12226 mng_info->ping_exclude_zTXt=MagickTrue;
12229 if (LocaleNCompare(value+i,"bkgd",4) == 0)
12230 mng_info->ping_exclude_bKGD=MagickFalse;
12232 if (LocaleNCompare(value+i,"chrm",4) == 0)
12233 mng_info->ping_exclude_cHRM=MagickFalse;
12235 if (LocaleNCompare(value+i,"date",4) == 0)
12236 mng_info->ping_exclude_date=MagickFalse;
12238 if (LocaleNCompare(value+i,"exif",4) == 0)
12239 mng_info->ping_exclude_EXIF=MagickFalse;
12241 if (LocaleNCompare(value+i,"gama",4) == 0)
12242 mng_info->ping_exclude_gAMA=MagickFalse;
12244 if (LocaleNCompare(value+i,"iccp",4) == 0)
12245 mng_info->ping_exclude_iCCP=MagickFalse;
12248 if (LocaleNCompare(value+i,"itxt",4) == 0)
12249 mng_info->ping_exclude_iTXt=MagickFalse;
12252 if (LocaleNCompare(value+i,"gama",4) == 0)
12253 mng_info->ping_exclude_gAMA=MagickFalse;
12255 if (LocaleNCompare(value+i,"offs",4) == 0)
12256 mng_info->ping_exclude_oFFs=MagickFalse;
12258 if (LocaleNCompare(value+i,"phys",4) == 0)
12259 mng_info->ping_exclude_pHYs=MagickFalse;
12261 if (LocaleNCompare(value+i,"srgb",4) == 0)
12262 mng_info->ping_exclude_sRGB=MagickFalse;
12264 if (LocaleNCompare(value+i,"text",4) == 0)
12265 mng_info->ping_exclude_tEXt=MagickFalse;
12267 if (LocaleNCompare(value+i,"trns",4) == 0)
12268 mng_info->ping_exclude_tRNS=MagickFalse;
12270 if (LocaleNCompare(value+i,"vpag",4) == 0)
12271 mng_info->ping_exclude_vpAg=MagickFalse;
12273 if (LocaleNCompare(value+i,"zccp",4) == 0)
12274 mng_info->ping_exclude_zCCP=MagickFalse;
12276 if (LocaleNCompare(value+i,"ztxt",4) == 0)
12277 mng_info->ping_exclude_zTXt=MagickFalse;
12279 if (LocaleNCompare(value+i,"all",3) == 0)
12281 mng_info->ping_exclude_bKGD=MagickFalse;
12282 mng_info->ping_exclude_cHRM=MagickFalse;
12283 mng_info->ping_exclude_date=MagickFalse;
12284 mng_info->ping_exclude_EXIF=MagickFalse;
12285 mng_info->ping_exclude_gAMA=MagickFalse;
12286 mng_info->ping_exclude_iCCP=MagickFalse;
12287 /* mng_info->ping_exclude_iTXt=MagickFalse; */
12288 mng_info->ping_exclude_oFFs=MagickFalse;
12289 mng_info->ping_exclude_pHYs=MagickFalse;
12290 mng_info->ping_exclude_sRGB=MagickFalse;
12291 mng_info->ping_exclude_tEXt=MagickFalse;
12292 mng_info->ping_exclude_tRNS=MagickFalse;
12293 mng_info->ping_exclude_vpAg=MagickFalse;
12294 mng_info->ping_exclude_zCCP=MagickFalse;
12295 mng_info->ping_exclude_zTXt=MagickFalse;
12302 if (excluding != MagickFalse && logging != MagickFalse)
12304 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12305 " Chunks to be excluded from the output png:");
12306 if (mng_info->ping_exclude_bKGD != MagickFalse)
12307 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12309 if (mng_info->ping_exclude_cHRM != MagickFalse)
12310 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12312 if (mng_info->ping_exclude_date != MagickFalse)
12313 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12315 if (mng_info->ping_exclude_EXIF != MagickFalse)
12316 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12318 if (mng_info->ping_exclude_gAMA != MagickFalse)
12319 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12321 if (mng_info->ping_exclude_iCCP != MagickFalse)
12322 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12325 if (mng_info->ping_exclude_iTXt != MagickFalse)
12326 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12329 if (mng_info->ping_exclude_oFFs != MagickFalse)
12330 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12332 if (mng_info->ping_exclude_pHYs != MagickFalse)
12333 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12335 if (mng_info->ping_exclude_sRGB != MagickFalse)
12336 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12338 if (mng_info->ping_exclude_tEXt != MagickFalse)
12339 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12341 if (mng_info->ping_exclude_tRNS != MagickFalse)
12342 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12344 if (mng_info->ping_exclude_vpAg != MagickFalse)
12345 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12347 if (mng_info->ping_exclude_zCCP != MagickFalse)
12348 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12350 if (mng_info->ping_exclude_zTXt != MagickFalse)
12351 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12355 mng_info->need_blob = MagickTrue;
12357 status=WriteOnePNGImage(mng_info,image_info,image,exception);
12359 MngInfoFreeStruct(mng_info,&have_mng_structure);
12361 if (logging != MagickFalse)
12362 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit WritePNGImage()");
12367 #if defined(JNG_SUPPORTED)
12369 /* Write one JNG image */
12370 static MagickBooleanType WriteOneJNGImage(MngInfo *mng_info,
12371 const ImageInfo *image_info,Image *image,ExceptionInfo *exception)
12392 jng_alpha_compression_method,
12393 jng_alpha_sample_depth,
12401 logging=LogMagickEvent(CoderEvent,GetMagickModule(),
12402 " Enter WriteOneJNGImage()");
12404 blob=(unsigned char *) NULL;
12405 jpeg_image=(Image *) NULL;
12406 jpeg_image_info=(ImageInfo *) NULL;
12409 transparent=image_info->type==GrayscaleMatteType ||
12410 image_info->type==TrueColorMatteType || image->alpha_trait == BlendPixelTrait;
12412 jng_alpha_sample_depth = 0;
12414 jng_quality=image_info->quality == 0UL ? 75UL : image_info->quality%1000;
12416 jng_alpha_compression_method=image->compression==JPEGCompression? 8 : 0;
12418 jng_alpha_quality=image_info->quality == 0UL ? 75UL :
12419 image_info->quality;
12421 if (jng_alpha_quality >= 1000)
12422 jng_alpha_quality /= 1000;
12430 /* Create JPEG blob, image, and image_info */
12431 if (logging != MagickFalse)
12432 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12433 " Creating jpeg_image_info for alpha.");
12435 jpeg_image_info=(ImageInfo *) CloneImageInfo(image_info);
12437 if (jpeg_image_info == (ImageInfo *) NULL)
12438 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
12440 if (logging != MagickFalse)
12441 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12442 " Creating jpeg_image.");
12444 jpeg_image=SeparateImage(image,AlphaChannel,exception);
12445 if (jpeg_image == (Image *) NULL)
12446 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
12447 (void) CopyMagickString(jpeg_image->magick,"JPEG",MaxTextExtent);
12448 jpeg_image->alpha_trait=UndefinedPixelTrait;
12449 jpeg_image->quality=jng_alpha_quality;
12450 jpeg_image_info->type=GrayscaleType;
12451 (void) SetImageType(jpeg_image,GrayscaleType,exception);
12452 (void) AcquireUniqueFilename(jpeg_image->filename);
12453 (void) FormatLocaleString(jpeg_image_info->filename,MaxTextExtent,
12454 "%s",jpeg_image->filename);
12458 jng_alpha_compression_method=0;
12460 jng_alpha_sample_depth=0;
12463 /* To do: check bit depth of PNG alpha channel */
12465 /* Check if image is grayscale. */
12466 if (image_info->type != TrueColorMatteType && image_info->type !=
12467 TrueColorType && IsImageGray(image,exception))
12470 if (logging != MagickFalse)
12472 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12473 " JNG Quality = %d",(int) jng_quality);
12474 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12475 " JNG Color Type = %d",jng_color_type);
12478 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12479 " JNG Alpha Compression = %d",jng_alpha_compression_method);
12480 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12481 " JNG Alpha Depth = %d",jng_alpha_sample_depth);
12482 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12483 " JNG Alpha Quality = %d",(int) jng_alpha_quality);
12489 if (jng_alpha_compression_method==0)
12494 /* Encode alpha as a grayscale PNG blob */
12495 status=OpenBlob(jpeg_image_info,jpeg_image,WriteBinaryBlobMode,
12497 if (logging != MagickFalse)
12498 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12499 " Creating PNG blob.");
12501 (void) CopyMagickString(jpeg_image_info->magick,"PNG",MaxTextExtent);
12502 (void) CopyMagickString(jpeg_image->magick,"PNG",MaxTextExtent);
12503 jpeg_image_info->interlace=NoInterlace;
12505 /* Exclude all ancillary chunks */
12506 (void) SetImageArtifact(jpeg_image,"png:exclude-chunks","all");
12508 blob=ImageToBlob(jpeg_image_info,jpeg_image,&length,
12511 /* Retrieve sample depth used */
12512 value=GetImageProperty(jpeg_image,"png:bit-depth-written",exception);
12513 if (value != (char *) NULL)
12514 jng_alpha_sample_depth= (unsigned int) value[0];
12518 /* Encode alpha as a grayscale JPEG blob */
12520 status=OpenBlob(jpeg_image_info,jpeg_image,WriteBinaryBlobMode,
12523 (void) CopyMagickString(jpeg_image_info->magick,"JPEG",MaxTextExtent);
12524 (void) CopyMagickString(jpeg_image->magick,"JPEG",MaxTextExtent);
12525 jpeg_image_info->interlace=NoInterlace;
12526 if (logging != MagickFalse)
12527 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12528 " Creating blob.");
12529 blob=ImageToBlob(jpeg_image_info,jpeg_image,&length,
12531 jng_alpha_sample_depth=8;
12533 if (logging != MagickFalse)
12534 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12535 " Successfully read jpeg_image into a blob, length=%.20g.",
12539 /* Destroy JPEG image and image_info */
12540 jpeg_image=DestroyImage(jpeg_image);
12541 (void) RelinquishUniqueFileResource(jpeg_image_info->filename);
12542 jpeg_image_info=DestroyImageInfo(jpeg_image_info);
12545 /* Write JHDR chunk */
12546 (void) WriteBlobMSBULong(image,16L); /* chunk data length=16 */
12547 PNGType(chunk,mng_JHDR);
12548 LogPNGChunk(logging,mng_JHDR,16L);
12549 PNGLong(chunk+4,(png_uint_32) image->columns);
12550 PNGLong(chunk+8,(png_uint_32) image->rows);
12551 chunk[12]=jng_color_type;
12552 chunk[13]=8; /* sample depth */
12553 chunk[14]=8; /*jng_image_compression_method */
12554 chunk[15]=(unsigned char) (image_info->interlace == NoInterlace ? 0 : 8);
12555 chunk[16]=jng_alpha_sample_depth;
12556 chunk[17]=jng_alpha_compression_method;
12557 chunk[18]=0; /*jng_alpha_filter_method */
12558 chunk[19]=0; /*jng_alpha_interlace_method */
12559 (void) WriteBlob(image,20,chunk);
12560 (void) WriteBlobMSBULong(image,crc32(0,chunk,20));
12561 if (logging != MagickFalse)
12563 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12564 " JNG width:%15lu",(unsigned long) image->columns);
12566 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12567 " JNG height:%14lu",(unsigned long) image->rows);
12569 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12570 " JNG color type:%10d",jng_color_type);
12572 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12573 " JNG sample depth:%8d",8);
12575 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12576 " JNG compression:%9d",8);
12578 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12579 " JNG interlace:%11d",0);
12581 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12582 " JNG alpha depth:%9d",jng_alpha_sample_depth);
12584 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12585 " JNG alpha compression:%3d",jng_alpha_compression_method);
12587 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12588 " JNG alpha filter:%8d",0);
12590 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12591 " JNG alpha interlace:%5d",0);
12594 /* Write any JNG-chunk-b profiles */
12595 (void) Magick_png_write_chunk_from_profile(image,"JNG-chunk-b",logging);
12598 Write leading ancillary chunks
12604 Write JNG bKGD chunk
12615 if (jng_color_type == 8 || jng_color_type == 12)
12619 (void) WriteBlobMSBULong(image,(size_t) (num_bytes-4L));
12620 PNGType(chunk,mng_bKGD);
12621 LogPNGChunk(logging,mng_bKGD,(size_t) (num_bytes-4L));
12622 red=ScaleQuantumToChar(image->background_color.red);
12623 green=ScaleQuantumToChar(image->background_color.green);
12624 blue=ScaleQuantumToChar(image->background_color.blue);
12631 (void) WriteBlob(image,(size_t) num_bytes,chunk);
12632 (void) WriteBlobMSBULong(image,crc32(0,chunk,(uInt) num_bytes));
12635 if ((image->colorspace == sRGBColorspace || image->rendering_intent))
12638 Write JNG sRGB chunk
12640 (void) WriteBlobMSBULong(image,1L);
12641 PNGType(chunk,mng_sRGB);
12642 LogPNGChunk(logging,mng_sRGB,1L);
12644 if (image->rendering_intent != UndefinedIntent)
12645 chunk[4]=(unsigned char)
12646 Magick_RenderingIntent_to_PNG_RenderingIntent(
12647 (image->rendering_intent));
12650 chunk[4]=(unsigned char)
12651 Magick_RenderingIntent_to_PNG_RenderingIntent(
12652 (PerceptualIntent));
12654 (void) WriteBlob(image,5,chunk);
12655 (void) WriteBlobMSBULong(image,crc32(0,chunk,5));
12659 if (image->gamma != 0.0)
12662 Write JNG gAMA chunk
12664 (void) WriteBlobMSBULong(image,4L);
12665 PNGType(chunk,mng_gAMA);
12666 LogPNGChunk(logging,mng_gAMA,4L);
12667 PNGLong(chunk+4,(png_uint_32) (100000*image->gamma+0.5));
12668 (void) WriteBlob(image,8,chunk);
12669 (void) WriteBlobMSBULong(image,crc32(0,chunk,8));
12672 if ((mng_info->equal_chrms == MagickFalse) &&
12673 (image->chromaticity.red_primary.x != 0.0))
12679 Write JNG cHRM chunk
12681 (void) WriteBlobMSBULong(image,32L);
12682 PNGType(chunk,mng_cHRM);
12683 LogPNGChunk(logging,mng_cHRM,32L);
12684 primary=image->chromaticity.white_point;
12685 PNGLong(chunk+4,(png_uint_32) (100000*primary.x+0.5));
12686 PNGLong(chunk+8,(png_uint_32) (100000*primary.y+0.5));
12687 primary=image->chromaticity.red_primary;
12688 PNGLong(chunk+12,(png_uint_32) (100000*primary.x+0.5));
12689 PNGLong(chunk+16,(png_uint_32) (100000*primary.y+0.5));
12690 primary=image->chromaticity.green_primary;
12691 PNGLong(chunk+20,(png_uint_32) (100000*primary.x+0.5));
12692 PNGLong(chunk+24,(png_uint_32) (100000*primary.y+0.5));
12693 primary=image->chromaticity.blue_primary;
12694 PNGLong(chunk+28,(png_uint_32) (100000*primary.x+0.5));
12695 PNGLong(chunk+32,(png_uint_32) (100000*primary.y+0.5));
12696 (void) WriteBlob(image,36,chunk);
12697 (void) WriteBlobMSBULong(image,crc32(0,chunk,36));
12701 if (image->resolution.x && image->resolution.y && !mng_info->equal_physs)
12704 Write JNG pHYs chunk
12706 (void) WriteBlobMSBULong(image,9L);
12707 PNGType(chunk,mng_pHYs);
12708 LogPNGChunk(logging,mng_pHYs,9L);
12709 if (image->units == PixelsPerInchResolution)
12711 PNGLong(chunk+4,(png_uint_32)
12712 (image->resolution.x*100.0/2.54+0.5));
12714 PNGLong(chunk+8,(png_uint_32)
12715 (image->resolution.y*100.0/2.54+0.5));
12722 if (image->units == PixelsPerCentimeterResolution)
12724 PNGLong(chunk+4,(png_uint_32)
12725 (image->resolution.x*100.0+0.5));
12727 PNGLong(chunk+8,(png_uint_32)
12728 (image->resolution.y*100.0+0.5));
12735 PNGLong(chunk+4,(png_uint_32) (image->resolution.x+0.5));
12736 PNGLong(chunk+8,(png_uint_32) (image->resolution.y+0.5));
12740 (void) WriteBlob(image,13,chunk);
12741 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
12744 if (mng_info->write_mng == 0 && (image->page.x || image->page.y))
12747 Write JNG oFFs chunk
12749 (void) WriteBlobMSBULong(image,9L);
12750 PNGType(chunk,mng_oFFs);
12751 LogPNGChunk(logging,mng_oFFs,9L);
12752 PNGsLong(chunk+4,(ssize_t) (image->page.x));
12753 PNGsLong(chunk+8,(ssize_t) (image->page.y));
12755 (void) WriteBlob(image,13,chunk);
12756 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
12758 if (mng_info->write_mng == 0 && (image->page.width || image->page.height))
12760 (void) WriteBlobMSBULong(image,9L); /* data length=8 */
12761 PNGType(chunk,mng_vpAg);
12762 LogPNGChunk(logging,mng_vpAg,9L);
12763 PNGLong(chunk+4,(png_uint_32) image->page.width);
12764 PNGLong(chunk+8,(png_uint_32) image->page.height);
12765 chunk[12]=0; /* unit = pixels */
12766 (void) WriteBlob(image,13,chunk);
12767 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
12773 if (jng_alpha_compression_method==0)
12781 /* Write IDAT chunk header */
12782 if (logging != MagickFalse)
12783 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12784 " Write IDAT chunks from blob, length=%.20g.",(double)
12787 /* Copy IDAT chunks */
12790 for (i=8; i<(ssize_t) length; i+=len+12)
12792 len=(*p<<24)|((*(p+1))<<16)|((*(p+2))<<8)|(*(p+3));
12795 if (*(p)==73 && *(p+1)==68 && *(p+2)==65 && *(p+3)==84) /* IDAT */
12797 /* Found an IDAT chunk. */
12798 (void) WriteBlobMSBULong(image,(size_t) len);
12799 LogPNGChunk(logging,mng_IDAT,(size_t) len);
12800 (void) WriteBlob(image,(size_t) len+4,p);
12801 (void) WriteBlobMSBULong(image,
12802 crc32(0,p,(uInt) len+4));
12807 if (logging != MagickFalse)
12808 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12809 " Skipping %c%c%c%c chunk, length=%.20g.",
12810 *(p),*(p+1),*(p+2),*(p+3),(double) len);
12817 /* Write JDAA chunk header */
12818 if (logging != MagickFalse)
12819 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12820 " Write JDAA chunk, length=%.20g.",(double) length);
12821 (void) WriteBlobMSBULong(image,(size_t) length);
12822 PNGType(chunk,mng_JDAA);
12823 LogPNGChunk(logging,mng_JDAA,length);
12824 /* Write JDAT chunk(s) data */
12825 (void) WriteBlob(image,4,chunk);
12826 (void) WriteBlob(image,length,blob);
12827 (void) WriteBlobMSBULong(image,crc32(crc32(0,chunk,4),blob,
12830 blob=(unsigned char *) RelinquishMagickMemory(blob);
12833 /* Encode image as a JPEG blob */
12834 if (logging != MagickFalse)
12835 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12836 " Creating jpeg_image_info.");
12837 jpeg_image_info=(ImageInfo *) CloneImageInfo(image_info);
12838 if (jpeg_image_info == (ImageInfo *) NULL)
12839 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
12841 if (logging != MagickFalse)
12842 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12843 " Creating jpeg_image.");
12845 jpeg_image=CloneImage(image,0,0,MagickTrue,exception);
12846 if (jpeg_image == (Image *) NULL)
12847 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
12848 (void) CopyMagickString(jpeg_image->magick,"JPEG",MaxTextExtent);
12850 (void) AcquireUniqueFilename(jpeg_image->filename);
12851 (void) FormatLocaleString(jpeg_image_info->filename,MaxTextExtent,"%s",
12852 jpeg_image->filename);
12854 status=OpenBlob(jpeg_image_info,jpeg_image,WriteBinaryBlobMode,
12857 if (logging != MagickFalse)
12858 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12859 " Created jpeg_image, %.20g x %.20g.",(double) jpeg_image->columns,
12860 (double) jpeg_image->rows);
12862 if (jng_color_type == 8 || jng_color_type == 12)
12863 jpeg_image_info->type=GrayscaleType;
12865 jpeg_image_info->quality=jng_quality;
12866 jpeg_image->quality=jng_quality;
12867 (void) CopyMagickString(jpeg_image_info->magick,"JPEG",MaxTextExtent);
12868 (void) CopyMagickString(jpeg_image->magick,"JPEG",MaxTextExtent);
12870 if (logging != MagickFalse)
12871 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12872 " Creating blob.");
12874 blob=ImageToBlob(jpeg_image_info,jpeg_image,&length,exception);
12876 if (logging != MagickFalse)
12878 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12879 " Successfully read jpeg_image into a blob, length=%.20g.",
12882 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12883 " Write JDAT chunk, length=%.20g.",(double) length);
12886 /* Write JDAT chunk(s) */
12887 (void) WriteBlobMSBULong(image,(size_t) length);
12888 PNGType(chunk,mng_JDAT);
12889 LogPNGChunk(logging,mng_JDAT,length);
12890 (void) WriteBlob(image,4,chunk);
12891 (void) WriteBlob(image,length,blob);
12892 (void) WriteBlobMSBULong(image,crc32(crc32(0,chunk,4),blob,(uInt) length));
12894 jpeg_image=DestroyImage(jpeg_image);
12895 (void) RelinquishUniqueFileResource(jpeg_image_info->filename);
12896 jpeg_image_info=DestroyImageInfo(jpeg_image_info);
12897 blob=(unsigned char *) RelinquishMagickMemory(blob);
12899 /* Write any JNG-chunk-e profiles */
12900 (void) Magick_png_write_chunk_from_profile(image,"JNG-chunk-e",logging);
12902 /* Write IEND chunk */
12903 (void) WriteBlobMSBULong(image,0L);
12904 PNGType(chunk,mng_IEND);
12905 LogPNGChunk(logging,mng_IEND,0);
12906 (void) WriteBlob(image,4,chunk);
12907 (void) WriteBlobMSBULong(image,crc32(0,chunk,4));
12909 if (logging != MagickFalse)
12910 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12911 " exit WriteOneJNGImage()");
12918 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12922 % W r i t e J N G I m a g e %
12926 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12928 % WriteJNGImage() writes a JPEG Network Graphics (JNG) image file.
12930 % JNG support written by Glenn Randers-Pehrson, glennrp@image...
12932 % The format of the WriteJNGImage method is:
12934 % MagickBooleanType WriteJNGImage(const ImageInfo *image_info,
12935 % Image *image,ExceptionInfo *exception)
12937 % A description of each parameter follows:
12939 % o image_info: the image info.
12941 % o image: The image.
12943 % o exception: return any errors or warnings in this structure.
12945 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12947 static MagickBooleanType WriteJNGImage(const ImageInfo *image_info,Image *image,
12948 ExceptionInfo *exception)
12951 have_mng_structure,
12961 assert(image_info != (const ImageInfo *) NULL);
12962 assert(image_info->signature == MagickSignature);
12963 assert(image != (Image *) NULL);
12964 assert(image->signature == MagickSignature);
12965 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
12966 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter WriteJNGImage()");
12967 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
12968 if (status == MagickFalse)
12972 Allocate a MngInfo structure.
12974 have_mng_structure=MagickFalse;
12975 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
12976 if (mng_info == (MngInfo *) NULL)
12977 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
12979 Initialize members of the MngInfo structure.
12981 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
12982 mng_info->image=image;
12983 have_mng_structure=MagickTrue;
12985 (void) WriteBlob(image,8,(const unsigned char *) "\213JNG\r\n\032\n");
12987 status=WriteOneJNGImage(mng_info,image_info,image,exception);
12988 (void) CloseBlob(image);
12990 (void) CatchImageException(image);
12991 MngInfoFreeStruct(mng_info,&have_mng_structure);
12992 if (logging != MagickFalse)
12993 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit WriteJNGImage()");
12998 static MagickBooleanType WriteMNGImage(const ImageInfo *image_info,Image *image,
12999 ExceptionInfo *exception)
13008 have_mng_structure,
13011 volatile MagickBooleanType
13023 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
13024 defined(PNG_MNG_FEATURES_SUPPORTED)
13027 all_images_are_gray,
13037 volatile unsigned int
13048 #if (PNG_LIBPNG_VER < 10200)
13049 if (image_info->verbose)
13050 printf("Your PNG library (libpng-%s) is rather old.\n",
13051 PNG_LIBPNG_VER_STRING);
13057 assert(image_info != (const ImageInfo *) NULL);
13058 assert(image_info->signature == MagickSignature);
13059 assert(image != (Image *) NULL);
13060 assert(image->signature == MagickSignature);
13061 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
13062 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter WriteMNGImage()");
13063 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
13064 if (status == MagickFalse)
13068 Allocate a MngInfo structure.
13070 have_mng_structure=MagickFalse;
13071 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
13072 if (mng_info == (MngInfo *) NULL)
13073 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
13075 Initialize members of the MngInfo structure.
13077 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
13078 mng_info->image=image;
13079 have_mng_structure=MagickTrue;
13080 write_mng=LocaleCompare(image_info->magick,"MNG") == 0;
13083 * See if user has requested a specific PNG subformat to be used
13084 * for all of the PNGs in the MNG being written, e.g.,
13086 * convert *.png png8:animation.mng
13088 * To do: check -define png:bit_depth and png:color_type as well,
13089 * or perhaps use mng:bit_depth and mng:color_type instead for
13093 mng_info->write_png8=LocaleCompare(image_info->magick,"PNG8") == 0;
13094 mng_info->write_png24=LocaleCompare(image_info->magick,"PNG24") == 0;
13095 mng_info->write_png32=LocaleCompare(image_info->magick,"PNG32") == 0;
13097 write_jng=MagickFalse;
13098 if (image_info->compression == JPEGCompression)
13099 write_jng=MagickTrue;
13101 mng_info->adjoin=image_info->adjoin &&
13102 (GetNextImageInList(image) != (Image *) NULL) && write_mng;
13104 if (logging != MagickFalse)
13106 /* Log some info about the input */
13110 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
13111 " Checking input image(s)");
13113 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
13114 " Image_info depth: %.20g",(double) image_info->depth);
13116 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
13117 " Type: %d",image_info->type);
13120 for (p=image; p != (Image *) NULL; p=GetNextImageInList(p))
13122 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
13123 " Scene: %.20g",(double) scene++);
13125 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
13126 " Image depth: %.20g",(double) p->depth);
13128 if (p->alpha_trait == BlendPixelTrait)
13129 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
13133 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
13136 if (p->storage_class == PseudoClass)
13137 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
13138 " Storage class: PseudoClass");
13141 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
13142 " Storage class: DirectClass");
13145 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
13146 " Number of colors: %.20g",(double) p->colors);
13149 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
13150 " Number of colors: unspecified");
13152 if (mng_info->adjoin == MagickFalse)
13157 use_global_plte=MagickFalse;
13158 all_images_are_gray=MagickFalse;
13159 #ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
13160 need_local_plte=MagickTrue;
13162 need_defi=MagickFalse;
13163 need_matte=MagickFalse;
13164 mng_info->framing_mode=1;
13165 mng_info->old_framing_mode=1;
13168 if (image_info->page != (char *) NULL)
13171 Determine image bounding box.
13173 SetGeometry(image,&mng_info->page);
13174 (void) ParseMetaGeometry(image_info->page,&mng_info->page.x,
13175 &mng_info->page.y,&mng_info->page.width,&mng_info->page.height);
13187 mng_info->page=image->page;
13188 need_geom=MagickTrue;
13189 if (mng_info->page.width || mng_info->page.height)
13190 need_geom=MagickFalse;
13192 Check all the scenes.
13194 initial_delay=image->delay;
13195 need_iterations=MagickFalse;
13196 mng_info->equal_chrms=image->chromaticity.red_primary.x != 0.0;
13197 mng_info->equal_physs=MagickTrue,
13198 mng_info->equal_gammas=MagickTrue;
13199 mng_info->equal_srgbs=MagickTrue;
13200 mng_info->equal_backgrounds=MagickTrue;
13202 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
13203 defined(PNG_MNG_FEATURES_SUPPORTED)
13204 all_images_are_gray=MagickTrue;
13205 mng_info->equal_palettes=MagickFalse;
13206 need_local_plte=MagickFalse;
13208 for (next_image=image; next_image != (Image *) NULL; )
13212 if ((next_image->columns+next_image->page.x) > mng_info->page.width)
13213 mng_info->page.width=next_image->columns+next_image->page.x;
13215 if ((next_image->rows+next_image->page.y) > mng_info->page.height)
13216 mng_info->page.height=next_image->rows+next_image->page.y;
13219 if (next_image->page.x || next_image->page.y)
13220 need_defi=MagickTrue;
13222 if (next_image->alpha_trait == BlendPixelTrait)
13223 need_matte=MagickTrue;
13225 if ((int) next_image->dispose >= BackgroundDispose)
13226 if ((next_image->alpha_trait == BlendPixelTrait) ||
13227 next_image->page.x || next_image->page.y ||
13228 ((next_image->columns < mng_info->page.width) &&
13229 (next_image->rows < mng_info->page.height)))
13230 mng_info->need_fram=MagickTrue;
13232 if (next_image->iterations)
13233 need_iterations=MagickTrue;
13235 final_delay=next_image->delay;
13237 if (final_delay != initial_delay || final_delay > 1UL*
13238 next_image->ticks_per_second)
13239 mng_info->need_fram=1;
13241 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
13242 defined(PNG_MNG_FEATURES_SUPPORTED)
13244 check for global palette possibility.
13246 if (image->alpha_trait == BlendPixelTrait)
13247 need_local_plte=MagickTrue;
13249 if (need_local_plte == 0)
13251 if (IsImageGray(image,exception) == MagickFalse)
13252 all_images_are_gray=MagickFalse;
13253 mng_info->equal_palettes=PalettesAreEqual(image,next_image);
13254 if (use_global_plte == 0)
13255 use_global_plte=mng_info->equal_palettes;
13256 need_local_plte=!mng_info->equal_palettes;
13259 if (GetNextImageInList(next_image) != (Image *) NULL)
13261 if (next_image->background_color.red !=
13262 next_image->next->background_color.red ||
13263 next_image->background_color.green !=
13264 next_image->next->background_color.green ||
13265 next_image->background_color.blue !=
13266 next_image->next->background_color.blue)
13267 mng_info->equal_backgrounds=MagickFalse;
13269 if (next_image->gamma != next_image->next->gamma)
13270 mng_info->equal_gammas=MagickFalse;
13272 if (next_image->rendering_intent !=
13273 next_image->next->rendering_intent)
13274 mng_info->equal_srgbs=MagickFalse;
13276 if ((next_image->units != next_image->next->units) ||
13277 (next_image->resolution.x != next_image->next->resolution.x) ||
13278 (next_image->resolution.y != next_image->next->resolution.y))
13279 mng_info->equal_physs=MagickFalse;
13281 if (mng_info->equal_chrms)
13283 if (next_image->chromaticity.red_primary.x !=
13284 next_image->next->chromaticity.red_primary.x ||
13285 next_image->chromaticity.red_primary.y !=
13286 next_image->next->chromaticity.red_primary.y ||
13287 next_image->chromaticity.green_primary.x !=
13288 next_image->next->chromaticity.green_primary.x ||
13289 next_image->chromaticity.green_primary.y !=
13290 next_image->next->chromaticity.green_primary.y ||
13291 next_image->chromaticity.blue_primary.x !=
13292 next_image->next->chromaticity.blue_primary.x ||
13293 next_image->chromaticity.blue_primary.y !=
13294 next_image->next->chromaticity.blue_primary.y ||
13295 next_image->chromaticity.white_point.x !=
13296 next_image->next->chromaticity.white_point.x ||
13297 next_image->chromaticity.white_point.y !=
13298 next_image->next->chromaticity.white_point.y)
13299 mng_info->equal_chrms=MagickFalse;
13303 next_image=GetNextImageInList(next_image);
13305 if (image_count < 2)
13307 mng_info->equal_backgrounds=MagickFalse;
13308 mng_info->equal_chrms=MagickFalse;
13309 mng_info->equal_gammas=MagickFalse;
13310 mng_info->equal_srgbs=MagickFalse;
13311 mng_info->equal_physs=MagickFalse;
13312 use_global_plte=MagickFalse;
13313 #ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
13314 need_local_plte=MagickTrue;
13316 need_iterations=MagickFalse;
13319 if (mng_info->need_fram == MagickFalse)
13322 Only certain framing rates 100/n are exactly representable without
13323 the FRAM chunk but we'll allow some slop in VLC files
13325 if (final_delay == 0)
13327 if (need_iterations != MagickFalse)
13330 It's probably a GIF with loop; don't run it *too* fast.
13332 if (mng_info->adjoin)
13335 (void) ThrowMagickException(exception,GetMagickModule(),
13337 "input has zero delay between all frames; assuming",
13342 mng_info->ticks_per_second=0;
13344 if (final_delay != 0)
13345 mng_info->ticks_per_second=(png_uint_32)
13346 (image->ticks_per_second/final_delay);
13347 if (final_delay > 50)
13348 mng_info->ticks_per_second=2;
13350 if (final_delay > 75)
13351 mng_info->ticks_per_second=1;
13353 if (final_delay > 125)
13354 mng_info->need_fram=MagickTrue;
13356 if (need_defi && final_delay > 2 && (final_delay != 4) &&
13357 (final_delay != 5) && (final_delay != 10) && (final_delay != 20) &&
13358 (final_delay != 25) && (final_delay != 50) && (1UL*final_delay !=
13359 1UL*image->ticks_per_second))
13360 mng_info->need_fram=MagickTrue; /* make it exact; cannot be VLC */
13363 if (mng_info->need_fram != MagickFalse)
13364 mng_info->ticks_per_second=1UL*image->ticks_per_second;
13366 If pseudocolor, we should also check to see if all the
13367 palettes are identical and write a global PLTE if they are.
13371 Write the MNG version 1.0 signature and MHDR chunk.
13373 (void) WriteBlob(image,8,(const unsigned char *) "\212MNG\r\n\032\n");
13374 (void) WriteBlobMSBULong(image,28L); /* chunk data length=28 */
13375 PNGType(chunk,mng_MHDR);
13376 LogPNGChunk(logging,mng_MHDR,28L);
13377 PNGLong(chunk+4,(png_uint_32) mng_info->page.width);
13378 PNGLong(chunk+8,(png_uint_32) mng_info->page.height);
13379 PNGLong(chunk+12,mng_info->ticks_per_second);
13380 PNGLong(chunk+16,0L); /* layer count=unknown */
13381 PNGLong(chunk+20,0L); /* frame count=unknown */
13382 PNGLong(chunk+24,0L); /* play time=unknown */
13387 if (need_defi || mng_info->need_fram || use_global_plte)
13388 PNGLong(chunk+28,27L); /* simplicity=LC+JNG */
13391 PNGLong(chunk+28,25L); /* simplicity=VLC+JNG */
13396 if (need_defi || mng_info->need_fram || use_global_plte)
13397 PNGLong(chunk+28,19L); /* simplicity=LC+JNG, no transparency */
13400 PNGLong(chunk+28,17L); /* simplicity=VLC+JNG, no transparency */
13408 if (need_defi || mng_info->need_fram || use_global_plte)
13409 PNGLong(chunk+28,11L); /* simplicity=LC */
13412 PNGLong(chunk+28,9L); /* simplicity=VLC */
13417 if (need_defi || mng_info->need_fram || use_global_plte)
13418 PNGLong(chunk+28,3L); /* simplicity=LC, no transparency */
13421 PNGLong(chunk+28,1L); /* simplicity=VLC, no transparency */
13424 (void) WriteBlob(image,32,chunk);
13425 (void) WriteBlobMSBULong(image,crc32(0,chunk,32));
13426 option=GetImageOption(image_info,"mng:need-cacheoff");
13427 if (option != (const char *) NULL)
13433 Write "nEED CACHEOFF" to turn playback caching off for streaming MNG.
13435 PNGType(chunk,mng_nEED);
13436 length=CopyMagickString((char *) chunk+4,"CACHEOFF",20);
13437 (void) WriteBlobMSBULong(image,(size_t) length);
13438 LogPNGChunk(logging,mng_nEED,(size_t) length);
13440 (void) WriteBlob(image,length,chunk);
13441 (void) WriteBlobMSBULong(image,crc32(0,chunk,(uInt) length));
13443 if ((GetPreviousImageInList(image) == (Image *) NULL) &&
13444 (GetNextImageInList(image) != (Image *) NULL) &&
13445 (image->iterations != 1))
13448 Write MNG TERM chunk
13450 (void) WriteBlobMSBULong(image,10L); /* data length=10 */
13451 PNGType(chunk,mng_TERM);
13452 LogPNGChunk(logging,mng_TERM,10L);
13453 chunk[4]=3; /* repeat animation */
13454 chunk[5]=0; /* show last frame when done */
13455 PNGLong(chunk+6,(png_uint_32) (mng_info->ticks_per_second*
13456 final_delay/MagickMax(image->ticks_per_second,1)));
13458 if (image->iterations == 0)
13459 PNGLong(chunk+10,PNG_UINT_31_MAX);
13462 PNGLong(chunk+10,(png_uint_32) image->iterations);
13464 if (logging != MagickFalse)
13466 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
13467 " TERM delay: %.20g",(double) (mng_info->ticks_per_second*
13468 final_delay/MagickMax(image->ticks_per_second,1)));
13470 if (image->iterations == 0)
13471 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
13472 " TERM iterations: %.20g",(double) PNG_UINT_31_MAX);
13475 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
13476 " Image iterations: %.20g",(double) image->iterations);
13478 (void) WriteBlob(image,14,chunk);
13479 (void) WriteBlobMSBULong(image,crc32(0,chunk,14));
13482 To do: check for cHRM+gAMA == sRGB, and write sRGB instead.
13484 if ((image->colorspace == sRGBColorspace || image->rendering_intent) &&
13485 mng_info->equal_srgbs)
13488 Write MNG sRGB chunk
13490 (void) WriteBlobMSBULong(image,1L);
13491 PNGType(chunk,mng_sRGB);
13492 LogPNGChunk(logging,mng_sRGB,1L);
13494 if (image->rendering_intent != UndefinedIntent)
13495 chunk[4]=(unsigned char)
13496 Magick_RenderingIntent_to_PNG_RenderingIntent(
13497 (image->rendering_intent));
13500 chunk[4]=(unsigned char)
13501 Magick_RenderingIntent_to_PNG_RenderingIntent(
13502 (PerceptualIntent));
13504 (void) WriteBlob(image,5,chunk);
13505 (void) WriteBlobMSBULong(image,crc32(0,chunk,5));
13506 mng_info->have_write_global_srgb=MagickTrue;
13511 if (image->gamma && mng_info->equal_gammas)
13514 Write MNG gAMA chunk
13516 (void) WriteBlobMSBULong(image,4L);
13517 PNGType(chunk,mng_gAMA);
13518 LogPNGChunk(logging,mng_gAMA,4L);
13519 PNGLong(chunk+4,(png_uint_32) (100000*image->gamma+0.5));
13520 (void) WriteBlob(image,8,chunk);
13521 (void) WriteBlobMSBULong(image,crc32(0,chunk,8));
13522 mng_info->have_write_global_gama=MagickTrue;
13524 if (mng_info->equal_chrms)
13530 Write MNG cHRM chunk
13532 (void) WriteBlobMSBULong(image,32L);
13533 PNGType(chunk,mng_cHRM);
13534 LogPNGChunk(logging,mng_cHRM,32L);
13535 primary=image->chromaticity.white_point;
13536 PNGLong(chunk+4,(png_uint_32) (100000*primary.x+0.5));
13537 PNGLong(chunk+8,(png_uint_32) (100000*primary.y+0.5));
13538 primary=image->chromaticity.red_primary;
13539 PNGLong(chunk+12,(png_uint_32) (100000*primary.x+0.5));
13540 PNGLong(chunk+16,(png_uint_32) (100000*primary.y+0.5));
13541 primary=image->chromaticity.green_primary;
13542 PNGLong(chunk+20,(png_uint_32) (100000*primary.x+0.5));
13543 PNGLong(chunk+24,(png_uint_32) (100000*primary.y+0.5));
13544 primary=image->chromaticity.blue_primary;
13545 PNGLong(chunk+28,(png_uint_32) (100000*primary.x+0.5));
13546 PNGLong(chunk+32,(png_uint_32) (100000*primary.y+0.5));
13547 (void) WriteBlob(image,36,chunk);
13548 (void) WriteBlobMSBULong(image,crc32(0,chunk,36));
13549 mng_info->have_write_global_chrm=MagickTrue;
13552 if (image->resolution.x && image->resolution.y && mng_info->equal_physs)
13555 Write MNG pHYs chunk
13557 (void) WriteBlobMSBULong(image,9L);
13558 PNGType(chunk,mng_pHYs);
13559 LogPNGChunk(logging,mng_pHYs,9L);
13561 if (image->units == PixelsPerInchResolution)
13563 PNGLong(chunk+4,(png_uint_32)
13564 (image->resolution.x*100.0/2.54+0.5));
13566 PNGLong(chunk+8,(png_uint_32)
13567 (image->resolution.y*100.0/2.54+0.5));
13574 if (image->units == PixelsPerCentimeterResolution)
13576 PNGLong(chunk+4,(png_uint_32)
13577 (image->resolution.x*100.0+0.5));
13579 PNGLong(chunk+8,(png_uint_32)
13580 (image->resolution.y*100.0+0.5));
13587 PNGLong(chunk+4,(png_uint_32) (image->resolution.x+0.5));
13588 PNGLong(chunk+8,(png_uint_32) (image->resolution.y+0.5));
13592 (void) WriteBlob(image,13,chunk);
13593 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
13596 Write MNG BACK chunk and global bKGD chunk, if the image is transparent
13597 or does not cover the entire frame.
13599 if (write_mng && ((image->alpha_trait == BlendPixelTrait) ||
13600 image->page.x > 0 || image->page.y > 0 || (image->page.width &&
13601 (image->page.width+image->page.x < mng_info->page.width))
13602 || (image->page.height && (image->page.height+image->page.y
13603 < mng_info->page.height))))
13605 (void) WriteBlobMSBULong(image,6L);
13606 PNGType(chunk,mng_BACK);
13607 LogPNGChunk(logging,mng_BACK,6L);
13608 red=ScaleQuantumToShort(image->background_color.red);
13609 green=ScaleQuantumToShort(image->background_color.green);
13610 blue=ScaleQuantumToShort(image->background_color.blue);
13611 PNGShort(chunk+4,red);
13612 PNGShort(chunk+6,green);
13613 PNGShort(chunk+8,blue);
13614 (void) WriteBlob(image,10,chunk);
13615 (void) WriteBlobMSBULong(image,crc32(0,chunk,10));
13616 if (mng_info->equal_backgrounds)
13618 (void) WriteBlobMSBULong(image,6L);
13619 PNGType(chunk,mng_bKGD);
13620 LogPNGChunk(logging,mng_bKGD,6L);
13621 (void) WriteBlob(image,10,chunk);
13622 (void) WriteBlobMSBULong(image,crc32(0,chunk,10));
13626 #ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
13627 if ((need_local_plte == MagickFalse) &&
13628 (image->storage_class == PseudoClass) &&
13629 (all_images_are_gray == MagickFalse))
13635 Write MNG PLTE chunk
13637 data_length=3*image->colors;
13638 (void) WriteBlobMSBULong(image,data_length);
13639 PNGType(chunk,mng_PLTE);
13640 LogPNGChunk(logging,mng_PLTE,data_length);
13642 for (i=0; i < (ssize_t) image->colors; i++)
13644 chunk[4+i*3]=(unsigned char) (ScaleQuantumToChar(
13645 image->colormap[i].red) & 0xff);
13646 chunk[5+i*3]=(unsigned char) (ScaleQuantumToChar(
13647 image->colormap[i].green) & 0xff);
13648 chunk[6+i*3]=(unsigned char) (ScaleQuantumToChar(
13649 image->colormap[i].blue) & 0xff);
13652 (void) WriteBlob(image,data_length+4,chunk);
13653 (void) WriteBlobMSBULong(image,crc32(0,chunk,(uInt) (data_length+4)));
13654 mng_info->have_write_global_plte=MagickTrue;
13660 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
13661 defined(PNG_MNG_FEATURES_SUPPORTED)
13662 mng_info->equal_palettes=MagickFalse;
13666 if (mng_info->adjoin)
13668 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
13669 defined(PNG_MNG_FEATURES_SUPPORTED)
13671 If we aren't using a global palette for the entire MNG, check to
13672 see if we can use one for two or more consecutive images.
13674 if (need_local_plte && use_global_plte && !all_images_are_gray)
13676 if (mng_info->IsPalette)
13679 When equal_palettes is true, this image has the same palette
13680 as the previous PseudoClass image
13682 mng_info->have_write_global_plte=mng_info->equal_palettes;
13683 mng_info->equal_palettes=PalettesAreEqual(image,image->next);
13684 if (mng_info->equal_palettes && !mng_info->have_write_global_plte)
13687 Write MNG PLTE chunk
13692 data_length=3*image->colors;
13693 (void) WriteBlobMSBULong(image,data_length);
13694 PNGType(chunk,mng_PLTE);
13695 LogPNGChunk(logging,mng_PLTE,data_length);
13697 for (i=0; i < (ssize_t) image->colors; i++)
13699 chunk[4+i*3]=ScaleQuantumToChar(image->colormap[i].red);
13700 chunk[5+i*3]=ScaleQuantumToChar(image->colormap[i].green);
13701 chunk[6+i*3]=ScaleQuantumToChar(image->colormap[i].blue);
13704 (void) WriteBlob(image,data_length+4,chunk);
13705 (void) WriteBlobMSBULong(image,crc32(0,chunk,
13706 (uInt) (data_length+4)));
13707 mng_info->have_write_global_plte=MagickTrue;
13711 mng_info->have_write_global_plte=MagickFalse;
13722 previous_x=mng_info->page.x;
13723 previous_y=mng_info->page.y;
13730 mng_info->page=image->page;
13731 if ((mng_info->page.x != previous_x) ||
13732 (mng_info->page.y != previous_y))
13734 (void) WriteBlobMSBULong(image,12L); /* data length=12 */
13735 PNGType(chunk,mng_DEFI);
13736 LogPNGChunk(logging,mng_DEFI,12L);
13737 chunk[4]=0; /* object 0 MSB */
13738 chunk[5]=0; /* object 0 LSB */
13739 chunk[6]=0; /* visible */
13740 chunk[7]=0; /* abstract */
13741 PNGLong(chunk+8,(png_uint_32) mng_info->page.x);
13742 PNGLong(chunk+12,(png_uint_32) mng_info->page.y);
13743 (void) WriteBlob(image,16,chunk);
13744 (void) WriteBlobMSBULong(image,crc32(0,chunk,16));
13749 mng_info->write_mng=write_mng;
13751 if ((int) image->dispose >= 3)
13752 mng_info->framing_mode=3;
13754 if (mng_info->need_fram && mng_info->adjoin &&
13755 ((image->delay != mng_info->delay) ||
13756 (mng_info->framing_mode != mng_info->old_framing_mode)))
13758 if (image->delay == mng_info->delay)
13761 Write a MNG FRAM chunk with the new framing mode.
13763 (void) WriteBlobMSBULong(image,1L); /* data length=1 */
13764 PNGType(chunk,mng_FRAM);
13765 LogPNGChunk(logging,mng_FRAM,1L);
13766 chunk[4]=(unsigned char) mng_info->framing_mode;
13767 (void) WriteBlob(image,5,chunk);
13768 (void) WriteBlobMSBULong(image,crc32(0,chunk,5));
13773 Write a MNG FRAM chunk with the delay.
13775 (void) WriteBlobMSBULong(image,10L); /* data length=10 */
13776 PNGType(chunk,mng_FRAM);
13777 LogPNGChunk(logging,mng_FRAM,10L);
13778 chunk[4]=(unsigned char) mng_info->framing_mode;
13779 chunk[5]=0; /* frame name separator (no name) */
13780 chunk[6]=2; /* flag for changing default delay */
13781 chunk[7]=0; /* flag for changing frame timeout */
13782 chunk[8]=0; /* flag for changing frame clipping */
13783 chunk[9]=0; /* flag for changing frame sync_id */
13784 PNGLong(chunk+10,(png_uint_32)
13785 ((mng_info->ticks_per_second*
13786 image->delay)/MagickMax(image->ticks_per_second,1)));
13787 (void) WriteBlob(image,14,chunk);
13788 (void) WriteBlobMSBULong(image,crc32(0,chunk,14));
13789 mng_info->delay=(png_uint_32) image->delay;
13791 mng_info->old_framing_mode=mng_info->framing_mode;
13794 #if defined(JNG_SUPPORTED)
13795 if (image_info->compression == JPEGCompression)
13800 if (logging != MagickFalse)
13801 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
13802 " Writing JNG object.");
13803 /* To do: specify the desired alpha compression method. */
13804 write_info=CloneImageInfo(image_info);
13805 write_info->compression=UndefinedCompression;
13806 status=WriteOneJNGImage(mng_info,write_info,image,exception);
13807 write_info=DestroyImageInfo(write_info);
13812 if (logging != MagickFalse)
13813 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
13814 " Writing PNG object.");
13816 mng_info->need_blob = MagickFalse;
13817 mng_info->ping_preserve_colormap = MagickFalse;
13819 /* We don't want any ancillary chunks written */
13820 mng_info->ping_exclude_bKGD=MagickTrue;
13821 mng_info->ping_exclude_cHRM=MagickTrue;
13822 mng_info->ping_exclude_date=MagickTrue;
13823 mng_info->ping_exclude_EXIF=MagickTrue;
13824 mng_info->ping_exclude_gAMA=MagickTrue;
13825 mng_info->ping_exclude_iCCP=MagickTrue;
13826 /* mng_info->ping_exclude_iTXt=MagickTrue; */
13827 mng_info->ping_exclude_oFFs=MagickTrue;
13828 mng_info->ping_exclude_pHYs=MagickTrue;
13829 mng_info->ping_exclude_sRGB=MagickTrue;
13830 mng_info->ping_exclude_tEXt=MagickTrue;
13831 mng_info->ping_exclude_tRNS=MagickTrue;
13832 mng_info->ping_exclude_vpAg=MagickTrue;
13833 mng_info->ping_exclude_zCCP=MagickTrue;
13834 mng_info->ping_exclude_zTXt=MagickTrue;
13836 status=WriteOnePNGImage(mng_info,image_info,image,exception);
13839 if (status == MagickFalse)
13841 MngInfoFreeStruct(mng_info,&have_mng_structure);
13842 (void) CloseBlob(image);
13843 return(MagickFalse);
13845 (void) CatchImageException(image);
13846 if (GetNextImageInList(image) == (Image *) NULL)
13848 image=SyncNextImageInList(image);
13849 status=SetImageProgress(image,SaveImagesTag,scene++,
13850 GetImageListLength(image));
13852 if (status == MagickFalse)
13855 } while (mng_info->adjoin);
13859 while (GetPreviousImageInList(image) != (Image *) NULL)
13860 image=GetPreviousImageInList(image);
13862 Write the MEND chunk.
13864 (void) WriteBlobMSBULong(image,0x00000000L);
13865 PNGType(chunk,mng_MEND);
13866 LogPNGChunk(logging,mng_MEND,0L);
13867 (void) WriteBlob(image,4,chunk);
13868 (void) WriteBlobMSBULong(image,crc32(0,chunk,4));
13871 Relinquish resources.
13873 (void) CloseBlob(image);
13874 MngInfoFreeStruct(mng_info,&have_mng_structure);
13876 if (logging != MagickFalse)
13877 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit WriteMNGImage()");
13879 return(MagickTrue);
13881 #else /* PNG_LIBPNG_VER > 10011 */
13883 static MagickBooleanType WritePNGImage(const ImageInfo *image_info,Image *image)
13886 printf("Your PNG library is too old: You have libpng-%s\n",
13887 PNG_LIBPNG_VER_STRING);
13889 ThrowBinaryException(CoderError,"PNG library is too old",
13890 image_info->filename);
13893 static MagickBooleanType WriteMNGImage(const ImageInfo *image_info,Image *image)
13895 return(WritePNGImage(image_info,image));
13897 #endif /* PNG_LIBPNG_VER > 10011 */