2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13 % Read/Write Portable Network Graphics Image Format %
17 % Glenn Randers-Pehrson %
21 % Copyright 1999-2013 ImageMagick Studio LLC, a non-profit organization %
22 % dedicated to making software imaging solutions freely available. %
24 % You may not use this file except in compliance with the License. You may %
25 % obtain a copy of the License at %
27 % http://www.imagemagick.org/script/license.php %
29 % Unless required by applicable law or agreed to in writing, software %
30 % distributed under the License is distributed on an "AS IS" BASIS, %
31 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
32 % See the License for the specific language governing permissions and %
33 % limitations under the License. %
35 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
44 #include "MagickCore/studio.h"
45 #include "MagickCore/artifact.h"
46 #include "MagickCore/attribute.h"
47 #include "MagickCore/blob.h"
48 #include "MagickCore/blob-private.h"
49 #include "MagickCore/cache.h"
50 #include "MagickCore/channel.h"
51 #include "MagickCore/color.h"
52 #include "MagickCore/color-private.h"
53 #include "MagickCore/colormap.h"
54 #include "MagickCore/colorspace.h"
55 #include "MagickCore/colorspace-private.h"
56 #include "MagickCore/constitute.h"
57 #include "MagickCore/enhance.h"
58 #include "MagickCore/exception.h"
59 #include "MagickCore/exception-private.h"
60 #include "MagickCore/geometry.h"
61 #include "MagickCore/histogram.h"
62 #include "MagickCore/image.h"
63 #include "MagickCore/image-private.h"
64 #include "MagickCore/layer.h"
65 #include "MagickCore/list.h"
66 #include "MagickCore/log.h"
67 #include "MagickCore/MagickCore.h"
68 #include "MagickCore/memory_.h"
69 #include "MagickCore/module.h"
70 #include "MagickCore/monitor.h"
71 #include "MagickCore/monitor-private.h"
72 #include "MagickCore/option.h"
73 #include "MagickCore/pixel.h"
74 #include "MagickCore/pixel-accessor.h"
75 #include "MagickCore/profile.h"
76 #include "MagickCore/property.h"
77 #include "MagickCore/quantum-private.h"
78 #include "MagickCore/resource_.h"
79 #include "MagickCore/semaphore.h"
80 #include "MagickCore/quantum-private.h"
81 #include "MagickCore/static.h"
82 #include "MagickCore/statistic.h"
83 #include "MagickCore/string_.h"
84 #include "MagickCore/string-private.h"
85 #include "MagickCore/transform.h"
86 #include "MagickCore/utility.h"
87 #if defined(MAGICKCORE_PNG_DELEGATE)
89 /* Suppress libpng pedantic warnings that were added in
90 * libpng-1.2.41 and libpng-1.4.0. If you are working on
91 * migration to libpng-1.5, remove these defines and then
92 * fix any code that generates warnings.
94 /* #define PNG_DEPRECATED Use of this function is deprecated */
95 /* #define PNG_USE_RESULT The result of this function must be checked */
96 /* #define PNG_NORETURN This function does not return */
97 /* #define PNG_ALLOCATED The result of the function is new memory */
98 /* #define PNG_DEPSTRUCT Access to this struct member is deprecated */
100 /* PNG_PTR_NORETURN does not work on some platforms, in libpng-1.5.x */
101 #define PNG_PTR_NORETURN
106 /* ImageMagick differences */
107 #define first_scene scene
109 #if PNG_LIBPNG_VER > 10011
111 Optional declarations. Define or undefine them as you like.
113 /* #define PNG_DEBUG -- turning this on breaks VisualC compiling */
116 Features under construction. Define these to work on them.
118 #undef MNG_OBJECT_BUFFERS
119 #undef MNG_BASI_SUPPORTED
120 #define MNG_COALESCE_LAYERS /* In 5.4.4, this interfered with MMAP'ed files. */
121 #define MNG_INSERT_LAYERS /* Troublesome, but seem to work as of 5.4.4 */
122 #if defined(MAGICKCORE_JPEG_DELEGATE)
123 # define JNG_SUPPORTED /* Not finished as of 5.5.2. See "To do" comments. */
125 #if !defined(RGBColorMatchExact)
126 #define IsPNGColorEqual(color,target) \
127 (((color).red == (target).red) && \
128 ((color).green == (target).green) && \
129 ((color).blue == (target).blue))
132 /* Macros for left-bit-replication to ensure that pixels
133 * and PixelInfos all have the same image->depth, and for use
134 * in PNG8 quantization.
138 /* LBR01: Replicate top bit */
140 #define LBR01PacketRed(pixelpacket) \
141 (pixelpacket).red=(ScaleQuantumToChar((pixelpacket).red) < 0x10 ? \
144 #define LBR01PacketGreen(pixelpacket) \
145 (pixelpacket).green=(ScaleQuantumToChar((pixelpacket).green) < 0x10 ? \
148 #define LBR01PacketBlue(pixelpacket) \
149 (pixelpacket).blue=(ScaleQuantumToChar((pixelpacket).blue) < 0x10 ? \
152 #define LBR01PacketAlpha(pixelpacket) \
153 (pixelpacket).alpha=(ScaleQuantumToChar((pixelpacket).alpha) < 0x10 ? \
156 #define LBR01PacketRGB(pixelpacket) \
158 LBR01PacketRed((pixelpacket)); \
159 LBR01PacketGreen((pixelpacket)); \
160 LBR01PacketBlue((pixelpacket)); \
163 #define LBR01PacketRGBO(pixelpacket) \
165 LBR01PacketRGB((pixelpacket)); \
166 LBR01PacketAlpha((pixelpacket)); \
169 #define LBR01PixelRed(pixel) \
170 (SetPixelRed(image, \
171 ScaleQuantumToChar(GetPixelRed(image,(pixel))) < 0x10 ? \
172 0 : QuantumRange,(pixel)));
174 #define LBR01PixelGreen(pixel) \
175 (SetPixelGreen(image, \
176 ScaleQuantumToChar(GetPixelGreen(image,(pixel))) < 0x10 ? \
177 0 : QuantumRange,(pixel)));
179 #define LBR01PixelBlue(pixel) \
180 (SetPixelBlue(image, \
181 ScaleQuantumToChar(GetPixelBlue(image,(pixel))) < 0x10 ? \
182 0 : QuantumRange,(pixel)));
184 #define LBR01PixelAlpha(pixel) \
185 (SetPixelAlpha(image, \
186 ScaleQuantumToChar(GetPixelAlpha(image,(pixel))) < 0x10 ? \
187 0 : QuantumRange,(pixel)));
189 #define LBR01PixelRGB(pixel) \
191 LBR01PixelRed((pixel)); \
192 LBR01PixelGreen((pixel)); \
193 LBR01PixelBlue((pixel)); \
196 #define LBR01PixelRGBA(pixel) \
198 LBR01PixelRGB((pixel)); \
199 LBR01PixelAlpha((pixel)); \
202 /* LBR02: Replicate top 2 bits */
204 #define LBR02PacketRed(pixelpacket) \
206 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).red) & 0xc0; \
207 (pixelpacket).red=ScaleCharToQuantum( \
208 (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))); \
210 #define LBR02PacketGreen(pixelpacket) \
212 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).green) & 0xc0; \
213 (pixelpacket).green=ScaleCharToQuantum( \
214 (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))); \
216 #define LBR02PacketBlue(pixelpacket) \
218 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).blue) & 0xc0; \
219 (pixelpacket).blue=ScaleCharToQuantum( \
220 (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))); \
222 #define LBR02PacketAlpha(pixelpacket) \
224 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).alpha) & 0xc0; \
225 (pixelpacket).alpha=ScaleCharToQuantum( \
226 (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))); \
229 #define LBR02PacketRGB(pixelpacket) \
231 LBR02PacketRed((pixelpacket)); \
232 LBR02PacketGreen((pixelpacket)); \
233 LBR02PacketBlue((pixelpacket)); \
236 #define LBR02PacketRGBO(pixelpacket) \
238 LBR02PacketRGB((pixelpacket)); \
239 LBR02PacketAlpha((pixelpacket)); \
242 #define LBR02PixelRed(pixel) \
244 unsigned char lbr_bits=ScaleQuantumToChar(GetPixelRed(image,(pixel))) \
246 SetPixelRed(image, ScaleCharToQuantum( \
247 (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))), \
250 #define LBR02PixelGreen(pixel) \
252 unsigned char lbr_bits=ScaleQuantumToChar(GetPixelGreen(image,(pixel)))\
254 SetPixelGreen(image, ScaleCharToQuantum( \
255 (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))), \
258 #define LBR02PixelBlue(pixel) \
260 unsigned char lbr_bits= \
261 ScaleQuantumToChar(GetPixelBlue(image,(pixel))) & 0xc0; \
262 SetPixelBlue(image, ScaleCharToQuantum( \
263 (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))), \
266 #define LBR02PixelAlpha(pixel) \
268 unsigned char lbr_bits= \
269 ScaleQuantumToChar(GetPixelAlpha(image,(pixel))) & 0xc0; \
270 SetPixelAlpha(image, ScaleCharToQuantum( \
271 (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))), \
275 #define LBR02PixelRGB(pixel) \
277 LBR02PixelRed((pixel)); \
278 LBR02PixelGreen((pixel)); \
279 LBR02PixelBlue((pixel)); \
282 #define LBR02PixelRGBA(pixel) \
284 LBR02PixelRGB((pixel)); \
285 LBR02PixelAlpha((pixel)); \
288 /* LBR03: Replicate top 3 bits (only used with opaque pixels during
289 PNG8 quantization) */
291 #define LBR03PacketRed(pixelpacket) \
293 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).red) & 0xe0; \
294 (pixelpacket).red=ScaleCharToQuantum( \
295 (lbr_bits | (lbr_bits >> 3) | (lbr_bits >> 6))); \
297 #define LBR03PacketGreen(pixelpacket) \
299 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).green) & 0xe0; \
300 (pixelpacket).green=ScaleCharToQuantum( \
301 (lbr_bits | (lbr_bits >> 3) | (lbr_bits >> 6))); \
303 #define LBR03PacketBlue(pixelpacket) \
305 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).blue) & 0xe0; \
306 (pixelpacket).blue=ScaleCharToQuantum( \
307 (lbr_bits | (lbr_bits >> 3) | (lbr_bits >> 6))); \
310 #define LBR03PacketRGB(pixelpacket) \
312 LBR03PacketRed((pixelpacket)); \
313 LBR03PacketGreen((pixelpacket)); \
314 LBR03PacketBlue((pixelpacket)); \
317 #define LBR03PixelRed(pixel) \
319 unsigned char lbr_bits=ScaleQuantumToChar(GetPixelRed(image,(pixel))) \
321 SetPixelRed(image, ScaleCharToQuantum( \
322 (lbr_bits | (lbr_bits >> 3) | (lbr_bits >> 6))), (pixel)); \
324 #define LBR03Green(pixel) \
326 unsigned char lbr_bits=ScaleQuantumToChar(GetPixelGreen(image,(pixel)))\
328 SetPixelGreen(image, ScaleCharToQuantum( \
329 (lbr_bits | (lbr_bits >> 3) | (lbr_bits >> 6))), (pixel)); \
331 #define LBR03Blue(pixel) \
333 unsigned char lbr_bits=ScaleQuantumToChar(GetPixelBlue(image,(pixel))) \
335 SetPixelBlue(image, ScaleCharToQuantum( \
336 (lbr_bits | (lbr_bits >> 3) | (lbr_bits >> 6))), (pixel)); \
339 #define LBR03RGB(pixel) \
341 LBR03PixelRed((pixel)); \
342 LBR03Green((pixel)); \
343 LBR03Blue((pixel)); \
346 /* LBR04: Replicate top 4 bits */
348 #define LBR04PacketRed(pixelpacket) \
350 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).red) & 0xf0; \
351 (pixelpacket).red=ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))); \
353 #define LBR04PacketGreen(pixelpacket) \
355 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).green) & 0xf0; \
356 (pixelpacket).green=ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))); \
358 #define LBR04PacketBlue(pixelpacket) \
360 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).blue) & 0xf0; \
361 (pixelpacket).blue=ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))); \
363 #define LBR04PacketAlpha(pixelpacket) \
365 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).alpha) & 0xf0; \
366 (pixelpacket).alpha=ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))); \
369 #define LBR04PacketRGB(pixelpacket) \
371 LBR04PacketRed((pixelpacket)); \
372 LBR04PacketGreen((pixelpacket)); \
373 LBR04PacketBlue((pixelpacket)); \
376 #define LBR04PacketRGBO(pixelpacket) \
378 LBR04PacketRGB((pixelpacket)); \
379 LBR04PacketAlpha((pixelpacket)); \
382 #define LBR04PixelRed(pixel) \
384 unsigned char lbr_bits=ScaleQuantumToChar(GetPixelRed(image,(pixel))) \
387 ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))), (pixel)); \
389 #define LBR04PixelGreen(pixel) \
391 unsigned char lbr_bits=ScaleQuantumToChar(GetPixelGreen(image,(pixel)))\
393 SetPixelGreen(image,\
394 ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))), (pixel)); \
396 #define LBR04PixelBlue(pixel) \
398 unsigned char lbr_bits= \
399 ScaleQuantumToChar(GetPixelBlue(image,(pixel))) & 0xf0; \
401 ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))), (pixel)); \
403 #define LBR04PixelAlpha(pixel) \
405 unsigned char lbr_bits= \
406 ScaleQuantumToChar(GetPixelAlpha(image,(pixel))) & 0xf0; \
407 SetPixelAlpha(image,\
408 ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))), (pixel)); \
411 #define LBR04PixelRGB(pixel) \
413 LBR04PixelRed((pixel)); \
414 LBR04PixelGreen((pixel)); \
415 LBR04PixelBlue((pixel)); \
418 #define LBR04PixelRGBA(pixel) \
420 LBR04PixelRGB((pixel)); \
421 LBR04PixelAlpha((pixel)); \
425 #if MAGICKCORE_QUANTUM_DEPTH > 8
426 /* LBR08: Replicate top 8 bits */
428 #define LBR08PacketRed(pixelpacket) \
430 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).red); \
431 (pixelpacket).red=ScaleCharToQuantum((lbr_bits)); \
433 #define LBR08PacketGreen(pixelpacket) \
435 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).green); \
436 (pixelpacket).green=ScaleCharToQuantum((lbr_bits)); \
438 #define LBR08PacketBlue(pixelpacket) \
440 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).blue); \
441 (pixelpacket).blue=ScaleCharToQuantum((lbr_bits)); \
443 #define LBR08PacketAlpha(pixelpacket) \
445 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).alpha); \
446 (pixelpacket).alpha=ScaleCharToQuantum((lbr_bits)); \
449 #define LBR08PacketRGB(pixelpacket) \
451 LBR08PacketRed((pixelpacket)); \
452 LBR08PacketGreen((pixelpacket)); \
453 LBR08PacketBlue((pixelpacket)); \
456 #define LBR08PacketRGBO(pixelpacket) \
458 LBR08PacketRGB((pixelpacket)); \
459 LBR08PacketAlpha((pixelpacket)); \
462 #define LBR08PixelRed(pixel) \
464 unsigned char lbr_bits= \
465 ScaleQuantumToChar(GetPixelRed(image,(pixel))); \
467 ScaleCharToQuantum((lbr_bits)), (pixel)); \
469 #define LBR08PixelGreen(pixel) \
471 unsigned char lbr_bits= \
472 ScaleQuantumToChar(GetPixelGreen(image,(pixel))); \
473 SetPixelGreen(image,\
474 ScaleCharToQuantum((lbr_bits)), (pixel)); \
476 #define LBR08PixelBlue(pixel) \
478 unsigned char lbr_bits= \
479 ScaleQuantumToChar(GetPixelBlue(image,(pixel))); \
481 ScaleCharToQuantum((lbr_bits)), (pixel)); \
483 #define LBR08PixelAlpha(pixel) \
485 unsigned char lbr_bits= \
486 ScaleQuantumToChar(GetPixelAlpha(image,(pixel))); \
487 SetPixelAlpha(image,\
488 ScaleCharToQuantum((lbr_bits)), (pixel)); \
491 #define LBR08PixelRGB(pixel) \
493 LBR08PixelRed((pixel)); \
494 LBR08PixelGreen((pixel)); \
495 LBR08PixelBlue((pixel)); \
498 #define LBR08PixelRGBA(pixel) \
500 LBR08PixelRGB((pixel)); \
501 LBR08PixelAlpha((pixel)); \
503 #endif /* MAGICKCORE_QUANTUM_DEPTH > 8 */
506 #if MAGICKCORE_QUANTUM_DEPTH > 16
507 /* LBR16: Replicate top 16 bits */
509 #define LBR16PacketRed(pixelpacket) \
511 unsigned short lbr_bits=ScaleQuantumToShort((pixelpacket).red); \
512 (pixelpacket).red=ScaleShortToQuantum((lbr_bits)); \
514 #define LBR16PacketGreen(pixelpacket) \
516 unsigned short lbr_bits=ScaleQuantumToShort((pixelpacket).green); \
517 (pixelpacket).green=ScaleShortToQuantum((lbr_bits)); \
519 #define LBR16PacketBlue(pixelpacket) \
521 unsigned short lbr_bits=ScaleQuantumToShort((pixelpacket).blue); \
522 (pixelpacket).blue=ScaleShortToQuantum((lbr_bits)); \
524 #define LBR16PacketAlpha(pixelpacket) \
526 unsigned short lbr_bits=ScaleQuantumToShort((pixelpacket).alpha); \
527 (pixelpacket).alpha=ScaleShortToQuantum((lbr_bits)); \
530 #define LBR16PacketRGB(pixelpacket) \
532 LBR16PacketRed((pixelpacket)); \
533 LBR16PacketGreen((pixelpacket)); \
534 LBR16PacketBlue((pixelpacket)); \
537 #define LBR16PacketRGBO(pixelpacket) \
539 LBR16PacketRGB((pixelpacket)); \
540 LBR16PacketAlpha((pixelpacket)); \
543 #define LBR16PixelRed(pixel) \
545 unsigned short lbr_bits= \
546 ScaleQuantumToShort(GetPixelRed(image,(pixel))); \
548 ScaleShortToQuantum((lbr_bits)),(pixel)); \
550 #define LBR16PixelGreen(pixel) \
552 unsigned short lbr_bits= \
553 ScaleQuantumToShort(GetPixelGreen(image,(pixel))); \
554 SetPixelGreen(image,\
555 ScaleShortToQuantum((lbr_bits)),(pixel)); \
557 #define LBR16PixelBlue(pixel) \
559 unsigned short lbr_bits= \
560 ScaleQuantumToShort(GetPixelBlue(image,(pixel))); \
562 ScaleShortToQuantum((lbr_bits)),(pixel)); \
564 #define LBR16PixelAlpha(pixel) \
566 unsigned short lbr_bits= \
567 ScaleQuantumToShort(GetPixelAlpha(image,(pixel))); \
568 SetPixelAlpha(image,\
569 ScaleShortToQuantum((lbr_bits)),(pixel)); \
572 #define LBR16PixelRGB(pixel) \
574 LBR16PixelRed((pixel)); \
575 LBR16PixelGreen((pixel)); \
576 LBR16PixelBlue((pixel)); \
579 #define LBR16PixelRGBA(pixel) \
581 LBR16PixelRGB((pixel)); \
582 LBR16PixelAlpha((pixel)); \
584 #endif /* MAGICKCORE_QUANTUM_DEPTH > 16 */
587 Establish thread safety.
588 setjmp/longjmp is claimed to be safe on these platforms:
589 setjmp/longjmp is alleged to be unsafe on these platforms:
591 #ifndef SETJMP_IS_THREAD_SAFE
592 #define PNG_SETJMP_NOT_THREAD_SAFE
595 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
597 *ping_semaphore = (SemaphoreInfo *) NULL;
601 This temporary until I set up malloc'ed object attributes array.
602 Recompile with MNG_MAX_OBJECTS=65536L to avoid this limit but
605 #define MNG_MAX_OBJECTS 256
608 If this not defined, spec is interpreted strictly. If it is
609 defined, an attempt will be made to recover from some errors,
611 o global PLTE too short
616 Don't try to define PNG_MNG_FEATURES_SUPPORTED here. Make sure
617 it's defined in libpng/pngconf.h, version 1.0.9 or later. It won't work
618 with earlier versions of libpng. From libpng-1.0.3a to libpng-1.0.8,
619 PNG_READ|WRITE_EMPTY_PLTE were used but those have been deprecated in
620 libpng in favor of PNG_MNG_FEATURES_SUPPORTED, so we set them here.
621 PNG_MNG_FEATURES_SUPPORTED is disabled by default in libpng-1.0.9 and
622 will be enabled by default in libpng-1.2.0.
624 #ifdef PNG_MNG_FEATURES_SUPPORTED
625 # ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
626 # define PNG_READ_EMPTY_PLTE_SUPPORTED
628 # ifndef PNG_WRITE_EMPTY_PLTE_SUPPORTED
629 # define PNG_WRITE_EMPTY_PLTE_SUPPORTED
634 Maximum valid size_t in PNG/MNG chunks is (2^31)-1
635 This macro is only defined in libpng-1.0.3 and later.
636 Previously it was PNG_MAX_UINT but that was deprecated in libpng-1.2.6
638 #ifndef PNG_UINT_31_MAX
639 #define PNG_UINT_31_MAX (png_uint_32) 0x7fffffffL
643 Constant strings for known chunk types. If you need to add a chunk,
644 add a string holding the name here. To make the code more
645 portable, we use ASCII numbers like this, not characters.
648 static png_byte mng_MHDR[5]={ 77, 72, 68, 82, (png_byte) '\0'};
649 static png_byte mng_BACK[5]={ 66, 65, 67, 75, (png_byte) '\0'};
650 static png_byte mng_BASI[5]={ 66, 65, 83, 73, (png_byte) '\0'};
651 static png_byte mng_CLIP[5]={ 67, 76, 73, 80, (png_byte) '\0'};
652 static png_byte mng_CLON[5]={ 67, 76, 79, 78, (png_byte) '\0'};
653 static png_byte mng_DEFI[5]={ 68, 69, 70, 73, (png_byte) '\0'};
654 static png_byte mng_DHDR[5]={ 68, 72, 68, 82, (png_byte) '\0'};
655 static png_byte mng_DISC[5]={ 68, 73, 83, 67, (png_byte) '\0'};
656 static png_byte mng_ENDL[5]={ 69, 78, 68, 76, (png_byte) '\0'};
657 static png_byte mng_FRAM[5]={ 70, 82, 65, 77, (png_byte) '\0'};
658 static png_byte mng_IEND[5]={ 73, 69, 78, 68, (png_byte) '\0'};
659 static png_byte mng_IHDR[5]={ 73, 72, 68, 82, (png_byte) '\0'};
660 static png_byte mng_JHDR[5]={ 74, 72, 68, 82, (png_byte) '\0'};
661 static png_byte mng_LOOP[5]={ 76, 79, 79, 80, (png_byte) '\0'};
662 static png_byte mng_MAGN[5]={ 77, 65, 71, 78, (png_byte) '\0'};
663 static png_byte mng_MEND[5]={ 77, 69, 78, 68, (png_byte) '\0'};
664 static png_byte mng_MOVE[5]={ 77, 79, 86, 69, (png_byte) '\0'};
665 static png_byte mng_PAST[5]={ 80, 65, 83, 84, (png_byte) '\0'};
666 static png_byte mng_PLTE[5]={ 80, 76, 84, 69, (png_byte) '\0'};
667 static png_byte mng_SAVE[5]={ 83, 65, 86, 69, (png_byte) '\0'};
668 static png_byte mng_SEEK[5]={ 83, 69, 69, 75, (png_byte) '\0'};
669 static png_byte mng_SHOW[5]={ 83, 72, 79, 87, (png_byte) '\0'};
670 static png_byte mng_TERM[5]={ 84, 69, 82, 77, (png_byte) '\0'};
671 static png_byte mng_bKGD[5]={ 98, 75, 71, 68, (png_byte) '\0'};
672 static png_byte mng_cHRM[5]={ 99, 72, 82, 77, (png_byte) '\0'};
673 static png_byte mng_gAMA[5]={103, 65, 77, 65, (png_byte) '\0'};
674 static png_byte mng_iCCP[5]={105, 67, 67, 80, (png_byte) '\0'};
675 static png_byte mng_nEED[5]={110, 69, 69, 68, (png_byte) '\0'};
676 static png_byte mng_pHYg[5]={112, 72, 89, 103, (png_byte) '\0'};
677 static png_byte mng_vpAg[5]={118, 112, 65, 103, (png_byte) '\0'};
678 static png_byte mng_pHYs[5]={112, 72, 89, 115, (png_byte) '\0'};
679 static png_byte mng_sBIT[5]={115, 66, 73, 84, (png_byte) '\0'};
680 static png_byte mng_sRGB[5]={115, 82, 71, 66, (png_byte) '\0'};
681 static png_byte mng_tRNS[5]={116, 82, 78, 83, (png_byte) '\0'};
683 #if defined(JNG_SUPPORTED)
684 static png_byte mng_IDAT[5]={ 73, 68, 65, 84, (png_byte) '\0'};
685 static png_byte mng_JDAT[5]={ 74, 68, 65, 84, (png_byte) '\0'};
686 static png_byte mng_JDAA[5]={ 74, 68, 65, 65, (png_byte) '\0'};
687 static png_byte mng_JdAA[5]={ 74, 100, 65, 65, (png_byte) '\0'};
688 static png_byte mng_JSEP[5]={ 74, 83, 69, 80, (png_byte) '\0'};
689 static png_byte mng_oFFs[5]={111, 70, 70, 115, (png_byte) '\0'};
693 Other known chunks that are not yet supported by ImageMagick:
694 static png_byte mng_hIST[5]={104, 73, 83, 84, (png_byte) '\0'};
695 static png_byte mng_iCCP[5]={105, 67, 67, 80, (png_byte) '\0'};
696 static png_byte mng_iTXt[5]={105, 84, 88, 116, (png_byte) '\0'};
697 static png_byte mng_sPLT[5]={115, 80, 76, 84, (png_byte) '\0'};
698 static png_byte mng_sTER[5]={115, 84, 69, 82, (png_byte) '\0'};
699 static png_byte mng_tEXt[5]={116, 69, 88, 116, (png_byte) '\0'};
700 static png_byte mng_tIME[5]={116, 73, 77, 69, (png_byte) '\0'};
701 static png_byte mng_zTXt[5]={122, 84, 88, 116, (png_byte) '\0'};
704 typedef struct _MngBox
713 typedef struct _MngPair
720 #ifdef MNG_OBJECT_BUFFERS
721 typedef struct _MngBuffer
753 typedef struct _MngInfo
756 #ifdef MNG_OBJECT_BUFFERS
758 *ob[MNG_MAX_OBJECTS];
769 #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
770 bytes_in_read_buffer,
776 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
777 defined(PNG_MNG_FEATURES_SUPPORTED)
789 have_saved_bkgd_index,
790 have_write_global_chrm,
791 have_write_global_gama,
792 have_write_global_plte,
793 have_write_global_srgb,
807 x_off[MNG_MAX_OBJECTS],
808 y_off[MNG_MAX_OBJECTS];
814 object_clip[MNG_MAX_OBJECTS];
817 /* These flags could be combined into one byte */
818 exists[MNG_MAX_OBJECTS],
819 frozen[MNG_MAX_OBJECTS],
821 invisible[MNG_MAX_OBJECTS],
822 viewable[MNG_MAX_OBJECTS];
834 #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
852 global_x_pixels_per_unit,
853 global_y_pixels_per_unit,
863 global_phys_unit_type,
878 write_png_compression_level,
879 write_png_compression_strategy,
880 write_png_compression_filter,
887 #ifdef MNG_BASI_SUPPORTED
895 basi_compression_method,
897 basi_interlace_method,
920 /* Added at version 6.6.6-7 */
928 /* ping_exclude_iTXt, */
935 ping_exclude_zCCP, /* hex-encoded iCCP */
937 ping_preserve_colormap;
943 Forward declarations.
945 static MagickBooleanType
946 WritePNGImage(const ImageInfo *,Image *,ExceptionInfo *);
948 static MagickBooleanType
949 WriteMNGImage(const ImageInfo *,Image *,ExceptionInfo *);
951 #if defined(JNG_SUPPORTED)
952 static MagickBooleanType
953 WriteJNGImage(const ImageInfo *,Image *,ExceptionInfo *);
956 #if PNG_LIBPNG_VER > 10011
959 #if (MAGICKCORE_QUANTUM_DEPTH >= 16)
960 static MagickBooleanType
961 LosslessReduceDepthOK(Image *image,ExceptionInfo *exception)
963 /* Reduce bit depth if it can be reduced losslessly from 16+ to 8.
965 * This is true if the high byte and the next highest byte of
966 * each sample of the image, the colormap, and the background color
967 * are equal to each other. We check this by seeing if the samples
968 * are unchanged when we scale them down to 8 and back up to Quantum.
970 * We don't use the method GetImageDepth() because it doesn't check
971 * background and doesn't handle PseudoClass specially.
974 #define QuantumToCharToQuantumEqQuantum(quantum) \
975 ((ScaleCharToQuantum((unsigned char) ScaleQuantumToChar(quantum))) == quantum)
978 ok_to_reduce=MagickFalse;
980 if (image->depth >= 16)
987 QuantumToCharToQuantumEqQuantum(image->background_color.red) &&
988 QuantumToCharToQuantumEqQuantum(image->background_color.green) &&
989 QuantumToCharToQuantumEqQuantum(image->background_color.blue) ?
990 MagickTrue : MagickFalse;
992 if (ok_to_reduce != MagickFalse && image->storage_class == PseudoClass)
996 for (indx=0; indx < (ssize_t) image->colors; indx++)
999 QuantumToCharToQuantumEqQuantum(
1000 image->colormap[indx].red) &&
1001 QuantumToCharToQuantumEqQuantum(
1002 image->colormap[indx].green) &&
1003 QuantumToCharToQuantumEqQuantum(
1004 image->colormap[indx].blue)) ?
1005 MagickTrue : MagickFalse;
1007 if (ok_to_reduce == MagickFalse)
1012 if ((ok_to_reduce != MagickFalse) &&
1013 (image->storage_class != PseudoClass))
1021 for (y=0; y < (ssize_t) image->rows; y++)
1023 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1025 if (p == (const Quantum *) NULL)
1027 ok_to_reduce = MagickFalse;
1031 for (x=(ssize_t) image->columns-1; x >= 0; x--)
1034 QuantumToCharToQuantumEqQuantum(GetPixelRed(image,p)) &&
1035 QuantumToCharToQuantumEqQuantum(GetPixelGreen(image,p)) &&
1036 QuantumToCharToQuantumEqQuantum(GetPixelBlue(image,p)) ?
1037 MagickTrue : MagickFalse;
1039 if (ok_to_reduce == MagickFalse)
1042 p+=GetPixelChannels(image);
1049 if (ok_to_reduce != MagickFalse)
1051 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1052 " OK to reduce PNG bit depth to 8 without loss of info");
1056 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1057 " Not OK to reduce PNG bit depth to 8 without loss of info");
1061 return ok_to_reduce;
1063 #endif /* MAGICKCORE_QUANTUM_DEPTH >= 16 */
1065 static const char* PngColorTypeToString(const unsigned int color_type)
1068 *result = "Unknown";
1072 case PNG_COLOR_TYPE_GRAY:
1075 case PNG_COLOR_TYPE_GRAY_ALPHA:
1076 result = "Gray+Alpha";
1078 case PNG_COLOR_TYPE_PALETTE:
1081 case PNG_COLOR_TYPE_RGB:
1084 case PNG_COLOR_TYPE_RGB_ALPHA:
1085 result = "RGB+Alpha";
1093 Magick_RenderingIntent_to_PNG_RenderingIntent(const RenderingIntent intent)
1097 case PerceptualIntent:
1100 case RelativeIntent:
1103 case SaturationIntent:
1106 case AbsoluteIntent:
1114 static RenderingIntent
1115 Magick_RenderingIntent_from_PNG_RenderingIntent(const int ping_intent)
1117 switch (ping_intent)
1120 return PerceptualIntent;
1123 return RelativeIntent;
1126 return SaturationIntent;
1129 return AbsoluteIntent;
1132 return UndefinedIntent;
1137 Magick_RenderingIntentString_from_PNG_RenderingIntent(const int ping_intent)
1139 switch (ping_intent)
1142 return "Perceptual Intent";
1145 return "Relative Intent";
1148 return "Saturation Intent";
1151 return "Absolute Intent";
1154 return "Undefined Intent";
1158 static inline ssize_t MagickMax(const ssize_t x,const ssize_t y)
1167 Magick_ColorType_from_PNG_ColorType(const int ping_colortype)
1169 switch (ping_colortype)
1187 return "UndefinedColorType";
1192 static inline ssize_t MagickMin(const ssize_t x,const ssize_t y)
1199 #endif /* PNG_LIBPNG_VER > 10011 */
1200 #endif /* MAGICKCORE_PNG_DELEGATE */
1203 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1211 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1213 % IsMNG() returns MagickTrue if the image format type, identified by the
1214 % magick string, is MNG.
1216 % The format of the IsMNG method is:
1218 % MagickBooleanType IsMNG(const unsigned char *magick,const size_t length)
1220 % A description of each parameter follows:
1222 % o magick: compare image format pattern against these bytes.
1224 % o length: Specifies the length of the magick string.
1228 static MagickBooleanType IsMNG(const unsigned char *magick,const size_t length)
1231 return(MagickFalse);
1233 if (memcmp(magick,"\212MNG\r\n\032\n",8) == 0)
1236 return(MagickFalse);
1240 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1248 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1250 % IsJNG() returns MagickTrue if the image format type, identified by the
1251 % magick string, is JNG.
1253 % The format of the IsJNG method is:
1255 % MagickBooleanType IsJNG(const unsigned char *magick,const size_t length)
1257 % A description of each parameter follows:
1259 % o magick: compare image format pattern against these bytes.
1261 % o length: Specifies the length of the magick string.
1265 static MagickBooleanType IsJNG(const unsigned char *magick,const size_t length)
1268 return(MagickFalse);
1270 if (memcmp(magick,"\213JNG\r\n\032\n",8) == 0)
1273 return(MagickFalse);
1277 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1285 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1287 % IsPNG() returns MagickTrue if the image format type, identified by the
1288 % magick string, is PNG.
1290 % The format of the IsPNG method is:
1292 % MagickBooleanType IsPNG(const unsigned char *magick,const size_t length)
1294 % A description of each parameter follows:
1296 % o magick: compare image format pattern against these bytes.
1298 % o length: Specifies the length of the magick string.
1301 static MagickBooleanType IsPNG(const unsigned char *magick,const size_t length)
1304 return(MagickFalse);
1306 if (memcmp(magick,"\211PNG\r\n\032\n",8) == 0)
1309 return(MagickFalse);
1312 #if defined(MAGICKCORE_PNG_DELEGATE)
1313 #if defined(__cplusplus) || defined(c_plusplus)
1317 #if (PNG_LIBPNG_VER > 10011)
1318 static size_t WriteBlobMSBULong(Image *image,const size_t value)
1323 assert(image != (Image *) NULL);
1324 assert(image->signature == MagickSignature);
1325 buffer[0]=(unsigned char) (value >> 24);
1326 buffer[1]=(unsigned char) (value >> 16);
1327 buffer[2]=(unsigned char) (value >> 8);
1328 buffer[3]=(unsigned char) value;
1329 return((size_t) WriteBlob(image,4,buffer));
1332 static void PNGLong(png_bytep p,png_uint_32 value)
1334 *p++=(png_byte) ((value >> 24) & 0xff);
1335 *p++=(png_byte) ((value >> 16) & 0xff);
1336 *p++=(png_byte) ((value >> 8) & 0xff);
1337 *p++=(png_byte) (value & 0xff);
1340 #if defined(JNG_SUPPORTED)
1341 static void PNGsLong(png_bytep p,png_int_32 value)
1343 *p++=(png_byte) ((value >> 24) & 0xff);
1344 *p++=(png_byte) ((value >> 16) & 0xff);
1345 *p++=(png_byte) ((value >> 8) & 0xff);
1346 *p++=(png_byte) (value & 0xff);
1350 static void PNGShort(png_bytep p,png_uint_16 value)
1352 *p++=(png_byte) ((value >> 8) & 0xff);
1353 *p++=(png_byte) (value & 0xff);
1356 static void PNGType(png_bytep p,png_bytep type)
1358 (void) CopyMagickMemory(p,type,4*sizeof(png_byte));
1361 static void LogPNGChunk(MagickBooleanType logging, png_bytep type,
1364 if (logging != MagickFalse)
1365 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1366 " Writing %c%c%c%c chunk, length: %.20g",
1367 type[0],type[1],type[2],type[3],(double) length);
1369 #endif /* PNG_LIBPNG_VER > 10011 */
1371 #if defined(__cplusplus) || defined(c_plusplus)
1375 #if PNG_LIBPNG_VER > 10011
1377 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1381 % R e a d P N G I m a g e %
1385 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1387 % ReadPNGImage() reads a Portable Network Graphics (PNG) or
1388 % Multiple-image Network Graphics (MNG) image file and returns it. It
1389 % allocates the memory necessary for the new Image structure and returns a
1390 % pointer to the new image or set of images.
1392 % MNG support written by Glenn Randers-Pehrson, glennrp@image...
1394 % The format of the ReadPNGImage method is:
1396 % Image *ReadPNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
1398 % A description of each parameter follows:
1400 % o image_info: the image info.
1402 % o exception: return any errors or warnings in this structure.
1404 % To do, more or less in chronological order (as of version 5.5.2,
1405 % November 26, 2002 -- glennrp -- see also "To do" under WriteMNGImage):
1407 % Get 16-bit cheap transparency working.
1409 % (At this point, PNG decoding is supposed to be in full MNG-LC compliance)
1411 % Preserve all unknown and not-yet-handled known chunks found in input
1412 % PNG file and copy them into output PNG files according to the PNG
1415 % (At this point, PNG encoding should be in full MNG compliance)
1417 % Provide options for choice of background to use when the MNG BACK
1418 % chunk is not present or is not mandatory (i.e., leave transparent,
1419 % user specified, MNG BACK, PNG bKGD)
1421 % Implement LOOP/ENDL [done, but could do discretionary loops more
1422 % efficiently by linking in the duplicate frames.].
1424 % Decode and act on the MHDR simplicity profile (offer option to reject
1425 % files or attempt to process them anyway when the profile isn't LC or VLC).
1427 % Upgrade to full MNG without Delta-PNG.
1429 % o BACK [done a while ago except for background image ID]
1430 % o MOVE [done 15 May 1999]
1431 % o CLIP [done 15 May 1999]
1432 % o DISC [done 19 May 1999]
1433 % o SAVE [partially done 19 May 1999 (marks objects frozen)]
1434 % o SEEK [partially done 19 May 1999 (discard function only)]
1438 % o MNG-level tEXt/iTXt/zTXt
1443 % o iTXt (wait for libpng implementation).
1445 % Use the scene signature to discover when an identical scene is
1446 % being reused, and just point to the original image->exception instead
1447 % of storing another set of pixels. This not specific to MNG
1448 % but could be applied generally.
1450 % Upgrade to full MNG with Delta-PNG.
1452 % JNG tEXt/iTXt/zTXt
1454 % We will not attempt to read files containing the CgBI chunk.
1455 % They are really Xcode files meant for display on the iPhone.
1456 % These are not valid PNG files and it is impossible to recover
1457 % the original PNG from files that have been converted to Xcode-PNG,
1458 % since irretrievable loss of color data has occurred due to the
1459 % use of premultiplied alpha.
1462 #if defined(__cplusplus) || defined(c_plusplus)
1467 This the function that does the actual reading of data. It is
1468 the same as the one supplied in libpng, except that it receives the
1469 datastream from the ReadBlob() function instead of standard input.
1471 static void png_get_data(png_structp png_ptr,png_bytep data,png_size_t length)
1476 image=(Image *) png_get_io_ptr(png_ptr);
1482 check=(png_size_t) ReadBlob(image,(size_t) length,data);
1483 if (check != length)
1488 (void) FormatLocaleString(msg,MaxTextExtent,
1489 "Expected %.20g bytes; found %.20g bytes",(double) length,
1491 png_warning(png_ptr,msg);
1492 png_error(png_ptr,"Read Exception");
1497 #if !defined(PNG_READ_EMPTY_PLTE_SUPPORTED) && \
1498 !defined(PNG_MNG_FEATURES_SUPPORTED)
1499 /* We use mng_get_data() instead of png_get_data() if we have a libpng
1500 * older than libpng-1.0.3a, which was the first to allow the empty
1501 * PLTE, or a newer libpng in which PNG_MNG_FEATURES_SUPPORTED was
1502 * ifdef'ed out. Earlier versions would crash if the bKGD chunk was
1503 * encountered after an empty PLTE, so we have to look ahead for bKGD
1504 * chunks and remove them from the datastream that is passed to libpng,
1505 * and store their contents for later use.
1507 static void mng_get_data(png_structp png_ptr,png_bytep data,png_size_t length)
1522 mng_info=(MngInfo *) png_get_io_ptr(png_ptr);
1523 image=(Image *) mng_info->image;
1524 while (mng_info->bytes_in_read_buffer && length)
1526 data[i]=mng_info->read_buffer[i];
1527 mng_info->bytes_in_read_buffer--;
1533 check=(png_size_t) ReadBlob(image,(size_t) length,(char *) data);
1535 if (check != length)
1536 png_error(png_ptr,"Read Exception");
1540 if ((data[0] == 0) && (data[1] == 0) && (data[2] == 0) &&
1543 check=(png_size_t) ReadBlob(image,(size_t) length,
1544 (char *) mng_info->read_buffer);
1545 mng_info->read_buffer[4]=0;
1546 mng_info->bytes_in_read_buffer=4;
1547 if (memcmp(mng_info->read_buffer,mng_PLTE,4) == 0)
1548 mng_info->found_empty_plte=MagickTrue;
1549 if (memcmp(mng_info->read_buffer,mng_IEND,4) == 0)
1551 mng_info->found_empty_plte=MagickFalse;
1552 mng_info->have_saved_bkgd_index=MagickFalse;
1556 if ((data[0] == 0) && (data[1] == 0) && (data[2] == 0) &&
1559 check=(png_size_t) ReadBlob(image,(size_t) length,
1560 (char *) mng_info->read_buffer);
1561 mng_info->read_buffer[4]=0;
1562 mng_info->bytes_in_read_buffer=4;
1563 if (memcmp(mng_info->read_buffer,mng_bKGD,4) == 0)
1564 if (mng_info->found_empty_plte)
1567 Skip the bKGD data byte and CRC.
1570 ReadBlob(image,5,(char *) mng_info->read_buffer);
1571 check=(png_size_t) ReadBlob(image,(size_t) length,
1572 (char *) mng_info->read_buffer);
1573 mng_info->saved_bkgd_index=mng_info->read_buffer[0];
1574 mng_info->have_saved_bkgd_index=MagickTrue;
1575 mng_info->bytes_in_read_buffer=0;
1583 static void png_put_data(png_structp png_ptr,png_bytep data,png_size_t length)
1588 image=(Image *) png_get_io_ptr(png_ptr);
1594 check=(png_size_t) WriteBlob(image,(size_t) length,data);
1596 if (check != length)
1597 png_error(png_ptr,"WriteBlob Failed");
1601 static void png_flush_data(png_structp png_ptr)
1606 #ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
1607 static int PalettesAreEqual(Image *a,Image *b)
1612 if ((a == (Image *) NULL) || (b == (Image *) NULL))
1613 return((int) MagickFalse);
1615 if (a->storage_class != PseudoClass || b->storage_class != PseudoClass)
1616 return((int) MagickFalse);
1618 if (a->colors != b->colors)
1619 return((int) MagickFalse);
1621 for (i=0; i < (ssize_t) a->colors; i++)
1623 if ((a->colormap[i].red != b->colormap[i].red) ||
1624 (a->colormap[i].green != b->colormap[i].green) ||
1625 (a->colormap[i].blue != b->colormap[i].blue))
1626 return((int) MagickFalse);
1629 return((int) MagickTrue);
1633 static void MngInfoDiscardObject(MngInfo *mng_info,int i)
1635 if (i && (i < MNG_MAX_OBJECTS) && (mng_info != (MngInfo *) NULL) &&
1636 mng_info->exists[i] && !mng_info->frozen[i])
1638 #ifdef MNG_OBJECT_BUFFERS
1639 if (mng_info->ob[i] != (MngBuffer *) NULL)
1641 if (mng_info->ob[i]->reference_count > 0)
1642 mng_info->ob[i]->reference_count--;
1644 if (mng_info->ob[i]->reference_count == 0)
1646 if (mng_info->ob[i]->image != (Image *) NULL)
1647 mng_info->ob[i]->image=DestroyImage(mng_info->ob[i]->image);
1649 mng_info->ob[i]=DestroyString(mng_info->ob[i]);
1652 mng_info->ob[i]=(MngBuffer *) NULL;
1654 mng_info->exists[i]=MagickFalse;
1655 mng_info->invisible[i]=MagickFalse;
1656 mng_info->viewable[i]=MagickFalse;
1657 mng_info->frozen[i]=MagickFalse;
1658 mng_info->x_off[i]=0;
1659 mng_info->y_off[i]=0;
1660 mng_info->object_clip[i].left=0;
1661 mng_info->object_clip[i].right=(ssize_t) PNG_UINT_31_MAX;
1662 mng_info->object_clip[i].top=0;
1663 mng_info->object_clip[i].bottom=(ssize_t) PNG_UINT_31_MAX;
1667 static void MngInfoFreeStruct(MngInfo *mng_info,
1668 MagickBooleanType *have_mng_structure)
1670 if (*have_mng_structure != MagickFalse && (mng_info != (MngInfo *) NULL))
1675 for (i=1; i < MNG_MAX_OBJECTS; i++)
1676 MngInfoDiscardObject(mng_info,i);
1678 if (mng_info->global_plte != (png_colorp) NULL)
1679 mng_info->global_plte=(png_colorp)
1680 RelinquishMagickMemory(mng_info->global_plte);
1682 mng_info=(MngInfo *) RelinquishMagickMemory(mng_info);
1683 *have_mng_structure=MagickFalse;
1687 static MngBox mng_minimum_box(MngBox box1,MngBox box2)
1693 if (box.left < box2.left)
1696 if (box.top < box2.top)
1699 if (box.right > box2.right)
1700 box.right=box2.right;
1702 if (box.bottom > box2.bottom)
1703 box.bottom=box2.bottom;
1708 static MngBox mng_read_box(MngBox previous_box,char delta_type,unsigned char *p)
1714 Read clipping boundaries from DEFI, CLIP, FRAM, or PAST chunk.
1716 box.left=(ssize_t) ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]);
1717 box.right=(ssize_t) ((p[4] << 24) | (p[5] << 16) | (p[6] << 8) | p[7]);
1718 box.top=(ssize_t) ((p[8] << 24) | (p[9] << 16) | (p[10] << 8) | p[11]);
1719 box.bottom=(ssize_t) ((p[12] << 24) | (p[13] << 16) | (p[14] << 8) | p[15]);
1720 if (delta_type != 0)
1722 box.left+=previous_box.left;
1723 box.right+=previous_box.right;
1724 box.top+=previous_box.top;
1725 box.bottom+=previous_box.bottom;
1731 static MngPair mng_read_pair(MngPair previous_pair,int delta_type,
1737 Read two ssize_ts from CLON, MOVE or PAST chunk
1739 pair.a=(long) ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]);
1740 pair.b=(long) ((p[4] << 24) | (p[5] << 16) | (p[6] << 8) | p[7]);
1742 if (delta_type != 0)
1744 pair.a+=previous_pair.a;
1745 pair.b+=previous_pair.b;
1751 static long mng_get_long(unsigned char *p)
1753 return((long) ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]));
1756 typedef struct _PNGErrorInfo
1765 static void MagickPNGErrorHandler(png_struct *ping,png_const_charp message)
1776 error_info=(PNGErrorInfo *) png_get_error_ptr(ping);
1777 image=error_info->image;
1778 exception=error_info->exception;
1780 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1781 " libpng-%s error: %s", PNG_LIBPNG_VER_STRING,message);
1783 (void) ThrowMagickException(exception,GetMagickModule(),CoderError,message,
1784 "`%s'",image->filename);
1786 #if (PNG_LIBPNG_VER < 10500)
1787 /* A warning about deprecated use of jmpbuf here is unavoidable if you
1788 * are building with libpng-1.4.x and can be ignored.
1790 longjmp(ping->jmpbuf,1);
1792 png_longjmp(ping,1);
1796 static void MagickPNGWarningHandler(png_struct *ping,png_const_charp message)
1807 if (LocaleCompare(message, "Missing PLTE before tRNS") == 0)
1808 png_error(ping, message);
1810 error_info=(PNGErrorInfo *) png_get_error_ptr(ping);
1811 image=error_info->image;
1812 exception=error_info->exception;
1813 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1814 " libpng-%s warning: %s", PNG_LIBPNG_VER_STRING,message);
1816 (void) ThrowMagickException(exception,GetMagickModule(),CoderWarning,
1817 message,"`%s'",image->filename);
1820 #ifdef PNG_USER_MEM_SUPPORTED
1821 #if PNG_LIBPNG_VER >= 14000
1822 static png_voidp Magick_png_malloc(png_structp png_ptr,png_alloc_size_t size)
1824 static png_voidp Magick_png_malloc(png_structp png_ptr,png_size_t size)
1828 return((png_voidp) AcquireMagickMemory((size_t) size));
1832 Free a pointer. It is removed from the list at the same time.
1834 static png_free_ptr Magick_png_free(png_structp png_ptr,png_voidp ptr)
1837 ptr=RelinquishMagickMemory(ptr);
1838 return((png_free_ptr) NULL);
1842 #if defined(__cplusplus) || defined(c_plusplus)
1847 Magick_png_read_raw_profile(png_struct *ping,Image *image,
1848 const ImageInfo *image_info, png_textp text,int ii,ExceptionInfo *exception)
1853 register unsigned char
1867 unhex[103]={0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,
1868 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,
1869 0,0,0,0,0,0,0,0,0,1, 2,3,4,5,6,7,8,9,0,0,
1870 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,
1871 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,10,11,12,
1875 /* look for newline */
1879 /* look for length */
1880 while (*sp == '\0' || *sp == ' ' || *sp == '\n')
1883 length=(png_uint_32) StringToLong(sp);
1885 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1886 " length: %lu",(unsigned long) length);
1888 while (*sp != ' ' && *sp != '\n')
1891 /* allocate space */
1894 png_warning(ping,"invalid profile length");
1895 return(MagickFalse);
1898 profile=BlobToStringInfo((const void *) NULL,length);
1900 if (profile == (StringInfo *) NULL)
1902 png_warning(ping, "unable to copy profile");
1903 return(MagickFalse);
1906 /* copy profile, skipping white space and column 1 "=" signs */
1907 dp=GetStringInfoDatum(profile);
1910 for (i=0; i < (ssize_t) nibbles; i++)
1912 while (*sp < '0' || (*sp > '9' && *sp < 'a') || *sp > 'f')
1916 png_warning(ping, "ran out of profile data");
1917 profile=DestroyStringInfo(profile);
1918 return(MagickFalse);
1924 *dp=(unsigned char) (16*unhex[(int) *sp++]);
1927 (*dp++)+=unhex[(int) *sp++];
1930 We have already read "Raw profile type.
1932 (void) SetImageProfile(image,&text[ii].key[17],profile,exception);
1933 profile=DestroyStringInfo(profile);
1935 if (image_info->verbose)
1936 (void) printf(" Found a generic profile, type %s\n",&text[ii].key[17]);
1941 #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
1942 static int read_vpag_chunk_callback(png_struct *ping, png_unknown_chunkp chunk)
1948 /* The unknown chunk structure contains the chunk data:
1953 Note that libpng has already taken care of the CRC handling.
1957 if (chunk->name[0] != 118 || chunk->name[1] != 112 ||
1958 chunk->name[2] != 65 ||chunk-> name[3] != 103)
1959 return(0); /* Did not recognize */
1961 /* recognized vpAg */
1963 if (chunk->size != 9)
1964 return(-1); /* Error return */
1966 if (chunk->data[8] != 0)
1967 return(0); /* ImageMagick requires pixel units */
1969 image=(Image *) png_get_user_chunk_ptr(ping);
1971 image->page.width=(size_t) ((chunk->data[0] << 24) |
1972 (chunk->data[1] << 16) | (chunk->data[2] << 8) | chunk->data[3]);
1974 image->page.height=(size_t) ((chunk->data[4] << 24) |
1975 (chunk->data[5] << 16) | (chunk->data[6] << 8) | chunk->data[7]);
1977 /* Return one of the following: */
1978 /* return(-n); chunk had an error */
1979 /* return(0); did not recognize */
1980 /* return(n); success */
1988 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1992 % R e a d O n e P N G I m a g e %
1996 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1998 % ReadOnePNGImage() reads a Portable Network Graphics (PNG) image file
1999 % (minus the 8-byte signature) and returns it. It allocates the memory
2000 % necessary for the new Image structure and returns a pointer to the new
2003 % The format of the ReadOnePNGImage method is:
2005 % Image *ReadOnePNGImage(MngInfo *mng_info, const ImageInfo *image_info,
2006 % ExceptionInfo *exception)
2008 % A description of each parameter follows:
2010 % o mng_info: Specifies a pointer to a MngInfo structure.
2012 % o image_info: the image info.
2014 % o exception: return any errors or warnings in this structure.
2017 static Image *ReadOnePNGImage(MngInfo *mng_info,
2018 const ImageInfo *image_info, ExceptionInfo *exception)
2020 /* Read one PNG image */
2022 /* To do: Read the tIME chunk into the date:modify property */
2023 /* To do: Read the tEXt/Creation Time chunk into the date:create property */
2029 intent, /* "PNG Rendering intent", which is ICC intent + 1 */
2039 ping_interlace_method,
2040 ping_compression_method,
2054 ping_found_sRGB_cHRM,
2093 register unsigned char
2111 *volatile ping_pixels;
2113 #ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED
2114 png_byte unused_chunks[]=
2116 104, 73, 83, 84, (png_byte) '\0', /* hIST */
2117 105, 84, 88, 116, (png_byte) '\0', /* iTXt */
2118 112, 67, 65, 76, (png_byte) '\0', /* pCAL */
2119 115, 67, 65, 76, (png_byte) '\0', /* sCAL */
2120 115, 80, 76, 84, (png_byte) '\0', /* sPLT */
2121 116, 73, 77, 69, (png_byte) '\0', /* tIME */
2122 #ifdef PNG_APNG_SUPPORTED /* libpng was built with APNG patch; */
2123 /* ignore the APNG chunks */
2124 97, 99, 84, 76, (png_byte) '\0', /* acTL */
2125 102, 99, 84, 76, (png_byte) '\0', /* fcTL */
2126 102, 100, 65, 84, (png_byte) '\0', /* fdAT */
2131 logging=LogMagickEvent(CoderEvent,GetMagickModule(),
2132 " Enter ReadOnePNGImage()");
2134 #if (PNG_LIBPNG_VER < 10200)
2135 if (image_info->verbose)
2136 printf("Your PNG library (libpng-%s) is rather old.\n",
2137 PNG_LIBPNG_VER_STRING);
2140 #if (PNG_LIBPNG_VER >= 10400)
2141 # ifndef PNG_TRANSFORM_GRAY_TO_RGB /* Added at libpng-1.4.0beta67 */
2142 if (image_info->verbose)
2144 printf("Your PNG library (libpng-%s) is an old beta version.\n",
2145 PNG_LIBPNG_VER_STRING);
2146 printf("Please update it.\n");
2152 quantum_info = (QuantumInfo *) NULL;
2153 image=mng_info->image;
2155 if (logging != MagickFalse)
2157 (void)LogMagickEvent(CoderEvent,GetMagickModule(),
2158 " Before reading:");
2160 (void)LogMagickEvent(CoderEvent,GetMagickModule(),
2161 " image->alpha_trait=%d",(int) image->alpha_trait);
2163 (void)LogMagickEvent(CoderEvent,GetMagickModule(),
2164 " image->rendering_intent=%d",(int) image->rendering_intent);
2166 (void)LogMagickEvent(CoderEvent,GetMagickModule(),
2167 " image->colorspace=%d",(int) image->colorspace);
2169 (void)LogMagickEvent(CoderEvent,GetMagickModule(),
2170 " image->gamma=%f", image->gamma);
2172 intent=Magick_RenderingIntent_to_PNG_RenderingIntent(image->rendering_intent);
2174 /* Set to an out-of-range color unless tRNS chunk is present */
2175 transparent_color.red=65537;
2176 transparent_color.green=65537;
2177 transparent_color.blue=65537;
2178 transparent_color.alpha=65537;
2183 num_raw_profiles = 0;
2185 ping_found_cHRM = MagickFalse;
2186 ping_found_gAMA = MagickFalse;
2187 ping_found_iCCP = MagickFalse;
2188 ping_found_sRGB = MagickFalse;
2191 Allocate the PNG structures
2193 #ifdef PNG_USER_MEM_SUPPORTED
2194 error_info.image=image;
2195 error_info.exception=exception;
2196 ping=png_create_read_struct_2(PNG_LIBPNG_VER_STRING,&error_info,
2197 MagickPNGErrorHandler,MagickPNGWarningHandler, NULL,
2198 (png_malloc_ptr) Magick_png_malloc,(png_free_ptr) Magick_png_free);
2200 ping=png_create_read_struct(PNG_LIBPNG_VER_STRING,&error_info,
2201 MagickPNGErrorHandler,MagickPNGWarningHandler);
2203 if (ping == (png_struct *) NULL)
2204 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2206 ping_info=png_create_info_struct(ping);
2208 if (ping_info == (png_info *) NULL)
2210 png_destroy_read_struct(&ping,(png_info **) NULL,(png_info **) NULL);
2211 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2214 end_info=png_create_info_struct(ping);
2216 if (end_info == (png_info *) NULL)
2218 png_destroy_read_struct(&ping,&ping_info,(png_info **) NULL);
2219 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2222 ping_pixels=(unsigned char *) NULL;
2224 if (setjmp(png_jmpbuf(ping)))
2227 PNG image is corrupt.
2229 png_destroy_read_struct(&ping,&ping_info,&end_info);
2231 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
2232 UnlockSemaphoreInfo(ping_semaphore);
2235 if (ping_pixels != (unsigned char *) NULL)
2236 ping_pixels=(unsigned char *) RelinquishMagickMemory(ping_pixels);
2238 if (logging != MagickFalse)
2239 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2240 " exit ReadOnePNGImage() with error.");
2242 if (image != (Image *) NULL)
2244 InheritException(exception,exception);
2248 return(GetFirstImageInList(image));
2251 /* { For navigation to end of SETJMP-protected block. Within this
2252 * block, use png_error() instead of Throwing an Exception, to ensure
2253 * that libpng is able to clean up, and that the semaphore is unlocked.
2256 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
2257 LockSemaphoreInfo(ping_semaphore);
2261 Prepare PNG for reading.
2264 mng_info->image_found++;
2265 png_set_sig_bytes(ping,8);
2267 if (LocaleCompare(image_info->magick,"MNG") == 0)
2269 #if defined(PNG_MNG_FEATURES_SUPPORTED)
2270 (void) png_permit_mng_features(ping,PNG_ALL_MNG_FEATURES);
2271 png_set_read_fn(ping,image,png_get_data);
2273 #if defined(PNG_READ_EMPTY_PLTE_SUPPORTED)
2274 png_permit_empty_plte(ping,MagickTrue);
2275 png_set_read_fn(ping,image,png_get_data);
2277 mng_info->image=image;
2278 mng_info->bytes_in_read_buffer=0;
2279 mng_info->found_empty_plte=MagickFalse;
2280 mng_info->have_saved_bkgd_index=MagickFalse;
2281 png_set_read_fn(ping,mng_info,mng_get_data);
2287 png_set_read_fn(ping,image,png_get_data);
2289 #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
2290 /* Ignore unused chunks and all unknown chunks except for vpAg */
2291 png_set_keep_unknown_chunks(ping, 1, NULL, 0);
2292 png_set_keep_unknown_chunks(ping, 2, mng_vpAg, 1);
2293 png_set_keep_unknown_chunks(ping, 1, unused_chunks,
2294 (int)sizeof(unused_chunks)/5);
2295 /* Callback for other unknown chunks */
2296 png_set_read_user_chunk_fn(ping, image, read_vpag_chunk_callback);
2299 #ifdef PNG_SET_USER_LIMITS_SUPPORTED
2300 # if (PNG_LIBPNG_VER >= 10400)
2301 /* Limit the size of the chunk storage cache used for sPLT, text,
2302 * and unknown chunks.
2304 png_set_chunk_cache_max(ping, 32767);
2308 #ifdef PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED
2309 /* Disable new libpng-1.5.10 feature */
2310 png_set_check_for_invalid_index (ping, 0);
2313 #if (PNG_LIBPNG_VER < 10400)
2314 # if defined(PNG_USE_PNGGCCRD) && defined(PNG_ASSEMBLER_CODE_SUPPORTED) && \
2315 (PNG_LIBPNG_VER >= 10200) && (PNG_LIBPNG_VER < 10220) && defined(__i386__)
2316 /* Disable thread-unsafe features of pnggccrd */
2317 if (png_access_version_number() >= 10200)
2319 png_uint_32 mmx_disable_mask=0;
2320 png_uint_32 asm_flags;
2322 mmx_disable_mask |= ( PNG_ASM_FLAG_MMX_READ_COMBINE_ROW \
2323 | PNG_ASM_FLAG_MMX_READ_FILTER_SUB \
2324 | PNG_ASM_FLAG_MMX_READ_FILTER_AVG \
2325 | PNG_ASM_FLAG_MMX_READ_FILTER_PAETH );
2326 asm_flags=png_get_asm_flags(ping);
2327 png_set_asm_flags(ping, asm_flags & ~mmx_disable_mask);
2332 png_read_info(ping,ping_info);
2334 png_get_IHDR(ping,ping_info,&ping_width,&ping_height,
2335 &ping_bit_depth,&ping_color_type,
2336 &ping_interlace_method,&ping_compression_method,
2337 &ping_filter_method);
2339 ping_file_depth = ping_bit_depth;
2341 /* Save bit-depth and color-type in case we later want to write a PNG00 */
2346 (void) FormatLocaleString(msg,MaxTextExtent,"%d",(int) ping_color_type);
2347 (void) SetImageProperty(image,"png:IHDR.color-type-orig ",msg,exception);
2349 (void) FormatLocaleString(msg,MaxTextExtent,"%d",(int) ping_bit_depth);
2350 (void) SetImageProperty(image,"png:IHDR.bit-depth-orig ",msg,exception);
2353 (void) png_get_tRNS(ping, ping_info, &ping_trans_alpha, &ping_num_trans,
2356 (void) png_get_bKGD(ping, ping_info, &ping_background);
2358 if (ping_bit_depth < 8)
2360 png_set_packing(ping);
2364 image->depth=ping_bit_depth;
2365 image->depth=GetImageQuantumDepth(image,MagickFalse);
2366 image->interlace=ping_interlace_method != 0 ? PNGInterlace : NoInterlace;
2368 if (((int) ping_color_type == PNG_COLOR_TYPE_GRAY) ||
2369 ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA))
2371 image->rendering_intent=UndefinedIntent;
2372 intent=Magick_RenderingIntent_to_PNG_RenderingIntent(UndefinedIntent);
2374 (void) ResetMagickMemory(&image->chromaticity,0,
2375 sizeof(image->chromaticity));
2378 if (logging != MagickFalse)
2380 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2381 " PNG width: %.20g, height: %.20g",
2382 (double) ping_width, (double) ping_height);
2384 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2385 " PNG color_type: %d, bit_depth: %d",
2386 ping_color_type, ping_bit_depth);
2388 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2389 " PNG compression_method: %d",
2390 ping_compression_method);
2392 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2393 " PNG interlace_method: %d, filter_method: %d",
2394 ping_interlace_method,ping_filter_method);
2397 if (png_get_valid(ping,ping_info,PNG_INFO_gAMA))
2399 ping_found_gAMA=MagickTrue;
2400 if (logging != MagickFalse)
2401 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2402 " Found PNG gAMA chunk.");
2405 if (png_get_valid(ping,ping_info,PNG_INFO_cHRM))
2407 ping_found_cHRM=MagickTrue;
2408 if (logging != MagickFalse)
2409 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2410 " Found PNG cHRM chunk.");
2413 if (png_get_valid(ping,ping_info,PNG_INFO_iCCP))
2415 ping_found_iCCP=MagickTrue;
2416 if (logging != MagickFalse)
2417 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2418 " Found PNG iCCP chunk.");
2421 if (png_get_valid(ping,ping_info,PNG_INFO_sRGB))
2423 ping_found_sRGB=MagickTrue;
2424 if (logging != MagickFalse)
2425 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2426 " Found PNG sRGB chunk.");
2429 #ifdef PNG_READ_iCCP_SUPPORTED
2430 if (png_get_valid(ping,ping_info,PNG_INFO_iCCP))
2435 #if (PNG_LIBPNG_VER < 10500)
2449 (void) png_get_iCCP(ping,ping_info,&name,(int *) &compression,&info,
2452 if (profile_length != 0)
2457 if (logging != MagickFalse)
2458 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2459 " Reading PNG iCCP chunk.");
2460 profile=BlobToStringInfo(info,profile_length);
2461 if (profile == (StringInfo *) NULL)
2463 png_warning(ping, "ICC profile is NULL");
2464 profile=DestroyStringInfo(profile);
2468 (void) SetImageProfile(image,"icc",profile,exception);
2469 profile=DestroyStringInfo(profile);
2474 #if defined(PNG_READ_sRGB_SUPPORTED)
2476 if (mng_info->have_global_srgb)
2478 image->rendering_intent=Magick_RenderingIntent_from_PNG_RenderingIntent
2479 (mng_info->global_srgb_intent);
2482 if (png_get_sRGB(ping,ping_info,&intent))
2484 image->rendering_intent=Magick_RenderingIntent_from_PNG_RenderingIntent
2487 if (logging != MagickFalse)
2488 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2489 " Reading PNG sRGB chunk: rendering_intent: %d",intent);
2494 if (!png_get_gAMA(ping,ping_info,&file_gamma))
2495 if (mng_info->have_global_gama)
2496 png_set_gAMA(ping,ping_info,mng_info->global_gamma);
2498 if (png_get_gAMA(ping,ping_info,&file_gamma))
2500 image->gamma=(float) file_gamma;
2501 if (logging != MagickFalse)
2502 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2503 " Reading PNG gAMA chunk: gamma: %f",file_gamma);
2507 if (!png_get_valid(ping,ping_info,PNG_INFO_cHRM))
2509 if (mng_info->have_global_chrm != MagickFalse)
2511 (void) png_set_cHRM(ping,ping_info,
2512 mng_info->global_chrm.white_point.x,
2513 mng_info->global_chrm.white_point.y,
2514 mng_info->global_chrm.red_primary.x,
2515 mng_info->global_chrm.red_primary.y,
2516 mng_info->global_chrm.green_primary.x,
2517 mng_info->global_chrm.green_primary.y,
2518 mng_info->global_chrm.blue_primary.x,
2519 mng_info->global_chrm.blue_primary.y);
2523 if (png_get_valid(ping,ping_info,PNG_INFO_cHRM))
2525 (void) png_get_cHRM(ping,ping_info,
2526 &image->chromaticity.white_point.x,
2527 &image->chromaticity.white_point.y,
2528 &image->chromaticity.red_primary.x,
2529 &image->chromaticity.red_primary.y,
2530 &image->chromaticity.green_primary.x,
2531 &image->chromaticity.green_primary.y,
2532 &image->chromaticity.blue_primary.x,
2533 &image->chromaticity.blue_primary.y);
2535 if (image->chromaticity.red_primary.x>0.6399f &&
2536 image->chromaticity.red_primary.x<0.6401f &&
2537 image->chromaticity.red_primary.y>0.3299f &&
2538 image->chromaticity.red_primary.y<0.3301f &&
2539 image->chromaticity.green_primary.x>0.2999f &&
2540 image->chromaticity.green_primary.x<0.3001f &&
2541 image->chromaticity.green_primary.y>0.5999f &&
2542 image->chromaticity.green_primary.y<0.6001f &&
2543 image->chromaticity.blue_primary.x>0.1499f &&
2544 image->chromaticity.blue_primary.x<0.1501f &&
2545 image->chromaticity.blue_primary.y>0.0599f &&
2546 image->chromaticity.blue_primary.y<0.0601f &&
2547 image->chromaticity.white_point.x>0.3126f &&
2548 image->chromaticity.white_point.x<0.3128f &&
2549 image->chromaticity.white_point.y>0.3289f &&
2550 image->chromaticity.white_point.y<0.3291f)
2551 ping_found_sRGB_cHRM=MagickTrue;
2553 ping_found_cHRM=MagickTrue;
2556 if (image->rendering_intent != UndefinedIntent)
2558 if (ping_found_sRGB != MagickTrue &&
2559 (ping_found_gAMA != MagickTrue ||
2560 (image->gamma > .45 && image->gamma < .46)) &&
2561 (ping_found_cHRM != MagickTrue ||
2562 ping_found_sRGB_cHRM == MagickTrue) &&
2563 ping_found_iCCP != MagickTrue)
2565 png_set_sRGB(ping,ping_info,
2566 Magick_RenderingIntent_to_PNG_RenderingIntent
2567 (image->rendering_intent));
2568 if (ping_found_gAMA != MagickTrue)
2569 png_set_gAMA(ping,ping_info,1.000f/2.200f);
2570 file_gamma=1.000f/2.200f;
2571 ping_found_sRGB=MagickTrue;
2572 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2573 " Setting sRGB and gAMA as if in input");
2577 #if defined(PNG_oFFs_SUPPORTED)
2578 if (png_get_valid(ping,ping_info,PNG_INFO_oFFs))
2580 image->page.x=(ssize_t) png_get_x_offset_pixels(ping, ping_info);
2581 image->page.y=(ssize_t) png_get_y_offset_pixels(ping, ping_info);
2583 if (logging != MagickFalse)
2584 if (image->page.x || image->page.y)
2585 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2586 " Reading PNG oFFs chunk: x: %.20g, y: %.20g.",(double)
2587 image->page.x,(double) image->page.y);
2590 #if defined(PNG_pHYs_SUPPORTED)
2591 if (!png_get_valid(ping,ping_info,PNG_INFO_pHYs))
2593 if (mng_info->have_global_phys)
2595 png_set_pHYs(ping,ping_info,
2596 mng_info->global_x_pixels_per_unit,
2597 mng_info->global_y_pixels_per_unit,
2598 mng_info->global_phys_unit_type);
2602 if (png_get_valid(ping,ping_info,PNG_INFO_pHYs))
2605 Set image resolution.
2607 (void) png_get_pHYs(ping,ping_info,&x_resolution,&y_resolution,
2609 image->resolution.x=(double) x_resolution;
2610 image->resolution.y=(double) y_resolution;
2612 if (unit_type == PNG_RESOLUTION_METER)
2614 image->units=PixelsPerCentimeterResolution;
2615 image->resolution.x=(double) x_resolution/100.0;
2616 image->resolution.y=(double) y_resolution/100.0;
2619 if (logging != MagickFalse)
2620 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2621 " Reading PNG pHYs chunk: xres: %.20g, yres: %.20g, units: %d.",
2622 (double) x_resolution,(double) y_resolution,unit_type);
2626 if (png_get_valid(ping,ping_info,PNG_INFO_PLTE))
2631 (void) png_get_PLTE(ping,ping_info,&palette,&number_colors);
2633 if ((number_colors == 0) &&
2634 ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE))
2636 if (mng_info->global_plte_length)
2638 png_set_PLTE(ping,ping_info,mng_info->global_plte,
2639 (int) mng_info->global_plte_length);
2641 if (!png_get_valid(ping,ping_info,PNG_INFO_tRNS))
2643 if (mng_info->global_trns_length)
2646 "global tRNS has more entries than global PLTE");
2650 png_set_tRNS(ping,ping_info,mng_info->global_trns,
2651 (int) mng_info->global_trns_length,NULL);
2654 #ifdef PNG_READ_bKGD_SUPPORTED
2656 #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
2657 mng_info->have_saved_bkgd_index ||
2659 png_get_valid(ping,ping_info,PNG_INFO_bKGD))
2664 #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
2665 if (mng_info->have_saved_bkgd_index)
2666 background.index=mng_info->saved_bkgd_index;
2668 if (png_get_valid(ping, ping_info, PNG_INFO_bKGD))
2669 background.index=ping_background->index;
2671 background.red=(png_uint_16)
2672 mng_info->global_plte[background.index].red;
2674 background.green=(png_uint_16)
2675 mng_info->global_plte[background.index].green;
2677 background.blue=(png_uint_16)
2678 mng_info->global_plte[background.index].blue;
2680 background.gray=(png_uint_16)
2681 mng_info->global_plte[background.index].green;
2683 png_set_bKGD(ping,ping_info,&background);
2688 png_error(ping,"No global PLTE in file");
2692 #ifdef PNG_READ_bKGD_SUPPORTED
2693 if (mng_info->have_global_bkgd &&
2694 (!png_get_valid(ping,ping_info,PNG_INFO_bKGD)))
2695 image->background_color=mng_info->mng_global_bkgd;
2697 if (png_get_valid(ping,ping_info,PNG_INFO_bKGD))
2703 Set image background color.
2705 if (logging != MagickFalse)
2706 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2707 " Reading PNG bKGD chunk.");
2709 /* Scale background components to 16-bit, then scale
2712 if (logging != MagickFalse)
2713 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2714 " raw ping_background=(%d,%d,%d).",ping_background->red,
2715 ping_background->green,ping_background->blue);
2719 if (ping_file_depth == 1)
2722 else if (ping_file_depth == 2)
2725 else if (ping_file_depth == 4)
2728 if (ping_file_depth <= 8)
2731 ping_background->red *= bkgd_scale;
2732 ping_background->green *= bkgd_scale;
2733 ping_background->blue *= bkgd_scale;
2735 if (logging != MagickFalse)
2737 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2738 " bkgd_scale=%d.",bkgd_scale);
2740 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2741 " ping_background=(%d,%d,%d).",ping_background->red,
2742 ping_background->green,ping_background->blue);
2745 image->background_color.red=
2746 ScaleShortToQuantum(ping_background->red);
2748 image->background_color.green=
2749 ScaleShortToQuantum(ping_background->green);
2751 image->background_color.blue=
2752 ScaleShortToQuantum(ping_background->blue);
2754 image->background_color.alpha=OpaqueAlpha;
2756 if (logging != MagickFalse)
2757 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2758 " image->background_color=(%.20g,%.20g,%.20g).",
2759 (double) image->background_color.red,
2760 (double) image->background_color.green,
2761 (double) image->background_color.blue);
2763 #endif /* PNG_READ_bKGD_SUPPORTED */
2765 if (png_get_valid(ping,ping_info,PNG_INFO_tRNS))
2768 Image has a tRNS chunk.
2776 if (logging != MagickFalse)
2777 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2778 " Reading PNG tRNS chunk.");
2780 max_sample = (int) ((one << ping_file_depth) - 1);
2782 if ((ping_color_type == PNG_COLOR_TYPE_GRAY &&
2783 (int)ping_trans_color->gray > max_sample) ||
2784 (ping_color_type == PNG_COLOR_TYPE_RGB &&
2785 ((int)ping_trans_color->red > max_sample ||
2786 (int)ping_trans_color->green > max_sample ||
2787 (int)ping_trans_color->blue > max_sample)))
2789 if (logging != MagickFalse)
2790 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2791 " Ignoring PNG tRNS chunk with out-of-range sample.");
2792 png_free_data(ping, ping_info, PNG_FREE_TRNS, 0);
2793 png_set_invalid(ping,ping_info,PNG_INFO_tRNS);
2794 image->alpha_trait=UndefinedPixelTrait;
2801 scale_to_short = 65535L/((1UL << ping_file_depth)-1);
2803 /* Scale transparent_color to short */
2804 transparent_color.red= scale_to_short*ping_trans_color->red;
2805 transparent_color.green= scale_to_short*ping_trans_color->green;
2806 transparent_color.blue= scale_to_short*ping_trans_color->blue;
2807 transparent_color.alpha= scale_to_short*ping_trans_color->gray;
2809 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
2811 if (logging != MagickFalse)
2813 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2814 " Raw tRNS graylevel is %d.",ping_trans_color->gray);
2816 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2817 " scaled graylevel is %.20g.",transparent_color.alpha);
2819 transparent_color.red=transparent_color.alpha;
2820 transparent_color.green=transparent_color.alpha;
2821 transparent_color.blue=transparent_color.alpha;
2825 #if defined(PNG_READ_sBIT_SUPPORTED)
2826 if (mng_info->have_global_sbit)
2828 if (!png_get_valid(ping,ping_info,PNG_INFO_sBIT))
2829 png_set_sBIT(ping,ping_info,&mng_info->global_sbit);
2832 num_passes=png_set_interlace_handling(ping);
2834 png_read_update_info(ping,ping_info);
2836 ping_rowbytes=png_get_rowbytes(ping,ping_info);
2839 Initialize image structure.
2841 mng_info->image_box.left=0;
2842 mng_info->image_box.right=(ssize_t) ping_width;
2843 mng_info->image_box.top=0;
2844 mng_info->image_box.bottom=(ssize_t) ping_height;
2845 if (mng_info->mng_type == 0)
2847 mng_info->mng_width=ping_width;
2848 mng_info->mng_height=ping_height;
2849 mng_info->frame=mng_info->image_box;
2850 mng_info->clip=mng_info->image_box;
2855 image->page.y=mng_info->y_off[mng_info->object_id];
2858 image->compression=ZipCompression;
2859 image->columns=ping_width;
2860 image->rows=ping_height;
2862 if (((int) ping_color_type == PNG_COLOR_TYPE_GRAY) ||
2863 ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA))
2865 if ((!png_get_valid(ping,ping_info,PNG_INFO_gAMA) ||
2866 image->gamma == 1.0) && ping_found_sRGB != MagickTrue)
2868 /* Set image->gamma to 1.0, image->rendering_intent to Undefined,
2869 * image->colorspace to GRAY, and reset image->chromaticity.
2871 SetImageColorspace(image,GRAYColorspace,exception);
2875 (void)LogMagickEvent(CoderEvent,GetMagickModule(),
2876 " image->colorspace=%d",(int) image->colorspace);
2878 if (((int) ping_color_type == PNG_COLOR_TYPE_PALETTE) ||
2879 ((int) ping_bit_depth < 16 &&
2880 (int) ping_color_type == PNG_COLOR_TYPE_GRAY))
2885 image->storage_class=PseudoClass;
2887 image->colors=one << ping_file_depth;
2888 #if (MAGICKCORE_QUANTUM_DEPTH == 8)
2889 if (image->colors > 256)
2892 if (image->colors > 65536L)
2893 image->colors=65536L;
2895 if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
2900 (void) png_get_PLTE(ping,ping_info,&palette,&number_colors);
2901 image->colors=(size_t) number_colors;
2903 if (logging != MagickFalse)
2904 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2905 " Reading PNG PLTE chunk: number_colors: %d.",number_colors);
2909 if (image->storage_class == PseudoClass)
2912 Initialize image colormap.
2914 if (AcquireImageColormap(image,image->colors,exception) == MagickFalse)
2915 png_error(ping,"Memory allocation failed");
2917 if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
2922 (void) png_get_PLTE(ping,ping_info,&palette,&number_colors);
2924 for (i=0; i < (ssize_t) number_colors; i++)
2926 image->colormap[i].red=ScaleCharToQuantum(palette[i].red);
2927 image->colormap[i].green=ScaleCharToQuantum(palette[i].green);
2928 image->colormap[i].blue=ScaleCharToQuantum(palette[i].blue);
2931 for ( ; i < (ssize_t) image->colors; i++)
2933 image->colormap[i].red=0;
2934 image->colormap[i].green=0;
2935 image->colormap[i].blue=0;
2944 scale=(QuantumRange/((1UL << ping_file_depth)-1));
2949 for (i=0; i < (ssize_t) image->colors; i++)
2951 image->colormap[i].red=(Quantum) (i*scale);
2952 image->colormap[i].green=(Quantum) (i*scale);
2953 image->colormap[i].blue=(Quantum) (i*scale);
2958 /* Set some properties for reporting by "identify" */
2963 /* encode ping_width, ping_height, ping_file_depth, ping_color_type,
2964 ping_interlace_method in value */
2966 (void) FormatLocaleString(msg,MaxTextExtent,
2967 "%d, %d",(int) ping_width, (int) ping_height);
2968 (void) SetImageProperty(image,"png:IHDR.width,height ",msg,exception);
2970 (void) FormatLocaleString(msg,MaxTextExtent,"%d",(int) ping_file_depth);
2971 (void) SetImageProperty(image,"png:IHDR.bit_depth ",msg,exception);
2973 (void) FormatLocaleString(msg,MaxTextExtent,"%d (%s)",
2974 (int) ping_color_type,
2975 Magick_ColorType_from_PNG_ColorType((int)ping_color_type));
2976 (void) SetImageProperty(image,"png:IHDR.color_type ",msg,exception);
2978 if (ping_interlace_method == 0)
2980 (void) FormatLocaleString(msg,MaxTextExtent,"%d (Not interlaced)",
2981 (int) ping_interlace_method);
2983 else if (ping_interlace_method == 1)
2985 (void) FormatLocaleString(msg,MaxTextExtent,"%d (Adam7 method)",
2986 (int) ping_interlace_method);
2990 (void) FormatLocaleString(msg,MaxTextExtent,"%d (Unknown method)",
2991 (int) ping_interlace_method);
2993 (void) SetImageProperty(image,"png:IHDR.interlace_method",msg,exception);
2995 if (number_colors != 0)
2997 (void) FormatLocaleString(msg,MaxTextExtent,"%d",
2998 (int) number_colors);
2999 (void) SetImageProperty(image,"png:PLTE.number_colors ",msg,
3005 Read image scanlines.
3007 if (image->delay != 0)
3008 mng_info->scenes_found++;
3010 if ((mng_info->mng_type == 0 && (image->ping != MagickFalse)) || (
3011 (image_info->number_scenes != 0) && (mng_info->scenes_found > (ssize_t)
3012 (image_info->first_scene+image_info->number_scenes))))
3014 /* This happens later in non-ping decodes */
3015 if (png_get_valid(ping,ping_info,PNG_INFO_tRNS))
3016 image->storage_class=DirectClass;
3018 if (logging != MagickFalse)
3019 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3020 " Skipping PNG image data for scene %.20g",(double)
3021 mng_info->scenes_found-1);
3022 png_destroy_read_struct(&ping,&ping_info,&end_info);
3024 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
3025 UnlockSemaphoreInfo(ping_semaphore);
3028 if (logging != MagickFalse)
3029 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3030 " exit ReadOnePNGImage().");
3035 if (logging != MagickFalse)
3036 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3037 " Reading PNG IDAT chunk(s)");
3040 ping_pixels=(unsigned char *) AcquireQuantumMemory(image->rows,
3041 ping_rowbytes*sizeof(*ping_pixels));
3044 ping_pixels=(unsigned char *) AcquireQuantumMemory(ping_rowbytes,
3045 sizeof(*ping_pixels));
3047 if (ping_pixels == (unsigned char *) NULL)
3048 png_error(ping,"Memory allocation failed");
3050 if (logging != MagickFalse)
3051 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3052 " Converting PNG pixels to pixel packets");
3054 Convert PNG pixels to pixel packets.
3056 quantum_info=AcquireQuantumInfo(image_info,image);
3058 if (quantum_info == (QuantumInfo *) NULL)
3059 png_error(ping,"Failed to allocate quantum_info");
3061 (void) SetQuantumEndian(image,quantum_info,MSBEndian);
3066 found_transparent_pixel;
3068 found_transparent_pixel=MagickFalse;
3070 if (image->storage_class == DirectClass)
3072 for (pass=0; pass < num_passes; pass++)
3075 Convert image to DirectClass pixel packets.
3077 image->alpha_trait=(((int) ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA) ||
3078 ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) ||
3079 (png_get_valid(ping,ping_info,PNG_INFO_tRNS))) ?
3080 BlendPixelTrait : UndefinedPixelTrait;
3082 for (y=0; y < (ssize_t) image->rows; y++)
3085 row_offset=ping_rowbytes*y;
3090 png_read_row(ping,ping_pixels+row_offset,NULL);
3092 if (pass < num_passes-1)
3095 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
3097 if (q == (Quantum *) NULL)
3100 if ((int) ping_color_type == PNG_COLOR_TYPE_GRAY)
3101 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
3102 GrayQuantum,ping_pixels+row_offset,exception);
3104 else if ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
3105 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
3106 GrayAlphaQuantum,ping_pixels+row_offset,exception);
3108 else if ((int) ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA)
3109 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
3110 RGBAQuantum,ping_pixels+row_offset,exception);
3112 else if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
3113 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
3114 IndexQuantum,ping_pixels+row_offset,exception);
3116 else /* ping_color_type == PNG_COLOR_TYPE_RGB */
3117 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
3118 RGBQuantum,ping_pixels+row_offset,exception);
3120 if (found_transparent_pixel == MagickFalse)
3122 /* Is there a transparent pixel in the row? */
3123 if (y== 0 && logging != MagickFalse)
3124 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3125 " Looking for cheap transparent pixel");
3127 for (x=(ssize_t) image->columns-1; x >= 0; x--)
3129 if ((ping_color_type == PNG_COLOR_TYPE_RGBA ||
3130 ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) &&
3131 (GetPixelAlpha(image,q) != OpaqueAlpha))
3133 if (logging != MagickFalse)
3134 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3137 found_transparent_pixel = MagickTrue;
3140 if ((ping_color_type == PNG_COLOR_TYPE_RGB ||
3141 ping_color_type == PNG_COLOR_TYPE_GRAY) &&
3142 (ScaleQuantumToShort(GetPixelRed(image,q)) ==
3143 transparent_color.red &&
3144 ScaleQuantumToShort(GetPixelGreen(image,q)) ==
3145 transparent_color.green &&
3146 ScaleQuantumToShort(GetPixelBlue(image,q)) ==
3147 transparent_color.blue))
3149 if (logging != MagickFalse)
3150 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3152 found_transparent_pixel = MagickTrue;
3155 q+=GetPixelChannels(image);
3159 if ((image->previous == (Image *) NULL) && (num_passes == 1))
3161 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
3164 if (status == MagickFalse)
3167 if (SyncAuthenticPixels(image,exception) == MagickFalse)
3171 if ((image->previous == (Image *) NULL) && (num_passes != 1))
3173 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
3174 if (status == MagickFalse)
3180 else /* image->storage_class != DirectClass */
3182 for (pass=0; pass < num_passes; pass++)
3191 Convert grayscale image to PseudoClass pixel packets.
3193 if (logging != MagickFalse)
3194 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3195 " Converting grayscale pixels to pixel packets");
3197 image->alpha_trait=ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA ?
3198 BlendPixelTrait : UndefinedPixelTrait;
3200 quantum_scanline=(Quantum *) AcquireQuantumMemory(image->columns,
3201 (image->alpha_trait == BlendPixelTrait? 2 : 1)*
3202 sizeof(*quantum_scanline));
3204 if (quantum_scanline == (Quantum *) NULL)
3205 png_error(ping,"Memory allocation failed");
3207 for (y=0; y < (ssize_t) image->rows; y++)
3213 row_offset=ping_rowbytes*y;
3218 png_read_row(ping,ping_pixels+row_offset,NULL);
3220 if (pass < num_passes-1)
3223 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
3225 if (q == (Quantum *) NULL)
3228 p=ping_pixels+row_offset;
3231 switch (ping_bit_depth)
3236 if (ping_color_type == 4)
3237 for (x=(ssize_t) image->columns-1; x >= 0; x--)
3241 alpha=ScaleCharToQuantum((unsigned char)*p++);
3243 SetPixelAlpha(image,alpha,q);
3245 if (alpha != OpaqueAlpha)
3246 found_transparent_pixel = MagickTrue;
3248 q+=GetPixelChannels(image);
3252 for (x=(ssize_t) image->columns-1; x >= 0; x--)
3260 for (x=(ssize_t) image->columns-1; x >= 0; x--)
3262 #if (MAGICKCORE_QUANTUM_DEPTH == 16) || (MAGICKCORE_QUANTUM_DEPTH == 32)
3266 if (image->colors > 256)
3267 quantum=((*p++) << 8);
3273 *r=ScaleShortToQuantum(quantum);
3276 if (ping_color_type == 4)
3278 if (image->colors > 256)
3279 quantum=((*p++) << 8);
3285 alpha=ScaleShortToQuantum(quantum);
3286 SetPixelAlpha(image,alpha,q);
3288 if (alpha != OpaqueAlpha)
3289 found_transparent_pixel = MagickTrue;
3291 q+=GetPixelChannels(image);
3294 #else /* MAGICKCORE_QUANTUM_DEPTH == 8 */
3296 p++; /* strip low byte */
3298 if (ping_color_type == 4)
3300 SetPixelAlpha(image,*p++,q);
3302 if (GetPixelAlpha(image,q) != OpaqueAlpha)
3303 found_transparent_pixel = MagickTrue;
3306 q+=GetPixelChannels(image);
3319 Transfer image scanline.
3323 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
3325 if (q == (Quantum *) NULL)
3327 for (x=0; x < (ssize_t) image->columns; x++)
3329 SetPixelIndex(image,*r++,q);
3330 q+=GetPixelChannels(image);
3333 if (SyncAuthenticPixels(image,exception) == MagickFalse)
3336 if ((image->previous == (Image *) NULL) && (num_passes == 1))
3338 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
3341 if (status == MagickFalse)
3346 if ((image->previous == (Image *) NULL) && (num_passes != 1))
3348 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
3350 if (status == MagickFalse)
3354 quantum_scanline=(Quantum *) RelinquishMagickMemory(quantum_scanline);
3357 image->alpha_trait=found_transparent_pixel ? BlendPixelTrait :
3358 UndefinedPixelTrait;
3360 if (logging != MagickFalse)
3362 if (found_transparent_pixel != MagickFalse)
3363 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3364 " Found transparent pixel");
3367 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3368 " No transparent pixel was found");
3370 ping_color_type&=0x03;
3375 if (quantum_info != (QuantumInfo *) NULL)
3376 quantum_info=DestroyQuantumInfo(quantum_info);
3378 if (image->storage_class == PseudoClass)
3383 alpha_trait=image->alpha_trait;
3384 image->alpha_trait=UndefinedPixelTrait;
3385 (void) SyncImage(image,exception);
3386 image->alpha_trait=alpha_trait;
3389 png_read_end(ping,end_info);
3391 if (image_info->number_scenes != 0 && mng_info->scenes_found-1 <
3392 (ssize_t) image_info->first_scene && image->delay != 0)
3394 png_destroy_read_struct(&ping,&ping_info,&end_info);
3395 ping_pixels=(unsigned char *) RelinquishMagickMemory(ping_pixels);
3397 (void) SetImageBackgroundColor(image,exception);
3398 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
3399 UnlockSemaphoreInfo(ping_semaphore);
3401 if (logging != MagickFalse)
3402 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3403 " exit ReadOnePNGImage() early.");
3407 if (png_get_valid(ping,ping_info,PNG_INFO_tRNS))
3413 Image has a transparent background.
3415 storage_class=image->storage_class;
3416 image->alpha_trait=BlendPixelTrait;
3418 /* Balfour fix from imagemagick discourse server, 5 Feb 2010 */
3420 if (storage_class == PseudoClass)
3422 if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
3424 for (x=0; x < ping_num_trans; x++)
3426 image->colormap[x].alpha_trait=BlendPixelTrait;
3427 image->colormap[x].alpha =
3428 ScaleCharToQuantum((unsigned char)ping_trans_alpha[x]);
3432 else if (ping_color_type == PNG_COLOR_TYPE_GRAY)
3434 for (x=0; x < (int) image->colors; x++)
3436 if (ScaleQuantumToShort(image->colormap[x].red) ==
3437 transparent_color.alpha)
3439 image->colormap[x].alpha_trait=BlendPixelTrait;
3440 image->colormap[x].alpha = (Quantum) TransparentAlpha;
3444 (void) SyncImage(image,exception);
3447 #if 1 /* Should have already been done above, but glennrp problem P10
3452 for (y=0; y < (ssize_t) image->rows; y++)
3454 image->storage_class=storage_class;
3455 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
3457 if (q == (Quantum *) NULL)
3461 /* Caution: on a Q8 build, this does not distinguish between
3462 * 16-bit colors that differ only in the low byte
3464 for (x=(ssize_t) image->columns-1; x >= 0; x--)
3466 if (ScaleQuantumToShort(GetPixelRed(image,q)) ==
3467 transparent_color.red &&
3468 ScaleQuantumToShort(GetPixelGreen(image,q)) ==
3469 transparent_color.green &&
3470 ScaleQuantumToShort(GetPixelBlue(image,q)) ==
3471 transparent_color.blue)
3473 SetPixelAlpha(image,TransparentAlpha,q);
3476 #if 0 /* I have not found a case where this is needed. */
3479 SetPixelAlpha(image,q)=(Quantum) OpaqueAlpha;
3483 q+=GetPixelChannels(image);
3486 if (SyncAuthenticPixels(image,exception) == MagickFalse)
3492 image->storage_class=DirectClass;
3495 for (j = 0; j < 2; j++)
3498 status = png_get_text(ping,ping_info,&text,&num_text) != 0 ?
3499 MagickTrue : MagickFalse;
3501 status = png_get_text(ping,end_info,&text,&num_text) != 0 ?
3502 MagickTrue : MagickFalse;
3504 if (status != MagickFalse)
3505 for (i=0; i < (ssize_t) num_text; i++)
3507 /* Check for a profile */
3509 if (logging != MagickFalse)
3510 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3511 " Reading PNG text chunk");
3513 if (memcmp(text[i].key, "Raw profile type ",17) == 0)
3515 (void) Magick_png_read_raw_profile(ping,image,image_info,text,
3525 length=text[i].text_length;
3526 value=(char *) AcquireQuantumMemory(length+MaxTextExtent,
3528 if (value == (char *) NULL)
3530 png_error(ping,"Memory allocation failed");
3534 (void) ConcatenateMagickString(value,text[i].text,length+2);
3536 /* Don't save "density" or "units" property if we have a pHYs
3539 if (!png_get_valid(ping,ping_info,PNG_INFO_pHYs) ||
3540 (LocaleCompare(text[i].key,"density") != 0 &&
3541 LocaleCompare(text[i].key,"units") != 0))
3542 (void) SetImageProperty(image,text[i].key,value,exception);
3544 if (logging != MagickFalse)
3546 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3547 " length: %lu",(unsigned long) length);
3548 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3549 " Keyword: %s",text[i].key);
3552 value=DestroyString(value);
3555 num_text_total += num_text;
3558 #ifdef MNG_OBJECT_BUFFERS
3560 Store the object if necessary.
3562 if (object_id && !mng_info->frozen[object_id])
3564 if (mng_info->ob[object_id] == (MngBuffer *) NULL)
3567 create a new object buffer.
3569 mng_info->ob[object_id]=(MngBuffer *)
3570 AcquireMagickMemory(sizeof(MngBuffer));
3572 if (mng_info->ob[object_id] != (MngBuffer *) NULL)
3574 mng_info->ob[object_id]->image=(Image *) NULL;
3575 mng_info->ob[object_id]->reference_count=1;
3579 if ((mng_info->ob[object_id] == (MngBuffer *) NULL) ||
3580 mng_info->ob[object_id]->frozen)
3582 if (mng_info->ob[object_id] == (MngBuffer *) NULL)
3583 png_error(ping,"Memory allocation failed");
3585 if (mng_info->ob[object_id]->frozen)
3586 png_error(ping,"Cannot overwrite frozen MNG object buffer");
3592 if (mng_info->ob[object_id]->image != (Image *) NULL)
3593 mng_info->ob[object_id]->image=DestroyImage
3594 (mng_info->ob[object_id]->image);
3596 mng_info->ob[object_id]->image=CloneImage(image,0,0,MagickTrue,
3599 if (mng_info->ob[object_id]->image != (Image *) NULL)
3600 mng_info->ob[object_id]->image->file=(FILE *) NULL;
3603 png_error(ping, "Cloning image for object buffer failed");
3605 if (ping_width > 250000L || ping_height > 250000L)
3606 png_error(ping,"PNG Image dimensions are too large.");
3608 mng_info->ob[object_id]->width=ping_width;
3609 mng_info->ob[object_id]->height=ping_height;
3610 mng_info->ob[object_id]->color_type=ping_color_type;
3611 mng_info->ob[object_id]->sample_depth=ping_bit_depth;
3612 mng_info->ob[object_id]->interlace_method=ping_interlace_method;
3613 mng_info->ob[object_id]->compression_method=
3614 ping_compression_method;
3615 mng_info->ob[object_id]->filter_method=ping_filter_method;
3617 if (png_get_valid(ping,ping_info,PNG_INFO_PLTE))
3623 Copy the PLTE to the object buffer.
3625 png_get_PLTE(ping,ping_info,&plte,&number_colors);
3626 mng_info->ob[object_id]->plte_length=number_colors;
3628 for (i=0; i < number_colors; i++)
3630 mng_info->ob[object_id]->plte[i]=plte[i];
3635 mng_info->ob[object_id]->plte_length=0;
3640 /* Set image->alpha_trait to MagickTrue if the input colortype supports
3641 * alpha or if a valid tRNS chunk is present, no matter whether there
3642 * is actual transparency present.
3644 image->alpha_trait=(((int) ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA) ||
3645 ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) ||
3646 (png_get_valid(ping,ping_info,PNG_INFO_tRNS))) ?
3647 BlendPixelTrait : UndefinedPixelTrait;
3649 #if 0 /* I'm not sure what's wrong here but it does not work. */
3650 if (image->alpha_trait == BlendPixelTrait)
3652 if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
3653 (void) SetImageType(image,GrayscaleMatteType,exception);
3655 else if (ping_color_type == PNG_COLOR_TYPE_PALETTE)
3656 (void) SetImageType(image,PaletteMatteType,exception);
3659 (void) SetImageType(image,TrueColorMatteType,exception);
3664 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
3665 (void) SetImageType(image,GrayscaleType,exception);
3667 else if (ping_color_type == PNG_COLOR_TYPE_PALETTE)
3668 (void) SetImageType(image,PaletteType,exception);
3671 (void) SetImageType(image,TrueColorType,exception);
3675 /* Set more properties for identify to retrieve */
3680 if (num_text_total != 0)
3682 /* libpng doesn't tell us whether they were tEXt, zTXt, or iTXt */
3683 (void) FormatLocaleString(msg,MaxTextExtent,
3684 "%d tEXt/zTXt/iTXt chunks were found", num_text_total);
3685 (void) SetImageProperty(image,"png:text ",msg,
3689 if (num_raw_profiles != 0)
3691 (void) FormatLocaleString(msg,MaxTextExtent,
3692 "%d were found", num_raw_profiles);
3693 (void) SetImageProperty(image,"png:text-encoded profiles",msg,
3697 if (ping_found_cHRM != MagickFalse)
3699 (void) FormatLocaleString(msg,MaxTextExtent,"%s",
3700 "chunk was found (see Chromaticity, above)");
3701 (void) SetImageProperty(image,"png:cHRM ",msg,
3705 if (png_get_valid(ping,ping_info,PNG_INFO_bKGD))
3707 (void) FormatLocaleString(msg,MaxTextExtent,"%s",
3708 "chunk was found (see Background color, above)");
3709 (void) SetImageProperty(image,"png:bKGD ",msg,
3713 (void) FormatLocaleString(msg,MaxTextExtent,"%s",
3716 #if defined(PNG_iCCP_SUPPORTED)
3717 if (ping_found_iCCP != MagickFalse)
3718 (void) SetImageProperty(image,"png:iCCP ",msg,
3722 if (png_get_valid(ping,ping_info,PNG_INFO_tRNS))
3723 (void) SetImageProperty(image,"png:tRNS ",msg,
3726 #if defined(PNG_sRGB_SUPPORTED)
3727 if (ping_found_sRGB != MagickFalse)
3729 (void) FormatLocaleString(msg,MaxTextExtent,
3732 Magick_RenderingIntentString_from_PNG_RenderingIntent(intent));
3733 (void) SetImageProperty(image,"png:sRGB ",msg,
3738 if (ping_found_gAMA != MagickFalse)
3740 (void) FormatLocaleString(msg,MaxTextExtent,
3741 "gamma=%.8g (See Gamma, above)",
3743 (void) SetImageProperty(image,"png:gAMA ",msg,
3747 #if defined(PNG_pHYs_SUPPORTED)
3748 if (png_get_valid(ping,ping_info,PNG_INFO_pHYs))
3750 (void) FormatLocaleString(msg,MaxTextExtent,
3751 "x_res=%.10g, y_res=%.10g, units=%d",
3752 (double) x_resolution,(double) y_resolution, unit_type);
3753 (void) SetImageProperty(image,"png:pHYs ",msg,
3758 #if defined(PNG_oFFs_SUPPORTED)
3759 if (png_get_valid(ping,ping_info,PNG_INFO_oFFs))
3761 (void) FormatLocaleString(msg,MaxTextExtent,"x_off=%.20g, y_off=%.20g",
3762 (double) image->page.x,(double) image->page.y);
3763 (void) SetImageProperty(image,"png:oFFs ",msg,
3768 if ((image->page.width != 0 && image->page.width != image->columns) ||
3769 (image->page.height != 0 && image->page.height != image->rows))
3771 (void) FormatLocaleString(msg,MaxTextExtent,
3772 "width=%.20g, height=%.20g",
3773 (double) image->page.width,(double) image->page.height);
3774 (void) SetImageProperty(image,"png:vpAg ",msg,
3780 Relinquish resources.
3782 png_destroy_read_struct(&ping,&ping_info,&end_info);
3784 ping_pixels=(unsigned char *) RelinquishMagickMemory(ping_pixels);
3786 if (logging != MagickFalse)
3787 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3788 " exit ReadOnePNGImage()");
3790 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
3791 UnlockSemaphoreInfo(ping_semaphore);
3794 /* } for navigation to beginning of SETJMP-protected block, revert to
3795 * Throwing an Exception when an error occurs.
3800 /* end of reading one PNG image */
3803 static Image *ReadPNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
3818 magic_number[MaxTextExtent];
3826 assert(image_info != (const ImageInfo *) NULL);
3827 assert(image_info->signature == MagickSignature);
3829 if (image_info->debug != MagickFalse)
3830 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
3831 image_info->filename);
3833 assert(exception != (ExceptionInfo *) NULL);
3834 assert(exception->signature == MagickSignature);
3835 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter ReadPNGImage()");
3836 image=AcquireImage(image_info,exception);
3837 mng_info=(MngInfo *) NULL;
3838 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
3840 if (status == MagickFalse)
3841 ThrowReaderException(FileOpenError,"UnableToOpenFile");
3844 Verify PNG signature.
3846 count=ReadBlob(image,8,(unsigned char *) magic_number);
3848 if (count < 8 || memcmp(magic_number,"\211PNG\r\n\032\n",8) != 0)
3849 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
3852 Allocate a MngInfo structure.
3854 have_mng_structure=MagickFalse;
3855 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
3857 if (mng_info == (MngInfo *) NULL)
3858 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
3861 Initialize members of the MngInfo structure.
3863 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
3864 mng_info->image=image;
3865 have_mng_structure=MagickTrue;
3868 image=ReadOnePNGImage(mng_info,image_info,exception);
3869 MngInfoFreeStruct(mng_info,&have_mng_structure);
3871 if (image == (Image *) NULL)
3873 if (previous != (Image *) NULL)
3875 if (previous->signature != MagickSignature)
3876 ThrowReaderException(CorruptImageError,"CorruptImage");
3878 (void) CloseBlob(previous);
3879 (void) DestroyImageList(previous);
3882 if (logging != MagickFalse)
3883 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3884 "exit ReadPNGImage() with error");
3886 return((Image *) NULL);
3889 (void) CloseBlob(image);
3891 if ((image->columns == 0) || (image->rows == 0))
3893 if (logging != MagickFalse)
3894 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3895 "exit ReadPNGImage() with error.");
3897 ThrowReaderException(CorruptImageError,"CorruptImage");
3900 if ((IssRGBColorspace(image->colorspace) != MagickFalse) &&
3901 ((image->gamma < .45) || (image->gamma > .46)) &&
3902 !(image->chromaticity.red_primary.x>0.6399f &&
3903 image->chromaticity.red_primary.x<0.6401f &&
3904 image->chromaticity.red_primary.y>0.3299f &&
3905 image->chromaticity.red_primary.y<0.3301f &&
3906 image->chromaticity.green_primary.x>0.2999f &&
3907 image->chromaticity.green_primary.x<0.3001f &&
3908 image->chromaticity.green_primary.y>0.5999f &&
3909 image->chromaticity.green_primary.y<0.6001f &&
3910 image->chromaticity.blue_primary.x>0.1499f &&
3911 image->chromaticity.blue_primary.x<0.1501f &&
3912 image->chromaticity.blue_primary.y>0.0599f &&
3913 image->chromaticity.blue_primary.y<0.0601f &&
3914 image->chromaticity.white_point.x>0.3126f &&
3915 image->chromaticity.white_point.x<0.3128f &&
3916 image->chromaticity.white_point.y>0.3289f &&
3917 image->chromaticity.white_point.y<0.3291f))
3918 SetImageColorspace(image,RGBColorspace,exception);
3920 if (logging != MagickFalse)
3921 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3922 " page.w: %.20g, page.h: %.20g,page.x: %.20g, page.y: %.20g.",
3923 (double) image->page.width,(double) image->page.height,
3924 (double) image->page.x,(double) image->page.y);
3926 if (logging != MagickFalse)
3927 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit ReadPNGImage()");
3934 #if defined(JNG_SUPPORTED)
3936 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3940 % R e a d O n e J N G I m a g e %
3944 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3946 % ReadOneJNGImage() reads a JPEG Network Graphics (JNG) image file
3947 % (minus the 8-byte signature) and returns it. It allocates the memory
3948 % necessary for the new Image structure and returns a pointer to the new
3951 % JNG support written by Glenn Randers-Pehrson, glennrp@image...
3953 % The format of the ReadOneJNGImage method is:
3955 % Image *ReadOneJNGImage(MngInfo *mng_info, const ImageInfo *image_info,
3956 % ExceptionInfo *exception)
3958 % A description of each parameter follows:
3960 % o mng_info: Specifies a pointer to a MngInfo structure.
3962 % o image_info: the image info.
3964 % o exception: return any errors or warnings in this structure.
3967 static Image *ReadOneJNGImage(MngInfo *mng_info,
3968 const ImageInfo *image_info, ExceptionInfo *exception)
3995 jng_image_sample_depth,
3996 jng_image_compression_method,
3997 jng_image_interlace_method,
3998 jng_alpha_sample_depth,
3999 jng_alpha_compression_method,
4000 jng_alpha_filter_method,
4001 jng_alpha_interlace_method;
4003 register const Quantum
4013 register unsigned char
4024 jng_alpha_compression_method=0;
4025 jng_alpha_sample_depth=8;
4029 alpha_image=(Image *) NULL;
4030 color_image=(Image *) NULL;
4031 alpha_image_info=(ImageInfo *) NULL;
4032 color_image_info=(ImageInfo *) NULL;
4034 logging=LogMagickEvent(CoderEvent,GetMagickModule(),
4035 " Enter ReadOneJNGImage()");
4037 image=mng_info->image;
4039 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
4042 Allocate next image structure.
4044 if (logging != MagickFalse)
4045 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4046 " AcquireNextImage()");
4048 AcquireNextImage(image_info,image,exception);
4050 if (GetNextImageInList(image) == (Image *) NULL)
4051 return((Image *) NULL);
4053 image=SyncNextImageInList(image);
4055 mng_info->image=image;
4058 Signature bytes have already been read.
4061 read_JSEP=MagickFalse;
4062 reading_idat=MagickFalse;
4063 skip_to_iend=MagickFalse;
4067 type[MaxTextExtent];
4076 Read a new JNG chunk.
4078 status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
4079 2*GetBlobSize(image));
4081 if (status == MagickFalse)
4085 (void) ConcatenateMagickString(type,"errr",MaxTextExtent);
4086 length=ReadBlobMSBLong(image);
4087 count=(unsigned int) ReadBlob(image,4,(unsigned char *) type);
4089 if (logging != MagickFalse)
4090 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4091 " Reading JNG chunk type %c%c%c%c, length: %.20g",
4092 type[0],type[1],type[2],type[3],(double) length);
4094 if (length > PNG_UINT_31_MAX || count == 0)
4095 ThrowReaderException(CorruptImageError,"CorruptImage");
4098 chunk=(unsigned char *) NULL;
4102 chunk=(unsigned char *) AcquireQuantumMemory(length,sizeof(*chunk));
4104 if (chunk == (unsigned char *) NULL)
4105 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
4107 for (i=0; i < (ssize_t) length; i++)
4108 chunk[i]=(unsigned char) ReadBlobByte(image);
4113 (void) ReadBlobMSBLong(image); /* read crc word */
4118 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4123 if (memcmp(type,mng_JHDR,4) == 0)
4127 jng_width=(size_t) ((p[0] << 24) | (p[1] << 16) |
4128 (p[2] << 8) | p[3]);
4129 jng_height=(size_t) ((p[4] << 24) | (p[5] << 16) |
4130 (p[6] << 8) | p[7]);
4131 jng_color_type=p[8];
4132 jng_image_sample_depth=p[9];
4133 jng_image_compression_method=p[10];
4134 jng_image_interlace_method=p[11];
4136 image->interlace=jng_image_interlace_method != 0 ? PNGInterlace :
4139 jng_alpha_sample_depth=p[12];
4140 jng_alpha_compression_method=p[13];
4141 jng_alpha_filter_method=p[14];
4142 jng_alpha_interlace_method=p[15];
4144 if (logging != MagickFalse)
4146 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4147 " jng_width: %16lu",(unsigned long) jng_width);
4149 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4150 " jng_width: %16lu",(unsigned long) jng_height);
4152 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4153 " jng_color_type: %16d",jng_color_type);
4155 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4156 " jng_image_sample_depth: %3d",
4157 jng_image_sample_depth);
4159 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4160 " jng_image_compression_method:%3d",
4161 jng_image_compression_method);
4163 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4164 " jng_image_interlace_method: %3d",
4165 jng_image_interlace_method);
4167 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4168 " jng_alpha_sample_depth: %3d",
4169 jng_alpha_sample_depth);
4171 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4172 " jng_alpha_compression_method:%3d",
4173 jng_alpha_compression_method);
4175 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4176 " jng_alpha_filter_method: %3d",
4177 jng_alpha_filter_method);
4179 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4180 " jng_alpha_interlace_method: %3d",
4181 jng_alpha_interlace_method);
4186 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4192 if ((reading_idat == MagickFalse) && (read_JSEP == MagickFalse) &&
4193 ((memcmp(type,mng_JDAT,4) == 0) || (memcmp(type,mng_JdAA,4) == 0) ||
4194 (memcmp(type,mng_IDAT,4) == 0) || (memcmp(type,mng_JDAA,4) == 0)))
4197 o create color_image
4198 o open color_blob, attached to color_image
4199 o if (color type has alpha)
4200 open alpha_blob, attached to alpha_image
4203 color_image_info=(ImageInfo *)AcquireMagickMemory(sizeof(ImageInfo));
4205 if (color_image_info == (ImageInfo *) NULL)
4206 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
4208 GetImageInfo(color_image_info);
4209 color_image=AcquireImage(color_image_info,exception);
4211 if (color_image == (Image *) NULL)
4212 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
4214 if (logging != MagickFalse)
4215 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4216 " Creating color_blob.");
4218 (void) AcquireUniqueFilename(color_image->filename);
4219 status=OpenBlob(color_image_info,color_image,WriteBinaryBlobMode,
4222 if (status == MagickFalse)
4223 return((Image *) NULL);
4225 if ((image_info->ping == MagickFalse) && (jng_color_type >= 12))
4227 alpha_image_info=(ImageInfo *)
4228 AcquireMagickMemory(sizeof(ImageInfo));
4230 if (alpha_image_info == (ImageInfo *) NULL)
4231 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
4233 GetImageInfo(alpha_image_info);
4234 alpha_image=AcquireImage(alpha_image_info,exception);
4236 if (alpha_image == (Image *) NULL)
4238 alpha_image=DestroyImage(alpha_image);
4239 ThrowReaderException(ResourceLimitError,
4240 "MemoryAllocationFailed");
4243 if (logging != MagickFalse)
4244 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4245 " Creating alpha_blob.");
4247 (void) AcquireUniqueFilename(alpha_image->filename);
4248 status=OpenBlob(alpha_image_info,alpha_image,WriteBinaryBlobMode,
4251 if (status == MagickFalse)
4252 return((Image *) NULL);
4254 if (jng_alpha_compression_method == 0)
4259 if (logging != MagickFalse)
4260 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4261 " Writing IHDR chunk to alpha_blob.");
4263 (void) WriteBlob(alpha_image,8,(const unsigned char *)
4264 "\211PNG\r\n\032\n");
4266 (void) WriteBlobMSBULong(alpha_image,13L);
4267 PNGType(data,mng_IHDR);
4268 LogPNGChunk(logging,mng_IHDR,13L);
4269 PNGLong(data+4,jng_width);
4270 PNGLong(data+8,jng_height);
4271 data[12]=jng_alpha_sample_depth;
4272 data[13]=0; /* color_type gray */
4273 data[14]=0; /* compression method 0 */
4274 data[15]=0; /* filter_method 0 */
4275 data[16]=0; /* interlace_method 0 */
4276 (void) WriteBlob(alpha_image,17,data);
4277 (void) WriteBlobMSBULong(alpha_image,crc32(0,data,17));
4280 reading_idat=MagickTrue;
4283 if (memcmp(type,mng_JDAT,4) == 0)
4285 /* Copy chunk to color_image->blob */
4287 if (logging != MagickFalse)
4288 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4289 " Copying JDAT chunk data to color_blob.");
4291 (void) WriteBlob(color_image,length,chunk);
4294 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4299 if (memcmp(type,mng_IDAT,4) == 0)
4304 /* Copy IDAT header and chunk data to alpha_image->blob */
4306 if (image_info->ping == MagickFalse)
4308 if (logging != MagickFalse)
4309 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4310 " Copying IDAT chunk data to alpha_blob.");
4312 (void) WriteBlobMSBULong(alpha_image,(size_t) length);
4313 PNGType(data,mng_IDAT);
4314 LogPNGChunk(logging,mng_IDAT,length);
4315 (void) WriteBlob(alpha_image,4,data);
4316 (void) WriteBlob(alpha_image,length,chunk);
4317 (void) WriteBlobMSBULong(alpha_image,
4318 crc32(crc32(0,data,4),chunk,(uInt) length));
4322 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4327 if ((memcmp(type,mng_JDAA,4) == 0) || (memcmp(type,mng_JdAA,4) == 0))
4329 /* Copy chunk data to alpha_image->blob */
4331 if (image_info->ping == MagickFalse)
4333 if (logging != MagickFalse)
4334 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4335 " Copying JDAA chunk data to alpha_blob.");
4337 (void) WriteBlob(alpha_image,length,chunk);
4341 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4346 if (memcmp(type,mng_JSEP,4) == 0)
4348 read_JSEP=MagickTrue;
4351 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4356 if (memcmp(type,mng_bKGD,4) == 0)
4360 image->background_color.red=ScaleCharToQuantum(p[1]);
4361 image->background_color.green=image->background_color.red;
4362 image->background_color.blue=image->background_color.red;
4367 image->background_color.red=ScaleCharToQuantum(p[1]);
4368 image->background_color.green=ScaleCharToQuantum(p[3]);
4369 image->background_color.blue=ScaleCharToQuantum(p[5]);
4372 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4376 if (memcmp(type,mng_gAMA,4) == 0)
4379 image->gamma=((float) mng_get_long(p))*0.00001;
4381 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4385 if (memcmp(type,mng_cHRM,4) == 0)
4389 image->chromaticity.white_point.x=0.00001*mng_get_long(p);
4390 image->chromaticity.white_point.y=0.00001*mng_get_long(&p[4]);
4391 image->chromaticity.red_primary.x=0.00001*mng_get_long(&p[8]);
4392 image->chromaticity.red_primary.y=0.00001*mng_get_long(&p[12]);
4393 image->chromaticity.green_primary.x=0.00001*mng_get_long(&p[16]);
4394 image->chromaticity.green_primary.y=0.00001*mng_get_long(&p[20]);
4395 image->chromaticity.blue_primary.x=0.00001*mng_get_long(&p[24]);
4396 image->chromaticity.blue_primary.y=0.00001*mng_get_long(&p[28]);
4399 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4403 if (memcmp(type,mng_sRGB,4) == 0)
4407 image->rendering_intent=
4408 Magick_RenderingIntent_from_PNG_RenderingIntent(p[0]);
4409 image->gamma=1.000f/2.200f;
4410 image->chromaticity.red_primary.x=0.6400f;
4411 image->chromaticity.red_primary.y=0.3300f;
4412 image->chromaticity.green_primary.x=0.3000f;
4413 image->chromaticity.green_primary.y=0.6000f;
4414 image->chromaticity.blue_primary.x=0.1500f;
4415 image->chromaticity.blue_primary.y=0.0600f;
4416 image->chromaticity.white_point.x=0.3127f;
4417 image->chromaticity.white_point.y=0.3290f;
4420 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4424 if (memcmp(type,mng_oFFs,4) == 0)
4428 image->page.x=(ssize_t) mng_get_long(p);
4429 image->page.y=(ssize_t) mng_get_long(&p[4]);
4431 if ((int) p[8] != 0)
4433 image->page.x/=10000;
4434 image->page.y/=10000;
4439 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4444 if (memcmp(type,mng_pHYs,4) == 0)
4448 image->resolution.x=(double) mng_get_long(p);
4449 image->resolution.y=(double) mng_get_long(&p[4]);
4450 if ((int) p[8] == PNG_RESOLUTION_METER)
4452 image->units=PixelsPerCentimeterResolution;
4453 image->resolution.x=image->resolution.x/100.0f;
4454 image->resolution.y=image->resolution.y/100.0f;
4458 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4463 if (memcmp(type,mng_iCCP,4) == 0)
4467 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4474 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4476 if (memcmp(type,mng_IEND,4))
4486 Finish up reading image data:
4488 o read main image from color_blob.
4492 o if (color_type has alpha)
4493 if alpha_encoding is PNG
4494 read secondary image from alpha_blob via ReadPNG
4495 if alpha_encoding is JPEG
4496 read secondary image from alpha_blob via ReadJPEG
4500 o copy intensity of secondary image into
4501 alpha samples of main image.
4503 o destroy the secondary image.
4506 (void) CloseBlob(color_image);
4508 if (logging != MagickFalse)
4509 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4510 " Reading jng_image from color_blob.");
4512 (void) FormatLocaleString(color_image_info->filename,MaxTextExtent,"%s",
4513 color_image->filename);
4515 color_image_info->ping=MagickFalse; /* To do: avoid this */
4516 jng_image=ReadImage(color_image_info,exception);
4518 if (jng_image == (Image *) NULL)
4519 return((Image *) NULL);
4521 (void) RelinquishUniqueFileResource(color_image->filename);
4522 color_image=DestroyImage(color_image);
4523 color_image_info=DestroyImageInfo(color_image_info);
4525 if (jng_image == (Image *) NULL)
4526 return((Image *) NULL);
4528 if (logging != MagickFalse)
4529 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4530 " Copying jng_image pixels to main image.");
4532 image->rows=jng_height;
4533 image->columns=jng_width;
4535 for (y=0; y < (ssize_t) image->rows; y++)
4537 s=GetVirtualPixels(jng_image,0,y,image->columns,1,exception);
4538 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
4539 for (x=(ssize_t) image->columns; x != 0; x--)
4541 SetPixelRed(image,GetPixelRed(jng_image,s),q);
4542 SetPixelGreen(image,GetPixelGreen(jng_image,s),q);
4543 SetPixelBlue(image,GetPixelBlue(jng_image,s),q);
4544 q+=GetPixelChannels(image);
4545 s+=GetPixelChannels(jng_image);
4548 if (SyncAuthenticPixels(image,exception) == MagickFalse)
4552 jng_image=DestroyImage(jng_image);
4554 if (image_info->ping == MagickFalse)
4556 if (jng_color_type >= 12)
4558 if (jng_alpha_compression_method == 0)
4562 (void) WriteBlobMSBULong(alpha_image,0x00000000L);
4563 PNGType(data,mng_IEND);
4564 LogPNGChunk(logging,mng_IEND,0L);
4565 (void) WriteBlob(alpha_image,4,data);
4566 (void) WriteBlobMSBULong(alpha_image,crc32(0,data,4));
4569 (void) CloseBlob(alpha_image);
4571 if (logging != MagickFalse)
4572 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4573 " Reading alpha from alpha_blob.");
4575 (void) FormatLocaleString(alpha_image_info->filename,MaxTextExtent,
4576 "%s",alpha_image->filename);
4578 jng_image=ReadImage(alpha_image_info,exception);
4580 if (jng_image != (Image *) NULL)
4581 for (y=0; y < (ssize_t) image->rows; y++)
4583 s=GetVirtualPixels(jng_image,0,y,image->columns,1,
4585 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
4587 if (image->alpha_trait == BlendPixelTrait)
4588 for (x=(ssize_t) image->columns; x != 0; x--)
4590 SetPixelAlpha(image,GetPixelRed(jng_image,s),q);
4591 q+=GetPixelChannels(image);
4592 s+=GetPixelChannels(jng_image);
4596 for (x=(ssize_t) image->columns; x != 0; x--)
4598 SetPixelAlpha(image,GetPixelRed(jng_image,s),q);
4599 if (GetPixelAlpha(image,q) != OpaqueAlpha)
4600 image->alpha_trait=BlendPixelTrait;
4601 q+=GetPixelChannels(image);
4602 s+=GetPixelChannels(jng_image);
4605 if (SyncAuthenticPixels(image,exception) == MagickFalse)
4608 (void) RelinquishUniqueFileResource(alpha_image->filename);
4609 alpha_image=DestroyImage(alpha_image);
4610 alpha_image_info=DestroyImageInfo(alpha_image_info);
4611 if (jng_image != (Image *) NULL)
4612 jng_image=DestroyImage(jng_image);
4616 /* Read the JNG image. */
4618 if (mng_info->mng_type == 0)
4620 mng_info->mng_width=jng_width;
4621 mng_info->mng_height=jng_height;
4624 if (image->page.width == 0 && image->page.height == 0)
4626 image->page.width=jng_width;
4627 image->page.height=jng_height;
4630 if (image->page.x == 0 && image->page.y == 0)
4632 image->page.x=mng_info->x_off[mng_info->object_id];
4633 image->page.y=mng_info->y_off[mng_info->object_id];
4638 image->page.y=mng_info->y_off[mng_info->object_id];
4641 mng_info->image_found++;
4642 status=SetImageProgress(image,LoadImagesTag,2*TellBlob(image),
4643 2*GetBlobSize(image));
4645 if (logging != MagickFalse)
4646 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4647 " exit ReadOneJNGImage()");
4653 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4657 % R e a d J N G I m a g e %
4661 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4663 % ReadJNGImage() reads a JPEG Network Graphics (JNG) image file
4664 % (including the 8-byte signature) and returns it. It allocates the memory
4665 % necessary for the new Image structure and returns a pointer to the new
4668 % JNG support written by Glenn Randers-Pehrson, glennrp@image...
4670 % The format of the ReadJNGImage method is:
4672 % Image *ReadJNGImage(const ImageInfo *image_info, ExceptionInfo
4675 % A description of each parameter follows:
4677 % o image_info: the image info.
4679 % o exception: return any errors or warnings in this structure.
4683 static Image *ReadJNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
4698 magic_number[MaxTextExtent];
4706 assert(image_info != (const ImageInfo *) NULL);
4707 assert(image_info->signature == MagickSignature);
4708 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image_info->filename);
4709 assert(exception != (ExceptionInfo *) NULL);
4710 assert(exception->signature == MagickSignature);
4711 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter ReadJNGImage()");
4712 image=AcquireImage(image_info,exception);
4713 mng_info=(MngInfo *) NULL;
4714 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
4716 if (status == MagickFalse)
4717 return((Image *) NULL);
4719 if (LocaleCompare(image_info->magick,"JNG") != 0)
4720 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
4722 /* Verify JNG signature. */
4724 count=(size_t) ReadBlob(image,8,(unsigned char *) magic_number);
4726 if (count < 8 || memcmp(magic_number,"\213JNG\r\n\032\n",8) != 0)
4727 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
4729 /* Allocate a MngInfo structure. */
4731 have_mng_structure=MagickFalse;
4732 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(*mng_info));
4734 if (mng_info == (MngInfo *) NULL)
4735 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
4737 /* Initialize members of the MngInfo structure. */
4739 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
4740 have_mng_structure=MagickTrue;
4742 mng_info->image=image;
4744 image=ReadOneJNGImage(mng_info,image_info,exception);
4745 MngInfoFreeStruct(mng_info,&have_mng_structure);
4747 if (image == (Image *) NULL)
4749 if (IsImageObject(previous) != MagickFalse)
4751 (void) CloseBlob(previous);
4752 (void) DestroyImageList(previous);
4755 if (logging != MagickFalse)
4756 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4757 "exit ReadJNGImage() with error");
4759 return((Image *) NULL);
4761 (void) CloseBlob(image);
4763 if (image->columns == 0 || image->rows == 0)
4765 if (logging != MagickFalse)
4766 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4767 "exit ReadJNGImage() with error");
4769 ThrowReaderException(CorruptImageError,"CorruptImage");
4772 if (logging != MagickFalse)
4773 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit ReadJNGImage()");
4779 static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
4782 page_geometry[MaxTextExtent];
4815 #if defined(MNG_INSERT_LAYERS)
4817 mng_background_color;
4820 register unsigned char
4835 #if defined(MNG_INSERT_LAYERS)
4840 volatile unsigned int
4841 #ifdef MNG_OBJECT_BUFFERS
4842 mng_background_object=0,
4844 mng_type=0; /* 0: PNG or JNG; 1: MNG; 2: MNG-LC; 3: MNG-VLC */
4847 default_frame_timeout,
4849 #if defined(MNG_INSERT_LAYERS)
4855 /* These delays are all measured in image ticks_per_second,
4856 * not in MNG ticks_per_second
4859 default_frame_delay,
4863 #if defined(MNG_INSERT_LAYERS)
4872 previous_fb.bottom=0;
4874 previous_fb.right=0;
4876 default_fb.bottom=0;
4880 /* Open image file. */
4882 assert(image_info != (const ImageInfo *) NULL);
4883 assert(image_info->signature == MagickSignature);
4884 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image_info->filename);
4885 assert(exception != (ExceptionInfo *) NULL);
4886 assert(exception->signature == MagickSignature);
4887 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter ReadMNGImage()");
4888 image=AcquireImage(image_info,exception);
4889 mng_info=(MngInfo *) NULL;
4890 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
4892 if (status == MagickFalse)
4893 return((Image *) NULL);
4895 first_mng_object=MagickFalse;
4897 have_mng_structure=MagickFalse;
4899 /* Allocate a MngInfo structure. */
4901 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
4903 if (mng_info == (MngInfo *) NULL)
4904 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
4906 /* Initialize members of the MngInfo structure. */
4908 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
4909 mng_info->image=image;
4910 have_mng_structure=MagickTrue;
4912 if (LocaleCompare(image_info->magick,"MNG") == 0)
4915 magic_number[MaxTextExtent];
4917 /* Verify MNG signature. */
4918 count=(size_t) ReadBlob(image,8,(unsigned char *) magic_number);
4919 if (memcmp(magic_number,"\212MNG\r\n\032\n",8) != 0)
4920 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
4922 /* Initialize some nonzero members of the MngInfo structure. */
4923 for (i=0; i < MNG_MAX_OBJECTS; i++)
4925 mng_info->object_clip[i].right=(ssize_t) PNG_UINT_31_MAX;
4926 mng_info->object_clip[i].bottom=(ssize_t) PNG_UINT_31_MAX;
4928 mng_info->exists[0]=MagickTrue;
4931 first_mng_object=MagickTrue;
4933 #if defined(MNG_INSERT_LAYERS)
4934 insert_layers=MagickFalse; /* should be False when converting or mogrifying */
4936 default_frame_delay=0;
4937 default_frame_timeout=0;
4940 mng_info->ticks_per_second=1UL*image->ticks_per_second;
4942 skip_to_iend=MagickFalse;
4943 term_chunk_found=MagickFalse;
4944 mng_info->framing_mode=1;
4945 #if defined(MNG_INSERT_LAYERS)
4946 mandatory_back=MagickFalse;
4948 #if defined(MNG_INSERT_LAYERS)
4949 mng_background_color=image->background_color;
4951 default_fb=mng_info->frame;
4952 previous_fb=mng_info->frame;
4956 type[MaxTextExtent];
4958 if (LocaleCompare(image_info->magick,"MNG") == 0)
4967 (void) ConcatenateMagickString(type,"errr",MaxTextExtent);
4968 length=ReadBlobMSBLong(image);
4969 count=(size_t) ReadBlob(image,4,(unsigned char *) type);
4971 if (logging != MagickFalse)
4972 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4973 " Reading MNG chunk type %c%c%c%c, length: %.20g",
4974 type[0],type[1],type[2],type[3],(double) length);
4976 if (length > PNG_UINT_31_MAX)
4980 ThrowReaderException(CorruptImageError,"CorruptImage");
4983 chunk=(unsigned char *) NULL;
4987 chunk=(unsigned char *) AcquireQuantumMemory(length,sizeof(*chunk));
4989 if (chunk == (unsigned char *) NULL)
4990 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
4992 for (i=0; i < (ssize_t) length; i++)
4993 chunk[i]=(unsigned char) ReadBlobByte(image);
4998 (void) ReadBlobMSBLong(image); /* read crc word */
5000 #if !defined(JNG_SUPPORTED)
5001 if (memcmp(type,mng_JHDR,4) == 0)
5003 skip_to_iend=MagickTrue;
5005 if (mng_info->jhdr_warning == 0)
5006 (void) ThrowMagickException(exception,GetMagickModule(),
5007 CoderError,"JNGCompressNotSupported","`%s'",image->filename);
5009 mng_info->jhdr_warning++;
5012 if (memcmp(type,mng_DHDR,4) == 0)
5014 skip_to_iend=MagickTrue;
5016 if (mng_info->dhdr_warning == 0)
5017 (void) ThrowMagickException(exception,GetMagickModule(),
5018 CoderError,"DeltaPNGNotSupported","`%s'",image->filename);
5020 mng_info->dhdr_warning++;
5022 if (memcmp(type,mng_MEND,4) == 0)
5027 if (memcmp(type,mng_IEND,4) == 0)
5028 skip_to_iend=MagickFalse;
5031 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5033 if (logging != MagickFalse)
5034 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5040 if (memcmp(type,mng_MHDR,4) == 0)
5042 mng_info->mng_width=(size_t) ((p[0] << 24) | (p[1] << 16) |
5043 (p[2] << 8) | p[3]);
5045 mng_info->mng_height=(size_t) ((p[4] << 24) | (p[5] << 16) |
5046 (p[6] << 8) | p[7]);
5048 if (logging != MagickFalse)
5050 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5051 " MNG width: %.20g",(double) mng_info->mng_width);
5052 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5053 " MNG height: %.20g",(double) mng_info->mng_height);
5057 mng_info->ticks_per_second=(size_t) mng_get_long(p);
5059 if (mng_info->ticks_per_second == 0)
5060 default_frame_delay=0;
5063 default_frame_delay=1UL*image->ticks_per_second/
5064 mng_info->ticks_per_second;
5066 frame_delay=default_frame_delay;
5072 simplicity=(size_t) mng_get_long(p);
5075 mng_type=1; /* Full MNG */
5077 if ((simplicity != 0) && ((simplicity | 11) == 11))
5078 mng_type=2; /* LC */
5080 if ((simplicity != 0) && ((simplicity | 9) == 9))
5081 mng_type=3; /* VLC */
5083 #if defined(MNG_INSERT_LAYERS)
5085 insert_layers=MagickTrue;
5087 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
5089 /* Allocate next image structure. */
5090 AcquireNextImage(image_info,image,exception);
5092 if (GetNextImageInList(image) == (Image *) NULL)
5093 return((Image *) NULL);
5095 image=SyncNextImageInList(image);
5096 mng_info->image=image;
5099 if ((mng_info->mng_width > 65535L) ||
5100 (mng_info->mng_height > 65535L))
5101 ThrowReaderException(ImageError,"WidthOrHeightExceedsLimit");
5103 (void) FormatLocaleString(page_geometry,MaxTextExtent,
5104 "%.20gx%.20g+0+0",(double) mng_info->mng_width,(double)
5105 mng_info->mng_height);
5107 mng_info->frame.left=0;
5108 mng_info->frame.right=(ssize_t) mng_info->mng_width;
5109 mng_info->frame.top=0;
5110 mng_info->frame.bottom=(ssize_t) mng_info->mng_height;
5111 mng_info->clip=default_fb=previous_fb=mng_info->frame;
5113 for (i=0; i < MNG_MAX_OBJECTS; i++)
5114 mng_info->object_clip[i]=mng_info->frame;
5116 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5120 if (memcmp(type,mng_TERM,4) == 0)
5131 final_delay=(png_uint_32) mng_get_long(&p[2]);
5132 mng_iterations=(png_uint_32) mng_get_long(&p[6]);
5134 if (mng_iterations == PNG_UINT_31_MAX)
5137 image->iterations=mng_iterations;
5138 term_chunk_found=MagickTrue;
5141 if (logging != MagickFalse)
5143 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5144 " repeat=%d",repeat);
5146 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5147 " final_delay=%.20g",(double) final_delay);
5149 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5150 " image->iterations=%.20g",(double) image->iterations);
5153 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5156 if (memcmp(type,mng_DEFI,4) == 0)
5159 (void) ThrowMagickException(exception,GetMagickModule(),
5160 CoderError,"DEFI chunk found in MNG-VLC datastream","`%s'",
5163 object_id=(p[0] << 8) | p[1];
5165 if (mng_type == 2 && object_id != 0)
5166 (void) ThrowMagickException(exception,GetMagickModule(),
5167 CoderError,"Nonzero object_id in MNG-LC datastream","`%s'",
5170 if (object_id > MNG_MAX_OBJECTS)
5173 Instead of using a warning we should allocate a larger
5174 MngInfo structure and continue.
5176 (void) ThrowMagickException(exception,GetMagickModule(),
5177 CoderError,"object id too large","`%s'",image->filename);
5178 object_id=MNG_MAX_OBJECTS;
5181 if (mng_info->exists[object_id])
5182 if (mng_info->frozen[object_id])
5184 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5185 (void) ThrowMagickException(exception,
5186 GetMagickModule(),CoderError,
5187 "DEFI cannot redefine a frozen MNG object","`%s'",
5192 mng_info->exists[object_id]=MagickTrue;
5195 mng_info->invisible[object_id]=p[2];
5198 Extract object offset info.
5202 mng_info->x_off[object_id]=(ssize_t) ((p[4] << 24) |
5203 (p[5] << 16) | (p[6] << 8) | p[7]);
5205 mng_info->y_off[object_id]=(ssize_t) ((p[8] << 24) |
5206 (p[9] << 16) | (p[10] << 8) | p[11]);
5208 if (logging != MagickFalse)
5210 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5211 " x_off[%d]: %.20g",object_id,(double)
5212 mng_info->x_off[object_id]);
5214 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5215 " y_off[%d]: %.20g",object_id,(double)
5216 mng_info->y_off[object_id]);
5221 Extract object clipping info.
5224 mng_info->object_clip[object_id]=mng_read_box(mng_info->frame,0,
5227 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5230 if (memcmp(type,mng_bKGD,4) == 0)
5232 mng_info->have_global_bkgd=MagickFalse;
5236 mng_info->mng_global_bkgd.red=
5237 ScaleShortToQuantum((unsigned short) ((p[0] << 8) | p[1]));
5239 mng_info->mng_global_bkgd.green=
5240 ScaleShortToQuantum((unsigned short) ((p[2] << 8) | p[3]));
5242 mng_info->mng_global_bkgd.blue=
5243 ScaleShortToQuantum((unsigned short) ((p[4] << 8) | p[5]));
5245 mng_info->have_global_bkgd=MagickTrue;
5248 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5251 if (memcmp(type,mng_BACK,4) == 0)
5253 #if defined(MNG_INSERT_LAYERS)
5255 mandatory_back=p[6];
5260 if (mandatory_back && length > 5)
5262 mng_background_color.red=
5263 ScaleShortToQuantum((unsigned short) ((p[0] << 8) | p[1]));
5265 mng_background_color.green=
5266 ScaleShortToQuantum((unsigned short) ((p[2] << 8) | p[3]));
5268 mng_background_color.blue=
5269 ScaleShortToQuantum((unsigned short) ((p[4] << 8) | p[5]));
5271 mng_background_color.alpha=OpaqueAlpha;
5274 #ifdef MNG_OBJECT_BUFFERS
5276 mng_background_object=(p[7] << 8) | p[8];
5279 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5283 if (memcmp(type,mng_PLTE,4) == 0)
5285 /* Read global PLTE. */
5287 if (length && (length < 769))
5289 if (mng_info->global_plte == (png_colorp) NULL)
5290 mng_info->global_plte=(png_colorp) AcquireQuantumMemory(256,
5291 sizeof(*mng_info->global_plte));
5293 for (i=0; i < (ssize_t) (length/3); i++)
5295 mng_info->global_plte[i].red=p[3*i];
5296 mng_info->global_plte[i].green=p[3*i+1];
5297 mng_info->global_plte[i].blue=p[3*i+2];
5300 mng_info->global_plte_length=(unsigned int) (length/3);
5303 for ( ; i < 256; i++)
5305 mng_info->global_plte[i].red=i;
5306 mng_info->global_plte[i].green=i;
5307 mng_info->global_plte[i].blue=i;
5311 mng_info->global_plte_length=256;
5314 mng_info->global_plte_length=0;
5316 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5320 if (memcmp(type,mng_tRNS,4) == 0)
5322 /* read global tRNS */
5325 for (i=0; i < (ssize_t) length; i++)
5326 mng_info->global_trns[i]=p[i];
5329 for ( ; i < 256; i++)
5330 mng_info->global_trns[i]=255;
5332 mng_info->global_trns_length=(unsigned int) length;
5333 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5336 if (memcmp(type,mng_gAMA,4) == 0)
5343 igamma=mng_get_long(p);
5344 mng_info->global_gamma=((float) igamma)*0.00001;
5345 mng_info->have_global_gama=MagickTrue;
5349 mng_info->have_global_gama=MagickFalse;
5351 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5355 if (memcmp(type,mng_cHRM,4) == 0)
5357 /* Read global cHRM */
5361 mng_info->global_chrm.white_point.x=0.00001*mng_get_long(p);
5362 mng_info->global_chrm.white_point.y=0.00001*mng_get_long(&p[4]);
5363 mng_info->global_chrm.red_primary.x=0.00001*mng_get_long(&p[8]);
5364 mng_info->global_chrm.red_primary.y=0.00001*
5365 mng_get_long(&p[12]);
5366 mng_info->global_chrm.green_primary.x=0.00001*
5367 mng_get_long(&p[16]);
5368 mng_info->global_chrm.green_primary.y=0.00001*
5369 mng_get_long(&p[20]);
5370 mng_info->global_chrm.blue_primary.x=0.00001*
5371 mng_get_long(&p[24]);
5372 mng_info->global_chrm.blue_primary.y=0.00001*
5373 mng_get_long(&p[28]);
5374 mng_info->have_global_chrm=MagickTrue;
5377 mng_info->have_global_chrm=MagickFalse;
5379 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5383 if (memcmp(type,mng_sRGB,4) == 0)
5390 mng_info->global_srgb_intent=
5391 Magick_RenderingIntent_from_PNG_RenderingIntent(p[0]);
5392 mng_info->have_global_srgb=MagickTrue;
5395 mng_info->have_global_srgb=MagickFalse;
5397 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5401 if (memcmp(type,mng_iCCP,4) == 0)
5409 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5414 if (memcmp(type,mng_FRAM,4) == 0)
5417 (void) ThrowMagickException(exception,GetMagickModule(),
5418 CoderError,"FRAM chunk found in MNG-VLC datastream","`%s'",
5421 if ((mng_info->framing_mode == 2) || (mng_info->framing_mode == 4))
5422 image->delay=frame_delay;
5424 frame_delay=default_frame_delay;
5425 frame_timeout=default_frame_timeout;
5430 mng_info->framing_mode=p[0];
5432 if (logging != MagickFalse)
5433 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5434 " Framing_mode=%d",mng_info->framing_mode);
5438 /* Note the delay and frame clipping boundaries. */
5440 p++; /* framing mode */
5442 while (*p && ((p-chunk) < (ssize_t) length))
5443 p++; /* frame name */
5445 p++; /* frame name terminator */
5447 if ((p-chunk) < (ssize_t) (length-4))
5454 change_delay=(*p++);
5455 change_timeout=(*p++);
5456 change_clipping=(*p++);
5457 p++; /* change_sync */
5461 frame_delay=1UL*image->ticks_per_second*
5464 if (mng_info->ticks_per_second != 0)
5465 frame_delay/=mng_info->ticks_per_second;
5468 frame_delay=PNG_UINT_31_MAX;
5470 if (change_delay == 2)
5471 default_frame_delay=frame_delay;
5475 if (logging != MagickFalse)
5476 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5477 " Framing_delay=%.20g",(double) frame_delay);
5482 frame_timeout=1UL*image->ticks_per_second*
5485 if (mng_info->ticks_per_second != 0)
5486 frame_timeout/=mng_info->ticks_per_second;
5489 frame_timeout=PNG_UINT_31_MAX;
5491 if (change_delay == 2)
5492 default_frame_timeout=frame_timeout;
5496 if (logging != MagickFalse)
5497 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5498 " Framing_timeout=%.20g",(double) frame_timeout);
5501 if (change_clipping)
5503 fb=mng_read_box(previous_fb,(char) p[0],&p[1]);
5507 if (logging != MagickFalse)
5508 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5509 " Frame_clip: L=%.20g R=%.20g T=%.20g B=%.20g",
5510 (double) fb.left,(double) fb.right,(double) fb.top,
5511 (double) fb.bottom);
5513 if (change_clipping == 2)
5519 mng_info->clip=mng_minimum_box(fb,mng_info->frame);
5521 subframe_width=(size_t) (mng_info->clip.right
5522 -mng_info->clip.left);
5524 subframe_height=(size_t) (mng_info->clip.bottom
5525 -mng_info->clip.top);
5527 Insert a background layer behind the frame if framing_mode is 4.
5529 #if defined(MNG_INSERT_LAYERS)
5530 if (logging != MagickFalse)
5531 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5532 " subframe_width=%.20g, subframe_height=%.20g",(double)
5533 subframe_width,(double) subframe_height);
5535 if (insert_layers && (mng_info->framing_mode == 4) &&
5536 (subframe_width) && (subframe_height))
5538 /* Allocate next image structure. */
5539 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
5541 AcquireNextImage(image_info,image,exception);
5543 if (GetNextImageInList(image) == (Image *) NULL)
5545 image=DestroyImageList(image);
5546 MngInfoFreeStruct(mng_info,&have_mng_structure);
5547 return((Image *) NULL);
5550 image=SyncNextImageInList(image);
5553 mng_info->image=image;
5555 if (term_chunk_found)
5557 image->start_loop=MagickTrue;
5558 image->iterations=mng_iterations;
5559 term_chunk_found=MagickFalse;
5563 image->start_loop=MagickFalse;
5565 image->columns=subframe_width;
5566 image->rows=subframe_height;
5567 image->page.width=subframe_width;
5568 image->page.height=subframe_height;
5569 image->page.x=mng_info->clip.left;
5570 image->page.y=mng_info->clip.top;
5571 image->background_color=mng_background_color;
5572 image->alpha_trait=UndefinedPixelTrait;
5574 (void) SetImageBackgroundColor(image,exception);
5576 if (logging != MagickFalse)
5577 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5578 " Insert backgd layer, L=%.20g, R=%.20g T=%.20g, B=%.20g",
5579 (double) mng_info->clip.left,(double) mng_info->clip.right,
5580 (double) mng_info->clip.top,(double) mng_info->clip.bottom);
5583 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5586 if (memcmp(type,mng_CLIP,4) == 0)
5595 first_object=(p[0] << 8) | p[1];
5596 last_object=(p[2] << 8) | p[3];
5598 for (i=(int) first_object; i <= (int) last_object; i++)
5600 if (mng_info->exists[i] && !mng_info->frozen[i])
5605 box=mng_info->object_clip[i];
5606 mng_info->object_clip[i]=mng_read_box(box,(char) p[4],&p[5]);
5610 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5613 if (memcmp(type,mng_SAVE,4) == 0)
5615 for (i=1; i < MNG_MAX_OBJECTS; i++)
5616 if (mng_info->exists[i])
5618 mng_info->frozen[i]=MagickTrue;
5619 #ifdef MNG_OBJECT_BUFFERS
5620 if (mng_info->ob[i] != (MngBuffer *) NULL)
5621 mng_info->ob[i]->frozen=MagickTrue;
5626 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5631 if ((memcmp(type,mng_DISC,4) == 0) || (memcmp(type,mng_SEEK,4) == 0))
5633 /* Read DISC or SEEK. */
5635 if ((length == 0) || !memcmp(type,mng_SEEK,4))
5637 for (i=1; i < MNG_MAX_OBJECTS; i++)
5638 MngInfoDiscardObject(mng_info,i);
5646 for (j=0; j < (ssize_t) length; j+=2)
5648 i=p[j] << 8 | p[j+1];
5649 MngInfoDiscardObject(mng_info,i);
5654 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5659 if (memcmp(type,mng_MOVE,4) == 0)
5667 first_object=(p[0] << 8) | p[1];
5668 last_object=(p[2] << 8) | p[3];
5669 for (i=(ssize_t) first_object; i <= (ssize_t) last_object; i++)
5671 if (mng_info->exists[i] && !mng_info->frozen[i])
5679 old_pair.a=mng_info->x_off[i];
5680 old_pair.b=mng_info->y_off[i];
5681 new_pair=mng_read_pair(old_pair,(int) p[4],&p[5]);
5682 mng_info->x_off[i]=new_pair.a;
5683 mng_info->y_off[i]=new_pair.b;
5687 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5691 if (memcmp(type,mng_LOOP,4) == 0)
5693 ssize_t loop_iters=1;
5694 loop_level=chunk[0];
5695 mng_info->loop_active[loop_level]=1; /* mark loop active */
5697 /* Record starting point. */
5698 loop_iters=mng_get_long(&chunk[1]);
5700 if (logging != MagickFalse)
5701 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5702 " LOOP level %.20g has %.20g iterations ",(double) loop_level,
5703 (double) loop_iters);
5705 if (loop_iters == 0)
5706 skipping_loop=loop_level;
5710 mng_info->loop_jump[loop_level]=TellBlob(image);
5711 mng_info->loop_count[loop_level]=loop_iters;
5714 mng_info->loop_iteration[loop_level]=0;
5715 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5719 if (memcmp(type,mng_ENDL,4) == 0)
5721 loop_level=chunk[0];
5723 if (skipping_loop > 0)
5725 if (skipping_loop == loop_level)
5728 Found end of zero-iteration loop.
5731 mng_info->loop_active[loop_level]=0;
5737 if (mng_info->loop_active[loop_level] == 1)
5739 mng_info->loop_count[loop_level]--;
5740 mng_info->loop_iteration[loop_level]++;
5742 if (logging != MagickFalse)
5743 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5744 " ENDL: LOOP level %.20g has %.20g remaining iters ",
5745 (double) loop_level,(double)
5746 mng_info->loop_count[loop_level]);
5748 if (mng_info->loop_count[loop_level] != 0)
5750 offset=SeekBlob(image,mng_info->loop_jump[loop_level],
5754 ThrowReaderException(CorruptImageError,
5755 "ImproperImageHeader");
5766 mng_info->loop_active[loop_level]=0;
5768 for (i=0; i < loop_level; i++)
5769 if (mng_info->loop_active[i] == 1)
5770 last_level=(short) i;
5771 loop_level=last_level;
5776 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5780 if (memcmp(type,mng_CLON,4) == 0)
5782 if (mng_info->clon_warning == 0)
5783 (void) ThrowMagickException(exception,GetMagickModule(),
5784 CoderError,"CLON is not implemented yet","`%s'",
5787 mng_info->clon_warning++;
5790 if (memcmp(type,mng_MAGN,4) == 0)
5805 magn_first=(p[0] << 8) | p[1];
5811 magn_last=(p[2] << 8) | p[3];
5814 magn_last=magn_first;
5815 #ifndef MNG_OBJECT_BUFFERS
5816 if (magn_first || magn_last)
5817 if (mng_info->magn_warning == 0)
5819 (void) ThrowMagickException(exception,
5820 GetMagickModule(),CoderError,
5821 "MAGN is not implemented yet for nonzero objects",
5822 "`%s'",image->filename);
5824 mng_info->magn_warning++;
5834 magn_mx=(p[5] << 8) | p[6];
5843 magn_my=(p[7] << 8) | p[8];
5852 magn_ml=(p[9] << 8) | p[10];
5861 magn_mr=(p[11] << 8) | p[12];
5870 magn_mt=(p[13] << 8) | p[14];
5879 magn_mb=(p[15] << 8) | p[16];
5891 magn_methy=magn_methx;
5894 if (magn_methx > 5 || magn_methy > 5)
5895 if (mng_info->magn_warning == 0)
5897 (void) ThrowMagickException(exception,
5898 GetMagickModule(),CoderError,
5899 "Unknown MAGN method in MNG datastream","`%s'",
5902 mng_info->magn_warning++;
5904 #ifdef MNG_OBJECT_BUFFERS
5905 /* Magnify existing objects in the range magn_first to magn_last */
5907 if (magn_first == 0 || magn_last == 0)
5909 /* Save the magnification factors for object 0 */
5910 mng_info->magn_mb=magn_mb;
5911 mng_info->magn_ml=magn_ml;
5912 mng_info->magn_mr=magn_mr;
5913 mng_info->magn_mt=magn_mt;
5914 mng_info->magn_mx=magn_mx;
5915 mng_info->magn_my=magn_my;
5916 mng_info->magn_methx=magn_methx;
5917 mng_info->magn_methy=magn_methy;
5921 if (memcmp(type,mng_PAST,4) == 0)
5923 if (mng_info->past_warning == 0)
5924 (void) ThrowMagickException(exception,GetMagickModule(),
5925 CoderError,"PAST is not implemented yet","`%s'",
5928 mng_info->past_warning++;
5931 if (memcmp(type,mng_SHOW,4) == 0)
5933 if (mng_info->show_warning == 0)
5934 (void) ThrowMagickException(exception,GetMagickModule(),
5935 CoderError,"SHOW is not implemented yet","`%s'",
5938 mng_info->show_warning++;
5941 if (memcmp(type,mng_sBIT,4) == 0)
5944 mng_info->have_global_sbit=MagickFalse;
5948 mng_info->global_sbit.gray=p[0];
5949 mng_info->global_sbit.red=p[0];
5950 mng_info->global_sbit.green=p[1];
5951 mng_info->global_sbit.blue=p[2];
5952 mng_info->global_sbit.alpha=p[3];
5953 mng_info->have_global_sbit=MagickTrue;
5956 if (memcmp(type,mng_pHYs,4) == 0)
5960 mng_info->global_x_pixels_per_unit=
5961 (size_t) mng_get_long(p);
5962 mng_info->global_y_pixels_per_unit=
5963 (size_t) mng_get_long(&p[4]);
5964 mng_info->global_phys_unit_type=p[8];
5965 mng_info->have_global_phys=MagickTrue;
5969 mng_info->have_global_phys=MagickFalse;
5971 if (memcmp(type,mng_pHYg,4) == 0)
5973 if (mng_info->phyg_warning == 0)
5974 (void) ThrowMagickException(exception,GetMagickModule(),
5975 CoderError,"pHYg is not implemented.","`%s'",image->filename);
5977 mng_info->phyg_warning++;
5979 if (memcmp(type,mng_BASI,4) == 0)
5981 skip_to_iend=MagickTrue;
5983 if (mng_info->basi_warning == 0)
5984 (void) ThrowMagickException(exception,GetMagickModule(),
5985 CoderError,"BASI is not implemented yet","`%s'",
5988 mng_info->basi_warning++;
5989 #ifdef MNG_BASI_SUPPORTED
5990 basi_width=(size_t) ((p[0] << 24) | (p[1] << 16) |
5991 (p[2] << 8) | p[3]);
5992 basi_height=(size_t) ((p[4] << 24) | (p[5] << 16) |
5993 (p[6] << 8) | p[7]);
5994 basi_color_type=p[8];
5995 basi_compression_method=p[9];
5996 basi_filter_type=p[10];
5997 basi_interlace_method=p[11];
5999 basi_red=(p[12] << 8) & p[13];
6005 basi_green=(p[14] << 8) & p[15];
6011 basi_blue=(p[16] << 8) & p[17];
6017 basi_alpha=(p[18] << 8) & p[19];
6021 if (basi_sample_depth == 16)
6028 basi_viewable=p[20];
6034 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
6038 if (memcmp(type,mng_IHDR,4)
6039 #if defined(JNG_SUPPORTED)
6040 && memcmp(type,mng_JHDR,4)
6044 /* Not an IHDR or JHDR chunk */
6046 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
6051 if (logging != MagickFalse)
6052 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6053 " Processing %c%c%c%c chunk",type[0],type[1],type[2],type[3]);
6055 mng_info->exists[object_id]=MagickTrue;
6056 mng_info->viewable[object_id]=MagickTrue;
6058 if (mng_info->invisible[object_id])
6060 if (logging != MagickFalse)
6061 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6062 " Skipping invisible object");
6064 skip_to_iend=MagickTrue;
6065 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
6068 #if defined(MNG_INSERT_LAYERS)
6070 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
6072 image_width=(size_t) mng_get_long(p);
6073 image_height=(size_t) mng_get_long(&p[4]);
6075 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
6078 Insert a transparent background layer behind the entire animation
6079 if it is not full screen.
6081 #if defined(MNG_INSERT_LAYERS)
6082 if (insert_layers && mng_type && first_mng_object)
6084 if ((mng_info->clip.left > 0) || (mng_info->clip.top > 0) ||
6085 (image_width < mng_info->mng_width) ||
6086 (mng_info->clip.right < (ssize_t) mng_info->mng_width) ||
6087 (image_height < mng_info->mng_height) ||
6088 (mng_info->clip.bottom < (ssize_t) mng_info->mng_height))
6090 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
6093 Allocate next image structure.
6095 AcquireNextImage(image_info,image,exception);
6097 if (GetNextImageInList(image) == (Image *) NULL)
6099 image=DestroyImageList(image);
6100 MngInfoFreeStruct(mng_info,&have_mng_structure);
6101 return((Image *) NULL);
6104 image=SyncNextImageInList(image);
6106 mng_info->image=image;
6108 if (term_chunk_found)
6110 image->start_loop=MagickTrue;
6111 image->iterations=mng_iterations;
6112 term_chunk_found=MagickFalse;
6116 image->start_loop=MagickFalse;
6118 /* Make a background rectangle. */
6121 image->columns=mng_info->mng_width;
6122 image->rows=mng_info->mng_height;
6123 image->page.width=mng_info->mng_width;
6124 image->page.height=mng_info->mng_height;
6127 image->background_color=mng_background_color;
6128 (void) SetImageBackgroundColor(image,exception);
6129 if (logging != MagickFalse)
6130 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6131 " Inserted transparent background layer, W=%.20g, H=%.20g",
6132 (double) mng_info->mng_width,(double) mng_info->mng_height);
6136 Insert a background layer behind the upcoming image if
6137 framing_mode is 3, and we haven't already inserted one.
6139 if (insert_layers && (mng_info->framing_mode == 3) &&
6140 (subframe_width) && (subframe_height) && (simplicity == 0 ||
6141 (simplicity & 0x08)))
6143 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
6146 Allocate next image structure.
6148 AcquireNextImage(image_info,image,exception);
6150 if (GetNextImageInList(image) == (Image *) NULL)
6152 image=DestroyImageList(image);
6153 MngInfoFreeStruct(mng_info,&have_mng_structure);
6154 return((Image *) NULL);
6157 image=SyncNextImageInList(image);
6160 mng_info->image=image;
6162 if (term_chunk_found)
6164 image->start_loop=MagickTrue;
6165 image->iterations=mng_iterations;
6166 term_chunk_found=MagickFalse;
6170 image->start_loop=MagickFalse;
6173 image->columns=subframe_width;
6174 image->rows=subframe_height;
6175 image->page.width=subframe_width;
6176 image->page.height=subframe_height;
6177 image->page.x=mng_info->clip.left;
6178 image->page.y=mng_info->clip.top;
6179 image->background_color=mng_background_color;
6180 image->alpha_trait=UndefinedPixelTrait;
6181 (void) SetImageBackgroundColor(image,exception);
6183 if (logging != MagickFalse)
6184 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6185 " Insert background layer, L=%.20g, R=%.20g T=%.20g, B=%.20g",
6186 (double) mng_info->clip.left,(double) mng_info->clip.right,
6187 (double) mng_info->clip.top,(double) mng_info->clip.bottom);
6189 #endif /* MNG_INSERT_LAYERS */
6190 first_mng_object=MagickFalse;
6192 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
6195 Allocate next image structure.
6197 AcquireNextImage(image_info,image,exception);
6199 if (GetNextImageInList(image) == (Image *) NULL)
6201 image=DestroyImageList(image);
6202 MngInfoFreeStruct(mng_info,&have_mng_structure);
6203 return((Image *) NULL);
6206 image=SyncNextImageInList(image);
6208 mng_info->image=image;
6209 status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
6210 GetBlobSize(image));
6212 if (status == MagickFalse)
6215 if (term_chunk_found)
6217 image->start_loop=MagickTrue;
6218 term_chunk_found=MagickFalse;
6222 image->start_loop=MagickFalse;
6224 if (mng_info->framing_mode == 1 || mng_info->framing_mode == 3)
6226 image->delay=frame_delay;
6227 frame_delay=default_frame_delay;
6233 image->page.width=mng_info->mng_width;
6234 image->page.height=mng_info->mng_height;
6235 image->page.x=mng_info->x_off[object_id];
6236 image->page.y=mng_info->y_off[object_id];
6237 image->iterations=mng_iterations;
6240 Seek back to the beginning of the IHDR or JHDR chunk's length field.
6243 if (logging != MagickFalse)
6244 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6245 " Seeking back to beginning of %c%c%c%c chunk",type[0],type[1],
6248 offset=SeekBlob(image,-((ssize_t) length+12),SEEK_CUR);
6251 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
6255 mng_info->image=image;
6256 mng_info->mng_type=mng_type;
6257 mng_info->object_id=object_id;
6259 if (memcmp(type,mng_IHDR,4) == 0)
6260 image=ReadOnePNGImage(mng_info,image_info,exception);
6262 #if defined(JNG_SUPPORTED)
6264 image=ReadOneJNGImage(mng_info,image_info,exception);
6267 if (image == (Image *) NULL)
6269 if (IsImageObject(previous) != MagickFalse)
6271 (void) DestroyImageList(previous);
6272 (void) CloseBlob(previous);
6275 MngInfoFreeStruct(mng_info,&have_mng_structure);
6276 return((Image *) NULL);
6279 if (image->columns == 0 || image->rows == 0)
6281 (void) CloseBlob(image);
6282 image=DestroyImageList(image);
6283 MngInfoFreeStruct(mng_info,&have_mng_structure);
6284 return((Image *) NULL);
6287 mng_info->image=image;
6294 if (mng_info->magn_methx || mng_info->magn_methy)
6300 if (logging != MagickFalse)
6301 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6302 " Processing MNG MAGN chunk");
6304 if (mng_info->magn_methx == 1)
6306 magnified_width=mng_info->magn_ml;
6308 if (image->columns > 1)
6309 magnified_width += mng_info->magn_mr;
6311 if (image->columns > 2)
6312 magnified_width += (png_uint_32)
6313 ((image->columns-2)*(mng_info->magn_mx));
6318 magnified_width=(png_uint_32) image->columns;
6320 if (image->columns > 1)
6321 magnified_width += mng_info->magn_ml-1;
6323 if (image->columns > 2)
6324 magnified_width += mng_info->magn_mr-1;
6326 if (image->columns > 3)
6327 magnified_width += (png_uint_32)
6328 ((image->columns-3)*(mng_info->magn_mx-1));
6331 if (mng_info->magn_methy == 1)
6333 magnified_height=mng_info->magn_mt;
6335 if (image->rows > 1)
6336 magnified_height += mng_info->magn_mb;
6338 if (image->rows > 2)
6339 magnified_height += (png_uint_32)
6340 ((image->rows-2)*(mng_info->magn_my));
6345 magnified_height=(png_uint_32) image->rows;
6347 if (image->rows > 1)
6348 magnified_height += mng_info->magn_mt-1;
6350 if (image->rows > 2)
6351 magnified_height += mng_info->magn_mb-1;
6353 if (image->rows > 3)
6354 magnified_height += (png_uint_32)
6355 ((image->rows-3)*(mng_info->magn_my-1));
6358 if (magnified_height > image->rows ||
6359 magnified_width > image->columns)
6386 /* Allocate next image structure. */
6388 if (logging != MagickFalse)
6389 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6390 " Allocate magnified image");
6392 AcquireNextImage(image_info,image,exception);
6394 if (GetNextImageInList(image) == (Image *) NULL)
6396 image=DestroyImageList(image);
6397 MngInfoFreeStruct(mng_info,&have_mng_structure);
6398 return((Image *) NULL);
6401 large_image=SyncNextImageInList(image);
6403 large_image->columns=magnified_width;
6404 large_image->rows=magnified_height;
6406 magn_methx=mng_info->magn_methx;
6407 magn_methy=mng_info->magn_methy;
6409 #if (MAGICKCORE_QUANTUM_DEPTH > 16)
6410 #define QM unsigned short
6411 if (magn_methx != 1 || magn_methy != 1)
6414 Scale pixels to unsigned shorts to prevent
6415 overflow of intermediate values of interpolations
6417 for (y=0; y < (ssize_t) image->rows; y++)
6419 q=GetAuthenticPixels(image,0,y,image->columns,1,
6422 for (x=(ssize_t) image->columns-1; x >= 0; x--)
6424 SetPixelRed(image,ScaleQuantumToShort(
6425 GetPixelRed(image,q)),q);
6426 SetPixelGreen(image,ScaleQuantumToShort(
6427 GetPixelGreen(image,q)),q);
6428 SetPixelBlue(image,ScaleQuantumToShort(
6429 GetPixelBlue(image,q)),q);
6430 SetPixelAlpha(image,ScaleQuantumToShort(
6431 GetPixelAlpha(image,q)),q);
6432 q+=GetPixelChannels(image);
6435 if (SyncAuthenticPixels(image,exception) == MagickFalse)
6443 if (image->alpha_trait == BlendPixelTrait)
6444 (void) SetImageBackgroundColor(large_image,exception);
6448 large_image->background_color.alpha=OpaqueAlpha;
6449 (void) SetImageBackgroundColor(large_image,exception);
6451 if (magn_methx == 4)
6454 if (magn_methx == 5)
6457 if (magn_methy == 4)
6460 if (magn_methy == 5)
6464 /* magnify the rows into the right side of the large image */
6466 if (logging != MagickFalse)
6467 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6468 " Magnify the rows to %.20g",(double) large_image->rows);
6469 m=(ssize_t) mng_info->magn_mt;
6471 length=(size_t) image->columns*GetPixelChannels(image);
6472 next=(Quantum *) AcquireQuantumMemory(length,sizeof(*next));
6473 prev=(Quantum *) AcquireQuantumMemory(length,sizeof(*prev));
6475 if ((prev == (Quantum *) NULL) ||
6476 (next == (Quantum *) NULL))
6478 image=DestroyImageList(image);
6479 MngInfoFreeStruct(mng_info,&have_mng_structure);
6480 ThrowReaderException(ResourceLimitError,
6481 "MemoryAllocationFailed");
6484 n=GetAuthenticPixels(image,0,0,image->columns,1,exception);
6485 (void) CopyMagickMemory(next,n,length);
6487 for (y=0; y < (ssize_t) image->rows; y++)
6490 m=(ssize_t) mng_info->magn_mt;
6492 else if (magn_methy > 1 && y == (ssize_t) image->rows-2)
6493 m=(ssize_t) mng_info->magn_mb;
6495 else if (magn_methy <= 1 && y == (ssize_t) image->rows-1)
6496 m=(ssize_t) mng_info->magn_mb;
6498 else if (magn_methy > 1 && y == (ssize_t) image->rows-1)
6502 m=(ssize_t) mng_info->magn_my;
6508 if (y < (ssize_t) image->rows-1)
6510 n=GetAuthenticPixels(image,0,y+1,image->columns,1,
6512 (void) CopyMagickMemory(next,n,length);
6515 for (i=0; i < m; i++, yy++)
6520 assert(yy < (ssize_t) large_image->rows);
6523 q=GetAuthenticPixels(large_image,0,yy,large_image->columns,
6525 q+=(large_image->columns-image->columns)*
6526 GetPixelChannels(large_image);
6528 for (x=(ssize_t) image->columns-1; x >= 0; x--)
6530 /* To do: get color as function of indexes[x] */
6532 if (image->storage_class == PseudoClass)
6537 if (magn_methy <= 1)
6539 /* replicate previous */
6540 SetPixelRed(large_image,GetPixelRed(image,pixels),q);
6541 SetPixelGreen(large_image,GetPixelGreen(image,
6543 SetPixelBlue(large_image,GetPixelBlue(image,
6545 SetPixelAlpha(large_image,GetPixelAlpha(image,
6549 else if (magn_methy == 2 || magn_methy == 4)
6553 SetPixelRed(large_image,GetPixelRed(image,
6555 SetPixelGreen(large_image,GetPixelGreen(image,
6557 SetPixelBlue(large_image,GetPixelBlue(image,
6559 SetPixelAlpha(large_image,GetPixelAlpha(image,
6566 SetPixelRed(large_image,((QM) (((ssize_t)
6567 (2*i*(GetPixelRed(image,n)
6568 -GetPixelRed(image,pixels)+m))/
6570 +GetPixelRed(image,pixels)))),q);
6571 SetPixelGreen(large_image,((QM) (((ssize_t)
6572 (2*i*(GetPixelGreen(image,n)
6573 -GetPixelGreen(image,pixels)+m))/
6575 +GetPixelGreen(image,pixels)))),q);
6576 SetPixelBlue(large_image,((QM) (((ssize_t)
6577 (2*i*(GetPixelBlue(image,n)
6578 -GetPixelBlue(image,pixels)+m))/
6580 +GetPixelBlue(image,pixels)))),q);
6582 if (image->alpha_trait == BlendPixelTrait)
6583 SetPixelAlpha(large_image, ((QM) (((ssize_t)
6584 (2*i*(GetPixelAlpha(image,n)
6585 -GetPixelAlpha(image,pixels)+m))
6587 GetPixelAlpha(image,pixels)))),q);
6590 if (magn_methy == 4)
6592 /* Replicate nearest */
6593 if (i <= ((m+1) << 1))
6594 SetPixelAlpha(large_image,GetPixelAlpha(image,
6597 SetPixelAlpha(large_image,GetPixelAlpha(image,
6602 else /* if (magn_methy == 3 || magn_methy == 5) */
6604 /* Replicate nearest */
6605 if (i <= ((m+1) << 1))
6607 SetPixelRed(large_image,GetPixelRed(image,
6609 SetPixelGreen(large_image,GetPixelGreen(image,
6611 SetPixelBlue(large_image,GetPixelBlue(image,
6613 SetPixelAlpha(large_image,GetPixelAlpha(image,
6619 SetPixelRed(large_image,GetPixelRed(image,n),q);
6620 SetPixelGreen(large_image,GetPixelGreen(image,n),
6622 SetPixelBlue(large_image,GetPixelBlue(image,n),
6624 SetPixelAlpha(large_image,GetPixelAlpha(image,n),
6628 if (magn_methy == 5)
6630 SetPixelAlpha(large_image,(QM) (((ssize_t) (2*i*
6631 (GetPixelAlpha(image,n)
6632 -GetPixelAlpha(image,pixels))
6633 +m))/((ssize_t) (m*2))
6634 +GetPixelAlpha(image,pixels)),q);
6637 n+=GetPixelChannels(image);
6638 q+=GetPixelChannels(large_image);
6639 pixels+=GetPixelChannels(image);
6642 if (SyncAuthenticPixels(large_image,exception) == 0)
6648 prev=(Quantum *) RelinquishMagickMemory(prev);
6649 next=(Quantum *) RelinquishMagickMemory(next);
6651 length=image->columns;
6653 if (logging != MagickFalse)
6654 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6655 " Delete original image");
6657 DeleteImageFromList(&image);
6661 mng_info->image=image;
6663 /* magnify the columns */
6664 if (logging != MagickFalse)
6665 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6666 " Magnify the columns to %.20g",(double) image->columns);
6668 for (y=0; y < (ssize_t) image->rows; y++)
6673 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
6674 pixels=q+(image->columns-length)*GetPixelChannels(image);
6675 n=pixels+GetPixelChannels(image);
6677 for (x=(ssize_t) (image->columns-length);
6678 x < (ssize_t) image->columns; x++)
6680 /* To do: Rewrite using Get/Set***PixelChannel() */
6682 if (x == (ssize_t) (image->columns-length))
6683 m=(ssize_t) mng_info->magn_ml;
6685 else if (magn_methx > 1 && x == (ssize_t) image->columns-2)
6686 m=(ssize_t) mng_info->magn_mr;
6688 else if (magn_methx <= 1 && x == (ssize_t) image->columns-1)
6689 m=(ssize_t) mng_info->magn_mr;
6691 else if (magn_methx > 1 && x == (ssize_t) image->columns-1)
6695 m=(ssize_t) mng_info->magn_mx;
6697 for (i=0; i < m; i++)
6699 if (magn_methx <= 1)
6701 /* replicate previous */
6702 SetPixelRed(image,GetPixelRed(image,pixels),q);
6703 SetPixelGreen(image,GetPixelGreen(image,pixels),q);
6704 SetPixelBlue(image,GetPixelBlue(image,pixels),q);
6705 SetPixelAlpha(image,GetPixelAlpha(image,pixels),q);
6708 else if (magn_methx == 2 || magn_methx == 4)
6712 SetPixelRed(image,GetPixelRed(image,pixels),q);
6713 SetPixelGreen(image,GetPixelGreen(image,pixels),q);
6714 SetPixelBlue(image,GetPixelBlue(image,pixels),q);
6715 SetPixelAlpha(image,GetPixelAlpha(image,pixels),q);
6718 /* To do: Rewrite using Get/Set***PixelChannel() */
6722 SetPixelRed(image,(QM) ((2*i*(
6723 GetPixelRed(image,n)
6724 -GetPixelRed(image,pixels))+m)
6726 GetPixelRed(image,pixels)),q);
6728 SetPixelGreen(image,(QM) ((2*i*(
6729 GetPixelGreen(image,n)
6730 -GetPixelGreen(image,pixels))+m)
6732 GetPixelGreen(image,pixels)),q);
6734 SetPixelBlue(image,(QM) ((2*i*(
6735 GetPixelBlue(image,n)
6736 -GetPixelBlue(image,pixels))+m)
6738 GetPixelBlue(image,pixels)),q);
6739 if (image->alpha_trait == BlendPixelTrait)
6740 SetPixelAlpha(image,(QM) ((2*i*(
6741 GetPixelAlpha(image,n)
6742 -GetPixelAlpha(image,pixels))+m)
6744 GetPixelAlpha(image,pixels)),q);
6747 if (magn_methx == 4)
6749 /* Replicate nearest */
6750 if (i <= ((m+1) << 1))
6752 SetPixelAlpha(image,
6753 GetPixelAlpha(image,pixels)+0,q);
6757 SetPixelAlpha(image,
6758 GetPixelAlpha(image,n)+0,q);
6763 else /* if (magn_methx == 3 || magn_methx == 5) */
6765 /* Replicate nearest */
6766 if (i <= ((m+1) << 1))
6768 SetPixelRed(image,GetPixelRed(image,pixels),q);
6769 SetPixelGreen(image,GetPixelGreen(image,pixels),q);
6770 SetPixelBlue(image,GetPixelBlue(image,pixels),q);
6771 SetPixelAlpha(image,GetPixelAlpha(image,pixels),q);
6776 SetPixelRed(image,GetPixelRed(image,n),q);
6777 SetPixelGreen(image,GetPixelGreen(image,n),q);
6778 SetPixelBlue(image,GetPixelBlue(image,n),q);
6779 SetPixelAlpha(image,GetPixelAlpha(image,n),q);
6782 if (magn_methx == 5)
6785 SetPixelAlpha(image,
6786 (QM) ((2*i*( GetPixelAlpha(image,n)
6787 -GetPixelAlpha(image,pixels))+m)/
6789 +GetPixelAlpha(image,pixels)),q);
6792 q+=GetPixelChannels(image);
6794 n+=GetPixelChannels(image);
6795 p+=GetPixelChannels(image);
6798 if (SyncAuthenticPixels(image,exception) == MagickFalse)
6801 #if (MAGICKCORE_QUANTUM_DEPTH > 16)
6802 if (magn_methx != 1 || magn_methy != 1)
6805 Rescale pixels to Quantum
6807 for (y=0; y < (ssize_t) image->rows; y++)
6809 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
6811 for (x=(ssize_t) image->columns-1; x >= 0; x--)
6813 SetPixelRed(image,ScaleShortToQuantum(
6814 GetPixelRed(image,q)),q);
6815 SetPixelGreen(image,ScaleShortToQuantum(
6816 GetPixelGreen(image,q)),q);
6817 SetPixelBlue(image,ScaleShortToQuantum(
6818 GetPixelBlue(image,q)),q);
6819 SetPixelAlpha(image,ScaleShortToQuantum(
6820 GetPixelAlpha(image,q)),q);
6821 q+=GetPixelChannels(image);
6824 if (SyncAuthenticPixels(image,exception) == MagickFalse)
6829 if (logging != MagickFalse)
6830 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6831 " Finished MAGN processing");
6836 Crop_box is with respect to the upper left corner of the MNG.
6838 crop_box.left=mng_info->image_box.left+mng_info->x_off[object_id];
6839 crop_box.right=mng_info->image_box.right+mng_info->x_off[object_id];
6840 crop_box.top=mng_info->image_box.top+mng_info->y_off[object_id];
6841 crop_box.bottom=mng_info->image_box.bottom+mng_info->y_off[object_id];
6842 crop_box=mng_minimum_box(crop_box,mng_info->clip);
6843 crop_box=mng_minimum_box(crop_box,mng_info->frame);
6844 crop_box=mng_minimum_box(crop_box,mng_info->object_clip[object_id]);
6845 if ((crop_box.left != (mng_info->image_box.left
6846 +mng_info->x_off[object_id])) ||
6847 (crop_box.right != (mng_info->image_box.right
6848 +mng_info->x_off[object_id])) ||
6849 (crop_box.top != (mng_info->image_box.top
6850 +mng_info->y_off[object_id])) ||
6851 (crop_box.bottom != (mng_info->image_box.bottom
6852 +mng_info->y_off[object_id])))
6854 if (logging != MagickFalse)
6855 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6856 " Crop the PNG image");
6858 if ((crop_box.left < crop_box.right) &&
6859 (crop_box.top < crop_box.bottom))
6868 Crop_info is with respect to the upper left corner of
6871 crop_info.x=(crop_box.left-mng_info->x_off[object_id]);
6872 crop_info.y=(crop_box.top-mng_info->y_off[object_id]);
6873 crop_info.width=(size_t) (crop_box.right-crop_box.left);
6874 crop_info.height=(size_t) (crop_box.bottom-crop_box.top);
6875 image->page.width=image->columns;
6876 image->page.height=image->rows;
6879 im=CropImage(image,&crop_info,exception);
6881 if (im != (Image *) NULL)
6883 image->columns=im->columns;
6884 image->rows=im->rows;
6885 im=DestroyImage(im);
6886 image->page.width=image->columns;
6887 image->page.height=image->rows;
6888 image->page.x=crop_box.left;
6889 image->page.y=crop_box.top;
6896 No pixels in crop area. The MNG spec still requires
6897 a layer, though, so make a single transparent pixel in
6898 the top left corner.
6903 (void) SetImageBackgroundColor(image,exception);
6904 image->page.width=1;
6905 image->page.height=1;
6910 #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
6911 image=mng_info->image;
6915 #if (MAGICKCORE_QUANTUM_DEPTH > 16)
6916 /* PNG does not handle depths greater than 16 so reduce it even
6919 if (image->depth > 16)
6923 #if (MAGICKCORE_QUANTUM_DEPTH > 8)
6924 if (image->depth > 8)
6926 /* To do: fill low byte properly */
6930 if (LosslessReduceDepthOK(image,exception) != MagickFalse)
6934 if (image_info->number_scenes != 0)
6936 if (mng_info->scenes_found >
6937 (ssize_t) (image_info->first_scene+image_info->number_scenes))
6941 if (logging != MagickFalse)
6942 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6943 " Finished reading image datastream.");
6945 } while (LocaleCompare(image_info->magick,"MNG") == 0);
6947 (void) CloseBlob(image);
6949 if (logging != MagickFalse)
6950 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6951 " Finished reading all image datastreams.");
6953 #if defined(MNG_INSERT_LAYERS)
6954 if (insert_layers && !mng_info->image_found && (mng_info->mng_width) &&
6955 (mng_info->mng_height))
6958 Insert a background layer if nothing else was found.
6960 if (logging != MagickFalse)
6961 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6962 " No images found. Inserting a background layer.");
6964 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
6967 Allocate next image structure.
6969 AcquireNextImage(image_info,image,exception);
6970 if (GetNextImageInList(image) == (Image *) NULL)
6972 image=DestroyImageList(image);
6973 MngInfoFreeStruct(mng_info,&have_mng_structure);
6975 if (logging != MagickFalse)
6976 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6977 " Allocation failed, returning NULL.");
6979 return((Image *) NULL);
6981 image=SyncNextImageInList(image);
6983 image->columns=mng_info->mng_width;
6984 image->rows=mng_info->mng_height;
6985 image->page.width=mng_info->mng_width;
6986 image->page.height=mng_info->mng_height;
6989 image->background_color=mng_background_color;
6990 image->alpha_trait=UndefinedPixelTrait;
6992 if (image_info->ping == MagickFalse)
6993 (void) SetImageBackgroundColor(image,exception);
6995 mng_info->image_found++;
6998 image->iterations=mng_iterations;
7000 if (mng_iterations == 1)
7001 image->start_loop=MagickTrue;
7003 while (GetPreviousImageInList(image) != (Image *) NULL)
7006 if (image_count > 10*mng_info->image_found)
7008 if (logging != MagickFalse)
7009 (void) LogMagickEvent(CoderEvent,GetMagickModule()," No beginning");
7011 (void) ThrowMagickException(exception,GetMagickModule(),
7012 CoderError,"Linked list is corrupted, beginning of list not found",
7013 "`%s'",image_info->filename);
7015 return((Image *) NULL);
7018 image=GetPreviousImageInList(image);
7020 if (GetNextImageInList(image) == (Image *) NULL)
7022 if (logging != MagickFalse)
7023 (void) LogMagickEvent(CoderEvent,GetMagickModule()," Corrupt list");
7025 (void) ThrowMagickException(exception,GetMagickModule(),
7026 CoderError,"Linked list is corrupted; next_image is NULL","`%s'",
7027 image_info->filename);
7031 if (mng_info->ticks_per_second && mng_info->image_found > 1 &&
7032 GetNextImageInList(image) ==
7035 if (logging != MagickFalse)
7036 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7037 " First image null");
7039 (void) ThrowMagickException(exception,GetMagickModule(),
7040 CoderError,"image->next for first image is NULL but shouldn't be.",
7041 "`%s'",image_info->filename);
7044 if (mng_info->image_found == 0)
7046 if (logging != MagickFalse)
7047 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7048 " No visible images found.");
7050 (void) ThrowMagickException(exception,GetMagickModule(),
7051 CoderError,"No visible images in file","`%s'",image_info->filename);
7053 if (image != (Image *) NULL)
7054 image=DestroyImageList(image);
7056 MngInfoFreeStruct(mng_info,&have_mng_structure);
7057 return((Image *) NULL);
7060 if (mng_info->ticks_per_second)
7061 final_delay=1UL*MagickMax(image->ticks_per_second,1L)*
7062 final_delay/mng_info->ticks_per_second;
7065 image->start_loop=MagickTrue;
7067 /* Find final nonzero image delay */
7068 final_image_delay=0;
7070 while (GetNextImageInList(image) != (Image *) NULL)
7073 final_image_delay=image->delay;
7075 image=GetNextImageInList(image);
7078 if (final_delay < final_image_delay)
7079 final_delay=final_image_delay;
7081 image->delay=final_delay;
7083 if (logging != MagickFalse)
7084 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7085 " image->delay=%.20g, final_delay=%.20g",(double) image->delay,
7086 (double) final_delay);
7088 if (logging != MagickFalse)
7094 image=GetFirstImageInList(image);
7096 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7097 " Before coalesce:");
7099 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7100 " scene 0 delay=%.20g",(double) image->delay);
7102 while (GetNextImageInList(image) != (Image *) NULL)
7104 image=GetNextImageInList(image);
7105 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7106 " scene %.20g delay=%.20g",(double) scene++,(double) image->delay);
7110 image=GetFirstImageInList(image);
7111 #ifdef MNG_COALESCE_LAYERS
7121 if (logging != MagickFalse)
7122 (void) LogMagickEvent(CoderEvent,GetMagickModule()," Coalesce Images");
7125 next_image=CoalesceImages(image,exception);
7127 if (next_image == (Image *) NULL)
7128 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
7130 image=DestroyImageList(image);
7133 for (next=image; next != (Image *) NULL; next=next_image)
7135 next->page.width=mng_info->mng_width;
7136 next->page.height=mng_info->mng_height;
7139 next->scene=scene++;
7140 next_image=GetNextImageInList(next);
7142 if (next_image == (Image *) NULL)
7145 if (next->delay == 0)
7148 next_image->previous=GetPreviousImageInList(next);
7149 if (GetPreviousImageInList(next) == (Image *) NULL)
7152 next->previous->next=next_image;
7153 next=DestroyImage(next);
7159 while (GetNextImageInList(image) != (Image *) NULL)
7160 image=GetNextImageInList(image);
7162 image->dispose=BackgroundDispose;
7164 if (logging != MagickFalse)
7170 image=GetFirstImageInList(image);
7172 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7173 " After coalesce:");
7175 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7176 " scene 0 delay=%.20g dispose=%.20g",(double) image->delay,
7177 (double) image->dispose);
7179 while (GetNextImageInList(image) != (Image *) NULL)
7181 image=GetNextImageInList(image);
7183 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7184 " scene %.20g delay=%.20g dispose=%.20g",(double) scene++,
7185 (double) image->delay,(double) image->dispose);
7189 image=GetFirstImageInList(image);
7190 MngInfoFreeStruct(mng_info,&have_mng_structure);
7191 have_mng_structure=MagickFalse;
7193 if (logging != MagickFalse)
7194 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit ReadMNGImage()");
7196 return(GetFirstImageInList(image));
7198 #else /* PNG_LIBPNG_VER > 10011 */
7199 static Image *ReadPNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
7201 printf("Your PNG library is too old: You have libpng-%s\n",
7202 PNG_LIBPNG_VER_STRING);
7204 (void) ThrowMagickException(exception,GetMagickModule(),CoderError,
7205 "PNG library is too old","`%s'",image_info->filename);
7207 return(Image *) NULL;
7210 static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
7212 return(ReadPNGImage(image_info,exception));
7214 #endif /* PNG_LIBPNG_VER > 10011 */
7218 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7222 % R e g i s t e r P N G I m a g e %
7226 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7228 % RegisterPNGImage() adds properties for the PNG image format to
7229 % the list of supported formats. The properties include the image format
7230 % tag, a method to read and/or write the format, whether the format
7231 % supports the saving of more than one frame to the same file or blob,
7232 % whether the format supports native in-memory I/O, and a brief
7233 % description of the format.
7235 % The format of the RegisterPNGImage method is:
7237 % size_t RegisterPNGImage(void)
7240 ModuleExport size_t RegisterPNGImage(void)
7243 version[MaxTextExtent];
7251 "See http://www.libpng.org/ for details about the PNG format."
7256 "See http://www.libpng.org/pub/mng/ for details about the JNG\n"
7262 "See http://www.libpng.org/pub/mng/ for details about the MNG\n"
7268 #if defined(PNG_LIBPNG_VER_STRING)
7269 (void) ConcatenateMagickString(version,"libpng ",MaxTextExtent);
7270 (void) ConcatenateMagickString(version,PNG_LIBPNG_VER_STRING,MaxTextExtent);
7272 if (LocaleCompare(PNG_LIBPNG_VER_STRING,png_get_header_ver(NULL)) != 0)
7274 (void) ConcatenateMagickString(version,",",MaxTextExtent);
7275 (void) ConcatenateMagickString(version,png_get_libpng_ver(NULL),
7280 entry=SetMagickInfo("MNG");
7281 entry->seekable_stream=MagickTrue; /* To do: eliminate this. */
7283 #if defined(MAGICKCORE_PNG_DELEGATE)
7284 entry->decoder=(DecodeImageHandler *) ReadMNGImage;
7285 entry->encoder=(EncodeImageHandler *) WriteMNGImage;
7288 entry->magick=(IsImageFormatHandler *) IsMNG;
7289 entry->description=ConstantString("Multiple-image Network Graphics");
7291 if (*version != '\0')
7292 entry->version=ConstantString(version);
7294 entry->module=ConstantString("PNG");
7295 entry->note=ConstantString(MNGNote);
7296 (void) RegisterMagickInfo(entry);
7298 entry=SetMagickInfo("PNG");
7300 #if defined(MAGICKCORE_PNG_DELEGATE)
7301 entry->decoder=(DecodeImageHandler *) ReadPNGImage;
7302 entry->encoder=(EncodeImageHandler *) WritePNGImage;
7305 entry->magick=(IsImageFormatHandler *) IsPNG;
7306 entry->adjoin=MagickFalse;
7307 entry->description=ConstantString("Portable Network Graphics");
7308 entry->module=ConstantString("PNG");
7310 if (*version != '\0')
7311 entry->version=ConstantString(version);
7313 entry->note=ConstantString(PNGNote);
7314 (void) RegisterMagickInfo(entry);
7316 entry=SetMagickInfo("PNG8");
7318 #if defined(MAGICKCORE_PNG_DELEGATE)
7319 entry->decoder=(DecodeImageHandler *) ReadPNGImage;
7320 entry->encoder=(EncodeImageHandler *) WritePNGImage;
7323 entry->magick=(IsImageFormatHandler *) IsPNG;
7324 entry->adjoin=MagickFalse;
7325 entry->description=ConstantString(
7326 "8-bit indexed with optional binary transparency");
7327 entry->module=ConstantString("PNG");
7328 (void) RegisterMagickInfo(entry);
7330 entry=SetMagickInfo("PNG24");
7333 #if defined(ZLIB_VERSION)
7334 (void) ConcatenateMagickString(version,"zlib ",MaxTextExtent);
7335 (void) ConcatenateMagickString(version,ZLIB_VERSION,MaxTextExtent);
7337 if (LocaleCompare(ZLIB_VERSION,zlib_version) != 0)
7339 (void) ConcatenateMagickString(version,",",MaxTextExtent);
7340 (void) ConcatenateMagickString(version,zlib_version,MaxTextExtent);
7344 if (*version != '\0')
7345 entry->version=ConstantString(version);
7347 #if defined(MAGICKCORE_PNG_DELEGATE)
7348 entry->decoder=(DecodeImageHandler *) ReadPNGImage;
7349 entry->encoder=(EncodeImageHandler *) WritePNGImage;
7352 entry->magick=(IsImageFormatHandler *) IsPNG;
7353 entry->adjoin=MagickFalse;
7354 entry->description=ConstantString("opaque or binary transparent 24-bit RGB");
7355 entry->module=ConstantString("PNG");
7356 (void) RegisterMagickInfo(entry);
7358 entry=SetMagickInfo("PNG32");
7360 #if defined(MAGICKCORE_PNG_DELEGATE)
7361 entry->decoder=(DecodeImageHandler *) ReadPNGImage;
7362 entry->encoder=(EncodeImageHandler *) WritePNGImage;
7365 entry->magick=(IsImageFormatHandler *) IsPNG;
7366 entry->adjoin=MagickFalse;
7367 entry->description=ConstantString("opaque or transparent 32-bit RGBA");
7368 entry->module=ConstantString("PNG");
7369 (void) RegisterMagickInfo(entry);
7371 entry=SetMagickInfo("PNG48");
7373 #if defined(MAGICKCORE_PNG_DELEGATE)
7374 entry->decoder=(DecodeImageHandler *) ReadPNGImage;
7375 entry->encoder=(EncodeImageHandler *) WritePNGImage;
7378 entry->magick=(IsImageFormatHandler *) IsPNG;
7379 entry->adjoin=MagickFalse;
7380 entry->description=ConstantString("opaque or binary transparent 48-bit RGB");
7381 entry->module=ConstantString("PNG");
7382 (void) RegisterMagickInfo(entry);
7384 entry=SetMagickInfo("PNG64");
7386 #if defined(MAGICKCORE_PNG_DELEGATE)
7387 entry->decoder=(DecodeImageHandler *) ReadPNGImage;
7388 entry->encoder=(EncodeImageHandler *) WritePNGImage;
7391 entry->magick=(IsImageFormatHandler *) IsPNG;
7392 entry->adjoin=MagickFalse;
7393 entry->description=ConstantString("opaque or transparent 64-bit RGBA");
7394 entry->module=ConstantString("PNG");
7395 (void) RegisterMagickInfo(entry);
7397 entry=SetMagickInfo("PNG00");
7399 #if defined(MAGICKCORE_PNG_DELEGATE)
7400 entry->decoder=(DecodeImageHandler *) ReadPNGImage;
7401 entry->encoder=(EncodeImageHandler *) WritePNGImage;
7404 entry->magick=(IsImageFormatHandler *) IsPNG;
7405 entry->adjoin=MagickFalse;
7406 entry->description=ConstantString(
7407 "PNG inheriting bit-depth and color-type from original");
7408 entry->module=ConstantString("PNG");
7409 (void) RegisterMagickInfo(entry);
7411 entry=SetMagickInfo("JNG");
7413 #if defined(JNG_SUPPORTED)
7414 #if defined(MAGICKCORE_PNG_DELEGATE)
7415 entry->decoder=(DecodeImageHandler *) ReadJNGImage;
7416 entry->encoder=(EncodeImageHandler *) WriteJNGImage;
7420 entry->magick=(IsImageFormatHandler *) IsJNG;
7421 entry->adjoin=MagickFalse;
7422 entry->description=ConstantString("JPEG Network Graphics");
7423 entry->module=ConstantString("PNG");
7424 entry->note=ConstantString(JNGNote);
7425 (void) RegisterMagickInfo(entry);
7427 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
7428 ping_semaphore=AllocateSemaphoreInfo();
7431 return(MagickImageCoderSignature);
7435 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7439 % U n r e g i s t e r P N G I m a g e %
7443 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7445 % UnregisterPNGImage() removes format registrations made by the
7446 % PNG module from the list of supported formats.
7448 % The format of the UnregisterPNGImage method is:
7450 % UnregisterPNGImage(void)
7453 ModuleExport void UnregisterPNGImage(void)
7455 (void) UnregisterMagickInfo("MNG");
7456 (void) UnregisterMagickInfo("PNG");
7457 (void) UnregisterMagickInfo("PNG8");
7458 (void) UnregisterMagickInfo("PNG24");
7459 (void) UnregisterMagickInfo("PNG32");
7460 (void) UnregisterMagickInfo("PNG48");
7461 (void) UnregisterMagickInfo("PNG64");
7462 (void) UnregisterMagickInfo("PNG00");
7463 (void) UnregisterMagickInfo("JNG");
7465 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
7466 if (ping_semaphore != (SemaphoreInfo *) NULL)
7467 DestroySemaphoreInfo(&ping_semaphore);
7471 #if defined(MAGICKCORE_PNG_DELEGATE)
7472 #if PNG_LIBPNG_VER > 10011
7474 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7478 % W r i t e M N G I m a g e %
7482 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7484 % WriteMNGImage() writes an image in the Portable Network Graphics
7485 % Group's "Multiple-image Network Graphics" encoded image format.
7487 % MNG support written by Glenn Randers-Pehrson, glennrp@image...
7489 % The format of the WriteMNGImage method is:
7491 % MagickBooleanType WriteMNGImage(const ImageInfo *image_info,
7492 % Image *image,ExceptionInfo *exception)
7494 % A description of each parameter follows.
7496 % o image_info: the image info.
7498 % o image: The image.
7500 % o exception: return any errors or warnings in this structure.
7502 % To do (as of version 5.5.2, November 26, 2002 -- glennrp -- see also
7503 % "To do" under ReadPNGImage):
7505 % Preserve all unknown and not-yet-handled known chunks found in input
7506 % PNG file and copy them into output PNG files according to the PNG
7509 % Write the iCCP chunk at MNG level when (icc profile length > 0)
7511 % Improve selection of color type (use indexed-colour or indexed-colour
7512 % with tRNS when 256 or fewer unique RGBA values are present).
7514 % Figure out what to do with "dispose=<restore-to-previous>" (dispose == 3)
7515 % This will be complicated if we limit ourselves to generating MNG-LC
7516 % files. For now we ignore disposal method 3 and simply overlay the next
7519 % Check for identical PLTE's or PLTE/tRNS combinations and use a
7520 % global MNG PLTE or PLTE/tRNS combination when appropriate.
7521 % [mostly done 15 June 1999 but still need to take care of tRNS]
7523 % Check for identical sRGB and replace with a global sRGB (and remove
7524 % gAMA/cHRM if sRGB is found; check for identical gAMA/cHRM and
7525 % replace with global gAMA/cHRM (or with sRGB if appropriate; replace
7526 % local gAMA/cHRM with local sRGB if appropriate).
7528 % Check for identical sBIT chunks and write global ones.
7530 % Provide option to skip writing the signature tEXt chunks.
7532 % Use signatures to detect identical objects and reuse the first
7533 % instance of such objects instead of writing duplicate objects.
7535 % Use a smaller-than-32k value of compression window size when
7538 % Encode JNG datastreams. Mostly done as of 5.5.2; need to write
7539 % ancillary text chunks and save profiles.
7541 % Provide an option to force LC files (to ensure exact framing rate)
7544 % Provide an option to force VLC files instead of LC, even when offsets
7545 % are present. This will involve expanding the embedded images with a
7546 % transparent region at the top and/or left.
7550 Magick_png_write_raw_profile(const ImageInfo *image_info,png_struct *ping,
7551 png_info *ping_info, unsigned char *profile_type, unsigned char
7552 *profile_description, unsigned char *profile_data, png_uint_32 length)
7571 hex[16]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
7573 if (LocaleNCompare((char *) profile_type+1, "ng-chunk-",9) == 0)
7576 if (image_info->verbose)
7578 (void) printf("writing raw profile: type=%s, length=%.20g\n",
7579 (char *) profile_type, (double) length);
7582 #if PNG_LIBPNG_VER >= 14000
7583 text=(png_textp) png_malloc(ping,(png_alloc_size_t) sizeof(png_text));
7585 text=(png_textp) png_malloc(ping,(png_size_t) sizeof(png_text));
7587 description_length=(png_uint_32) strlen((const char *) profile_description);
7588 allocated_length=(png_uint_32) (length*2 + (length >> 5) + 20
7589 + description_length);
7590 #if PNG_LIBPNG_VER >= 14000
7591 text[0].text=(png_charp) png_malloc(ping,
7592 (png_alloc_size_t) allocated_length);
7593 text[0].key=(png_charp) png_malloc(ping, (png_alloc_size_t) 80);
7595 text[0].text=(png_charp) png_malloc(ping, (png_size_t) allocated_length);
7596 text[0].key=(png_charp) png_malloc(ping, (png_size_t) 80);
7598 text[0].key[0]='\0';
7599 (void) ConcatenateMagickString(text[0].key,
7600 "Raw profile type ",MaxTextExtent);
7601 (void) ConcatenateMagickString(text[0].key,(const char *) profile_type,62);
7605 (void) CopyMagickString(dp,(const char *) profile_description,
7607 dp+=description_length;
7609 (void) FormatLocaleString(dp,allocated_length-
7610 (png_size_t) (dp-text[0].text),"%8lu ",(unsigned long) length);
7613 for (i=0; i < (ssize_t) length; i++)
7617 *(dp++)=(char) hex[((*sp >> 4) & 0x0f)];
7618 *(dp++)=(char) hex[((*sp++ ) & 0x0f)];
7623 text[0].text_length=(png_size_t) (dp-text[0].text);
7624 text[0].compression=image_info->compression == NoCompression ||
7625 (image_info->compression == UndefinedCompression &&
7626 text[0].text_length < 128) ? -1 : 0;
7628 if (text[0].text_length <= allocated_length)
7629 png_set_text(ping,ping_info,text,1);
7631 png_free(ping,text[0].text);
7632 png_free(ping,text[0].key);
7633 png_free(ping,text);
7636 static MagickBooleanType Magick_png_write_chunk_from_profile(Image *image,
7637 const char *string, MagickBooleanType logging)
7650 ResetImageProfileIterator(image);
7652 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
7654 profile=GetImageProfile(image,name);
7656 if (profile != (const StringInfo *) NULL)
7661 if (LocaleNCompare(name,string,11) == 0)
7663 if (logging != MagickFalse)
7664 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7665 " Found %s profile",name);
7667 ping_profile=CloneStringInfo(profile);
7668 data=GetStringInfoDatum(ping_profile),
7669 length=(png_uint_32) GetStringInfoLength(ping_profile);
7674 (void) WriteBlobMSBULong(image,length-5); /* data length */
7675 (void) WriteBlob(image,length-1,data+1);
7676 (void) WriteBlobMSBULong(image,crc32(0,data+1,(uInt) length-1));
7677 ping_profile=DestroyStringInfo(ping_profile);
7681 name=GetNextImageProfile(image);
7688 /* Write one PNG image */
7689 static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
7690 const ImageInfo *IMimage_info,Image *IMimage,ExceptionInfo *exception)
7714 ping_trans_alpha[256];
7742 ping_have_cheap_transparency,
7753 /* ping_exclude_EXIF, */
7756 /* ping_exclude_iTXt, */
7761 /* ping_exclude_tRNS, */
7763 ping_exclude_zCCP, /* hex-encoded iCCP */
7766 ping_preserve_colormap,
7767 ping_need_colortype_warning,
7785 *volatile ping_pixels;
7791 ping_interlace_method,
7792 ping_compression_method,
7809 number_semitransparent,
7811 ping_pHYs_unit_type;
7814 ping_pHYs_x_resolution,
7815 ping_pHYs_y_resolution;
7817 logging=LogMagickEvent(CoderEvent,GetMagickModule(),
7818 " Enter WriteOnePNGImage()");
7820 image = CloneImage(IMimage,0,0,MagickFalse,exception);
7821 image_info=(ImageInfo *) CloneImageInfo(IMimage_info);
7822 if (image_info == (ImageInfo *) NULL)
7823 ThrowWriterException(ResourceLimitError, "MemoryAllocationFailed");
7825 /* Initialize some stuff */
7828 ping_interlace_method=0,
7829 ping_compression_method=0,
7830 ping_filter_method=0,
7833 ping_background.red = 0;
7834 ping_background.green = 0;
7835 ping_background.blue = 0;
7836 ping_background.gray = 0;
7837 ping_background.index = 0;
7839 ping_trans_color.red=0;
7840 ping_trans_color.green=0;
7841 ping_trans_color.blue=0;
7842 ping_trans_color.gray=0;
7844 ping_pHYs_unit_type = 0;
7845 ping_pHYs_x_resolution = 0;
7846 ping_pHYs_y_resolution = 0;
7848 ping_have_blob=MagickFalse;
7849 ping_have_color=MagickTrue;
7850 ping_have_non_bw=MagickTrue;
7851 ping_have_PLTE=MagickFalse;
7852 ping_have_bKGD=MagickFalse;
7853 ping_have_pHYs=MagickFalse;
7854 ping_have_tRNS=MagickFalse;
7856 ping_exclude_bKGD=mng_info->ping_exclude_bKGD;
7857 ping_exclude_cHRM=mng_info->ping_exclude_cHRM;
7858 ping_exclude_date=mng_info->ping_exclude_date;
7859 /* ping_exclude_EXIF=mng_info->ping_exclude_EXIF; */
7860 ping_exclude_gAMA=mng_info->ping_exclude_gAMA;
7861 ping_exclude_iCCP=mng_info->ping_exclude_iCCP;
7862 /* ping_exclude_iTXt=mng_info->ping_exclude_iTXt; */
7863 ping_exclude_oFFs=mng_info->ping_exclude_oFFs;
7864 ping_exclude_pHYs=mng_info->ping_exclude_pHYs;
7865 ping_exclude_sRGB=mng_info->ping_exclude_sRGB;
7866 ping_exclude_tEXt=mng_info->ping_exclude_tEXt;
7867 /* ping_exclude_tRNS=mng_info->ping_exclude_tRNS; */
7868 ping_exclude_vpAg=mng_info->ping_exclude_vpAg;
7869 ping_exclude_zCCP=mng_info->ping_exclude_zCCP; /* hex-encoded iCCP in zTXt */
7870 ping_exclude_zTXt=mng_info->ping_exclude_zTXt;
7872 ping_preserve_colormap = mng_info->ping_preserve_colormap;
7873 ping_need_colortype_warning = MagickFalse;
7875 /* Recognize the ICC sRGB profile and convert it to the sRGB chunk,
7876 * i.e., eliminate the ICC profile and set image->rendering_intent.
7877 * Note that this will not involve any changes to the actual pixels
7878 * but merely passes information to applications that read the resulting
7881 if (ping_exclude_sRGB == MagickFalse)
7889 ResetImageProfileIterator(image);
7890 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
7892 profile=GetImageProfile(image,name);
7894 if (profile != (StringInfo *) NULL)
7896 if ((LocaleCompare(name,"ICC") == 0) ||
7897 (LocaleCompare(name,"ICM") == 0))
7902 /* 0: not a known sRGB profile
7903 * 1: HP-Microsoft sRGB v2
7904 * 2: ICC sRGB v4 perceptual
7905 * 3: ICC sRGB v2 perceptual no black-compensation
7908 check_crc[4] = {0, 0xf29e526dUL, 0xbbef7812UL, 0x427ebb21UL},
7909 check_len[4] = {0, 3144, 60960, 3052};
7918 length=(png_uint_32) GetStringInfoLength(profile);
7920 for (icheck=3; icheck > 0; icheck--)
7922 if (length == check_len[icheck])
7924 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7925 " Got a %lu-byte ICC profile (potentially sRGB)",
7926 (unsigned long) length);
7928 data=GetStringInfoDatum(profile);
7929 profile_crc=crc32(0,data,length);
7931 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7932 " with crc=%8x",(unsigned int) profile_crc);
7934 if (profile_crc == check_crc[icheck])
7936 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7938 if (image->rendering_intent==UndefinedIntent)
7939 image->rendering_intent=PerceptualIntent;
7945 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7946 " Got a %lu-byte ICC profile",
7947 (unsigned long) length);
7950 name=GetNextImageProfile(image);
7955 number_semitransparent = 0;
7956 number_transparent = 0;
7958 if (logging != MagickFalse)
7960 if (image->storage_class == UndefinedClass)
7961 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7962 " storage_class=UndefinedClass");
7963 if (image->storage_class == DirectClass)
7964 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7965 " storage_class=DirectClass");
7966 if (image->storage_class == PseudoClass)
7967 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7968 " storage_class=PseudoClass");
7971 if (image->storage_class == PseudoClass &&
7972 (mng_info->write_png8 || mng_info->write_png24 || mng_info->write_png32 ||
7973 mng_info->write_png48 || mng_info->write_png64 ||
7974 (mng_info->write_png_colortype != 1 &&
7975 mng_info->write_png_colortype != 5)))
7977 (void) SyncImage(image,exception);
7978 image->storage_class = DirectClass;
7981 if (ping_preserve_colormap == MagickFalse)
7983 if (image->storage_class != PseudoClass && image->colormap != NULL)
7985 /* Free the bogus colormap; it can cause trouble later */
7986 if (logging != MagickFalse)
7987 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7988 " Freeing bogus colormap");
7989 (void) RelinquishMagickMemory(image->colormap);
7990 image->colormap=NULL;
7994 if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
7995 (void) TransformImageColorspace(image,sRGBColorspace,exception);
7998 Sometimes we get PseudoClass images whose RGB values don't match
7999 the colors in the colormap. This code syncs the RGB values.
8001 if (image->depth <= 8 && image->taint && image->storage_class == PseudoClass)
8002 (void) SyncImage(image,exception);
8004 #if (MAGICKCORE_QUANTUM_DEPTH == 8)
8005 if (image->depth > 8)
8007 if (logging != MagickFalse)
8008 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8009 " Reducing PNG bit depth to 8 since this is a Q8 build.");
8015 /* Respect the -depth option */
8016 if (image->depth < MAGICKCORE_QUANTUM_DEPTH)
8021 if (image->depth > 8)
8023 #if MAGICKCORE_QUANTUM_DEPTH > 16
8024 /* Scale to 16-bit */
8025 LBR16PacketRGBO(image->background_color);
8027 for (y=0; y < (ssize_t) image->rows; y++)
8029 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8031 if (r == (Quantum *) NULL)
8034 for (x=0; x < (ssize_t) image->columns; x++)
8037 r+=GetPixelChannels(image);
8040 if (SyncAuthenticPixels(image,exception) == MagickFalse)
8044 if (image->storage_class == PseudoClass && image->colormap != NULL)
8046 for (i=0; i < (ssize_t) image->colors; i++)
8048 LBR16PacketRGBO(image->colormap[i]);
8051 #endif /* MAGICKCORE_QUANTUM_DEPTH > 16 */
8054 else if (image->depth > 4)
8056 #if MAGICKCORE_QUANTUM_DEPTH > 8
8057 /* Scale to 8-bit */
8058 LBR08PacketRGBO(image->background_color);
8060 for (y=0; y < (ssize_t) image->rows; y++)
8062 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8064 if (r == (Quantum *) NULL)
8067 for (x=0; x < (ssize_t) image->columns; x++)
8070 r+=GetPixelChannels(image);
8073 if (SyncAuthenticPixels(image,exception) == MagickFalse)
8077 if (image->storage_class == PseudoClass && image->colormap != NULL)
8079 for (i=0; i < (ssize_t) image->colors; i++)
8081 LBR08PacketRGBO(image->colormap[i]);
8084 #endif /* MAGICKCORE_QUANTUM_DEPTH > 8 */
8087 if (image->depth > 2)
8089 /* Scale to 4-bit */
8090 LBR04PacketRGBO(image->background_color);
8092 for (y=0; y < (ssize_t) image->rows; y++)
8094 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8096 if (r == (Quantum *) NULL)
8099 for (x=0; x < (ssize_t) image->columns; x++)
8102 r+=GetPixelChannels(image);
8105 if (SyncAuthenticPixels(image,exception) == MagickFalse)
8109 if (image->storage_class == PseudoClass && image->colormap != NULL)
8111 for (i=0; i < (ssize_t) image->colors; i++)
8113 LBR04PacketRGBO(image->colormap[i]);
8118 else if (image->depth > 1)
8120 /* Scale to 2-bit */
8121 LBR02PacketRGBO(image->background_color);
8123 for (y=0; y < (ssize_t) image->rows; y++)
8125 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8127 if (r == (Quantum *) NULL)
8130 for (x=0; x < (ssize_t) image->columns; x++)
8133 r+=GetPixelChannels(image);
8136 if (SyncAuthenticPixels(image,exception) == MagickFalse)
8140 if (image->storage_class == PseudoClass && image->colormap != NULL)
8142 for (i=0; i < (ssize_t) image->colors; i++)
8144 LBR02PacketRGBO(image->colormap[i]);
8150 /* Scale to 1-bit */
8151 LBR01PacketRGBO(image->background_color);
8153 for (y=0; y < (ssize_t) image->rows; y++)
8155 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8157 if (r == (Quantum *) NULL)
8160 for (x=0; x < (ssize_t) image->columns; x++)
8163 r+=GetPixelChannels(image);
8166 if (SyncAuthenticPixels(image,exception) == MagickFalse)
8170 if (image->storage_class == PseudoClass && image->colormap != NULL)
8172 for (i=0; i < (ssize_t) image->colors; i++)
8174 LBR01PacketRGBO(image->colormap[i]);
8180 /* To do: set to next higher multiple of 8 */
8181 if (image->depth < 8)
8184 #if (MAGICKCORE_QUANTUM_DEPTH > 16)
8185 /* PNG does not handle depths greater than 16 so reduce it even
8188 if (image->depth > 8)
8192 #if (MAGICKCORE_QUANTUM_DEPTH > 8)
8193 if (image->depth > 8)
8195 /* To do: fill low byte properly */
8199 if (image->depth == 16 && mng_info->write_png_depth != 16)
8200 if (mng_info->write_png8 || LosslessReduceDepthOK(image,exception) != MagickFalse)
8204 if (image->storage_class != PseudoClass && mng_info->write_png_colortype &&
8205 (mng_info->write_png_colortype > 4 || (mng_info->write_png_depth >= 8 &&
8206 mng_info->write_png_colortype < 4 &&
8207 image->alpha_trait != BlendPixelTrait)))
8209 /* Avoid the expensive BUILD_PALETTE operation if we're sure that we
8210 * are not going to need the result.
8212 image_colors = (int) image->colors;
8213 number_opaque = (int) image->colors;
8214 if (mng_info->write_png_colortype == 1 ||
8215 mng_info->write_png_colortype == 5)
8216 ping_have_color=MagickFalse;
8218 ping_have_color=MagickTrue;
8219 ping_have_non_bw=MagickFalse;
8221 if (image->alpha_trait == BlendPixelTrait)
8223 number_transparent = 2;
8224 number_semitransparent = 1;
8229 number_transparent = 0;
8230 number_semitransparent = 0;
8238 * Normally we run this just once, but in the case of writing PNG8
8239 * we reduce the transparency to binary and run again, then if there
8240 * are still too many colors we reduce to a simple 4-4-4-1, then 3-3-3-1
8241 * RGBA palette and run again, and then to a simple 3-3-2-1 RGBA
8242 * palette. Then (To do) we take care of a final reduction that is only
8243 * needed if there are still 256 colors present and one of them has both
8244 * transparent and opaque instances.
8247 tried_332 = MagickFalse;
8248 tried_333 = MagickFalse;
8249 tried_444 = MagickFalse;
8254 * Sometimes we get DirectClass images that have 256 colors or fewer.
8255 * This code will build a colormap.
8257 * Also, sometimes we get PseudoClass images with an out-of-date
8258 * colormap. This code will replace the colormap with a new one.
8259 * Sometimes we get PseudoClass images that have more than 256 colors.
8260 * This code will delete the colormap and change the image to
8263 * If image->alpha_trait is MagickFalse, we ignore the alpha channel
8264 * even though it sometimes contains left-over non-opaque values.
8266 * Also we gather some information (number of opaque, transparent,
8267 * and semitransparent pixels, and whether the image has any non-gray
8268 * pixels or only black-and-white pixels) that we might need later.
8270 * Even if the user wants to force GrayAlpha or RGBA (colortype 4 or 6)
8271 * we need to check for bogus non-opaque values, at least.
8279 semitransparent[260],
8282 register const Quantum
8289 if (logging != MagickFalse)
8290 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8291 " Enter BUILD_PALETTE:");
8293 if (logging != MagickFalse)
8295 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8296 " image->columns=%.20g",(double) image->columns);
8297 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8298 " image->rows=%.20g",(double) image->rows);
8299 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8300 " image->alpha_trait=%.20g",(double) image->alpha_trait);
8301 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8302 " image->depth=%.20g",(double) image->depth);
8304 if (image->storage_class == PseudoClass && image->colormap != NULL)
8306 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8307 " Original colormap:");
8308 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8309 " i (red,green,blue,alpha)");
8311 for (i=0; i < 256; i++)
8313 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8314 " %d (%d,%d,%d,%d)",
8316 (int) image->colormap[i].red,
8317 (int) image->colormap[i].green,
8318 (int) image->colormap[i].blue,
8319 (int) image->colormap[i].alpha);
8322 for (i=image->colors - 10; i < (ssize_t) image->colors; i++)
8326 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8327 " %d (%d,%d,%d,%d)",
8329 (int) image->colormap[i].red,
8330 (int) image->colormap[i].green,
8331 (int) image->colormap[i].blue,
8332 (int) image->colormap[i].alpha);
8337 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8338 " image->colors=%d",(int) image->colors);
8340 if (image->colors == 0)
8341 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8342 " (zero means unknown)");
8344 if (ping_preserve_colormap == MagickFalse)
8345 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8346 " Regenerate the colormap");
8351 number_semitransparent = 0;
8352 number_transparent = 0;
8354 for (y=0; y < (ssize_t) image->rows; y++)
8356 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8358 if (q == (Quantum *) NULL)
8361 for (x=0; x < (ssize_t) image->columns; x++)
8363 if (image->alpha_trait != BlendPixelTrait ||
8364 GetPixelAlpha(image,q) == OpaqueAlpha)
8366 if (number_opaque < 259)
8368 if (number_opaque == 0)
8370 GetPixelInfoPixel(image, q, opaque);
8371 opaque[0].alpha=OpaqueAlpha;
8375 for (i=0; i< (ssize_t) number_opaque; i++)
8377 if (IsPixelEquivalent(image,q, opaque+i))
8381 if (i == (ssize_t) number_opaque && number_opaque < 259)
8384 GetPixelInfoPixel(image, q, opaque+i);
8385 opaque[i].alpha=OpaqueAlpha;
8389 else if (GetPixelAlpha(image,q) == TransparentAlpha)
8391 if (number_transparent < 259)
8393 if (number_transparent == 0)
8395 GetPixelInfoPixel(image, q, transparent);
8396 ping_trans_color.red=(unsigned short)
8397 GetPixelRed(image,q);
8398 ping_trans_color.green=(unsigned short)
8399 GetPixelGreen(image,q);
8400 ping_trans_color.blue=(unsigned short)
8401 GetPixelBlue(image,q);
8402 ping_trans_color.gray=(unsigned short)
8403 GetPixelGray(image,q);
8404 number_transparent = 1;
8407 for (i=0; i< (ssize_t) number_transparent; i++)
8409 if (IsPixelEquivalent(image,q, transparent+i))
8413 if (i == (ssize_t) number_transparent &&
8414 number_transparent < 259)
8416 number_transparent++;
8417 GetPixelInfoPixel(image,q,transparent+i);
8423 if (number_semitransparent < 259)
8425 if (number_semitransparent == 0)
8427 GetPixelInfoPixel(image,q,semitransparent);
8428 number_semitransparent = 1;
8431 for (i=0; i< (ssize_t) number_semitransparent; i++)
8433 if (IsPixelEquivalent(image,q, semitransparent+i)
8434 && GetPixelAlpha(image,q) ==
8435 semitransparent[i].alpha)
8439 if (i == (ssize_t) number_semitransparent &&
8440 number_semitransparent < 259)
8442 number_semitransparent++;
8443 GetPixelInfoPixel(image, q, semitransparent+i);
8447 q+=GetPixelChannels(image);
8451 if (mng_info->write_png8 == MagickFalse &&
8452 ping_exclude_bKGD == MagickFalse)
8454 /* Add the background color to the palette, if it
8455 * isn't already there.
8457 if (logging != MagickFalse)
8459 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8460 " Check colormap for background (%d,%d,%d)",
8461 (int) image->background_color.red,
8462 (int) image->background_color.green,
8463 (int) image->background_color.blue);
8465 for (i=0; i<number_opaque; i++)
8467 if (opaque[i].red == image->background_color.red &&
8468 opaque[i].green == image->background_color.green &&
8469 opaque[i].blue == image->background_color.blue)
8472 if (number_opaque < 259 && i == number_opaque)
8474 opaque[i] = image->background_color;
8475 ping_background.index = i;
8477 if (logging != MagickFalse)
8479 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8480 " background_color index is %d",(int) i);
8484 else if (logging != MagickFalse)
8485 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8486 " No room in the colormap to add background color");
8489 image_colors=number_opaque+number_transparent+number_semitransparent;
8491 if (mng_info->write_png8 != MagickFalse && image_colors > 256)
8493 /* No room for the background color; remove it. */
8498 if (logging != MagickFalse)
8500 if (image_colors > 256)
8501 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8502 " image has more than 256 colors");
8505 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8506 " image has %d colors",image_colors);
8509 if (ping_preserve_colormap != MagickFalse)
8512 if (mng_info->write_png_colortype != 7) /* We won't need this info */
8514 ping_have_color=MagickFalse;
8515 ping_have_non_bw=MagickFalse;
8517 if ((IssRGBCompatibleColorspace(image->colorspace) == MagickFalse) ||
8518 (IssRGBColorspace(image->colorspace) != MagickFalse))
8520 ping_have_color=MagickTrue;
8521 ping_have_non_bw=MagickTrue;
8524 if(image_colors > 256)
8526 for (y=0; y < (ssize_t) image->rows; y++)
8528 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8530 if (q == (Quantum *) NULL)
8534 for (x=0; x < (ssize_t) image->columns; x++)
8536 if (GetPixelRed(image,s) != GetPixelGreen(image,s) ||
8537 GetPixelRed(image,s) != GetPixelBlue(image,s))
8539 ping_have_color=MagickTrue;
8540 ping_have_non_bw=MagickTrue;
8543 s+=GetPixelChannels(image);
8546 if (ping_have_color != MagickFalse)
8549 /* Worst case is black-and-white; we are looking at every
8553 if (ping_have_non_bw == MagickFalse)
8556 for (x=0; x < (ssize_t) image->columns; x++)
8558 if (GetPixelRed(image,s) != 0 &&
8559 GetPixelRed(image,s) != QuantumRange)
8561 ping_have_non_bw=MagickTrue;
8564 s+=GetPixelChannels(image);
8571 if (image_colors < 257)
8577 * Initialize image colormap.
8580 if (logging != MagickFalse)
8581 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8582 " Sort the new colormap");
8584 /* Sort palette, transparent first */;
8588 for (i=0; i<number_transparent; i++)
8589 colormap[n++] = transparent[i];
8591 for (i=0; i<number_semitransparent; i++)
8592 colormap[n++] = semitransparent[i];
8594 for (i=0; i<number_opaque; i++)
8595 colormap[n++] = opaque[i];
8597 ping_background.index +=
8598 (number_transparent + number_semitransparent);
8600 /* image_colors < 257; search the colormap instead of the pixels
8601 * to get ping_have_color and ping_have_non_bw
8605 if (ping_have_color == MagickFalse)
8607 if (colormap[i].red != colormap[i].green ||
8608 colormap[i].red != colormap[i].blue)
8610 ping_have_color=MagickTrue;
8611 ping_have_non_bw=MagickTrue;
8616 if (ping_have_non_bw == MagickFalse)
8618 if (colormap[i].red != 0 && colormap[i].red != QuantumRange)
8619 ping_have_non_bw=MagickTrue;
8623 if ((mng_info->ping_exclude_tRNS == MagickFalse ||
8624 (number_transparent == 0 && number_semitransparent == 0)) &&
8625 (((mng_info->write_png_colortype-1) ==
8626 PNG_COLOR_TYPE_PALETTE) ||
8627 (mng_info->write_png_colortype == 0)))
8629 if (logging != MagickFalse)
8631 if (n != (ssize_t) image_colors)
8632 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8633 " image_colors (%d) and n (%d) don't match",
8636 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8637 " AcquireImageColormap");
8640 image->colors = image_colors;
8642 if (AcquireImageColormap(image,image_colors,exception) ==
8644 ThrowWriterException(ResourceLimitError,
8645 "MemoryAllocationFailed");
8647 for (i=0; i< (ssize_t) image_colors; i++)
8648 image->colormap[i] = colormap[i];
8650 if (logging != MagickFalse)
8652 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8653 " image->colors=%d (%d)",
8654 (int) image->colors, image_colors);
8656 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8657 " Update the pixel indexes");
8660 /* Sync the pixel indices with the new colormap */
8662 for (y=0; y < (ssize_t) image->rows; y++)
8664 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8666 if (q == (Quantum *) NULL)
8669 for (x=0; x < (ssize_t) image->columns; x++)
8671 for (i=0; i< (ssize_t) image_colors; i++)
8673 if ((image->alpha_trait != BlendPixelTrait ||
8674 image->colormap[i].alpha == GetPixelAlpha(image,q)) &&
8675 image->colormap[i].red == GetPixelRed(image,q) &&
8676 image->colormap[i].green == GetPixelGreen(image,q) &&
8677 image->colormap[i].blue == GetPixelBlue(image,q))
8679 SetPixelIndex(image,i,q);
8683 q+=GetPixelChannels(image);
8686 if (SyncAuthenticPixels(image,exception) == MagickFalse)
8692 if (logging != MagickFalse)
8694 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8695 " image->colors=%d", (int) image->colors);
8697 if (image->colormap != NULL)
8699 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8700 " i (red,green,blue,alpha)");
8702 for (i=0; i < (ssize_t) image->colors; i++)
8704 if (i < 300 || i >= (ssize_t) image->colors - 10)
8706 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8707 " %d (%d,%d,%d,%d)",
8709 (int) image->colormap[i].red,
8710 (int) image->colormap[i].green,
8711 (int) image->colormap[i].blue,
8712 (int) image->colormap[i].alpha);
8717 if (number_transparent < 257)
8718 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8719 " number_transparent = %d",
8720 number_transparent);
8723 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8724 " number_transparent > 256");
8726 if (number_opaque < 257)
8727 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8728 " number_opaque = %d",
8732 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8733 " number_opaque > 256");
8735 if (number_semitransparent < 257)
8736 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8737 " number_semitransparent = %d",
8738 number_semitransparent);
8741 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8742 " number_semitransparent > 256");
8744 if (ping_have_non_bw == MagickFalse)
8745 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8746 " All pixels and the background are black or white");
8748 else if (ping_have_color == MagickFalse)
8749 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8750 " All pixels and the background are gray");
8753 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8754 " At least one pixel or the background is non-gray");
8756 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8757 " Exit BUILD_PALETTE:");
8760 if (mng_info->write_png8 == MagickFalse)
8763 /* Make any reductions necessary for the PNG8 format */
8764 if (image_colors <= 256 &&
8765 image_colors != 0 && image->colormap != NULL &&
8766 number_semitransparent == 0 &&
8767 number_transparent <= 1)
8770 /* PNG8 can't have semitransparent colors so we threshold the
8771 * opacity to 0 or OpaqueOpacity, and PNG8 can only have one
8772 * transparent color so if more than one is transparent we merge
8773 * them into image->background_color.
8775 if (number_semitransparent != 0 || number_transparent > 1)
8777 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8778 " Thresholding the alpha channel to binary");
8780 for (y=0; y < (ssize_t) image->rows; y++)
8782 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8784 if (r == (Quantum *) NULL)
8787 for (x=0; x < (ssize_t) image->columns; x++)
8789 if (GetPixelAlpha(image,r) < OpaqueAlpha/2)
8791 SetPixelInfoPixel(image,&image->background_color,r);
8792 SetPixelAlpha(image,TransparentAlpha,r);
8795 SetPixelAlpha(image,OpaqueAlpha,r);
8796 r+=GetPixelChannels(image);
8799 if (SyncAuthenticPixels(image,exception) == MagickFalse)
8802 if (image_colors != 0 && image_colors <= 256 &&
8803 image->colormap != NULL)
8804 for (i=0; i<image_colors; i++)
8805 image->colormap[i].alpha =
8806 (image->colormap[i].alpha > TransparentAlpha/2 ?
8807 TransparentAlpha : OpaqueAlpha);
8812 /* PNG8 can't have more than 256 colors so we quantize the pixels and
8813 * background color to the 4-4-4-1, 3-3-3-1 or 3-3-2-1 palette. If the
8814 * image is mostly gray, the 4-4-4-1 palette is likely to end up with 256
8817 if (tried_444 == MagickFalse && (image_colors == 0 || image_colors > 256))
8819 if (logging != MagickFalse)
8820 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8821 " Quantizing the background color to 4-4-4");
8823 tried_444 = MagickTrue;
8825 LBR04PacketRGB(image->background_color);
8827 if (logging != MagickFalse)
8828 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8829 " Quantizing the pixel colors to 4-4-4");
8831 if (image->colormap == NULL)
8833 for (y=0; y < (ssize_t) image->rows; y++)
8835 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8837 if (r == (Quantum *) NULL)
8840 for (x=0; x < (ssize_t) image->columns; x++)
8842 if (GetPixelAlpha(image,r) == OpaqueAlpha)
8844 r+=GetPixelChannels(image);
8847 if (SyncAuthenticPixels(image,exception) == MagickFalse)
8852 else /* Should not reach this; colormap already exists and
8855 if (logging != MagickFalse)
8856 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8857 " Quantizing the colormap to 4-4-4");
8859 for (i=0; i<image_colors; i++)
8861 LBR04PacketRGB(image->colormap[i]);
8867 if (tried_333 == MagickFalse && (image_colors == 0 || image_colors > 256))
8869 if (logging != MagickFalse)
8870 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8871 " Quantizing the background color to 3-3-3");
8873 tried_333 = MagickTrue;
8875 LBR03PacketRGB(image->background_color);
8877 if (logging != MagickFalse)
8878 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8879 " Quantizing the pixel colors to 3-3-3-1");
8881 if (image->colormap == NULL)
8883 for (y=0; y < (ssize_t) image->rows; y++)
8885 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8887 if (r == (Quantum *) NULL)
8890 for (x=0; x < (ssize_t) image->columns; x++)
8892 if (GetPixelAlpha(image,r) == OpaqueAlpha)
8894 r+=GetPixelChannels(image);
8897 if (SyncAuthenticPixels(image,exception) == MagickFalse)
8902 else /* Should not reach this; colormap already exists and
8905 if (logging != MagickFalse)
8906 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8907 " Quantizing the colormap to 3-3-3-1");
8908 for (i=0; i<image_colors; i++)
8910 LBR03PacketRGB(image->colormap[i]);
8916 if (tried_332 == MagickFalse && (image_colors == 0 || image_colors > 256))
8918 if (logging != MagickFalse)
8919 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8920 " Quantizing the background color to 3-3-2");
8922 tried_332 = MagickTrue;
8924 /* Red and green were already done so we only quantize the blue
8928 LBR02PacketBlue(image->background_color);
8930 if (logging != MagickFalse)
8931 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8932 " Quantizing the pixel colors to 3-3-2-1");
8934 if (image->colormap == NULL)
8936 for (y=0; y < (ssize_t) image->rows; y++)
8938 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8940 if (r == (Quantum *) NULL)
8943 for (x=0; x < (ssize_t) image->columns; x++)
8945 if (GetPixelAlpha(image,r) == OpaqueAlpha)
8947 r+=GetPixelChannels(image);
8950 if (SyncAuthenticPixels(image,exception) == MagickFalse)
8955 else /* Should not reach this; colormap already exists and
8958 if (logging != MagickFalse)
8959 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8960 " Quantizing the colormap to 3-3-2-1");
8961 for (i=0; i<image_colors; i++)
8963 LBR02PacketBlue(image->colormap[i]);
8970 if (image_colors == 0 || image_colors > 256)
8972 /* Take care of special case with 256 colors + 1 transparent
8973 * color. We don't need to quantize to 2-3-2-1; we only need to
8974 * eliminate one color, so we'll merge the two darkest red
8975 * colors (0x49, 0, 0) -> (0x24, 0, 0).
8977 if (ScaleQuantumToChar(image->background_color.red) == 0x49 &&
8978 ScaleQuantumToChar(image->background_color.green) == 0x00 &&
8979 ScaleQuantumToChar(image->background_color.blue) == 0x00)
8981 image->background_color.red=ScaleCharToQuantum(0x24);
8984 if (image->colormap == NULL)
8986 for (y=0; y < (ssize_t) image->rows; y++)
8988 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8990 if (r == (Quantum *) NULL)
8993 for (x=0; x < (ssize_t) image->columns; x++)
8995 if (ScaleQuantumToChar(GetPixelRed(image,r)) == 0x49 &&
8996 ScaleQuantumToChar(GetPixelGreen(image,r)) == 0x00 &&
8997 ScaleQuantumToChar(GetPixelBlue(image,r)) == 0x00 &&
8998 GetPixelAlpha(image,r) == OpaqueAlpha)
9000 SetPixelRed(image,ScaleCharToQuantum(0x24),r);
9002 r+=GetPixelChannels(image);
9005 if (SyncAuthenticPixels(image,exception) == MagickFalse)
9013 for (i=0; i<image_colors; i++)
9015 if (ScaleQuantumToChar(image->colormap[i].red) == 0x49 &&
9016 ScaleQuantumToChar(image->colormap[i].green) == 0x00 &&
9017 ScaleQuantumToChar(image->colormap[i].blue) == 0x00)
9019 image->colormap[i].red=ScaleCharToQuantum(0x24);
9026 /* END OF BUILD_PALETTE */
9028 /* If we are excluding the tRNS chunk and there is transparency,
9029 * then we must write a Gray-Alpha (color-type 4) or RGBA (color-type 6)
9032 if (mng_info->ping_exclude_tRNS != MagickFalse &&
9033 (number_transparent != 0 || number_semitransparent != 0))
9035 unsigned int colortype=mng_info->write_png_colortype;
9037 if (ping_have_color == MagickFalse)
9038 mng_info->write_png_colortype = 5;
9041 mng_info->write_png_colortype = 7;
9043 if (colortype != 0 &&
9044 mng_info->write_png_colortype != colortype)
9045 ping_need_colortype_warning=MagickTrue;
9049 /* See if cheap transparency is possible. It is only possible
9050 * when there is a single transparent color, no semitransparent
9051 * color, and no opaque color that has the same RGB components
9052 * as the transparent color. We only need this information if
9053 * we are writing a PNG with colortype 0 or 2, and we have not
9054 * excluded the tRNS chunk.
9056 if (number_transparent == 1 &&
9057 mng_info->write_png_colortype < 4)
9059 ping_have_cheap_transparency = MagickTrue;
9061 if (number_semitransparent != 0)
9062 ping_have_cheap_transparency = MagickFalse;
9064 else if (image_colors == 0 || image_colors > 256 ||
9065 image->colormap == NULL)
9067 register const Quantum
9070 for (y=0; y < (ssize_t) image->rows; y++)
9072 q=GetVirtualPixels(image,0,y,image->columns,1, exception);
9074 if (q == (Quantum *) NULL)
9077 for (x=0; x < (ssize_t) image->columns; x++)
9079 if (GetPixelAlpha(image,q) != TransparentAlpha &&
9080 (unsigned short) GetPixelRed(image,q) ==
9081 ping_trans_color.red &&
9082 (unsigned short) GetPixelGreen(image,q) ==
9083 ping_trans_color.green &&
9084 (unsigned short) GetPixelBlue(image,q) ==
9085 ping_trans_color.blue)
9087 ping_have_cheap_transparency = MagickFalse;
9091 q+=GetPixelChannels(image);
9094 if (ping_have_cheap_transparency == MagickFalse)
9100 /* Assuming that image->colormap[0] is the one transparent color
9101 * and that all others are opaque.
9103 if (image_colors > 1)
9104 for (i=1; i<image_colors; i++)
9105 if (image->colormap[i].red == image->colormap[0].red &&
9106 image->colormap[i].green == image->colormap[0].green &&
9107 image->colormap[i].blue == image->colormap[0].blue)
9109 ping_have_cheap_transparency = MagickFalse;
9114 if (logging != MagickFalse)
9116 if (ping_have_cheap_transparency == MagickFalse)
9117 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9118 " Cheap transparency is not possible.");
9121 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9122 " Cheap transparency is possible.");
9126 ping_have_cheap_transparency = MagickFalse;
9128 image_depth=image->depth;
9130 quantum_info = (QuantumInfo *) NULL;
9132 image_colors=(int) image->colors;
9133 image_matte=image->alpha_trait == BlendPixelTrait ? MagickTrue : MagickFalse;
9135 mng_info->IsPalette=image->storage_class == PseudoClass &&
9136 image_colors <= 256 && image->colormap != NULL;
9138 if ((mng_info->write_png_colortype == 4 || mng_info->write_png8) &&
9139 (image->colors == 0 || image->colormap == NULL))
9141 image_info=DestroyImageInfo(image_info);
9142 image=DestroyImage(image);
9143 (void) ThrowMagickException(exception,GetMagickModule(),CoderError,
9144 "Cannot write PNG8 or color-type 3; colormap is NULL",
9145 "`%s'",IMimage->filename);
9146 return(MagickFalse);
9150 Allocate the PNG structures
9152 #ifdef PNG_USER_MEM_SUPPORTED
9153 error_info.image=image;
9154 error_info.exception=exception;
9155 ping=png_create_write_struct_2(PNG_LIBPNG_VER_STRING,&error_info,
9156 MagickPNGErrorHandler,MagickPNGWarningHandler,(void *) NULL,
9157 (png_malloc_ptr) Magick_png_malloc,(png_free_ptr) Magick_png_free);
9160 ping=png_create_write_struct(PNG_LIBPNG_VER_STRING,&error_info,
9161 MagickPNGErrorHandler,MagickPNGWarningHandler);
9164 if (ping == (png_struct *) NULL)
9165 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
9167 ping_info=png_create_info_struct(ping);
9169 if (ping_info == (png_info *) NULL)
9171 png_destroy_write_struct(&ping,(png_info **) NULL);
9172 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
9175 png_set_write_fn(ping,image,png_put_data,png_flush_data);
9176 ping_pixels=(unsigned char *) NULL;
9178 if (setjmp(png_jmpbuf(ping)))
9184 if (image_info->verbose)
9185 (void) printf("PNG write has failed.\n");
9187 png_destroy_write_struct(&ping,&ping_info);
9188 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
9189 UnlockSemaphoreInfo(ping_semaphore);
9192 if (ping_pixels != (unsigned char *) NULL)
9193 ping_pixels=(unsigned char *) RelinquishMagickMemory(ping_pixels);
9195 if (quantum_info != (QuantumInfo *) NULL)
9196 quantum_info=DestroyQuantumInfo(quantum_info);
9198 if (ping_have_blob != MagickFalse)
9199 (void) CloseBlob(image);
9200 image_info=DestroyImageInfo(image_info);
9201 image=DestroyImage(image);
9202 return(MagickFalse);
9205 /* { For navigation to end of SETJMP-protected block. Within this
9206 * block, use png_error() instead of Throwing an Exception, to ensure
9207 * that libpng is able to clean up, and that the semaphore is unlocked.
9210 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
9211 LockSemaphoreInfo(ping_semaphore);
9215 Prepare PNG for writing.
9218 #if defined(PNG_MNG_FEATURES_SUPPORTED)
9219 if (mng_info->write_mng)
9221 (void) png_permit_mng_features(ping,PNG_ALL_MNG_FEATURES);
9222 # ifdef PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED
9223 /* Disable new libpng-1.5.10 feature when writing a MNG because
9224 * zero-length PLTE is OK
9226 png_set_check_for_invalid_index (ping, 0);
9231 # ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
9232 if (mng_info->write_mng)
9233 png_permit_empty_plte(ping,MagickTrue);
9240 ping_width=(png_uint_32) image->columns;
9241 ping_height=(png_uint_32) image->rows;
9243 if (mng_info->write_png8 || mng_info->write_png24 || mng_info->write_png32)
9246 if (mng_info->write_png48 || mng_info->write_png64)
9249 if (mng_info->write_png_depth != 0)
9250 image_depth=mng_info->write_png_depth;
9252 /* Adjust requested depth to next higher valid depth if necessary */
9253 if (image_depth > 8)
9256 if ((image_depth > 4) && (image_depth < 8))
9259 if (image_depth == 3)
9262 if (logging != MagickFalse)
9264 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9265 " width=%.20g",(double) ping_width);
9266 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9267 " height=%.20g",(double) ping_height);
9268 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9269 " image_matte=%.20g",(double) image->alpha_trait);
9270 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9271 " image->depth=%.20g",(double) image->depth);
9272 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9273 " Tentative ping_bit_depth=%.20g",(double) image_depth);
9276 save_image_depth=image_depth;
9277 ping_bit_depth=(png_byte) save_image_depth;
9280 #if defined(PNG_pHYs_SUPPORTED)
9281 if (ping_exclude_pHYs == MagickFalse)
9283 if ((image->resolution.x != 0) && (image->resolution.y != 0) &&
9284 (!mng_info->write_mng || !mng_info->equal_physs))
9286 if (logging != MagickFalse)
9287 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9288 " Setting up pHYs chunk");
9290 if (image->units == PixelsPerInchResolution)
9292 ping_pHYs_unit_type=PNG_RESOLUTION_METER;
9293 ping_pHYs_x_resolution=
9294 (png_uint_32) ((100.0*image->resolution.x+0.5)/2.54);
9295 ping_pHYs_y_resolution=
9296 (png_uint_32) ((100.0*image->resolution.y+0.5)/2.54);
9299 else if (image->units == PixelsPerCentimeterResolution)
9301 ping_pHYs_unit_type=PNG_RESOLUTION_METER;
9302 ping_pHYs_x_resolution=(png_uint_32) (100.0*image->resolution.x+0.5);
9303 ping_pHYs_y_resolution=(png_uint_32) (100.0*image->resolution.y+0.5);
9308 ping_pHYs_unit_type=PNG_RESOLUTION_UNKNOWN;
9309 ping_pHYs_x_resolution=(png_uint_32) image->resolution.x;
9310 ping_pHYs_y_resolution=(png_uint_32) image->resolution.y;
9313 if (logging != MagickFalse)
9314 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9315 " Set up PNG pHYs chunk: xres: %.20g, yres: %.20g, units: %d.",
9316 (double) ping_pHYs_x_resolution,(double) ping_pHYs_y_resolution,
9317 (int) ping_pHYs_unit_type);
9318 ping_have_pHYs = MagickTrue;
9323 if (ping_exclude_bKGD == MagickFalse)
9325 if ((!mng_info->adjoin || !mng_info->equal_backgrounds))
9331 if (ping_bit_depth == 8)
9334 if (ping_bit_depth == 4)
9337 if (ping_bit_depth == 2)
9340 if (ping_bit_depth == 1)
9343 ping_background.red=(png_uint_16)
9344 (ScaleQuantumToShort(image->background_color.red) & mask);
9346 ping_background.green=(png_uint_16)
9347 (ScaleQuantumToShort(image->background_color.green) & mask);
9349 ping_background.blue=(png_uint_16)
9350 (ScaleQuantumToShort(image->background_color.blue) & mask);
9352 ping_background.gray=(png_uint_16) ping_background.green;
9355 if (logging != MagickFalse)
9357 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9358 " Setting up bKGD chunk (1)");
9359 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9360 " background_color index is %d",
9361 (int) ping_background.index);
9363 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9364 " ping_bit_depth=%d",ping_bit_depth);
9367 ping_have_bKGD = MagickTrue;
9371 Select the color type.
9376 if (mng_info->IsPalette && mng_info->write_png8)
9379 /* To do: make this a function cause it's used twice, except
9380 for reducing the sample depth from 8. */
9382 number_colors=image_colors;
9384 ping_have_tRNS=MagickFalse;
9389 ping_color_type=(png_byte) PNG_COLOR_TYPE_PALETTE;
9391 if (logging != MagickFalse)
9392 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9393 " Setting up PLTE chunk with %d colors (%d)",
9394 number_colors, image_colors);
9396 for (i=0; i < (ssize_t) number_colors; i++)
9398 palette[i].red=ScaleQuantumToChar(image->colormap[i].red);
9399 palette[i].green=ScaleQuantumToChar(image->colormap[i].green);
9400 palette[i].blue=ScaleQuantumToChar(image->colormap[i].blue);
9401 if (logging != MagickFalse)
9402 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9403 #if MAGICKCORE_QUANTUM_DEPTH == 8
9404 " %3ld (%3d,%3d,%3d)",
9406 " %5ld (%5d,%5d,%5d)",
9408 (long) i,palette[i].red,palette[i].green,palette[i].blue);
9412 ping_have_PLTE=MagickTrue;
9413 image_depth=ping_bit_depth;
9416 if (matte != MagickFalse)
9419 Identify which colormap entry is transparent.
9421 assert(number_colors <= 256);
9422 assert(image->colormap != NULL);
9424 for (i=0; i < (ssize_t) number_transparent; i++)
9425 ping_trans_alpha[i]=0;
9428 ping_num_trans=(unsigned short) (number_transparent +
9429 number_semitransparent);
9431 if (ping_num_trans == 0)
9432 ping_have_tRNS=MagickFalse;
9435 ping_have_tRNS=MagickTrue;
9438 if (ping_exclude_bKGD == MagickFalse)
9441 * Identify which colormap entry is the background color.
9444 for (i=0; i < (ssize_t) MagickMax(1L*number_colors-1L,1L); i++)
9445 if (IsPNGColorEqual(ping_background,image->colormap[i]))
9448 ping_background.index=(png_byte) i;
9450 if (logging != MagickFalse)
9452 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9453 " background_color index is %d",
9454 (int) ping_background.index);
9457 } /* end of write_png8 */
9459 else if (mng_info->write_png_colortype == 1)
9461 image_matte=MagickFalse;
9462 ping_color_type=(png_byte) PNG_COLOR_TYPE_GRAY;
9465 else if (mng_info->write_png24 || mng_info->write_png48 ||
9466 mng_info->write_png_colortype == 3)
9468 image_matte=MagickFalse;
9469 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB;
9472 else if (mng_info->write_png32 || mng_info->write_png64 ||
9473 mng_info->write_png_colortype == 7)
9475 image_matte=MagickTrue;
9476 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB_ALPHA;
9479 else /* mng_info->write_pngNN not specified */
9481 image_depth=ping_bit_depth;
9483 if (mng_info->write_png_colortype != 0)
9485 ping_color_type=(png_byte) mng_info->write_png_colortype-1;
9487 if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA ||
9488 ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA)
9489 image_matte=MagickTrue;
9492 image_matte=MagickFalse;
9494 if (logging != MagickFalse)
9495 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9496 " PNG colortype %d was specified:",(int) ping_color_type);
9499 else /* write_png_colortype not specified */
9501 if (logging != MagickFalse)
9502 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9503 " Selecting PNG colortype:");
9505 ping_color_type=(png_byte) ((matte != MagickFalse)?
9506 PNG_COLOR_TYPE_RGB_ALPHA:PNG_COLOR_TYPE_RGB);
9508 if (image_info->type == TrueColorType)
9510 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB;
9511 image_matte=MagickFalse;
9514 if (image_info->type == TrueColorMatteType)
9516 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB_ALPHA;
9517 image_matte=MagickTrue;
9520 if (image_info->type == PaletteType ||
9521 image_info->type == PaletteMatteType)
9522 ping_color_type=(png_byte) PNG_COLOR_TYPE_PALETTE;
9524 if (mng_info->write_png_colortype == 0 &&
9525 (image_info->type == UndefinedType ||
9526 image_info->type == OptimizeType))
9528 if (ping_have_color == MagickFalse)
9530 if (image_matte == MagickFalse)
9532 ping_color_type=(png_byte) PNG_COLOR_TYPE_GRAY;
9533 image_matte=MagickFalse;
9538 ping_color_type=(png_byte) PNG_COLOR_TYPE_GRAY_ALPHA;
9539 image_matte=MagickTrue;
9544 if (image_matte == MagickFalse)
9546 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB;
9547 image_matte=MagickFalse;
9552 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGBA;
9553 image_matte=MagickTrue;
9560 if (logging != MagickFalse)
9561 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9562 " Selected PNG colortype=%d",ping_color_type);
9564 if (ping_bit_depth < 8)
9566 if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA ||
9567 ping_color_type == PNG_COLOR_TYPE_RGB ||
9568 ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA)
9572 old_bit_depth=ping_bit_depth;
9574 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
9576 if (image->alpha_trait != BlendPixelTrait && ping_have_non_bw == MagickFalse)
9580 if (ping_color_type == PNG_COLOR_TYPE_PALETTE)
9585 if (image->colors == 0)
9588 png_error(ping,"image has 0 colors");
9591 while ((int) (one << ping_bit_depth) < (ssize_t) image_colors)
9592 ping_bit_depth <<= 1;
9595 if (logging != MagickFalse)
9597 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9598 " Number of colors: %.20g",(double) image_colors);
9600 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9601 " Tentative PNG bit depth: %d",ping_bit_depth);
9604 if (ping_bit_depth < (int) mng_info->write_png_depth)
9605 ping_bit_depth = mng_info->write_png_depth;
9608 image_depth=ping_bit_depth;
9610 if (logging != MagickFalse)
9612 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9613 " Tentative PNG color type: %s (%.20g)",
9614 PngColorTypeToString(ping_color_type),
9615 (double) ping_color_type);
9617 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9618 " image_info->type: %.20g",(double) image_info->type);
9620 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9621 " image_depth: %.20g",(double) image_depth);
9623 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9625 " image->depth: %.20g",(double) image->depth);
9627 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9628 " ping_bit_depth: %.20g",(double) ping_bit_depth);
9631 if (matte != MagickFalse)
9633 if (mng_info->IsPalette)
9635 if (mng_info->write_png_colortype == 0)
9637 ping_color_type=PNG_COLOR_TYPE_GRAY_ALPHA;
9639 if (ping_have_color != MagickFalse)
9640 ping_color_type=PNG_COLOR_TYPE_RGBA;
9644 * Determine if there is any transparent color.
9646 if (number_transparent + number_semitransparent == 0)
9649 No transparent pixels are present. Change 4 or 6 to 0 or 2.
9652 image_matte=MagickFalse;
9654 if (mng_info->write_png_colortype == 0)
9655 ping_color_type&=0x03;
9665 if (ping_bit_depth == 8)
9668 if (ping_bit_depth == 4)
9671 if (ping_bit_depth == 2)
9674 if (ping_bit_depth == 1)
9677 ping_trans_color.red=(png_uint_16)
9678 (ScaleQuantumToShort(image->colormap[0].red) & mask);
9680 ping_trans_color.green=(png_uint_16)
9681 (ScaleQuantumToShort(image->colormap[0].green) & mask);
9683 ping_trans_color.blue=(png_uint_16)
9684 (ScaleQuantumToShort(image->colormap[0].blue) & mask);
9686 ping_trans_color.gray=(png_uint_16)
9687 (ScaleQuantumToShort(GetPixelInfoIntensity(
9688 image->colormap)) & mask);
9690 ping_trans_color.index=(png_byte) 0;
9692 ping_have_tRNS=MagickTrue;
9695 if (ping_have_tRNS != MagickFalse)
9698 * Determine if there is one and only one transparent color
9699 * and if so if it is fully transparent.
9701 if (ping_have_cheap_transparency == MagickFalse)
9702 ping_have_tRNS=MagickFalse;
9705 if (ping_have_tRNS != MagickFalse)
9707 if (mng_info->write_png_colortype == 0)
9708 ping_color_type &= 0x03; /* changes 4 or 6 to 0 or 2 */
9710 if (image_depth == 8)
9712 ping_trans_color.red&=0xff;
9713 ping_trans_color.green&=0xff;
9714 ping_trans_color.blue&=0xff;
9715 ping_trans_color.gray&=0xff;
9721 if (image_depth == 8)
9723 ping_trans_color.red&=0xff;
9724 ping_trans_color.green&=0xff;
9725 ping_trans_color.blue&=0xff;
9726 ping_trans_color.gray&=0xff;
9733 if (ping_have_tRNS != MagickFalse)
9734 image_matte=MagickFalse;
9736 if ((mng_info->IsPalette) &&
9737 mng_info->write_png_colortype-1 != PNG_COLOR_TYPE_PALETTE &&
9738 ping_have_color == MagickFalse &&
9739 (image_matte == MagickFalse || image_depth >= 8))
9743 if (image_matte != MagickFalse)
9744 ping_color_type=PNG_COLOR_TYPE_GRAY_ALPHA;
9746 else if (mng_info->write_png_colortype-1 != PNG_COLOR_TYPE_GRAY_ALPHA)
9748 ping_color_type=PNG_COLOR_TYPE_GRAY;
9750 if (save_image_depth == 16 && image_depth == 8)
9752 if (logging != MagickFalse)
9754 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9755 " Scaling ping_trans_color (0)");
9757 ping_trans_color.gray*=0x0101;
9761 if (image_depth > MAGICKCORE_QUANTUM_DEPTH)
9762 image_depth=MAGICKCORE_QUANTUM_DEPTH;
9764 if ((image_colors == 0) ||
9765 ((ssize_t) (image_colors-1) > (ssize_t) MaxColormapSize))
9766 image_colors=(int) (one << image_depth);
9768 if (image_depth > 8)
9774 if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
9776 if(!mng_info->write_png_depth)
9780 while ((int) (one << ping_bit_depth)
9781 < (ssize_t) image_colors)
9782 ping_bit_depth <<= 1;
9786 else if (ping_color_type ==
9787 PNG_COLOR_TYPE_GRAY && image_colors < 17 &&
9788 mng_info->IsPalette)
9790 /* Check if grayscale is reducible */
9793 depth_4_ok=MagickTrue,
9794 depth_2_ok=MagickTrue,
9795 depth_1_ok=MagickTrue;
9797 for (i=0; i < (ssize_t) image_colors; i++)
9802 intensity=ScaleQuantumToChar(image->colormap[i].red);
9804 if ((intensity & 0x0f) != ((intensity & 0xf0) >> 4))
9805 depth_4_ok=depth_2_ok=depth_1_ok=MagickFalse;
9806 else if ((intensity & 0x03) != ((intensity & 0x0c) >> 2))
9807 depth_2_ok=depth_1_ok=MagickFalse;
9808 else if ((intensity & 0x01) != ((intensity & 0x02) >> 1))
9809 depth_1_ok=MagickFalse;
9812 if (depth_1_ok && mng_info->write_png_depth <= 1)
9815 else if (depth_2_ok && mng_info->write_png_depth <= 2)
9818 else if (depth_4_ok && mng_info->write_png_depth <= 4)
9823 image_depth=ping_bit_depth;
9828 if (mng_info->IsPalette)
9830 number_colors=image_colors;
9832 if (image_depth <= 8)
9837 ping_color_type=(png_byte) PNG_COLOR_TYPE_PALETTE;
9839 if (!(mng_info->have_write_global_plte && matte == MagickFalse))
9841 for (i=0; i < (ssize_t) number_colors; i++)
9843 palette[i].red=ScaleQuantumToChar(image->colormap[i].red);
9844 palette[i].green=ScaleQuantumToChar(image->colormap[i].green);
9845 palette[i].blue=ScaleQuantumToChar(image->colormap[i].blue);
9848 if (logging != MagickFalse)
9849 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9850 " Setting up PLTE chunk with %d colors",
9853 ping_have_PLTE=MagickTrue;
9856 /* color_type is PNG_COLOR_TYPE_PALETTE */
9857 if (mng_info->write_png_depth == 0)
9865 while ((one << ping_bit_depth) < (size_t) number_colors)
9866 ping_bit_depth <<= 1;
9871 if (matte != MagickFalse)
9874 * Set up trans_colors array.
9876 assert(number_colors <= 256);
9878 ping_num_trans=(unsigned short) (number_transparent +
9879 number_semitransparent);
9881 if (ping_num_trans == 0)
9882 ping_have_tRNS=MagickFalse;
9886 if (logging != MagickFalse)
9888 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9889 " Scaling ping_trans_color (1)");
9891 ping_have_tRNS=MagickTrue;
9893 for (i=0; i < ping_num_trans; i++)
9895 ping_trans_alpha[i]= (png_byte)
9896 ScaleQuantumToChar(image->colormap[i].alpha);
9906 if (image_depth < 8)
9909 if ((save_image_depth == 16) && (image_depth == 8))
9911 if (logging != MagickFalse)
9913 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9914 " Scaling ping_trans_color from (%d,%d,%d)",
9915 (int) ping_trans_color.red,
9916 (int) ping_trans_color.green,
9917 (int) ping_trans_color.blue);
9920 ping_trans_color.red*=0x0101;
9921 ping_trans_color.green*=0x0101;
9922 ping_trans_color.blue*=0x0101;
9923 ping_trans_color.gray*=0x0101;
9925 if (logging != MagickFalse)
9927 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9929 (int) ping_trans_color.red,
9930 (int) ping_trans_color.green,
9931 (int) ping_trans_color.blue);
9936 if (ping_bit_depth < (ssize_t) mng_info->write_png_depth)
9937 ping_bit_depth = (ssize_t) mng_info->write_png_depth;
9940 Adjust background and transparency samples in sub-8-bit grayscale files.
9942 if (ping_bit_depth < 8 && ping_color_type ==
9943 PNG_COLOR_TYPE_GRAY)
9951 maxval=(png_uint_16) ((one << ping_bit_depth)-1);
9953 if (ping_exclude_bKGD == MagickFalse)
9956 ping_background.gray=(png_uint_16) ((maxval/65535.)*
9957 (ScaleQuantumToShort(((GetPixelInfoIntensity(
9958 &image->background_color))) +.5)));
9960 if (logging != MagickFalse)
9961 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9962 " Setting up bKGD chunk (2)");
9963 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9964 " background_color index is %d",
9965 (int) ping_background.index);
9967 ping_have_bKGD = MagickTrue;
9970 if (logging != MagickFalse)
9971 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9972 " Scaling ping_trans_color.gray from %d",
9973 (int)ping_trans_color.gray);
9975 ping_trans_color.gray=(png_uint_16) ((maxval/255.)*(
9976 ping_trans_color.gray)+.5);
9978 if (logging != MagickFalse)
9979 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9980 " to %d", (int)ping_trans_color.gray);
9983 if (ping_exclude_bKGD == MagickFalse)
9985 if (mng_info->IsPalette && (int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
9988 Identify which colormap entry is the background color.
9991 number_colors=image_colors;
9993 for (i=0; i < (ssize_t) MagickMax(1L*number_colors,1L); i++)
9994 if (IsPNGColorEqual(image->background_color,image->colormap[i]))
9997 ping_background.index=(png_byte) i;
9999 if (logging != MagickFalse)
10001 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10002 " Setting up bKGD chunk with index=%d",(int) i);
10005 if (i < (ssize_t) number_colors)
10007 ping_have_bKGD = MagickTrue;
10009 if (logging != MagickFalse)
10011 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10012 " background =(%d,%d,%d)",
10013 (int) ping_background.red,
10014 (int) ping_background.green,
10015 (int) ping_background.blue);
10019 else /* Can't happen */
10021 if (logging != MagickFalse)
10022 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10023 " No room in PLTE to add bKGD color");
10024 ping_have_bKGD = MagickFalse;
10029 if (logging != MagickFalse)
10030 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10031 " PNG color type: %s (%d)", PngColorTypeToString(ping_color_type),
10034 Initialize compression level and filtering.
10036 if (logging != MagickFalse)
10038 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10039 " Setting up deflate compression");
10041 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10042 " Compression buffer size: 32768");
10045 png_set_compression_buffer_size(ping,32768L);
10047 if (logging != MagickFalse)
10048 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10049 " Compression mem level: 9");
10051 png_set_compression_mem_level(ping, 9);
10053 /* Untangle the "-quality" setting:
10055 Undefined is 0; the default is used.
10060 0: Use Z_HUFFMAN_ONLY strategy with the
10061 zlib default compression level
10063 1-9: the zlib compression level
10067 0-4: the PNG filter method
10069 5: libpng adaptive filtering if compression level > 5
10070 libpng filter type "none" if compression level <= 5
10071 or if image is grayscale or palette
10073 6: libpng adaptive filtering
10075 7: "LOCO" filtering (intrapixel differing) if writing
10076 a MNG, othewise "none". Did not work in IM-6.7.0-9
10077 and earlier because of a missing "else".
10079 8: Z_RLE strategy, all filters
10080 Unused prior to IM-6.7.0-10, was same as 6
10082 9: Z_RLE strategy, no PNG filters
10083 Unused prior to IM-6.7.0-10, was same as 6
10085 Note that using the -quality option, not all combinations of
10086 PNG filter type, zlib compression level, and zlib compression
10087 strategy are possible. This will be addressed soon in a
10088 release that accomodates "-define png:compression-strategy", etc.
10092 quality=image->quality == UndefinedCompressionQuality ? 75UL :
10097 if (mng_info->write_png_compression_strategy == 0)
10098 mng_info->write_png_compression_strategy = Z_HUFFMAN_ONLY+1;
10101 else if (mng_info->write_png_compression_level == 0)
10106 level=(int) MagickMin((ssize_t) quality/10,9);
10108 mng_info->write_png_compression_level = level+1;
10111 if (mng_info->write_png_compression_strategy == 0)
10113 if ((quality %10) == 8 || (quality %10) == 9)
10114 #ifdef Z_RLE /* Z_RLE was added to zlib-1.2.0 */
10115 mng_info->write_png_compression_strategy=Z_RLE+1;
10117 mng_info->write_png_compression_strategy = Z_DEFAULT_STRATEGY+1;
10121 if (mng_info->write_png_compression_filter == 0)
10122 mng_info->write_png_compression_filter=((int) quality % 10) + 1;
10124 if (logging != MagickFalse)
10126 if (mng_info->write_png_compression_level)
10127 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10128 " Compression level: %d",
10129 (int) mng_info->write_png_compression_level-1);
10131 if (mng_info->write_png_compression_strategy)
10132 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10133 " Compression strategy: %d",
10134 (int) mng_info->write_png_compression_strategy-1);
10136 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10137 " Setting up filtering");
10139 if (mng_info->write_png_compression_filter == 6)
10140 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10141 " Base filter method: ADAPTIVE");
10142 else if (mng_info->write_png_compression_filter == 0 ||
10143 mng_info->write_png_compression_filter == 1)
10144 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10145 " Base filter method: NONE");
10147 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10148 " Base filter method: %d",
10149 (int) mng_info->write_png_compression_filter-1);
10152 if (mng_info->write_png_compression_level != 0)
10153 png_set_compression_level(ping,mng_info->write_png_compression_level-1);
10155 if (mng_info->write_png_compression_filter == 6)
10157 if (((int) ping_color_type == PNG_COLOR_TYPE_GRAY) ||
10158 ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE) ||
10160 png_set_filter(ping,PNG_FILTER_TYPE_BASE,PNG_NO_FILTERS);
10162 png_set_filter(ping,PNG_FILTER_TYPE_BASE,PNG_ALL_FILTERS);
10164 else if (mng_info->write_png_compression_filter == 7 ||
10165 mng_info->write_png_compression_filter == 10)
10166 png_set_filter(ping,PNG_FILTER_TYPE_BASE,PNG_ALL_FILTERS);
10168 else if (mng_info->write_png_compression_filter == 8)
10170 #if defined(PNG_MNG_FEATURES_SUPPORTED) && defined(PNG_INTRAPIXEL_DIFFERENCING)
10171 if (mng_info->write_mng)
10173 if (((int) ping_color_type == PNG_COLOR_TYPE_RGB) ||
10174 ((int) ping_color_type == PNG_COLOR_TYPE_RGBA))
10175 ping_filter_method=PNG_INTRAPIXEL_DIFFERENCING;
10178 png_set_filter(ping,PNG_FILTER_TYPE_BASE,PNG_NO_FILTERS);
10181 else if (mng_info->write_png_compression_filter == 9)
10182 png_set_filter(ping,PNG_FILTER_TYPE_BASE,PNG_NO_FILTERS);
10184 else if (mng_info->write_png_compression_filter != 0)
10185 png_set_filter(ping,PNG_FILTER_TYPE_BASE,
10186 mng_info->write_png_compression_filter-1);
10188 if (mng_info->write_png_compression_strategy != 0)
10189 png_set_compression_strategy(ping,
10190 mng_info->write_png_compression_strategy-1);
10192 ping_interlace_method=image_info->interlace != NoInterlace;
10194 if (mng_info->write_mng)
10195 png_set_sig_bytes(ping,8);
10197 /* Bail out if cannot meet defined png:bit-depth or png:color-type */
10199 if (mng_info->write_png_colortype != 0)
10201 if (mng_info->write_png_colortype-1 == PNG_COLOR_TYPE_GRAY)
10202 if (ping_have_color != MagickFalse)
10204 ping_color_type = PNG_COLOR_TYPE_RGB;
10206 if (ping_bit_depth < 8)
10210 if (mng_info->write_png_colortype-1 == PNG_COLOR_TYPE_GRAY_ALPHA)
10211 if (ping_have_color != MagickFalse)
10212 ping_color_type = PNG_COLOR_TYPE_RGB_ALPHA;
10215 if (ping_need_colortype_warning != MagickFalse ||
10216 ((mng_info->write_png_depth &&
10217 (int) mng_info->write_png_depth != ping_bit_depth) ||
10218 (mng_info->write_png_colortype &&
10219 ((int) mng_info->write_png_colortype-1 != ping_color_type &&
10220 mng_info->write_png_colortype != 7 &&
10221 !(mng_info->write_png_colortype == 5 && ping_color_type == 0)))))
10223 if (logging != MagickFalse)
10225 if (ping_need_colortype_warning != MagickFalse)
10227 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10228 " Image has transparency but tRNS chunk was excluded");
10231 if (mng_info->write_png_depth)
10233 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10234 " Defined png:bit-depth=%u, Computed depth=%u",
10235 mng_info->write_png_depth,
10239 if (mng_info->write_png_colortype)
10241 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10242 " Defined png:color-type=%u, Computed color type=%u",
10243 mng_info->write_png_colortype-1,
10249 "Cannot write image with defined png:bit-depth or png:color-type.");
10252 if (image_matte != MagickFalse && image->alpha_trait != BlendPixelTrait)
10254 /* Add an opaque matte channel */
10255 image->alpha_trait = BlendPixelTrait;
10256 (void) SetImageAlpha(image,OpaqueAlpha,exception);
10258 if (logging != MagickFalse)
10259 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10260 " Added an opaque matte channel");
10263 if (number_transparent != 0 || number_semitransparent != 0)
10265 if (ping_color_type < 4)
10267 ping_have_tRNS=MagickTrue;
10268 if (logging != MagickFalse)
10269 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10270 " Setting ping_have_tRNS=MagickTrue.");
10274 if (logging != MagickFalse)
10275 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10276 " Writing PNG header chunks");
10278 png_set_IHDR(ping,ping_info,ping_width,ping_height,
10279 ping_bit_depth,ping_color_type,
10280 ping_interlace_method,ping_compression_method,
10281 ping_filter_method);
10283 if (ping_color_type == 3 && ping_have_PLTE != MagickFalse)
10285 png_set_PLTE(ping,ping_info,palette,number_colors);
10287 if (logging != MagickFalse)
10289 for (i=0; i< (ssize_t) number_colors; i++)
10291 if (i < ping_num_trans)
10292 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10293 " PLTE[%d] = (%d,%d,%d), tRNS[%d] = (%d)",
10295 (int) palette[i].red,
10296 (int) palette[i].green,
10297 (int) palette[i].blue,
10299 (int) ping_trans_alpha[i]);
10301 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10302 " PLTE[%d] = (%d,%d,%d)",
10304 (int) palette[i].red,
10305 (int) palette[i].green,
10306 (int) palette[i].blue);
10311 /* Only write the iCCP chunk if we are not writing the sRGB chunk. */
10312 if (ping_exclude_sRGB != MagickFalse ||
10313 (!png_get_valid(ping,ping_info,PNG_INFO_sRGB)))
10315 if ((ping_exclude_tEXt == MagickFalse ||
10316 ping_exclude_zTXt == MagickFalse) &&
10317 (ping_exclude_iCCP == MagickFalse || ping_exclude_zCCP == MagickFalse))
10319 ResetImageProfileIterator(image);
10320 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
10322 profile=GetImageProfile(image,name);
10324 if (profile != (StringInfo *) NULL)
10326 #ifdef PNG_WRITE_iCCP_SUPPORTED
10327 if ((LocaleCompare(name,"ICC") == 0) ||
10328 (LocaleCompare(name,"ICM") == 0))
10331 if (ping_exclude_iCCP == MagickFalse)
10333 png_set_iCCP(ping,ping_info,(png_charp) name,0,
10334 #if (PNG_LIBPNG_VER < 10500)
10335 (png_charp) GetStringInfoDatum(profile),
10337 (png_const_bytep) GetStringInfoDatum(profile),
10339 (png_uint_32) GetStringInfoLength(profile));
10345 if (ping_exclude_zCCP == MagickFalse)
10347 Magick_png_write_raw_profile(image_info,ping,ping_info,
10348 (unsigned char *) name,(unsigned char *) name,
10349 GetStringInfoDatum(profile),
10350 (png_uint_32) GetStringInfoLength(profile));
10354 if (logging != MagickFalse)
10355 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10356 " Setting up text chunk with %s profile",name);
10358 name=GetNextImageProfile(image);
10363 #if defined(PNG_WRITE_sRGB_SUPPORTED)
10364 if ((mng_info->have_write_global_srgb == 0) &&
10365 (png_get_valid(ping,ping_info,PNG_INFO_sRGB)))
10367 if (ping_exclude_sRGB == MagickFalse)
10370 Note image rendering intent.
10372 if (logging != MagickFalse)
10373 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10374 " Setting up sRGB chunk");
10376 (void) png_set_sRGB(ping,ping_info,(
10377 Magick_RenderingIntent_to_PNG_RenderingIntent(
10378 image->rendering_intent)));
10382 if ((!mng_info->write_mng) || (!png_get_valid(ping,ping_info,PNG_INFO_sRGB)))
10385 if (ping_exclude_gAMA == MagickFalse &&
10386 (ping_exclude_sRGB == MagickFalse ||
10387 (image->gamma < .45 || image->gamma > .46)))
10389 if ((mng_info->have_write_global_gama == 0) && (image->gamma != 0.0))
10393 To do: check for cHRM+gAMA == sRGB, and write sRGB instead.
10395 if (logging != MagickFalse)
10396 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10397 " Setting up gAMA chunk");
10399 png_set_gAMA(ping,ping_info,image->gamma);
10403 if (ping_exclude_cHRM == MagickFalse)
10405 if ((mng_info->have_write_global_chrm == 0) &&
10406 (image->chromaticity.red_primary.x != 0.0))
10409 Note image chromaticity.
10410 To do: check for cHRM+gAMA == sRGB, and write sRGB instead.
10418 wp=image->chromaticity.white_point;
10419 rp=image->chromaticity.red_primary;
10420 gp=image->chromaticity.green_primary;
10421 bp=image->chromaticity.blue_primary;
10423 if (logging != MagickFalse)
10424 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10425 " Setting up cHRM chunk");
10427 png_set_cHRM(ping,ping_info,wp.x,wp.y,rp.x,rp.y,gp.x,gp.y,
10433 if (ping_exclude_bKGD == MagickFalse)
10435 if (ping_have_bKGD != MagickFalse)
10437 png_set_bKGD(ping,ping_info,&ping_background);
10440 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10441 " Setting up bKGD chunk");
10442 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10443 " background color = (%d,%d,%d)",
10444 (int) ping_background.red,
10445 (int) ping_background.green,
10446 (int) ping_background.blue);
10447 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10448 " index = %d, gray=%d",
10449 (int) ping_background.index,
10450 (int) ping_background.gray);
10455 if (ping_exclude_pHYs == MagickFalse)
10457 if (ping_have_pHYs != MagickFalse)
10459 png_set_pHYs(ping,ping_info,
10460 ping_pHYs_x_resolution,
10461 ping_pHYs_y_resolution,
10462 ping_pHYs_unit_type);
10466 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10467 " Setting up pHYs chunk");
10468 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10469 " x_resolution=%lu",
10470 (unsigned long) ping_pHYs_x_resolution);
10471 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10472 " y_resolution=%lu",
10473 (unsigned long) ping_pHYs_y_resolution);
10474 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10476 (unsigned long) ping_pHYs_unit_type);
10481 #if defined(PNG_oFFs_SUPPORTED)
10482 if (ping_exclude_oFFs == MagickFalse)
10484 if (image->page.x || image->page.y)
10486 png_set_oFFs(ping,ping_info,(png_int_32) image->page.x,
10487 (png_int_32) image->page.y, 0);
10489 if (logging != MagickFalse)
10490 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10491 " Setting up oFFs chunk with x=%d, y=%d, units=0",
10492 (int) image->page.x, (int) image->page.y);
10497 if (mng_info->need_blob != MagickFalse)
10499 if (OpenBlob(image_info,image,WriteBinaryBlobMode,exception) ==
10501 png_error(ping,"WriteBlob Failed");
10503 ping_have_blob=MagickTrue;
10506 png_write_info_before_PLTE(ping, ping_info);
10508 if (ping_have_tRNS != MagickFalse && ping_color_type < 4)
10510 if (logging != MagickFalse)
10512 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10513 " Calling png_set_tRNS with num_trans=%d",ping_num_trans);
10516 if (ping_color_type == 3)
10517 (void) png_set_tRNS(ping, ping_info,
10524 (void) png_set_tRNS(ping, ping_info,
10527 &ping_trans_color);
10529 if (logging != MagickFalse)
10531 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10532 " tRNS color =(%d,%d,%d)",
10533 (int) ping_trans_color.red,
10534 (int) ping_trans_color.green,
10535 (int) ping_trans_color.blue);
10540 /* write any png-chunk-b profiles */
10541 (void) Magick_png_write_chunk_from_profile(image,"PNG-chunk-b",logging);
10543 png_write_info(ping,ping_info);
10545 /* write any PNG-chunk-m profiles */
10546 (void) Magick_png_write_chunk_from_profile(image,"PNG-chunk-m",logging);
10548 if (ping_exclude_vpAg == MagickFalse)
10550 if ((image->page.width != 0 && image->page.width != image->columns) ||
10551 (image->page.height != 0 && image->page.height != image->rows))
10556 (void) WriteBlobMSBULong(image,9L); /* data length=8 */
10557 PNGType(chunk,mng_vpAg);
10558 LogPNGChunk(logging,mng_vpAg,9L);
10559 PNGLong(chunk+4,(png_uint_32) image->page.width);
10560 PNGLong(chunk+8,(png_uint_32) image->page.height);
10561 chunk[12]=0; /* unit = pixels */
10562 (void) WriteBlob(image,13,chunk);
10563 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
10567 #if (PNG_LIBPNG_VER == 10206)
10568 /* avoid libpng-1.2.6 bug by setting PNG_HAVE_IDAT flag */
10569 #define PNG_HAVE_IDAT 0x04
10570 ping->mode |= PNG_HAVE_IDAT;
10571 #undef PNG_HAVE_IDAT
10574 png_set_packing(ping);
10578 rowbytes=image->columns;
10579 if (image_depth > 8)
10581 switch (ping_color_type)
10583 case PNG_COLOR_TYPE_RGB:
10587 case PNG_COLOR_TYPE_GRAY_ALPHA:
10591 case PNG_COLOR_TYPE_RGBA:
10599 if (logging != MagickFalse)
10601 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10602 " Writing PNG image data");
10604 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10605 " Allocating %.20g bytes of memory for pixels",(double) rowbytes);
10607 ping_pixels=(unsigned char *) AcquireQuantumMemory(rowbytes,
10608 sizeof(*ping_pixels));
10610 if (ping_pixels == (unsigned char *) NULL)
10611 png_error(ping,"Allocation of memory for pixels failed");
10614 Initialize image scanlines.
10616 quantum_info=AcquireQuantumInfo(image_info,image);
10617 if (quantum_info == (QuantumInfo *) NULL)
10618 png_error(ping,"Memory allocation for quantum_info failed");
10619 quantum_info->format=UndefinedQuantumFormat;
10620 quantum_info->depth=image_depth;
10621 (void) SetQuantumEndian(image,quantum_info,MSBEndian);
10622 num_passes=png_set_interlace_handling(ping);
10624 if ((!mng_info->write_png8 && !mng_info->write_png24 &&
10625 !mng_info->write_png48 && !mng_info->write_png64 &&
10626 !mng_info->write_png32) &&
10627 (mng_info->IsPalette ||
10628 (image_info->type == BilevelType)) &&
10629 image_matte == MagickFalse &&
10630 ping_have_non_bw == MagickFalse)
10632 /* Palette, Bilevel, or Opaque Monochrome */
10633 register const Quantum
10636 quantum_info->depth=8;
10637 for (pass=0; pass < num_passes; pass++)
10640 Convert PseudoClass image to a PNG monochrome image.
10642 for (y=0; y < (ssize_t) image->rows; y++)
10644 if (logging != MagickFalse && y == 0)
10645 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10646 " Writing row of pixels (0)");
10648 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
10650 if (p == (const Quantum *) NULL)
10653 if (mng_info->IsPalette)
10655 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10656 quantum_info,GrayQuantum,ping_pixels,exception);
10657 if (mng_info->write_png_colortype-1 == PNG_COLOR_TYPE_PALETTE &&
10658 mng_info->write_png_depth &&
10659 mng_info->write_png_depth != old_bit_depth)
10661 /* Undo pixel scaling */
10662 for (i=0; i < (ssize_t) image->columns; i++)
10663 *(ping_pixels+i)=(unsigned char) (*(ping_pixels+i)
10664 >> (8-old_bit_depth));
10670 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10671 quantum_info,RedQuantum,ping_pixels,exception);
10674 if (mng_info->write_png_colortype-1 != PNG_COLOR_TYPE_PALETTE)
10675 for (i=0; i < (ssize_t) image->columns; i++)
10676 *(ping_pixels+i)=(unsigned char) ((*(ping_pixels+i) > 127) ?
10679 if (logging != MagickFalse && y == 0)
10680 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10681 " Writing row of pixels (1)");
10683 png_write_row(ping,ping_pixels);
10685 if (image->previous == (Image *) NULL)
10687 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
10688 if (status == MagickFalse)
10694 else /* Not Palette, Bilevel, or Opaque Monochrome */
10696 if ((!mng_info->write_png8 && !mng_info->write_png24 &&
10697 !mng_info->write_png48 && !mng_info->write_png64 &&
10698 !mng_info->write_png32) && (image_matte != MagickFalse ||
10699 (ping_bit_depth >= MAGICKCORE_QUANTUM_DEPTH)) &&
10700 (mng_info->IsPalette) && ping_have_color == MagickFalse)
10702 register const Quantum
10705 for (pass=0; pass < num_passes; pass++)
10708 for (y=0; y < (ssize_t) image->rows; y++)
10710 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
10712 if (p == (const Quantum *) NULL)
10715 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
10717 if (mng_info->IsPalette)
10718 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10719 quantum_info,GrayQuantum,ping_pixels,exception);
10722 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10723 quantum_info,RedQuantum,ping_pixels,exception);
10725 if (logging != MagickFalse && y == 0)
10726 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10727 " Writing GRAY PNG pixels (2)");
10730 else /* PNG_COLOR_TYPE_GRAY_ALPHA */
10732 if (logging != MagickFalse && y == 0)
10733 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10734 " Writing GRAY_ALPHA PNG pixels (2)");
10736 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10737 quantum_info,GrayAlphaQuantum,ping_pixels,exception);
10740 if (logging != MagickFalse && y == 0)
10741 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10742 " Writing row of pixels (2)");
10744 png_write_row(ping,ping_pixels);
10747 if (image->previous == (Image *) NULL)
10749 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
10750 if (status == MagickFalse)
10758 register const Quantum
10761 for (pass=0; pass < num_passes; pass++)
10763 if ((image_depth > 8) ||
10764 mng_info->write_png24 ||
10765 mng_info->write_png32 ||
10766 mng_info->write_png48 ||
10767 mng_info->write_png64 ||
10768 (!mng_info->write_png8 && !mng_info->IsPalette))
10770 for (y=0; y < (ssize_t) image->rows; y++)
10772 p=GetVirtualPixels(image,0,y,image->columns,1, exception);
10774 if (p == (const Quantum *) NULL)
10777 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
10779 if (image->storage_class == DirectClass)
10780 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10781 quantum_info,RedQuantum,ping_pixels,exception);
10784 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10785 quantum_info,GrayQuantum,ping_pixels,exception);
10788 else if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
10790 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10791 quantum_info,GrayAlphaQuantum,ping_pixels,
10794 if (logging != MagickFalse && y == 0)
10795 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10796 " Writing GRAY_ALPHA PNG pixels (3)");
10799 else if (image_matte != MagickFalse)
10800 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10801 quantum_info,RGBAQuantum,ping_pixels,exception);
10804 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10805 quantum_info,RGBQuantum,ping_pixels,exception);
10807 if (logging != MagickFalse && y == 0)
10808 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10809 " Writing row of pixels (3)");
10811 png_write_row(ping,ping_pixels);
10816 /* not ((image_depth > 8) ||
10817 mng_info->write_png24 || mng_info->write_png32 ||
10818 mng_info->write_png48 || mng_info->write_png64 ||
10819 (!mng_info->write_png8 && !mng_info->IsPalette))
10822 if ((ping_color_type != PNG_COLOR_TYPE_GRAY) &&
10823 (ping_color_type != PNG_COLOR_TYPE_GRAY_ALPHA))
10825 if (logging != MagickFalse)
10826 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10827 " pass %d, Image Is not GRAY or GRAY_ALPHA",pass);
10829 quantum_info->depth=8;
10833 for (y=0; y < (ssize_t) image->rows; y++)
10835 if (logging != MagickFalse && y == 0)
10836 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10837 " pass %d, Image Is RGB, 16-bit GRAY, or GRAY_ALPHA",pass);
10839 p=GetVirtualPixels(image,0,y,image->columns,1, exception);
10841 if (p == (const Quantum *) NULL)
10844 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
10846 quantum_info->depth=image->depth;
10848 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10849 quantum_info,GrayQuantum,ping_pixels,exception);
10852 else if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
10854 if (logging != MagickFalse && y == 0)
10855 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10856 " Writing GRAY_ALPHA PNG pixels (4)");
10858 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10859 quantum_info,GrayAlphaQuantum,ping_pixels,
10865 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10866 quantum_info,IndexQuantum,ping_pixels,exception);
10868 if (logging != MagickFalse && y <= 2)
10870 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10871 " Writing row of non-gray pixels (4)");
10873 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10874 " ping_pixels[0]=%d,ping_pixels[1]=%d",
10875 (int)ping_pixels[0],(int)ping_pixels[1]);
10878 png_write_row(ping,ping_pixels);
10882 if (image->previous == (Image *) NULL)
10884 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
10885 if (status == MagickFalse)
10892 if (quantum_info != (QuantumInfo *) NULL)
10893 quantum_info=DestroyQuantumInfo(quantum_info);
10895 if (logging != MagickFalse)
10897 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10898 " Wrote PNG image data");
10900 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10901 " Width: %.20g",(double) ping_width);
10903 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10904 " Height: %.20g",(double) ping_height);
10906 if (mng_info->write_png_depth)
10908 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10909 " Defined png:bit-depth: %d",mng_info->write_png_depth);
10912 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10913 " PNG bit-depth written: %d",ping_bit_depth);
10915 if (mng_info->write_png_colortype)
10917 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10918 " Defined png:color-type: %d",mng_info->write_png_colortype-1);
10921 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10922 " PNG color-type written: %d",ping_color_type);
10924 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10925 " PNG Interlace method: %d",ping_interlace_method);
10928 Generate text chunks after IDAT.
10930 if (ping_exclude_tEXt == MagickFalse || ping_exclude_zTXt == MagickFalse)
10932 ResetImagePropertyIterator(image);
10933 property=GetNextImageProperty(image);
10934 while (property != (const char *) NULL)
10939 value=GetImageProperty(image,property,exception);
10941 /* Don't write any "png:" properties; those are just for "identify" */
10942 if (LocaleNCompare(property,"png:",4) != 0 &&
10944 /* Suppress density and units if we wrote a pHYs chunk */
10945 (ping_exclude_pHYs != MagickFalse ||
10946 LocaleCompare(property,"density") != 0 ||
10947 LocaleCompare(property,"units") != 0) &&
10949 /* Suppress the IM-generated Date:create and Date:modify */
10950 (ping_exclude_date == MagickFalse ||
10951 LocaleNCompare(property, "Date:",5) != 0))
10953 if (value != (const char *) NULL)
10956 #if PNG_LIBPNG_VER >= 14000
10957 text=(png_textp) png_malloc(ping,
10958 (png_alloc_size_t) sizeof(png_text));
10960 text=(png_textp) png_malloc(ping,(png_size_t) sizeof(png_text));
10962 text[0].key=(char *) property;
10963 text[0].text=(char *) value;
10964 text[0].text_length=strlen(value);
10966 if (ping_exclude_tEXt != MagickFalse)
10967 text[0].compression=PNG_TEXT_COMPRESSION_zTXt;
10969 else if (ping_exclude_zTXt != MagickFalse)
10970 text[0].compression=PNG_TEXT_COMPRESSION_NONE;
10974 text[0].compression=image_info->compression == NoCompression ||
10975 (image_info->compression == UndefinedCompression &&
10976 text[0].text_length < 128) ? PNG_TEXT_COMPRESSION_NONE :
10977 PNG_TEXT_COMPRESSION_zTXt ;
10980 if (logging != MagickFalse)
10982 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10983 " Setting up text chunk");
10985 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10986 " keyword: '%s'",text[0].key);
10989 png_set_text(ping,ping_info,text,1);
10990 png_free(ping,text);
10993 property=GetNextImageProperty(image);
10997 /* write any PNG-chunk-e profiles */
10998 (void) Magick_png_write_chunk_from_profile(image,"PNG-chunk-e",logging);
11000 if (logging != MagickFalse)
11001 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11002 " Writing PNG end info");
11004 png_write_end(ping,ping_info);
11006 if (mng_info->need_fram && (int) image->dispose == BackgroundDispose)
11008 if (mng_info->page.x || mng_info->page.y ||
11009 (ping_width != mng_info->page.width) ||
11010 (ping_height != mng_info->page.height))
11016 Write FRAM 4 with clipping boundaries followed by FRAM 1.
11018 (void) WriteBlobMSBULong(image,27L); /* data length=27 */
11019 PNGType(chunk,mng_FRAM);
11020 LogPNGChunk(logging,mng_FRAM,27L);
11022 chunk[5]=0; /* frame name separator (no name) */
11023 chunk[6]=1; /* flag for changing delay, for next frame only */
11024 chunk[7]=0; /* flag for changing frame timeout */
11025 chunk[8]=1; /* flag for changing frame clipping for next frame */
11026 chunk[9]=0; /* flag for changing frame sync_id */
11027 PNGLong(chunk+10,(png_uint_32) (0L)); /* temporary 0 delay */
11028 chunk[14]=0; /* clipping boundaries delta type */
11029 PNGLong(chunk+15,(png_uint_32) (mng_info->page.x)); /* left cb */
11031 (png_uint_32) (mng_info->page.x + ping_width));
11032 PNGLong(chunk+23,(png_uint_32) (mng_info->page.y)); /* top cb */
11034 (png_uint_32) (mng_info->page.y + ping_height));
11035 (void) WriteBlob(image,31,chunk);
11036 (void) WriteBlobMSBULong(image,crc32(0,chunk,31));
11037 mng_info->old_framing_mode=4;
11038 mng_info->framing_mode=1;
11042 mng_info->framing_mode=3;
11044 if (mng_info->write_mng && !mng_info->need_fram &&
11045 ((int) image->dispose == 3))
11046 png_error(ping, "Cannot convert GIF with disposal method 3 to MNG-LC");
11049 Free PNG resources.
11052 png_destroy_write_struct(&ping,&ping_info);
11054 ping_pixels=(unsigned char *) RelinquishMagickMemory(ping_pixels);
11056 if (ping_have_blob != MagickFalse)
11057 (void) CloseBlob(image);
11059 image_info=DestroyImageInfo(image_info);
11060 image=DestroyImage(image);
11062 /* Store bit depth actually written */
11063 s[0]=(char) ping_bit_depth;
11066 (void) SetImageProperty(IMimage,"png:bit-depth-written",s,exception);
11068 if (logging != MagickFalse)
11069 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11070 " exit WriteOnePNGImage()");
11072 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
11073 UnlockSemaphoreInfo(ping_semaphore);
11076 /* } for navigation to beginning of SETJMP-protected block. Revert to
11077 * Throwing an Exception when an error occurs.
11080 return(MagickTrue);
11081 /* End write one PNG image */
11086 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11090 % W r i t e P N G I m a g e %
11094 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11096 % WritePNGImage() writes a Portable Network Graphics (PNG) or
11097 % Multiple-image Network Graphics (MNG) image file.
11099 % MNG support written by Glenn Randers-Pehrson, glennrp@image...
11101 % The format of the WritePNGImage method is:
11103 % MagickBooleanType WritePNGImage(const ImageInfo *image_info,
11104 % Image *image,ExceptionInfo *exception)
11106 % A description of each parameter follows:
11108 % o image_info: the image info.
11110 % o image: The image.
11112 % o exception: return any errors or warnings in this structure.
11114 % Returns MagickTrue on success, MagickFalse on failure.
11116 % Communicating with the PNG encoder:
11118 % While the datastream written is always in PNG format and normally would
11119 % be given the "png" file extension, this method also writes the following
11120 % pseudo-formats which are subsets of png:
11122 % o PNG8: An 8-bit indexed PNG datastream is written. If the image has
11123 % a depth greater than 8, the depth is reduced. If transparency
11124 % is present, the tRNS chunk must only have values 0 and 255
11125 % (i.e., transparency is binary: fully opaque or fully
11126 % transparent). If other values are present they will be
11127 % 50%-thresholded to binary transparency. If more than 256
11128 % colors are present, they will be quantized to the 4-4-4-1,
11129 % 3-3-3-1, or 3-3-2-1 palette. The underlying RGB color
11130 % of any resulting fully-transparent pixels is changed to
11131 % the image's background color.
11133 % If you want better quantization or dithering of the colors
11134 % or alpha than that, you need to do it before calling the
11135 % PNG encoder. The pixels contain 8-bit indices even if
11136 % they could be represented with 1, 2, or 4 bits. Grayscale
11137 % images will be written as indexed PNG files even though the
11138 % PNG grayscale type might be slightly more efficient. Please
11139 % note that writing to the PNG8 format may result in loss
11140 % of color and alpha data.
11142 % o PNG24: An 8-bit per sample RGB PNG datastream is written. The tRNS
11143 % chunk can be present to convey binary transparency by naming
11144 % one of the colors as transparent. The only loss incurred
11145 % is reduction of sample depth to 8. If the image has more
11146 % than one transparent color, has semitransparent pixels, or
11147 % has an opaque pixel with the same RGB components as the
11148 % transparent color, an image is not written.
11150 % o PNG32: An 8-bit per sample RGBA PNG is written. Partial
11151 % transparency is permitted, i.e., the alpha sample for
11152 % each pixel can have any value from 0 to 255. The alpha
11153 % channel is present even if the image is fully opaque.
11154 % The only loss in data is the reduction of the sample depth
11157 % o PNG48: A 16-bit per sample RGB PNG datastream is written. The tRNS
11158 % chunk can be present to convey binary transparency by naming
11159 % one of the colors as transparent. If the image has more
11160 % than one transparent color, has semitransparent pixels, or
11161 % has an opaque pixel with the same RGB components as the
11162 % transparent color, an image is not written.
11164 % o PNG64: A 16-bit per sample RGBA PNG is written. Partial
11165 % transparency is permitted, i.e., the alpha sample for
11166 % each pixel can have any value from 0 to 65535. The alpha
11167 % channel is present even if the image is fully opaque.
11169 % o PNG00: A PNG that inherits its colortype and bit-depth from the input
11170 % image, if the input was a PNG, is written. If these values
11171 % cannot be found, then "PNG00" falls back to the regular "PNG"
11174 % o -define: For more precise control of the PNG output, you can use the
11175 % Image options "png:bit-depth" and "png:color-type". These
11176 % can be set from the commandline with "-define" and also
11177 % from the application programming interfaces. The options
11178 % are case-independent and are converted to lowercase before
11179 % being passed to this encoder.
11181 % png:color-type can be 0, 2, 3, 4, or 6.
11183 % When png:color-type is 0 (Grayscale), png:bit-depth can
11184 % be 1, 2, 4, 8, or 16.
11186 % When png:color-type is 2 (RGB), png:bit-depth can
11189 % When png:color-type is 3 (Indexed), png:bit-depth can
11190 % be 1, 2, 4, or 8. This refers to the number of bits
11191 % used to store the index. The color samples always have
11192 % bit-depth 8 in indexed PNG files.
11194 % When png:color-type is 4 (Gray-Matte) or 6 (RGB-Matte),
11195 % png:bit-depth can be 8 or 16.
11197 % If the image cannot be written without loss with the
11198 % requested bit-depth and color-type, a PNG file will not
11199 % be written, a warning will be issued, and the encoder will
11200 % return MagickFalse.
11202 % Since image encoders should not be responsible for the "heavy lifting",
11203 % the user should make sure that ImageMagick has already reduced the
11204 % image depth and number of colors and limit transparency to binary
11205 % transparency prior to attempting to write the image with depth, color,
11206 % or transparency limitations.
11208 % Note that another definition, "png:bit-depth-written" exists, but it
11209 % is not intended for external use. It is only used internally by the
11210 % PNG encoder to inform the JNG encoder of the depth of the alpha channel.
11212 % It is possible to request that the PNG encoder write previously-formatted
11213 % ancillary chunks in the output PNG file, using the "-profile" commandline
11214 % option as shown below or by setting the profile via a programming
11217 % -profile PNG-chunk-x:<file>
11219 % where x is a location flag and <file> is a file containing the chunk
11220 % name in the first 4 bytes, then a colon (":"), followed by the chunk data.
11221 % This encoder will compute the chunk length and CRC, so those must not
11222 % be included in the file.
11224 % "x" can be "b" (before PLTE), "m" (middle, i.e., between PLTE and IDAT),
11225 % or "e" (end, i.e., after IDAT). If you want to write multiple chunks
11226 % of the same type, then add a short unique string after the "x" to prevent
11227 % subsequent profiles from overwriting the preceding ones, e.g.,
11229 % -profile PNG-chunk-b01:file01 -profile PNG-chunk-b02:file02
11231 % As of version 6.6.6 the following optimizations are always done:
11233 % o 32-bit depth is reduced to 16.
11234 % o 16-bit depth is reduced to 8 if all pixels contain samples whose
11235 % high byte and low byte are identical.
11236 % o Palette is sorted to remove unused entries and to put a
11237 % transparent color first, if BUILD_PNG_PALETTE is defined.
11238 % o Opaque matte channel is removed when writing an indexed PNG.
11239 % o Grayscale images are reduced to 1, 2, or 4 bit depth if
11240 % this can be done without loss and a larger bit depth N was not
11241 % requested via the "-define png:bit-depth=N" option.
11242 % o If matte channel is present but only one transparent color is
11243 % present, RGB+tRNS is written instead of RGBA
11244 % o Opaque matte channel is removed (or added, if color-type 4 or 6
11245 % was requested when converting an opaque image).
11247 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11249 static MagickBooleanType WritePNGImage(const ImageInfo *image_info,
11250 Image *image,ExceptionInfo *exception)
11255 have_mng_structure,
11271 assert(image_info != (const ImageInfo *) NULL);
11272 assert(image_info->signature == MagickSignature);
11273 assert(image != (Image *) NULL);
11274 assert(image->signature == MagickSignature);
11275 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
11276 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter WritePNGImage()");
11278 Allocate a MngInfo structure.
11280 have_mng_structure=MagickFalse;
11281 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
11283 if (mng_info == (MngInfo *) NULL)
11284 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
11287 Initialize members of the MngInfo structure.
11289 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
11290 mng_info->image=image;
11291 mng_info->equal_backgrounds=MagickTrue;
11292 have_mng_structure=MagickTrue;
11294 /* See if user has requested a specific PNG subformat */
11296 mng_info->write_png8=LocaleCompare(image_info->magick,"PNG8") == 0;
11297 mng_info->write_png24=LocaleCompare(image_info->magick,"PNG24") == 0;
11298 mng_info->write_png32=LocaleCompare(image_info->magick,"PNG32") == 0;
11299 mng_info->write_png48=LocaleCompare(image_info->magick,"PNG48") == 0;
11300 mng_info->write_png64=LocaleCompare(image_info->magick,"PNG64") == 0;
11302 value=GetImageOption(image_info,"png:format");
11304 if (value != (char *) NULL)
11306 mng_info->write_png8 = MagickFalse;
11307 mng_info->write_png24 = MagickFalse;
11308 mng_info->write_png32 = MagickFalse;
11309 mng_info->write_png48 = MagickFalse;
11310 mng_info->write_png64 = MagickFalse;
11312 if (LocaleCompare(value,"png8") == 0)
11313 mng_info->write_png8 = MagickTrue;
11315 else if (LocaleCompare(value,"png24") == 0)
11316 mng_info->write_png24 = MagickTrue;
11318 else if (LocaleCompare(value,"png32") == 0)
11319 mng_info->write_png32 = MagickTrue;
11321 else if (LocaleCompare(value,"png48") == 0)
11322 mng_info->write_png48 = MagickTrue;
11324 else if (LocaleCompare(value,"png64") == 0)
11325 mng_info->write_png64 = MagickTrue;
11328 if (LocaleCompare(value,"png00") == 0)
11330 /* Retrieve png:IHDR.bit-depth-orig and png:IHDR.color-type-orig
11331 Note that whitespace at the end of the property names must match
11332 that in the corresponding SetImageProperty() calls.
11334 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11335 " Format=%s",value);
11337 value=GetImageProperty(image,"png:IHDR.bit-depth-orig ",exception);
11339 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11340 " png00 inherited bit depth=%s",value);
11342 if (value != (char *) NULL)
11344 if (LocaleCompare(value,"1") == 0)
11345 mng_info->write_png_depth = 1;
11347 else if (LocaleCompare(value,"1") == 0)
11348 mng_info->write_png_depth = 2;
11350 else if (LocaleCompare(value,"2") == 0)
11351 mng_info->write_png_depth = 4;
11353 else if (LocaleCompare(value,"8") == 0)
11354 mng_info->write_png_depth = 8;
11356 else if (LocaleCompare(value,"16") == 0)
11357 mng_info->write_png_depth = 16;
11360 value=GetImageProperty(image,"png:IHDR.color-type-orig ",exception);
11362 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11363 " png00 inherited color type=%s",value);
11365 if (value != (char *) NULL)
11367 if (LocaleCompare(value,"0") == 0)
11368 mng_info->write_png_colortype = 1;
11370 else if (LocaleCompare(value,"2") == 0)
11371 mng_info->write_png_colortype = 3;
11373 else if (LocaleCompare(value,"3") == 0)
11374 mng_info->write_png_colortype = 4;
11376 else if (LocaleCompare(value,"4") == 0)
11377 mng_info->write_png_colortype = 5;
11379 else if (LocaleCompare(value,"6") == 0)
11380 mng_info->write_png_colortype = 7;
11384 if (mng_info->write_png8)
11386 mng_info->write_png_colortype = /* 3 */ 4;
11387 mng_info->write_png_depth = 8;
11391 if (mng_info->write_png24)
11393 mng_info->write_png_colortype = /* 2 */ 3;
11394 mng_info->write_png_depth = 8;
11397 if (image->alpha_trait == BlendPixelTrait)
11398 (void) SetImageType(image,TrueColorMatteType,exception);
11401 (void) SetImageType(image,TrueColorType,exception);
11403 (void) SyncImage(image,exception);
11406 if (mng_info->write_png32)
11408 mng_info->write_png_colortype = /* 6 */ 7;
11409 mng_info->write_png_depth = 8;
11412 if (image->alpha_trait == BlendPixelTrait)
11413 (void) SetImageType(image,TrueColorMatteType,exception);
11416 (void) SetImageType(image,TrueColorType,exception);
11418 (void) SyncImage(image,exception);
11421 if (mng_info->write_png48)
11423 mng_info->write_png_colortype = /* 2 */ 3;
11424 mng_info->write_png_depth = 16;
11427 if (image->alpha_trait == BlendPixelTrait)
11428 (void) SetImageType(image,TrueColorMatteType,exception);
11431 (void) SetImageType(image,TrueColorType,exception);
11433 (void) SyncImage(image,exception);
11436 if (mng_info->write_png64)
11438 mng_info->write_png_colortype = /* 6 */ 7;
11439 mng_info->write_png_depth = 16;
11442 if (image->alpha_trait == BlendPixelTrait)
11443 (void) SetImageType(image,TrueColorMatteType,exception);
11446 (void) SetImageType(image,TrueColorType,exception);
11448 (void) SyncImage(image,exception);
11451 value=GetImageOption(image_info,"png:bit-depth");
11453 if (value != (char *) NULL)
11455 if (LocaleCompare(value,"1") == 0)
11456 mng_info->write_png_depth = 1;
11458 else if (LocaleCompare(value,"2") == 0)
11459 mng_info->write_png_depth = 2;
11461 else if (LocaleCompare(value,"4") == 0)
11462 mng_info->write_png_depth = 4;
11464 else if (LocaleCompare(value,"8") == 0)
11465 mng_info->write_png_depth = 8;
11467 else if (LocaleCompare(value,"16") == 0)
11468 mng_info->write_png_depth = 16;
11471 (void) ThrowMagickException(exception,
11472 GetMagickModule(),CoderWarning,
11473 "ignoring invalid defined png:bit-depth",
11476 if (logging != MagickFalse)
11477 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11478 " png:bit-depth=%d was defined.\n",mng_info->write_png_depth);
11481 value=GetImageOption(image_info,"png:color-type");
11483 if (value != (char *) NULL)
11485 /* We must store colortype+1 because 0 is a valid colortype */
11486 if (LocaleCompare(value,"0") == 0)
11487 mng_info->write_png_colortype = 1;
11489 else if (LocaleCompare(value,"1") == 0)
11490 mng_info->write_png_colortype = 2;
11492 else if (LocaleCompare(value,"2") == 0)
11493 mng_info->write_png_colortype = 3;
11495 else if (LocaleCompare(value,"3") == 0)
11496 mng_info->write_png_colortype = 4;
11498 else if (LocaleCompare(value,"4") == 0)
11499 mng_info->write_png_colortype = 5;
11501 else if (LocaleCompare(value,"6") == 0)
11502 mng_info->write_png_colortype = 7;
11505 (void) ThrowMagickException(exception,
11506 GetMagickModule(),CoderWarning,
11507 "ignoring invalid defined png:color-type",
11510 if (logging != MagickFalse)
11511 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11512 " png:color-type=%d was defined.\n",mng_info->write_png_colortype-1);
11515 /* Check for chunks to be excluded:
11517 * The default is to not exclude any known chunks except for any
11518 * listed in the "unused_chunks" array, above.
11520 * Chunks can be listed for exclusion via a "png:exclude-chunk"
11521 * define (in the image properties or in the image artifacts)
11522 * or via a mng_info member. For convenience, in addition
11523 * to or instead of a comma-separated list of chunks, the
11524 * "exclude-chunk" string can be simply "all" or "none".
11526 * The exclude-chunk define takes priority over the mng_info.
11528 * A "png:include-chunk" define takes priority over both the
11529 * mng_info and the "png:exclude-chunk" define. Like the
11530 * "exclude-chunk" string, it can define "all" or "none" as
11531 * well as a comma-separated list. Chunks that are unknown to
11532 * ImageMagick are always excluded, regardless of their "copy-safe"
11533 * status according to the PNG specification, and even if they
11534 * appear in the "include-chunk" list. Such defines appearing among
11535 * the image options take priority over those found among the image
11538 * Finally, all chunks listed in the "unused_chunks" array are
11539 * automatically excluded, regardless of the other instructions
11542 * if you exclude sRGB but not gAMA (recommended), then sRGB chunk
11543 * will not be written and the gAMA chunk will only be written if it
11544 * is not between .45 and .46, or approximately (1.0/2.2).
11546 * If you exclude tRNS and the image has transparency, the colortype
11547 * is forced to be 4 or 6 (GRAY_ALPHA or RGB_ALPHA).
11549 * The -strip option causes StripImage() to set the png:include-chunk
11550 * artifact to "none,trns,gama".
11553 mng_info->ping_exclude_bKGD=MagickFalse;
11554 mng_info->ping_exclude_cHRM=MagickFalse;
11555 mng_info->ping_exclude_date=MagickFalse;
11556 mng_info->ping_exclude_EXIF=MagickFalse; /* hex-encoded EXIF in zTXt */
11557 mng_info->ping_exclude_gAMA=MagickFalse;
11558 mng_info->ping_exclude_iCCP=MagickFalse;
11559 /* mng_info->ping_exclude_iTXt=MagickFalse; */
11560 mng_info->ping_exclude_oFFs=MagickFalse;
11561 mng_info->ping_exclude_pHYs=MagickFalse;
11562 mng_info->ping_exclude_sRGB=MagickFalse;
11563 mng_info->ping_exclude_tEXt=MagickFalse;
11564 mng_info->ping_exclude_tRNS=MagickFalse;
11565 mng_info->ping_exclude_vpAg=MagickFalse;
11566 mng_info->ping_exclude_zCCP=MagickFalse; /* hex-encoded iCCP in zTXt */
11567 mng_info->ping_exclude_zTXt=MagickFalse;
11569 mng_info->ping_preserve_colormap=MagickFalse;
11571 value=GetImageArtifact(image,"png:preserve-colormap");
11573 value=GetImageOption(image_info,"png:preserve-colormap");
11575 mng_info->ping_preserve_colormap=MagickTrue;
11577 /* Thes compression-level, compression-strategy, and compression-filter
11578 * defines take precedence over values from the -quality option.
11580 value=GetImageArtifact(image,"png:compression-level");
11582 value=GetImageOption(image_info,"png:compression-level");
11585 /* We have to add 1 to everything because 0 is a valid input,
11586 * and we want to use 0 (the default) to mean undefined.
11588 if (LocaleCompare(value,"0") == 0)
11589 mng_info->write_png_compression_level = 1;
11591 else if (LocaleCompare(value,"1") == 0)
11592 mng_info->write_png_compression_level = 2;
11594 else if (LocaleCompare(value,"2") == 0)
11595 mng_info->write_png_compression_level = 3;
11597 else if (LocaleCompare(value,"3") == 0)
11598 mng_info->write_png_compression_level = 4;
11600 else if (LocaleCompare(value,"4") == 0)
11601 mng_info->write_png_compression_level = 5;
11603 else if (LocaleCompare(value,"5") == 0)
11604 mng_info->write_png_compression_level = 6;
11606 else if (LocaleCompare(value,"6") == 0)
11607 mng_info->write_png_compression_level = 7;
11609 else if (LocaleCompare(value,"7") == 0)
11610 mng_info->write_png_compression_level = 8;
11612 else if (LocaleCompare(value,"8") == 0)
11613 mng_info->write_png_compression_level = 9;
11615 else if (LocaleCompare(value,"9") == 0)
11616 mng_info->write_png_compression_level = 10;
11619 (void) ThrowMagickException(exception,
11620 GetMagickModule(),CoderWarning,
11621 "ignoring invalid defined png:compression-level",
11625 value=GetImageArtifact(image,"png:compression-strategy");
11627 value=GetImageOption(image_info,"png:compression-strategy");
11631 if (LocaleCompare(value,"0") == 0)
11632 mng_info->write_png_compression_strategy = Z_DEFAULT_STRATEGY+1;
11634 else if (LocaleCompare(value,"1") == 0)
11635 mng_info->write_png_compression_strategy = Z_FILTERED+1;
11637 else if (LocaleCompare(value,"2") == 0)
11638 mng_info->write_png_compression_strategy = Z_HUFFMAN_ONLY+1;
11640 else if (LocaleCompare(value,"3") == 0)
11641 #ifdef Z_RLE /* Z_RLE was added to zlib-1.2.0 */
11642 mng_info->write_png_compression_strategy = Z_RLE+1;
11644 mng_info->write_png_compression_strategy = Z_DEFAULT_STRATEGY+1;
11647 else if (LocaleCompare(value,"4") == 0)
11648 #ifdef Z_FIXED /* Z_FIXED was added to zlib-1.2.2.2 */
11649 mng_info->write_png_compression_strategy = Z_FIXED+1;
11651 mng_info->write_png_compression_strategy = Z_DEFAULT_STRATEGY+1;
11655 (void) ThrowMagickException(exception,
11656 GetMagickModule(),CoderWarning,
11657 "ignoring invalid defined png:compression-strategy",
11661 value=GetImageArtifact(image,"png:compression-filter");
11663 value=GetImageOption(image_info,"png:compression-filter");
11667 /* To do: combinations of filters allowed by libpng
11668 * masks 0x08 through 0xf8
11670 * Implement this as a comma-separated list of 0,1,2,3,4,5
11671 * where 5 is a special case meaning PNG_ALL_FILTERS.
11674 if (LocaleCompare(value,"0") == 0)
11675 mng_info->write_png_compression_filter = 1;
11677 else if (LocaleCompare(value,"1") == 0)
11678 mng_info->write_png_compression_filter = 2;
11680 else if (LocaleCompare(value,"2") == 0)
11681 mng_info->write_png_compression_filter = 3;
11683 else if (LocaleCompare(value,"3") == 0)
11684 mng_info->write_png_compression_filter = 4;
11686 else if (LocaleCompare(value,"4") == 0)
11687 mng_info->write_png_compression_filter = 5;
11689 else if (LocaleCompare(value,"5") == 0)
11690 mng_info->write_png_compression_filter = 6;
11693 (void) ThrowMagickException(exception,
11694 GetMagickModule(),CoderWarning,
11695 "ignoring invalid defined png:compression-filter",
11699 excluding=MagickFalse;
11701 for (source=0; source<1; source++)
11705 value=GetImageArtifact(image,"png:exclude-chunk");
11708 value=GetImageArtifact(image,"png:exclude-chunks");
11712 value=GetImageOption(image_info,"png:exclude-chunk");
11715 value=GetImageOption(image_info,"png:exclude-chunks");
11724 excluding=MagickTrue;
11726 if (logging != MagickFalse)
11729 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11730 " png:exclude-chunk=%s found in image artifacts.\n", value);
11732 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11733 " png:exclude-chunk=%s found in image properties.\n", value);
11736 last=strlen(value);
11738 for (i=0; i<(int) last; i+=5)
11741 if (LocaleNCompare(value+i,"all",3) == 0)
11743 mng_info->ping_exclude_bKGD=MagickTrue;
11744 mng_info->ping_exclude_cHRM=MagickTrue;
11745 mng_info->ping_exclude_date=MagickTrue;
11746 mng_info->ping_exclude_EXIF=MagickTrue;
11747 mng_info->ping_exclude_gAMA=MagickTrue;
11748 mng_info->ping_exclude_iCCP=MagickTrue;
11749 /* mng_info->ping_exclude_iTXt=MagickTrue; */
11750 mng_info->ping_exclude_oFFs=MagickTrue;
11751 mng_info->ping_exclude_pHYs=MagickTrue;
11752 mng_info->ping_exclude_sRGB=MagickTrue;
11753 mng_info->ping_exclude_tEXt=MagickTrue;
11754 mng_info->ping_exclude_tRNS=MagickTrue;
11755 mng_info->ping_exclude_vpAg=MagickTrue;
11756 mng_info->ping_exclude_zCCP=MagickTrue;
11757 mng_info->ping_exclude_zTXt=MagickTrue;
11761 if (LocaleNCompare(value+i,"none",4) == 0)
11763 mng_info->ping_exclude_bKGD=MagickFalse;
11764 mng_info->ping_exclude_cHRM=MagickFalse;
11765 mng_info->ping_exclude_date=MagickFalse;
11766 mng_info->ping_exclude_EXIF=MagickFalse;
11767 mng_info->ping_exclude_gAMA=MagickFalse;
11768 mng_info->ping_exclude_iCCP=MagickFalse;
11769 /* mng_info->ping_exclude_iTXt=MagickFalse; */
11770 mng_info->ping_exclude_oFFs=MagickFalse;
11771 mng_info->ping_exclude_pHYs=MagickFalse;
11772 mng_info->ping_exclude_sRGB=MagickFalse;
11773 mng_info->ping_exclude_tEXt=MagickFalse;
11774 mng_info->ping_exclude_tRNS=MagickFalse;
11775 mng_info->ping_exclude_vpAg=MagickFalse;
11776 mng_info->ping_exclude_zCCP=MagickFalse;
11777 mng_info->ping_exclude_zTXt=MagickFalse;
11780 if (LocaleNCompare(value+i,"bkgd",4) == 0)
11781 mng_info->ping_exclude_bKGD=MagickTrue;
11783 if (LocaleNCompare(value+i,"chrm",4) == 0)
11784 mng_info->ping_exclude_cHRM=MagickTrue;
11786 if (LocaleNCompare(value+i,"date",4) == 0)
11787 mng_info->ping_exclude_date=MagickTrue;
11789 if (LocaleNCompare(value+i,"exif",4) == 0)
11790 mng_info->ping_exclude_EXIF=MagickTrue;
11792 if (LocaleNCompare(value+i,"gama",4) == 0)
11793 mng_info->ping_exclude_gAMA=MagickTrue;
11795 if (LocaleNCompare(value+i,"iccp",4) == 0)
11796 mng_info->ping_exclude_iCCP=MagickTrue;
11799 if (LocaleNCompare(value+i,"itxt",4) == 0)
11800 mng_info->ping_exclude_iTXt=MagickTrue;
11803 if (LocaleNCompare(value+i,"gama",4) == 0)
11804 mng_info->ping_exclude_gAMA=MagickTrue;
11806 if (LocaleNCompare(value+i,"offs",4) == 0)
11807 mng_info->ping_exclude_oFFs=MagickTrue;
11809 if (LocaleNCompare(value+i,"phys",4) == 0)
11810 mng_info->ping_exclude_pHYs=MagickTrue;
11812 if (LocaleNCompare(value+i,"srgb",4) == 0)
11813 mng_info->ping_exclude_sRGB=MagickTrue;
11815 if (LocaleNCompare(value+i,"text",4) == 0)
11816 mng_info->ping_exclude_tEXt=MagickTrue;
11818 if (LocaleNCompare(value+i,"trns",4) == 0)
11819 mng_info->ping_exclude_tRNS=MagickTrue;
11821 if (LocaleNCompare(value+i,"vpag",4) == 0)
11822 mng_info->ping_exclude_vpAg=MagickTrue;
11824 if (LocaleNCompare(value+i,"zccp",4) == 0)
11825 mng_info->ping_exclude_zCCP=MagickTrue;
11827 if (LocaleNCompare(value+i,"ztxt",4) == 0)
11828 mng_info->ping_exclude_zTXt=MagickTrue;
11834 for (source=0; source<1; source++)
11838 value=GetImageArtifact(image,"png:include-chunk");
11841 value=GetImageArtifact(image,"png:include-chunks");
11845 value=GetImageOption(image_info,"png:include-chunk");
11848 value=GetImageOption(image_info,"png:include-chunks");
11856 excluding=MagickTrue;
11858 if (logging != MagickFalse)
11861 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11862 " png:include-chunk=%s found in image artifacts.\n", value);
11864 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11865 " png:include-chunk=%s found in image properties.\n", value);
11868 last=strlen(value);
11870 for (i=0; i<(int) last; i+=5)
11872 if (LocaleNCompare(value+i,"all",3) == 0)
11874 mng_info->ping_exclude_bKGD=MagickFalse;
11875 mng_info->ping_exclude_cHRM=MagickFalse;
11876 mng_info->ping_exclude_date=MagickFalse;
11877 mng_info->ping_exclude_EXIF=MagickFalse;
11878 mng_info->ping_exclude_gAMA=MagickFalse;
11879 mng_info->ping_exclude_iCCP=MagickFalse;
11880 /* mng_info->ping_exclude_iTXt=MagickFalse; */
11881 mng_info->ping_exclude_oFFs=MagickFalse;
11882 mng_info->ping_exclude_pHYs=MagickFalse;
11883 mng_info->ping_exclude_sRGB=MagickFalse;
11884 mng_info->ping_exclude_tEXt=MagickFalse;
11885 mng_info->ping_exclude_tRNS=MagickFalse;
11886 mng_info->ping_exclude_vpAg=MagickFalse;
11887 mng_info->ping_exclude_zCCP=MagickFalse;
11888 mng_info->ping_exclude_zTXt=MagickFalse;
11892 if (LocaleNCompare(value+i,"none",4) == 0)
11894 mng_info->ping_exclude_bKGD=MagickTrue;
11895 mng_info->ping_exclude_cHRM=MagickTrue;
11896 mng_info->ping_exclude_date=MagickTrue;
11897 mng_info->ping_exclude_EXIF=MagickTrue;
11898 mng_info->ping_exclude_gAMA=MagickTrue;
11899 mng_info->ping_exclude_iCCP=MagickTrue;
11900 /* mng_info->ping_exclude_iTXt=MagickTrue; */
11901 mng_info->ping_exclude_oFFs=MagickTrue;
11902 mng_info->ping_exclude_pHYs=MagickTrue;
11903 mng_info->ping_exclude_sRGB=MagickTrue;
11904 mng_info->ping_exclude_tEXt=MagickTrue;
11905 mng_info->ping_exclude_tRNS=MagickTrue;
11906 mng_info->ping_exclude_vpAg=MagickTrue;
11907 mng_info->ping_exclude_zCCP=MagickTrue;
11908 mng_info->ping_exclude_zTXt=MagickTrue;
11911 if (LocaleNCompare(value+i,"bkgd",4) == 0)
11912 mng_info->ping_exclude_bKGD=MagickFalse;
11914 if (LocaleNCompare(value+i,"chrm",4) == 0)
11915 mng_info->ping_exclude_cHRM=MagickFalse;
11917 if (LocaleNCompare(value+i,"date",4) == 0)
11918 mng_info->ping_exclude_date=MagickFalse;
11920 if (LocaleNCompare(value+i,"exif",4) == 0)
11921 mng_info->ping_exclude_EXIF=MagickFalse;
11923 if (LocaleNCompare(value+i,"gama",4) == 0)
11924 mng_info->ping_exclude_gAMA=MagickFalse;
11926 if (LocaleNCompare(value+i,"iccp",4) == 0)
11927 mng_info->ping_exclude_iCCP=MagickFalse;
11930 if (LocaleNCompare(value+i,"itxt",4) == 0)
11931 mng_info->ping_exclude_iTXt=MagickFalse;
11934 if (LocaleNCompare(value+i,"gama",4) == 0)
11935 mng_info->ping_exclude_gAMA=MagickFalse;
11937 if (LocaleNCompare(value+i,"offs",4) == 0)
11938 mng_info->ping_exclude_oFFs=MagickFalse;
11940 if (LocaleNCompare(value+i,"phys",4) == 0)
11941 mng_info->ping_exclude_pHYs=MagickFalse;
11943 if (LocaleNCompare(value+i,"srgb",4) == 0)
11944 mng_info->ping_exclude_sRGB=MagickFalse;
11946 if (LocaleNCompare(value+i,"text",4) == 0)
11947 mng_info->ping_exclude_tEXt=MagickFalse;
11949 if (LocaleNCompare(value+i,"trns",4) == 0)
11950 mng_info->ping_exclude_tRNS=MagickFalse;
11952 if (LocaleNCompare(value+i,"vpag",4) == 0)
11953 mng_info->ping_exclude_vpAg=MagickFalse;
11955 if (LocaleNCompare(value+i,"zccp",4) == 0)
11956 mng_info->ping_exclude_zCCP=MagickFalse;
11958 if (LocaleNCompare(value+i,"ztxt",4) == 0)
11959 mng_info->ping_exclude_zTXt=MagickFalse;
11965 if (excluding != MagickFalse && logging != MagickFalse)
11967 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11968 " Chunks to be excluded from the output png:");
11969 if (mng_info->ping_exclude_bKGD != MagickFalse)
11970 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11972 if (mng_info->ping_exclude_cHRM != MagickFalse)
11973 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11975 if (mng_info->ping_exclude_date != MagickFalse)
11976 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11978 if (mng_info->ping_exclude_EXIF != MagickFalse)
11979 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11981 if (mng_info->ping_exclude_gAMA != MagickFalse)
11982 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11984 if (mng_info->ping_exclude_iCCP != MagickFalse)
11985 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11988 if (mng_info->ping_exclude_iTXt != MagickFalse)
11989 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11992 if (mng_info->ping_exclude_oFFs != MagickFalse)
11993 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11995 if (mng_info->ping_exclude_pHYs != MagickFalse)
11996 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11998 if (mng_info->ping_exclude_sRGB != MagickFalse)
11999 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12001 if (mng_info->ping_exclude_tEXt != MagickFalse)
12002 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12004 if (mng_info->ping_exclude_tRNS != MagickFalse)
12005 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12007 if (mng_info->ping_exclude_vpAg != MagickFalse)
12008 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12010 if (mng_info->ping_exclude_zCCP != MagickFalse)
12011 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12013 if (mng_info->ping_exclude_zTXt != MagickFalse)
12014 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12018 mng_info->need_blob = MagickTrue;
12020 status=WriteOnePNGImage(mng_info,image_info,image,exception);
12022 MngInfoFreeStruct(mng_info,&have_mng_structure);
12024 if (logging != MagickFalse)
12025 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit WritePNGImage()");
12030 #if defined(JNG_SUPPORTED)
12032 /* Write one JNG image */
12033 static MagickBooleanType WriteOneJNGImage(MngInfo *mng_info,
12034 const ImageInfo *image_info,Image *image,ExceptionInfo *exception)
12055 jng_alpha_compression_method,
12056 jng_alpha_sample_depth,
12064 logging=LogMagickEvent(CoderEvent,GetMagickModule(),
12065 " Enter WriteOneJNGImage()");
12067 blob=(unsigned char *) NULL;
12068 jpeg_image=(Image *) NULL;
12069 jpeg_image_info=(ImageInfo *) NULL;
12072 transparent=image_info->type==GrayscaleMatteType ||
12073 image_info->type==TrueColorMatteType || image->alpha_trait == BlendPixelTrait;
12075 jng_quality=image_info->quality == 0UL ? 75UL : image_info->quality%1000;
12077 jng_alpha_compression_method=image->compression==JPEGCompression? 8 : 0;
12079 jng_alpha_quality=image_info->quality == 0UL ? 75UL :
12080 image_info->quality;
12082 if (jng_alpha_quality >= 1000)
12083 jng_alpha_quality /= 1000;
12089 /* Create JPEG blob, image, and image_info */
12090 if (logging != MagickFalse)
12091 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12092 " Creating jpeg_image_info for alpha.");
12094 jpeg_image_info=(ImageInfo *) CloneImageInfo(image_info);
12096 if (jpeg_image_info == (ImageInfo *) NULL)
12097 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
12099 if (logging != MagickFalse)
12100 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12101 " Creating jpeg_image.");
12103 jpeg_image=SeparateImage(image,AlphaChannel,exception);
12104 if (jpeg_image == (Image *) NULL)
12105 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
12106 (void) CopyMagickString(jpeg_image->magick,"JPEG",MaxTextExtent);
12107 jpeg_image->alpha_trait=UndefinedPixelTrait;
12108 jpeg_image->quality=jng_alpha_quality;
12109 jpeg_image_info->type=GrayscaleType;
12110 (void) SetImageType(jpeg_image,GrayscaleType,exception);
12111 (void) AcquireUniqueFilename(jpeg_image->filename);
12112 (void) FormatLocaleString(jpeg_image_info->filename,MaxTextExtent,
12113 "%s",jpeg_image->filename);
12117 jng_alpha_compression_method=0;
12119 jng_alpha_sample_depth=0;
12122 /* To do: check bit depth of PNG alpha channel */
12124 /* Check if image is grayscale. */
12125 if (image_info->type != TrueColorMatteType && image_info->type !=
12126 TrueColorType && IsImageGray(image,exception))
12129 if (logging != MagickFalse)
12131 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12132 " JNG Quality = %d",(int) jng_quality);
12133 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12134 " JNG Color Type = %d",jng_color_type);
12137 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12138 " JNG Alpha Compression = %d",jng_alpha_compression_method);
12139 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12140 " JNG Alpha Depth = %d",jng_alpha_sample_depth);
12141 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12142 " JNG Alpha Quality = %d",(int) jng_alpha_quality);
12148 if (jng_alpha_compression_method==0)
12153 /* Encode alpha as a grayscale PNG blob */
12154 status=OpenBlob(jpeg_image_info,jpeg_image,WriteBinaryBlobMode,
12156 if (logging != MagickFalse)
12157 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12158 " Creating PNG blob.");
12161 (void) CopyMagickString(jpeg_image_info->magick,"PNG",MaxTextExtent);
12162 (void) CopyMagickString(jpeg_image->magick,"PNG",MaxTextExtent);
12163 jpeg_image_info->interlace=NoInterlace;
12165 /* Exclude all ancillary chunks */
12166 (void) SetImageArtifact(jpeg_image,"png:exclude-chunks","all");
12168 blob=ImageToBlob(jpeg_image_info,jpeg_image,&length,
12171 /* Retrieve sample depth used */
12172 value=GetImageProperty(jpeg_image,"png:bit-depth-written",exception);
12173 if (value != (char *) NULL)
12174 jng_alpha_sample_depth= (unsigned int) value[0];
12178 /* Encode alpha as a grayscale JPEG blob */
12180 status=OpenBlob(jpeg_image_info,jpeg_image,WriteBinaryBlobMode,
12183 (void) CopyMagickString(jpeg_image_info->magick,"JPEG",MaxTextExtent);
12184 (void) CopyMagickString(jpeg_image->magick,"JPEG",MaxTextExtent);
12185 jpeg_image_info->interlace=NoInterlace;
12186 if (logging != MagickFalse)
12187 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12188 " Creating blob.");
12189 blob=ImageToBlob(jpeg_image_info,jpeg_image,&length,
12191 jng_alpha_sample_depth=8;
12193 if (logging != MagickFalse)
12194 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12195 " Successfully read jpeg_image into a blob, length=%.20g.",
12199 /* Destroy JPEG image and image_info */
12200 jpeg_image=DestroyImage(jpeg_image);
12201 (void) RelinquishUniqueFileResource(jpeg_image_info->filename);
12202 jpeg_image_info=DestroyImageInfo(jpeg_image_info);
12205 /* Write JHDR chunk */
12206 (void) WriteBlobMSBULong(image,16L); /* chunk data length=16 */
12207 PNGType(chunk,mng_JHDR);
12208 LogPNGChunk(logging,mng_JHDR,16L);
12209 PNGLong(chunk+4,(png_uint_32) image->columns);
12210 PNGLong(chunk+8,(png_uint_32) image->rows);
12211 chunk[12]=jng_color_type;
12212 chunk[13]=8; /* sample depth */
12213 chunk[14]=8; /*jng_image_compression_method */
12214 chunk[15]=(unsigned char) (image_info->interlace == NoInterlace ? 0 : 8);
12215 chunk[16]=jng_alpha_sample_depth;
12216 chunk[17]=jng_alpha_compression_method;
12217 chunk[18]=0; /*jng_alpha_filter_method */
12218 chunk[19]=0; /*jng_alpha_interlace_method */
12219 (void) WriteBlob(image,20,chunk);
12220 (void) WriteBlobMSBULong(image,crc32(0,chunk,20));
12221 if (logging != MagickFalse)
12223 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12224 " JNG width:%15lu",(unsigned long) image->columns);
12226 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12227 " JNG height:%14lu",(unsigned long) image->rows);
12229 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12230 " JNG color type:%10d",jng_color_type);
12232 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12233 " JNG sample depth:%8d",8);
12235 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12236 " JNG compression:%9d",8);
12238 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12239 " JNG interlace:%11d",0);
12241 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12242 " JNG alpha depth:%9d",jng_alpha_sample_depth);
12244 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12245 " JNG alpha compression:%3d",jng_alpha_compression_method);
12247 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12248 " JNG alpha filter:%8d",0);
12250 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12251 " JNG alpha interlace:%5d",0);
12254 /* Write any JNG-chunk-b profiles */
12255 (void) Magick_png_write_chunk_from_profile(image,"JNG-chunk-b",logging);
12258 Write leading ancillary chunks
12264 Write JNG bKGD chunk
12275 if (jng_color_type == 8 || jng_color_type == 12)
12279 (void) WriteBlobMSBULong(image,(size_t) (num_bytes-4L));
12280 PNGType(chunk,mng_bKGD);
12281 LogPNGChunk(logging,mng_bKGD,(size_t) (num_bytes-4L));
12282 red=ScaleQuantumToChar(image->background_color.red);
12283 green=ScaleQuantumToChar(image->background_color.green);
12284 blue=ScaleQuantumToChar(image->background_color.blue);
12291 (void) WriteBlob(image,(size_t) num_bytes,chunk);
12292 (void) WriteBlobMSBULong(image,crc32(0,chunk,(uInt) num_bytes));
12295 if ((image->colorspace == sRGBColorspace || image->rendering_intent))
12298 Write JNG sRGB chunk
12300 (void) WriteBlobMSBULong(image,1L);
12301 PNGType(chunk,mng_sRGB);
12302 LogPNGChunk(logging,mng_sRGB,1L);
12304 if (image->rendering_intent != UndefinedIntent)
12305 chunk[4]=(unsigned char)
12306 Magick_RenderingIntent_to_PNG_RenderingIntent(
12307 (image->rendering_intent));
12310 chunk[4]=(unsigned char)
12311 Magick_RenderingIntent_to_PNG_RenderingIntent(
12312 (PerceptualIntent));
12314 (void) WriteBlob(image,5,chunk);
12315 (void) WriteBlobMSBULong(image,crc32(0,chunk,5));
12319 if (image->gamma != 0.0)
12322 Write JNG gAMA chunk
12324 (void) WriteBlobMSBULong(image,4L);
12325 PNGType(chunk,mng_gAMA);
12326 LogPNGChunk(logging,mng_gAMA,4L);
12327 PNGLong(chunk+4,(png_uint_32) (100000*image->gamma+0.5));
12328 (void) WriteBlob(image,8,chunk);
12329 (void) WriteBlobMSBULong(image,crc32(0,chunk,8));
12332 if ((mng_info->equal_chrms == MagickFalse) &&
12333 (image->chromaticity.red_primary.x != 0.0))
12339 Write JNG cHRM chunk
12341 (void) WriteBlobMSBULong(image,32L);
12342 PNGType(chunk,mng_cHRM);
12343 LogPNGChunk(logging,mng_cHRM,32L);
12344 primary=image->chromaticity.white_point;
12345 PNGLong(chunk+4,(png_uint_32) (100000*primary.x+0.5));
12346 PNGLong(chunk+8,(png_uint_32) (100000*primary.y+0.5));
12347 primary=image->chromaticity.red_primary;
12348 PNGLong(chunk+12,(png_uint_32) (100000*primary.x+0.5));
12349 PNGLong(chunk+16,(png_uint_32) (100000*primary.y+0.5));
12350 primary=image->chromaticity.green_primary;
12351 PNGLong(chunk+20,(png_uint_32) (100000*primary.x+0.5));
12352 PNGLong(chunk+24,(png_uint_32) (100000*primary.y+0.5));
12353 primary=image->chromaticity.blue_primary;
12354 PNGLong(chunk+28,(png_uint_32) (100000*primary.x+0.5));
12355 PNGLong(chunk+32,(png_uint_32) (100000*primary.y+0.5));
12356 (void) WriteBlob(image,36,chunk);
12357 (void) WriteBlobMSBULong(image,crc32(0,chunk,36));
12361 if (image->resolution.x && image->resolution.y && !mng_info->equal_physs)
12364 Write JNG pHYs chunk
12366 (void) WriteBlobMSBULong(image,9L);
12367 PNGType(chunk,mng_pHYs);
12368 LogPNGChunk(logging,mng_pHYs,9L);
12369 if (image->units == PixelsPerInchResolution)
12371 PNGLong(chunk+4,(png_uint_32)
12372 (image->resolution.x*100.0/2.54+0.5));
12374 PNGLong(chunk+8,(png_uint_32)
12375 (image->resolution.y*100.0/2.54+0.5));
12382 if (image->units == PixelsPerCentimeterResolution)
12384 PNGLong(chunk+4,(png_uint_32)
12385 (image->resolution.x*100.0+0.5));
12387 PNGLong(chunk+8,(png_uint_32)
12388 (image->resolution.y*100.0+0.5));
12395 PNGLong(chunk+4,(png_uint_32) (image->resolution.x+0.5));
12396 PNGLong(chunk+8,(png_uint_32) (image->resolution.y+0.5));
12400 (void) WriteBlob(image,13,chunk);
12401 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
12404 if (mng_info->write_mng == 0 && (image->page.x || image->page.y))
12407 Write JNG oFFs chunk
12409 (void) WriteBlobMSBULong(image,9L);
12410 PNGType(chunk,mng_oFFs);
12411 LogPNGChunk(logging,mng_oFFs,9L);
12412 PNGsLong(chunk+4,(ssize_t) (image->page.x));
12413 PNGsLong(chunk+8,(ssize_t) (image->page.y));
12415 (void) WriteBlob(image,13,chunk);
12416 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
12418 if (mng_info->write_mng == 0 && (image->page.width || image->page.height))
12420 (void) WriteBlobMSBULong(image,9L); /* data length=8 */
12421 PNGType(chunk,mng_vpAg);
12422 LogPNGChunk(logging,mng_vpAg,9L);
12423 PNGLong(chunk+4,(png_uint_32) image->page.width);
12424 PNGLong(chunk+8,(png_uint_32) image->page.height);
12425 chunk[12]=0; /* unit = pixels */
12426 (void) WriteBlob(image,13,chunk);
12427 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
12433 if (jng_alpha_compression_method==0)
12441 /* Write IDAT chunk header */
12442 if (logging != MagickFalse)
12443 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12444 " Write IDAT chunks from blob, length=%.20g.",(double)
12447 /* Copy IDAT chunks */
12450 for (i=8; i<(ssize_t) length; i+=len+12)
12452 len=(*p<<24)|((*(p+1))<<16)|((*(p+2))<<8)|(*(p+3));
12455 if (*(p)==73 && *(p+1)==68 && *(p+2)==65 && *(p+3)==84) /* IDAT */
12457 /* Found an IDAT chunk. */
12458 (void) WriteBlobMSBULong(image,(size_t) len);
12459 LogPNGChunk(logging,mng_IDAT,(size_t) len);
12460 (void) WriteBlob(image,(size_t) len+4,p);
12461 (void) WriteBlobMSBULong(image,
12462 crc32(0,p,(uInt) len+4));
12467 if (logging != MagickFalse)
12468 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12469 " Skipping %c%c%c%c chunk, length=%.20g.",
12470 *(p),*(p+1),*(p+2),*(p+3),(double) len);
12477 /* Write JDAA chunk header */
12478 if (logging != MagickFalse)
12479 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12480 " Write JDAA chunk, length=%.20g.",(double) length);
12481 (void) WriteBlobMSBULong(image,(size_t) length);
12482 PNGType(chunk,mng_JDAA);
12483 LogPNGChunk(logging,mng_JDAA,length);
12484 /* Write JDAT chunk(s) data */
12485 (void) WriteBlob(image,4,chunk);
12486 (void) WriteBlob(image,length,blob);
12487 (void) WriteBlobMSBULong(image,crc32(crc32(0,chunk,4),blob,
12490 blob=(unsigned char *) RelinquishMagickMemory(blob);
12493 /* Encode image as a JPEG blob */
12494 if (logging != MagickFalse)
12495 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12496 " Creating jpeg_image_info.");
12497 jpeg_image_info=(ImageInfo *) CloneImageInfo(image_info);
12498 if (jpeg_image_info == (ImageInfo *) NULL)
12499 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
12501 if (logging != MagickFalse)
12502 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12503 " Creating jpeg_image.");
12505 jpeg_image=CloneImage(image,0,0,MagickTrue,exception);
12506 if (jpeg_image == (Image *) NULL)
12507 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
12508 (void) CopyMagickString(jpeg_image->magick,"JPEG",MaxTextExtent);
12510 (void) AcquireUniqueFilename(jpeg_image->filename);
12511 (void) FormatLocaleString(jpeg_image_info->filename,MaxTextExtent,"%s",
12512 jpeg_image->filename);
12514 status=OpenBlob(jpeg_image_info,jpeg_image,WriteBinaryBlobMode,
12517 if (logging != MagickFalse)
12518 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12519 " Created jpeg_image, %.20g x %.20g.",(double) jpeg_image->columns,
12520 (double) jpeg_image->rows);
12522 if (jng_color_type == 8 || jng_color_type == 12)
12523 jpeg_image_info->type=GrayscaleType;
12525 jpeg_image_info->quality=jng_quality;
12526 jpeg_image->quality=jng_quality;
12527 (void) CopyMagickString(jpeg_image_info->magick,"JPEG",MaxTextExtent);
12528 (void) CopyMagickString(jpeg_image->magick,"JPEG",MaxTextExtent);
12530 if (logging != MagickFalse)
12531 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12532 " Creating blob.");
12534 blob=ImageToBlob(jpeg_image_info,jpeg_image,&length,exception);
12536 if (logging != MagickFalse)
12538 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12539 " Successfully read jpeg_image into a blob, length=%.20g.",
12542 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12543 " Write JDAT chunk, length=%.20g.",(double) length);
12546 /* Write JDAT chunk(s) */
12547 (void) WriteBlobMSBULong(image,(size_t) length);
12548 PNGType(chunk,mng_JDAT);
12549 LogPNGChunk(logging,mng_JDAT,length);
12550 (void) WriteBlob(image,4,chunk);
12551 (void) WriteBlob(image,length,blob);
12552 (void) WriteBlobMSBULong(image,crc32(crc32(0,chunk,4),blob,(uInt) length));
12554 jpeg_image=DestroyImage(jpeg_image);
12555 (void) RelinquishUniqueFileResource(jpeg_image_info->filename);
12556 jpeg_image_info=DestroyImageInfo(jpeg_image_info);
12557 blob=(unsigned char *) RelinquishMagickMemory(blob);
12559 /* Write any JNG-chunk-e profiles */
12560 (void) Magick_png_write_chunk_from_profile(image,"JNG-chunk-e",logging);
12562 /* Write IEND chunk */
12563 (void) WriteBlobMSBULong(image,0L);
12564 PNGType(chunk,mng_IEND);
12565 LogPNGChunk(logging,mng_IEND,0);
12566 (void) WriteBlob(image,4,chunk);
12567 (void) WriteBlobMSBULong(image,crc32(0,chunk,4));
12569 if (logging != MagickFalse)
12570 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12571 " exit WriteOneJNGImage()");
12578 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12582 % W r i t e J N G I m a g e %
12586 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12588 % WriteJNGImage() writes a JPEG Network Graphics (JNG) image file.
12590 % JNG support written by Glenn Randers-Pehrson, glennrp@image...
12592 % The format of the WriteJNGImage method is:
12594 % MagickBooleanType WriteJNGImage(const ImageInfo *image_info,
12595 % Image *image,ExceptionInfo *exception)
12597 % A description of each parameter follows:
12599 % o image_info: the image info.
12601 % o image: The image.
12603 % o exception: return any errors or warnings in this structure.
12605 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12607 static MagickBooleanType WriteJNGImage(const ImageInfo *image_info,Image *image,
12608 ExceptionInfo *exception)
12611 have_mng_structure,
12621 assert(image_info != (const ImageInfo *) NULL);
12622 assert(image_info->signature == MagickSignature);
12623 assert(image != (Image *) NULL);
12624 assert(image->signature == MagickSignature);
12625 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
12626 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter WriteJNGImage()");
12627 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
12628 if (status == MagickFalse)
12632 Allocate a MngInfo structure.
12634 have_mng_structure=MagickFalse;
12635 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
12636 if (mng_info == (MngInfo *) NULL)
12637 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
12639 Initialize members of the MngInfo structure.
12641 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
12642 mng_info->image=image;
12643 have_mng_structure=MagickTrue;
12645 (void) WriteBlob(image,8,(const unsigned char *) "\213JNG\r\n\032\n");
12647 status=WriteOneJNGImage(mng_info,image_info,image,exception);
12648 (void) CloseBlob(image);
12650 (void) CatchImageException(image);
12651 MngInfoFreeStruct(mng_info,&have_mng_structure);
12652 if (logging != MagickFalse)
12653 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit WriteJNGImage()");
12658 static MagickBooleanType WriteMNGImage(const ImageInfo *image_info,Image *image,
12659 ExceptionInfo *exception)
12668 have_mng_structure,
12671 volatile MagickBooleanType
12683 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
12684 defined(PNG_MNG_FEATURES_SUPPORTED)
12687 all_images_are_gray,
12697 volatile unsigned int
12708 #if (PNG_LIBPNG_VER < 10200)
12709 if (image_info->verbose)
12710 printf("Your PNG library (libpng-%s) is rather old.\n",
12711 PNG_LIBPNG_VER_STRING);
12717 assert(image_info != (const ImageInfo *) NULL);
12718 assert(image_info->signature == MagickSignature);
12719 assert(image != (Image *) NULL);
12720 assert(image->signature == MagickSignature);
12721 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
12722 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter WriteMNGImage()");
12723 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
12724 if (status == MagickFalse)
12728 Allocate a MngInfo structure.
12730 have_mng_structure=MagickFalse;
12731 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
12732 if (mng_info == (MngInfo *) NULL)
12733 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
12735 Initialize members of the MngInfo structure.
12737 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
12738 mng_info->image=image;
12739 have_mng_structure=MagickTrue;
12740 write_mng=LocaleCompare(image_info->magick,"MNG") == 0;
12743 * See if user has requested a specific PNG subformat to be used
12744 * for all of the PNGs in the MNG being written, e.g.,
12746 * convert *.png png8:animation.mng
12748 * To do: check -define png:bit_depth and png:color_type as well,
12749 * or perhaps use mng:bit_depth and mng:color_type instead for
12753 mng_info->write_png8=LocaleCompare(image_info->magick,"PNG8") == 0;
12754 mng_info->write_png24=LocaleCompare(image_info->magick,"PNG24") == 0;
12755 mng_info->write_png32=LocaleCompare(image_info->magick,"PNG32") == 0;
12757 write_jng=MagickFalse;
12758 if (image_info->compression == JPEGCompression)
12759 write_jng=MagickTrue;
12761 mng_info->adjoin=image_info->adjoin &&
12762 (GetNextImageInList(image) != (Image *) NULL) && write_mng;
12764 if (logging != MagickFalse)
12766 /* Log some info about the input */
12770 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12771 " Checking input image(s)");
12773 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12774 " Image_info depth: %.20g",(double) image_info->depth);
12776 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12777 " Type: %d",image_info->type);
12780 for (p=image; p != (Image *) NULL; p=GetNextImageInList(p))
12782 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12783 " Scene: %.20g",(double) scene++);
12785 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12786 " Image depth: %.20g",(double) p->depth);
12788 if (p->alpha_trait == BlendPixelTrait)
12789 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12793 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12796 if (p->storage_class == PseudoClass)
12797 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12798 " Storage class: PseudoClass");
12801 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12802 " Storage class: DirectClass");
12805 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12806 " Number of colors: %.20g",(double) p->colors);
12809 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12810 " Number of colors: unspecified");
12812 if (mng_info->adjoin == MagickFalse)
12817 use_global_plte=MagickFalse;
12818 all_images_are_gray=MagickFalse;
12819 #ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
12820 need_local_plte=MagickTrue;
12822 need_defi=MagickFalse;
12823 need_matte=MagickFalse;
12824 mng_info->framing_mode=1;
12825 mng_info->old_framing_mode=1;
12828 if (image_info->page != (char *) NULL)
12831 Determine image bounding box.
12833 SetGeometry(image,&mng_info->page);
12834 (void) ParseMetaGeometry(image_info->page,&mng_info->page.x,
12835 &mng_info->page.y,&mng_info->page.width,&mng_info->page.height);
12847 mng_info->page=image->page;
12848 need_geom=MagickTrue;
12849 if (mng_info->page.width || mng_info->page.height)
12850 need_geom=MagickFalse;
12852 Check all the scenes.
12854 initial_delay=image->delay;
12855 need_iterations=MagickFalse;
12856 mng_info->equal_chrms=image->chromaticity.red_primary.x != 0.0;
12857 mng_info->equal_physs=MagickTrue,
12858 mng_info->equal_gammas=MagickTrue;
12859 mng_info->equal_srgbs=MagickTrue;
12860 mng_info->equal_backgrounds=MagickTrue;
12862 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
12863 defined(PNG_MNG_FEATURES_SUPPORTED)
12864 all_images_are_gray=MagickTrue;
12865 mng_info->equal_palettes=MagickFalse;
12866 need_local_plte=MagickFalse;
12868 for (next_image=image; next_image != (Image *) NULL; )
12872 if ((next_image->columns+next_image->page.x) > mng_info->page.width)
12873 mng_info->page.width=next_image->columns+next_image->page.x;
12875 if ((next_image->rows+next_image->page.y) > mng_info->page.height)
12876 mng_info->page.height=next_image->rows+next_image->page.y;
12879 if (next_image->page.x || next_image->page.y)
12880 need_defi=MagickTrue;
12882 if (next_image->alpha_trait == BlendPixelTrait)
12883 need_matte=MagickTrue;
12885 if ((int) next_image->dispose >= BackgroundDispose)
12886 if ((next_image->alpha_trait == BlendPixelTrait) ||
12887 next_image->page.x || next_image->page.y ||
12888 ((next_image->columns < mng_info->page.width) &&
12889 (next_image->rows < mng_info->page.height)))
12890 mng_info->need_fram=MagickTrue;
12892 if (next_image->iterations)
12893 need_iterations=MagickTrue;
12895 final_delay=next_image->delay;
12897 if (final_delay != initial_delay || final_delay > 1UL*
12898 next_image->ticks_per_second)
12899 mng_info->need_fram=1;
12901 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
12902 defined(PNG_MNG_FEATURES_SUPPORTED)
12904 check for global palette possibility.
12906 if (image->alpha_trait == BlendPixelTrait)
12907 need_local_plte=MagickTrue;
12909 if (need_local_plte == 0)
12911 if (IsImageGray(image,exception) == MagickFalse)
12912 all_images_are_gray=MagickFalse;
12913 mng_info->equal_palettes=PalettesAreEqual(image,next_image);
12914 if (use_global_plte == 0)
12915 use_global_plte=mng_info->equal_palettes;
12916 need_local_plte=!mng_info->equal_palettes;
12919 if (GetNextImageInList(next_image) != (Image *) NULL)
12921 if (next_image->background_color.red !=
12922 next_image->next->background_color.red ||
12923 next_image->background_color.green !=
12924 next_image->next->background_color.green ||
12925 next_image->background_color.blue !=
12926 next_image->next->background_color.blue)
12927 mng_info->equal_backgrounds=MagickFalse;
12929 if (next_image->gamma != next_image->next->gamma)
12930 mng_info->equal_gammas=MagickFalse;
12932 if (next_image->rendering_intent !=
12933 next_image->next->rendering_intent)
12934 mng_info->equal_srgbs=MagickFalse;
12936 if ((next_image->units != next_image->next->units) ||
12937 (next_image->resolution.x != next_image->next->resolution.x) ||
12938 (next_image->resolution.y != next_image->next->resolution.y))
12939 mng_info->equal_physs=MagickFalse;
12941 if (mng_info->equal_chrms)
12943 if (next_image->chromaticity.red_primary.x !=
12944 next_image->next->chromaticity.red_primary.x ||
12945 next_image->chromaticity.red_primary.y !=
12946 next_image->next->chromaticity.red_primary.y ||
12947 next_image->chromaticity.green_primary.x !=
12948 next_image->next->chromaticity.green_primary.x ||
12949 next_image->chromaticity.green_primary.y !=
12950 next_image->next->chromaticity.green_primary.y ||
12951 next_image->chromaticity.blue_primary.x !=
12952 next_image->next->chromaticity.blue_primary.x ||
12953 next_image->chromaticity.blue_primary.y !=
12954 next_image->next->chromaticity.blue_primary.y ||
12955 next_image->chromaticity.white_point.x !=
12956 next_image->next->chromaticity.white_point.x ||
12957 next_image->chromaticity.white_point.y !=
12958 next_image->next->chromaticity.white_point.y)
12959 mng_info->equal_chrms=MagickFalse;
12963 next_image=GetNextImageInList(next_image);
12965 if (image_count < 2)
12967 mng_info->equal_backgrounds=MagickFalse;
12968 mng_info->equal_chrms=MagickFalse;
12969 mng_info->equal_gammas=MagickFalse;
12970 mng_info->equal_srgbs=MagickFalse;
12971 mng_info->equal_physs=MagickFalse;
12972 use_global_plte=MagickFalse;
12973 #ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
12974 need_local_plte=MagickTrue;
12976 need_iterations=MagickFalse;
12979 if (mng_info->need_fram == MagickFalse)
12982 Only certain framing rates 100/n are exactly representable without
12983 the FRAM chunk but we'll allow some slop in VLC files
12985 if (final_delay == 0)
12987 if (need_iterations != MagickFalse)
12990 It's probably a GIF with loop; don't run it *too* fast.
12992 if (mng_info->adjoin)
12995 (void) ThrowMagickException(exception,GetMagickModule(),
12997 "input has zero delay between all frames; assuming",
13002 mng_info->ticks_per_second=0;
13004 if (final_delay != 0)
13005 mng_info->ticks_per_second=(png_uint_32)
13006 (image->ticks_per_second/final_delay);
13007 if (final_delay > 50)
13008 mng_info->ticks_per_second=2;
13010 if (final_delay > 75)
13011 mng_info->ticks_per_second=1;
13013 if (final_delay > 125)
13014 mng_info->need_fram=MagickTrue;
13016 if (need_defi && final_delay > 2 && (final_delay != 4) &&
13017 (final_delay != 5) && (final_delay != 10) && (final_delay != 20) &&
13018 (final_delay != 25) && (final_delay != 50) && (final_delay !=
13019 1UL*image->ticks_per_second))
13020 mng_info->need_fram=MagickTrue; /* make it exact; cannot be VLC */
13023 if (mng_info->need_fram != MagickFalse)
13024 mng_info->ticks_per_second=1UL*image->ticks_per_second;
13026 If pseudocolor, we should also check to see if all the
13027 palettes are identical and write a global PLTE if they are.
13031 Write the MNG version 1.0 signature and MHDR chunk.
13033 (void) WriteBlob(image,8,(const unsigned char *) "\212MNG\r\n\032\n");
13034 (void) WriteBlobMSBULong(image,28L); /* chunk data length=28 */
13035 PNGType(chunk,mng_MHDR);
13036 LogPNGChunk(logging,mng_MHDR,28L);
13037 PNGLong(chunk+4,(png_uint_32) mng_info->page.width);
13038 PNGLong(chunk+8,(png_uint_32) mng_info->page.height);
13039 PNGLong(chunk+12,mng_info->ticks_per_second);
13040 PNGLong(chunk+16,0L); /* layer count=unknown */
13041 PNGLong(chunk+20,0L); /* frame count=unknown */
13042 PNGLong(chunk+24,0L); /* play time=unknown */
13047 if (need_defi || mng_info->need_fram || use_global_plte)
13048 PNGLong(chunk+28,27L); /* simplicity=LC+JNG */
13051 PNGLong(chunk+28,25L); /* simplicity=VLC+JNG */
13056 if (need_defi || mng_info->need_fram || use_global_plte)
13057 PNGLong(chunk+28,19L); /* simplicity=LC+JNG, no transparency */
13060 PNGLong(chunk+28,17L); /* simplicity=VLC+JNG, no transparency */
13068 if (need_defi || mng_info->need_fram || use_global_plte)
13069 PNGLong(chunk+28,11L); /* simplicity=LC */
13072 PNGLong(chunk+28,9L); /* simplicity=VLC */
13077 if (need_defi || mng_info->need_fram || use_global_plte)
13078 PNGLong(chunk+28,3L); /* simplicity=LC, no transparency */
13081 PNGLong(chunk+28,1L); /* simplicity=VLC, no transparency */
13084 (void) WriteBlob(image,32,chunk);
13085 (void) WriteBlobMSBULong(image,crc32(0,chunk,32));
13086 option=GetImageOption(image_info,"mng:need-cacheoff");
13087 if (option != (const char *) NULL)
13093 Write "nEED CACHEOFF" to turn playback caching off for streaming MNG.
13095 PNGType(chunk,mng_nEED);
13096 length=CopyMagickString((char *) chunk+4,"CACHEOFF",20);
13097 (void) WriteBlobMSBULong(image,(size_t) length);
13098 LogPNGChunk(logging,mng_nEED,(size_t) length);
13100 (void) WriteBlob(image,length,chunk);
13101 (void) WriteBlobMSBULong(image,crc32(0,chunk,(uInt) length));
13103 if ((GetPreviousImageInList(image) == (Image *) NULL) &&
13104 (GetNextImageInList(image) != (Image *) NULL) &&
13105 (image->iterations != 1))
13108 Write MNG TERM chunk
13110 (void) WriteBlobMSBULong(image,10L); /* data length=10 */
13111 PNGType(chunk,mng_TERM);
13112 LogPNGChunk(logging,mng_TERM,10L);
13113 chunk[4]=3; /* repeat animation */
13114 chunk[5]=0; /* show last frame when done */
13115 PNGLong(chunk+6,(png_uint_32) (mng_info->ticks_per_second*
13116 final_delay/MagickMax(image->ticks_per_second,1)));
13118 if (image->iterations == 0)
13119 PNGLong(chunk+10,PNG_UINT_31_MAX);
13122 PNGLong(chunk+10,(png_uint_32) image->iterations);
13124 if (logging != MagickFalse)
13126 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
13127 " TERM delay: %.20g",(double) (mng_info->ticks_per_second*
13128 final_delay/MagickMax(image->ticks_per_second,1)));
13130 if (image->iterations == 0)
13131 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
13132 " TERM iterations: %.20g",(double) PNG_UINT_31_MAX);
13135 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
13136 " Image iterations: %.20g",(double) image->iterations);
13138 (void) WriteBlob(image,14,chunk);
13139 (void) WriteBlobMSBULong(image,crc32(0,chunk,14));
13142 To do: check for cHRM+gAMA == sRGB, and write sRGB instead.
13144 if ((image->colorspace == sRGBColorspace || image->rendering_intent) &&
13145 mng_info->equal_srgbs)
13148 Write MNG sRGB chunk
13150 (void) WriteBlobMSBULong(image,1L);
13151 PNGType(chunk,mng_sRGB);
13152 LogPNGChunk(logging,mng_sRGB,1L);
13154 if (image->rendering_intent != UndefinedIntent)
13155 chunk[4]=(unsigned char)
13156 Magick_RenderingIntent_to_PNG_RenderingIntent(
13157 (image->rendering_intent));
13160 chunk[4]=(unsigned char)
13161 Magick_RenderingIntent_to_PNG_RenderingIntent(
13162 (PerceptualIntent));
13164 (void) WriteBlob(image,5,chunk);
13165 (void) WriteBlobMSBULong(image,crc32(0,chunk,5));
13166 mng_info->have_write_global_srgb=MagickTrue;
13171 if (image->gamma && mng_info->equal_gammas)
13174 Write MNG gAMA chunk
13176 (void) WriteBlobMSBULong(image,4L);
13177 PNGType(chunk,mng_gAMA);
13178 LogPNGChunk(logging,mng_gAMA,4L);
13179 PNGLong(chunk+4,(png_uint_32) (100000*image->gamma+0.5));
13180 (void) WriteBlob(image,8,chunk);
13181 (void) WriteBlobMSBULong(image,crc32(0,chunk,8));
13182 mng_info->have_write_global_gama=MagickTrue;
13184 if (mng_info->equal_chrms)
13190 Write MNG cHRM chunk
13192 (void) WriteBlobMSBULong(image,32L);
13193 PNGType(chunk,mng_cHRM);
13194 LogPNGChunk(logging,mng_cHRM,32L);
13195 primary=image->chromaticity.white_point;
13196 PNGLong(chunk+4,(png_uint_32) (100000*primary.x+0.5));
13197 PNGLong(chunk+8,(png_uint_32) (100000*primary.y+0.5));
13198 primary=image->chromaticity.red_primary;
13199 PNGLong(chunk+12,(png_uint_32) (100000*primary.x+0.5));
13200 PNGLong(chunk+16,(png_uint_32) (100000*primary.y+0.5));
13201 primary=image->chromaticity.green_primary;
13202 PNGLong(chunk+20,(png_uint_32) (100000*primary.x+0.5));
13203 PNGLong(chunk+24,(png_uint_32) (100000*primary.y+0.5));
13204 primary=image->chromaticity.blue_primary;
13205 PNGLong(chunk+28,(png_uint_32) (100000*primary.x+0.5));
13206 PNGLong(chunk+32,(png_uint_32) (100000*primary.y+0.5));
13207 (void) WriteBlob(image,36,chunk);
13208 (void) WriteBlobMSBULong(image,crc32(0,chunk,36));
13209 mng_info->have_write_global_chrm=MagickTrue;
13212 if (image->resolution.x && image->resolution.y && mng_info->equal_physs)
13215 Write MNG pHYs chunk
13217 (void) WriteBlobMSBULong(image,9L);
13218 PNGType(chunk,mng_pHYs);
13219 LogPNGChunk(logging,mng_pHYs,9L);
13221 if (image->units == PixelsPerInchResolution)
13223 PNGLong(chunk+4,(png_uint_32)
13224 (image->resolution.x*100.0/2.54+0.5));
13226 PNGLong(chunk+8,(png_uint_32)
13227 (image->resolution.y*100.0/2.54+0.5));
13234 if (image->units == PixelsPerCentimeterResolution)
13236 PNGLong(chunk+4,(png_uint_32)
13237 (image->resolution.x*100.0+0.5));
13239 PNGLong(chunk+8,(png_uint_32)
13240 (image->resolution.y*100.0+0.5));
13247 PNGLong(chunk+4,(png_uint_32) (image->resolution.x+0.5));
13248 PNGLong(chunk+8,(png_uint_32) (image->resolution.y+0.5));
13252 (void) WriteBlob(image,13,chunk);
13253 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
13256 Write MNG BACK chunk and global bKGD chunk, if the image is transparent
13257 or does not cover the entire frame.
13259 if (write_mng && ((image->alpha_trait == BlendPixelTrait) ||
13260 image->page.x > 0 || image->page.y > 0 || (image->page.width &&
13261 (image->page.width+image->page.x < mng_info->page.width))
13262 || (image->page.height && (image->page.height+image->page.y
13263 < mng_info->page.height))))
13265 (void) WriteBlobMSBULong(image,6L);
13266 PNGType(chunk,mng_BACK);
13267 LogPNGChunk(logging,mng_BACK,6L);
13268 red=ScaleQuantumToShort(image->background_color.red);
13269 green=ScaleQuantumToShort(image->background_color.green);
13270 blue=ScaleQuantumToShort(image->background_color.blue);
13271 PNGShort(chunk+4,red);
13272 PNGShort(chunk+6,green);
13273 PNGShort(chunk+8,blue);
13274 (void) WriteBlob(image,10,chunk);
13275 (void) WriteBlobMSBULong(image,crc32(0,chunk,10));
13276 if (mng_info->equal_backgrounds)
13278 (void) WriteBlobMSBULong(image,6L);
13279 PNGType(chunk,mng_bKGD);
13280 LogPNGChunk(logging,mng_bKGD,6L);
13281 (void) WriteBlob(image,10,chunk);
13282 (void) WriteBlobMSBULong(image,crc32(0,chunk,10));
13286 #ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
13287 if ((need_local_plte == MagickFalse) &&
13288 (image->storage_class == PseudoClass) &&
13289 (all_images_are_gray == MagickFalse))
13295 Write MNG PLTE chunk
13297 data_length=3*image->colors;
13298 (void) WriteBlobMSBULong(image,data_length);
13299 PNGType(chunk,mng_PLTE);
13300 LogPNGChunk(logging,mng_PLTE,data_length);
13302 for (i=0; i < (ssize_t) image->colors; i++)
13304 chunk[4+i*3]=(unsigned char) (ScaleQuantumToChar(
13305 image->colormap[i].red) & 0xff);
13306 chunk[5+i*3]=(unsigned char) (ScaleQuantumToChar(
13307 image->colormap[i].green) & 0xff);
13308 chunk[6+i*3]=(unsigned char) (ScaleQuantumToChar(
13309 image->colormap[i].blue) & 0xff);
13312 (void) WriteBlob(image,data_length+4,chunk);
13313 (void) WriteBlobMSBULong(image,crc32(0,chunk,(uInt) (data_length+4)));
13314 mng_info->have_write_global_plte=MagickTrue;
13320 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
13321 defined(PNG_MNG_FEATURES_SUPPORTED)
13322 mng_info->equal_palettes=MagickFalse;
13326 if (mng_info->adjoin)
13328 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
13329 defined(PNG_MNG_FEATURES_SUPPORTED)
13331 If we aren't using a global palette for the entire MNG, check to
13332 see if we can use one for two or more consecutive images.
13334 if (need_local_plte && use_global_plte && !all_images_are_gray)
13336 if (mng_info->IsPalette)
13339 When equal_palettes is true, this image has the same palette
13340 as the previous PseudoClass image
13342 mng_info->have_write_global_plte=mng_info->equal_palettes;
13343 mng_info->equal_palettes=PalettesAreEqual(image,image->next);
13344 if (mng_info->equal_palettes && !mng_info->have_write_global_plte)
13347 Write MNG PLTE chunk
13352 data_length=3*image->colors;
13353 (void) WriteBlobMSBULong(image,data_length);
13354 PNGType(chunk,mng_PLTE);
13355 LogPNGChunk(logging,mng_PLTE,data_length);
13357 for (i=0; i < (ssize_t) image->colors; i++)
13359 chunk[4+i*3]=ScaleQuantumToChar(image->colormap[i].red);
13360 chunk[5+i*3]=ScaleQuantumToChar(image->colormap[i].green);
13361 chunk[6+i*3]=ScaleQuantumToChar(image->colormap[i].blue);
13364 (void) WriteBlob(image,data_length+4,chunk);
13365 (void) WriteBlobMSBULong(image,crc32(0,chunk,
13366 (uInt) (data_length+4)));
13367 mng_info->have_write_global_plte=MagickTrue;
13371 mng_info->have_write_global_plte=MagickFalse;
13382 previous_x=mng_info->page.x;
13383 previous_y=mng_info->page.y;
13390 mng_info->page=image->page;
13391 if ((mng_info->page.x != previous_x) ||
13392 (mng_info->page.y != previous_y))
13394 (void) WriteBlobMSBULong(image,12L); /* data length=12 */
13395 PNGType(chunk,mng_DEFI);
13396 LogPNGChunk(logging,mng_DEFI,12L);
13397 chunk[4]=0; /* object 0 MSB */
13398 chunk[5]=0; /* object 0 LSB */
13399 chunk[6]=0; /* visible */
13400 chunk[7]=0; /* abstract */
13401 PNGLong(chunk+8,(png_uint_32) mng_info->page.x);
13402 PNGLong(chunk+12,(png_uint_32) mng_info->page.y);
13403 (void) WriteBlob(image,16,chunk);
13404 (void) WriteBlobMSBULong(image,crc32(0,chunk,16));
13409 mng_info->write_mng=write_mng;
13411 if ((int) image->dispose >= 3)
13412 mng_info->framing_mode=3;
13414 if (mng_info->need_fram && mng_info->adjoin &&
13415 ((image->delay != mng_info->delay) ||
13416 (mng_info->framing_mode != mng_info->old_framing_mode)))
13418 if (image->delay == mng_info->delay)
13421 Write a MNG FRAM chunk with the new framing mode.
13423 (void) WriteBlobMSBULong(image,1L); /* data length=1 */
13424 PNGType(chunk,mng_FRAM);
13425 LogPNGChunk(logging,mng_FRAM,1L);
13426 chunk[4]=(unsigned char) mng_info->framing_mode;
13427 (void) WriteBlob(image,5,chunk);
13428 (void) WriteBlobMSBULong(image,crc32(0,chunk,5));
13433 Write a MNG FRAM chunk with the delay.
13435 (void) WriteBlobMSBULong(image,10L); /* data length=10 */
13436 PNGType(chunk,mng_FRAM);
13437 LogPNGChunk(logging,mng_FRAM,10L);
13438 chunk[4]=(unsigned char) mng_info->framing_mode;
13439 chunk[5]=0; /* frame name separator (no name) */
13440 chunk[6]=2; /* flag for changing default delay */
13441 chunk[7]=0; /* flag for changing frame timeout */
13442 chunk[8]=0; /* flag for changing frame clipping */
13443 chunk[9]=0; /* flag for changing frame sync_id */
13444 PNGLong(chunk+10,(png_uint_32)
13445 ((mng_info->ticks_per_second*
13446 image->delay)/MagickMax(image->ticks_per_second,1)));
13447 (void) WriteBlob(image,14,chunk);
13448 (void) WriteBlobMSBULong(image,crc32(0,chunk,14));
13449 mng_info->delay=(png_uint_32) image->delay;
13451 mng_info->old_framing_mode=mng_info->framing_mode;
13454 #if defined(JNG_SUPPORTED)
13455 if (image_info->compression == JPEGCompression)
13460 if (logging != MagickFalse)
13461 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
13462 " Writing JNG object.");
13463 /* To do: specify the desired alpha compression method. */
13464 write_info=CloneImageInfo(image_info);
13465 write_info->compression=UndefinedCompression;
13466 status=WriteOneJNGImage(mng_info,write_info,image,exception);
13467 write_info=DestroyImageInfo(write_info);
13472 if (logging != MagickFalse)
13473 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
13474 " Writing PNG object.");
13476 mng_info->need_blob = MagickFalse;
13477 mng_info->ping_preserve_colormap = MagickFalse;
13479 /* We don't want any ancillary chunks written */
13480 mng_info->ping_exclude_bKGD=MagickTrue;
13481 mng_info->ping_exclude_cHRM=MagickTrue;
13482 mng_info->ping_exclude_date=MagickTrue;
13483 mng_info->ping_exclude_EXIF=MagickTrue;
13484 mng_info->ping_exclude_gAMA=MagickTrue;
13485 mng_info->ping_exclude_iCCP=MagickTrue;
13486 /* mng_info->ping_exclude_iTXt=MagickTrue; */
13487 mng_info->ping_exclude_oFFs=MagickTrue;
13488 mng_info->ping_exclude_pHYs=MagickTrue;
13489 mng_info->ping_exclude_sRGB=MagickTrue;
13490 mng_info->ping_exclude_tEXt=MagickTrue;
13491 mng_info->ping_exclude_tRNS=MagickTrue;
13492 mng_info->ping_exclude_vpAg=MagickTrue;
13493 mng_info->ping_exclude_zCCP=MagickTrue;
13494 mng_info->ping_exclude_zTXt=MagickTrue;
13496 status=WriteOnePNGImage(mng_info,image_info,image,exception);
13499 if (status == MagickFalse)
13501 MngInfoFreeStruct(mng_info,&have_mng_structure);
13502 (void) CloseBlob(image);
13503 return(MagickFalse);
13505 (void) CatchImageException(image);
13506 if (GetNextImageInList(image) == (Image *) NULL)
13508 image=SyncNextImageInList(image);
13509 status=SetImageProgress(image,SaveImagesTag,scene++,
13510 GetImageListLength(image));
13512 if (status == MagickFalse)
13515 } while (mng_info->adjoin);
13519 while (GetPreviousImageInList(image) != (Image *) NULL)
13520 image=GetPreviousImageInList(image);
13522 Write the MEND chunk.
13524 (void) WriteBlobMSBULong(image,0x00000000L);
13525 PNGType(chunk,mng_MEND);
13526 LogPNGChunk(logging,mng_MEND,0L);
13527 (void) WriteBlob(image,4,chunk);
13528 (void) WriteBlobMSBULong(image,crc32(0,chunk,4));
13531 Relinquish resources.
13533 (void) CloseBlob(image);
13534 MngInfoFreeStruct(mng_info,&have_mng_structure);
13536 if (logging != MagickFalse)
13537 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit WriteMNGImage()");
13539 return(MagickTrue);
13541 #else /* PNG_LIBPNG_VER > 10011 */
13543 static MagickBooleanType WritePNGImage(const ImageInfo *image_info,Image *image)
13546 printf("Your PNG library is too old: You have libpng-%s\n",
13547 PNG_LIBPNG_VER_STRING);
13549 ThrowBinaryException(CoderError,"PNG library is too old",
13550 image_info->filename);
13553 static MagickBooleanType WriteMNGImage(const ImageInfo *image_info,Image *image)
13555 return(WritePNGImage(image_info,image));
13557 #endif /* PNG_LIBPNG_VER > 10011 */