2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13 % Read/Write Portable Network Graphics Image Format %
17 % Glenn Randers-Pehrson %
21 % Copyright 1999-2013 ImageMagick Studio LLC, a non-profit organization %
22 % dedicated to making software imaging solutions freely available. %
24 % You may not use this file except in compliance with the License. You may %
25 % obtain a copy of the License at %
27 % http://www.imagemagick.org/script/license.php %
29 % Unless required by applicable law or agreed to in writing, software %
30 % distributed under the License is distributed on an "AS IS" BASIS, %
31 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
32 % See the License for the specific language governing permissions and %
33 % limitations under the License. %
35 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
44 #include "MagickCore/studio.h"
45 #include "MagickCore/artifact.h"
46 #include "MagickCore/attribute.h"
47 #include "MagickCore/blob.h"
48 #include "MagickCore/blob-private.h"
49 #include "MagickCore/cache.h"
50 #include "MagickCore/channel.h"
51 #include "MagickCore/color.h"
52 #include "MagickCore/color-private.h"
53 #include "MagickCore/colormap.h"
54 #include "MagickCore/colorspace.h"
55 #include "MagickCore/colorspace-private.h"
56 #include "MagickCore/constitute.h"
57 #include "MagickCore/enhance.h"
58 #include "MagickCore/exception.h"
59 #include "MagickCore/exception-private.h"
60 #include "MagickCore/geometry.h"
61 #include "MagickCore/histogram.h"
62 #include "MagickCore/image.h"
63 #include "MagickCore/image-private.h"
64 #include "MagickCore/layer.h"
65 #include "MagickCore/list.h"
66 #include "MagickCore/log.h"
67 #include "MagickCore/MagickCore.h"
68 #include "MagickCore/memory_.h"
69 #include "MagickCore/module.h"
70 #include "MagickCore/monitor.h"
71 #include "MagickCore/monitor-private.h"
72 #include "MagickCore/option.h"
73 #include "MagickCore/pixel.h"
74 #include "MagickCore/pixel-accessor.h"
75 #include "MagickCore/profile.h"
76 #include "MagickCore/property.h"
77 #include "MagickCore/quantum-private.h"
78 #include "MagickCore/resource_.h"
79 #include "MagickCore/semaphore.h"
80 #include "MagickCore/quantum-private.h"
81 #include "MagickCore/static.h"
82 #include "MagickCore/statistic.h"
83 #include "MagickCore/string_.h"
84 #include "MagickCore/string-private.h"
85 #include "MagickCore/transform.h"
86 #include "MagickCore/utility.h"
87 #if defined(MAGICKCORE_PNG_DELEGATE)
89 /* Suppress libpng pedantic warnings that were added in
90 * libpng-1.2.41 and libpng-1.4.0. If you are working on
91 * migration to libpng-1.5, remove these defines and then
92 * fix any code that generates warnings.
94 /* #define PNG_DEPRECATED Use of this function is deprecated */
95 /* #define PNG_USE_RESULT The result of this function must be checked */
96 /* #define PNG_NORETURN This function does not return */
97 /* #define PNG_ALLOCATED The result of the function is new memory */
98 /* #define PNG_DEPSTRUCT Access to this struct member is deprecated */
100 /* PNG_PTR_NORETURN does not work on some platforms, in libpng-1.5.x */
101 #define PNG_PTR_NORETURN
106 /* ImageMagick differences */
107 #define first_scene scene
109 #if PNG_LIBPNG_VER > 10011
111 Optional declarations. Define or undefine them as you like.
113 /* #define PNG_DEBUG -- turning this on breaks VisualC compiling */
116 Features under construction. Define these to work on them.
118 #undef MNG_OBJECT_BUFFERS
119 #undef MNG_BASI_SUPPORTED
120 #define MNG_COALESCE_LAYERS /* In 5.4.4, this interfered with MMAP'ed files. */
121 #define MNG_INSERT_LAYERS /* Troublesome, but seem to work as of 5.4.4 */
122 #if defined(MAGICKCORE_JPEG_DELEGATE)
123 # define JNG_SUPPORTED /* Not finished as of 5.5.2. See "To do" comments. */
125 #if !defined(RGBColorMatchExact)
126 #define IsPNGColorEqual(color,target) \
127 (((color).red == (target).red) && \
128 ((color).green == (target).green) && \
129 ((color).blue == (target).blue))
132 /* Macros for left-bit-replication to ensure that pixels
133 * and PixelInfos all have the same image->depth, and for use
134 * in PNG8 quantization.
138 /* LBR01: Replicate top bit */
140 #define LBR01PacketRed(pixelpacket) \
141 (pixelpacket).red=(ScaleQuantumToChar((pixelpacket).red) < 0x10 ? \
144 #define LBR01PacketGreen(pixelpacket) \
145 (pixelpacket).green=(ScaleQuantumToChar((pixelpacket).green) < 0x10 ? \
148 #define LBR01PacketBlue(pixelpacket) \
149 (pixelpacket).blue=(ScaleQuantumToChar((pixelpacket).blue) < 0x10 ? \
152 #define LBR01PacketAlpha(pixelpacket) \
153 (pixelpacket).alpha=(ScaleQuantumToChar((pixelpacket).alpha) < 0x10 ? \
156 #define LBR01PacketRGB(pixelpacket) \
158 LBR01PacketRed((pixelpacket)); \
159 LBR01PacketGreen((pixelpacket)); \
160 LBR01PacketBlue((pixelpacket)); \
163 #define LBR01PacketRGBO(pixelpacket) \
165 LBR01PacketRGB((pixelpacket)); \
166 LBR01PacketAlpha((pixelpacket)); \
169 #define LBR01PixelRed(pixel) \
170 (SetPixelRed(image, \
171 ScaleQuantumToChar(GetPixelRed(image,(pixel))) < 0x10 ? \
172 0 : QuantumRange,(pixel)));
174 #define LBR01PixelGreen(pixel) \
175 (SetPixelGreen(image, \
176 ScaleQuantumToChar(GetPixelGreen(image,(pixel))) < 0x10 ? \
177 0 : QuantumRange,(pixel)));
179 #define LBR01PixelBlue(pixel) \
180 (SetPixelBlue(image, \
181 ScaleQuantumToChar(GetPixelBlue(image,(pixel))) < 0x10 ? \
182 0 : QuantumRange,(pixel)));
184 #define LBR01PixelAlpha(pixel) \
185 (SetPixelAlpha(image, \
186 ScaleQuantumToChar(GetPixelAlpha(image,(pixel))) < 0x10 ? \
187 0 : QuantumRange,(pixel)));
189 #define LBR01PixelRGB(pixel) \
191 LBR01PixelRed((pixel)); \
192 LBR01PixelGreen((pixel)); \
193 LBR01PixelBlue((pixel)); \
196 #define LBR01PixelRGBA(pixel) \
198 LBR01PixelRGB((pixel)); \
199 LBR01PixelAlpha((pixel)); \
202 /* LBR02: Replicate top 2 bits */
204 #define LBR02PacketRed(pixelpacket) \
206 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).red) & 0xc0; \
207 (pixelpacket).red=ScaleCharToQuantum( \
208 (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))); \
210 #define LBR02PacketGreen(pixelpacket) \
212 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).green) & 0xc0; \
213 (pixelpacket).green=ScaleCharToQuantum( \
214 (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))); \
216 #define LBR02PacketBlue(pixelpacket) \
218 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).blue) & 0xc0; \
219 (pixelpacket).blue=ScaleCharToQuantum( \
220 (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))); \
222 #define LBR02PacketAlpha(pixelpacket) \
224 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).alpha) & 0xc0; \
225 (pixelpacket).alpha=ScaleCharToQuantum( \
226 (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))); \
229 #define LBR02PacketRGB(pixelpacket) \
231 LBR02PacketRed((pixelpacket)); \
232 LBR02PacketGreen((pixelpacket)); \
233 LBR02PacketBlue((pixelpacket)); \
236 #define LBR02PacketRGBO(pixelpacket) \
238 LBR02PacketRGB((pixelpacket)); \
239 LBR02PacketAlpha((pixelpacket)); \
242 #define LBR02PixelRed(pixel) \
244 unsigned char lbr_bits=ScaleQuantumToChar(GetPixelRed(image,(pixel))) \
246 SetPixelRed(image, ScaleCharToQuantum( \
247 (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))), \
250 #define LBR02PixelGreen(pixel) \
252 unsigned char lbr_bits=ScaleQuantumToChar(GetPixelGreen(image,(pixel)))\
254 SetPixelGreen(image, ScaleCharToQuantum( \
255 (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))), \
258 #define LBR02PixelBlue(pixel) \
260 unsigned char lbr_bits= \
261 ScaleQuantumToChar(GetPixelBlue(image,(pixel))) & 0xc0; \
262 SetPixelBlue(image, ScaleCharToQuantum( \
263 (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))), \
266 #define LBR02PixelAlpha(pixel) \
268 unsigned char lbr_bits= \
269 ScaleQuantumToChar(GetPixelAlpha(image,(pixel))) & 0xc0; \
270 SetPixelAlpha(image, ScaleCharToQuantum( \
271 (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))), \
275 #define LBR02PixelRGB(pixel) \
277 LBR02PixelRed((pixel)); \
278 LBR02PixelGreen((pixel)); \
279 LBR02PixelBlue((pixel)); \
282 #define LBR02PixelRGBA(pixel) \
284 LBR02PixelRGB((pixel)); \
285 LBR02PixelAlpha((pixel)); \
288 /* LBR03: Replicate top 3 bits (only used with opaque pixels during
289 PNG8 quantization) */
291 #define LBR03PacketRed(pixelpacket) \
293 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).red) & 0xe0; \
294 (pixelpacket).red=ScaleCharToQuantum( \
295 (lbr_bits | (lbr_bits >> 3) | (lbr_bits >> 6))); \
297 #define LBR03PacketGreen(pixelpacket) \
299 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).green) & 0xe0; \
300 (pixelpacket).green=ScaleCharToQuantum( \
301 (lbr_bits | (lbr_bits >> 3) | (lbr_bits >> 6))); \
303 #define LBR03PacketBlue(pixelpacket) \
305 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).blue) & 0xe0; \
306 (pixelpacket).blue=ScaleCharToQuantum( \
307 (lbr_bits | (lbr_bits >> 3) | (lbr_bits >> 6))); \
310 #define LBR03PacketRGB(pixelpacket) \
312 LBR03PacketRed((pixelpacket)); \
313 LBR03PacketGreen((pixelpacket)); \
314 LBR03PacketBlue((pixelpacket)); \
317 #define LBR03PixelRed(pixel) \
319 unsigned char lbr_bits=ScaleQuantumToChar(GetPixelRed(image,(pixel))) \
321 SetPixelRed(image, ScaleCharToQuantum( \
322 (lbr_bits | (lbr_bits >> 3) | (lbr_bits >> 6))), (pixel)); \
324 #define LBR03Green(pixel) \
326 unsigned char lbr_bits=ScaleQuantumToChar(GetPixelGreen(image,(pixel)))\
328 SetPixelGreen(image, ScaleCharToQuantum( \
329 (lbr_bits | (lbr_bits >> 3) | (lbr_bits >> 6))), (pixel)); \
331 #define LBR03Blue(pixel) \
333 unsigned char lbr_bits=ScaleQuantumToChar(GetPixelBlue(image,(pixel))) \
335 SetPixelBlue(image, ScaleCharToQuantum( \
336 (lbr_bits | (lbr_bits >> 3) | (lbr_bits >> 6))), (pixel)); \
339 #define LBR03RGB(pixel) \
341 LBR03PixelRed((pixel)); \
342 LBR03Green((pixel)); \
343 LBR03Blue((pixel)); \
346 /* LBR04: Replicate top 4 bits */
348 #define LBR04PacketRed(pixelpacket) \
350 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).red) & 0xf0; \
351 (pixelpacket).red=ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))); \
353 #define LBR04PacketGreen(pixelpacket) \
355 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).green) & 0xf0; \
356 (pixelpacket).green=ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))); \
358 #define LBR04PacketBlue(pixelpacket) \
360 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).blue) & 0xf0; \
361 (pixelpacket).blue=ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))); \
363 #define LBR04PacketAlpha(pixelpacket) \
365 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).alpha) & 0xf0; \
366 (pixelpacket).alpha=ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))); \
369 #define LBR04PacketRGB(pixelpacket) \
371 LBR04PacketRed((pixelpacket)); \
372 LBR04PacketGreen((pixelpacket)); \
373 LBR04PacketBlue((pixelpacket)); \
376 #define LBR04PacketRGBO(pixelpacket) \
378 LBR04PacketRGB((pixelpacket)); \
379 LBR04PacketAlpha((pixelpacket)); \
382 #define LBR04PixelRed(pixel) \
384 unsigned char lbr_bits=ScaleQuantumToChar(GetPixelRed(image,(pixel))) \
387 ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))), (pixel)); \
389 #define LBR04PixelGreen(pixel) \
391 unsigned char lbr_bits=ScaleQuantumToChar(GetPixelGreen(image,(pixel)))\
393 SetPixelGreen(image,\
394 ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))), (pixel)); \
396 #define LBR04PixelBlue(pixel) \
398 unsigned char lbr_bits= \
399 ScaleQuantumToChar(GetPixelBlue(image,(pixel))) & 0xf0; \
401 ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))), (pixel)); \
403 #define LBR04PixelAlpha(pixel) \
405 unsigned char lbr_bits= \
406 ScaleQuantumToChar(GetPixelAlpha(image,(pixel))) & 0xf0; \
407 SetPixelAlpha(image,\
408 ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))), (pixel)); \
411 #define LBR04PixelRGB(pixel) \
413 LBR04PixelRed((pixel)); \
414 LBR04PixelGreen((pixel)); \
415 LBR04PixelBlue((pixel)); \
418 #define LBR04PixelRGBA(pixel) \
420 LBR04PixelRGB((pixel)); \
421 LBR04PixelAlpha((pixel)); \
425 #if MAGICKCORE_QUANTUM_DEPTH > 8
426 /* LBR08: Replicate top 8 bits */
428 #define LBR08PacketRed(pixelpacket) \
430 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).red); \
431 (pixelpacket).red=ScaleCharToQuantum((lbr_bits)); \
433 #define LBR08PacketGreen(pixelpacket) \
435 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).green); \
436 (pixelpacket).green=ScaleCharToQuantum((lbr_bits)); \
438 #define LBR08PacketBlue(pixelpacket) \
440 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).blue); \
441 (pixelpacket).blue=ScaleCharToQuantum((lbr_bits)); \
443 #define LBR08PacketAlpha(pixelpacket) \
445 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).alpha); \
446 (pixelpacket).alpha=ScaleCharToQuantum((lbr_bits)); \
449 #define LBR08PacketRGB(pixelpacket) \
451 LBR08PacketRed((pixelpacket)); \
452 LBR08PacketGreen((pixelpacket)); \
453 LBR08PacketBlue((pixelpacket)); \
456 #define LBR08PacketRGBO(pixelpacket) \
458 LBR08PacketRGB((pixelpacket)); \
459 LBR08PacketAlpha((pixelpacket)); \
462 #define LBR08PixelRed(pixel) \
464 unsigned char lbr_bits= \
465 ScaleQuantumToChar(GetPixelRed(image,(pixel))); \
467 ScaleCharToQuantum((lbr_bits)), (pixel)); \
469 #define LBR08PixelGreen(pixel) \
471 unsigned char lbr_bits= \
472 ScaleQuantumToChar(GetPixelGreen(image,(pixel))); \
473 SetPixelGreen(image,\
474 ScaleCharToQuantum((lbr_bits)), (pixel)); \
476 #define LBR08PixelBlue(pixel) \
478 unsigned char lbr_bits= \
479 ScaleQuantumToChar(GetPixelBlue(image,(pixel))); \
481 ScaleCharToQuantum((lbr_bits)), (pixel)); \
483 #define LBR08PixelAlpha(pixel) \
485 unsigned char lbr_bits= \
486 ScaleQuantumToChar(GetPixelAlpha(image,(pixel))); \
487 SetPixelAlpha(image,\
488 ScaleCharToQuantum((lbr_bits)), (pixel)); \
491 #define LBR08PixelRGB(pixel) \
493 LBR08PixelRed((pixel)); \
494 LBR08PixelGreen((pixel)); \
495 LBR08PixelBlue((pixel)); \
498 #define LBR08PixelRGBA(pixel) \
500 LBR08PixelRGB((pixel)); \
501 LBR08PixelAlpha((pixel)); \
503 #endif /* MAGICKCORE_QUANTUM_DEPTH > 8 */
506 #if MAGICKCORE_QUANTUM_DEPTH > 16
507 /* LBR16: Replicate top 16 bits */
509 #define LBR16PacketRed(pixelpacket) \
511 unsigned short lbr_bits=ScaleQuantumToShort((pixelpacket).red); \
512 (pixelpacket).red=ScaleShortToQuantum((lbr_bits)); \
514 #define LBR16PacketGreen(pixelpacket) \
516 unsigned short lbr_bits=ScaleQuantumToShort((pixelpacket).green); \
517 (pixelpacket).green=ScaleShortToQuantum((lbr_bits)); \
519 #define LBR16PacketBlue(pixelpacket) \
521 unsigned short lbr_bits=ScaleQuantumToShort((pixelpacket).blue); \
522 (pixelpacket).blue=ScaleShortToQuantum((lbr_bits)); \
524 #define LBR16PacketAlpha(pixelpacket) \
526 unsigned short lbr_bits=ScaleQuantumToShort((pixelpacket).alpha); \
527 (pixelpacket).alpha=ScaleShortToQuantum((lbr_bits)); \
530 #define LBR16PacketRGB(pixelpacket) \
532 LBR16PacketRed((pixelpacket)); \
533 LBR16PacketGreen((pixelpacket)); \
534 LBR16PacketBlue((pixelpacket)); \
537 #define LBR16PacketRGBO(pixelpacket) \
539 LBR16PacketRGB((pixelpacket)); \
540 LBR16PacketAlpha((pixelpacket)); \
543 #define LBR16PixelRed(pixel) \
545 unsigned short lbr_bits= \
546 ScaleQuantumToShort(GetPixelRed(image,(pixel))); \
548 ScaleShortToQuantum((lbr_bits)),(pixel)); \
550 #define LBR16PixelGreen(pixel) \
552 unsigned short lbr_bits= \
553 ScaleQuantumToShort(GetPixelGreen(image,(pixel))); \
554 SetPixelGreen(image,\
555 ScaleShortToQuantum((lbr_bits)),(pixel)); \
557 #define LBR16PixelBlue(pixel) \
559 unsigned short lbr_bits= \
560 ScaleQuantumToShort(GetPixelBlue(image,(pixel))); \
562 ScaleShortToQuantum((lbr_bits)),(pixel)); \
564 #define LBR16PixelAlpha(pixel) \
566 unsigned short lbr_bits= \
567 ScaleQuantumToShort(GetPixelAlpha(image,(pixel))); \
568 SetPixelAlpha(image,\
569 ScaleShortToQuantum((lbr_bits)),(pixel)); \
572 #define LBR16PixelRGB(pixel) \
574 LBR16PixelRed((pixel)); \
575 LBR16PixelGreen((pixel)); \
576 LBR16PixelBlue((pixel)); \
579 #define LBR16PixelRGBA(pixel) \
581 LBR16PixelRGB((pixel)); \
582 LBR16PixelAlpha((pixel)); \
584 #endif /* MAGICKCORE_QUANTUM_DEPTH > 16 */
587 Establish thread safety.
588 setjmp/longjmp is claimed to be safe on these platforms:
589 setjmp/longjmp is alleged to be unsafe on these platforms:
591 #ifndef SETJMP_IS_THREAD_SAFE
592 #define PNG_SETJMP_NOT_THREAD_SAFE
595 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
597 *ping_semaphore = (SemaphoreInfo *) NULL;
601 This temporary until I set up malloc'ed object attributes array.
602 Recompile with MNG_MAX_OBJECTS=65536L to avoid this limit but
605 #define MNG_MAX_OBJECTS 256
608 If this not defined, spec is interpreted strictly. If it is
609 defined, an attempt will be made to recover from some errors,
611 o global PLTE too short
616 Don't try to define PNG_MNG_FEATURES_SUPPORTED here. Make sure
617 it's defined in libpng/pngconf.h, version 1.0.9 or later. It won't work
618 with earlier versions of libpng. From libpng-1.0.3a to libpng-1.0.8,
619 PNG_READ|WRITE_EMPTY_PLTE were used but those have been deprecated in
620 libpng in favor of PNG_MNG_FEATURES_SUPPORTED, so we set them here.
621 PNG_MNG_FEATURES_SUPPORTED is disabled by default in libpng-1.0.9 and
622 will be enabled by default in libpng-1.2.0.
624 #ifdef PNG_MNG_FEATURES_SUPPORTED
625 # ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
626 # define PNG_READ_EMPTY_PLTE_SUPPORTED
628 # ifndef PNG_WRITE_EMPTY_PLTE_SUPPORTED
629 # define PNG_WRITE_EMPTY_PLTE_SUPPORTED
634 Maximum valid size_t in PNG/MNG chunks is (2^31)-1
635 This macro is only defined in libpng-1.0.3 and later.
636 Previously it was PNG_MAX_UINT but that was deprecated in libpng-1.2.6
638 #ifndef PNG_UINT_31_MAX
639 #define PNG_UINT_31_MAX (png_uint_32) 0x7fffffffL
643 Constant strings for known chunk types. If you need to add a chunk,
644 add a string holding the name here. To make the code more
645 portable, we use ASCII numbers like this, not characters.
648 static png_byte mng_MHDR[5]={ 77, 72, 68, 82, (png_byte) '\0'};
649 static png_byte mng_BACK[5]={ 66, 65, 67, 75, (png_byte) '\0'};
650 static png_byte mng_BASI[5]={ 66, 65, 83, 73, (png_byte) '\0'};
651 static png_byte mng_CLIP[5]={ 67, 76, 73, 80, (png_byte) '\0'};
652 static png_byte mng_CLON[5]={ 67, 76, 79, 78, (png_byte) '\0'};
653 static png_byte mng_DEFI[5]={ 68, 69, 70, 73, (png_byte) '\0'};
654 static png_byte mng_DHDR[5]={ 68, 72, 68, 82, (png_byte) '\0'};
655 static png_byte mng_DISC[5]={ 68, 73, 83, 67, (png_byte) '\0'};
656 static png_byte mng_ENDL[5]={ 69, 78, 68, 76, (png_byte) '\0'};
657 static png_byte mng_FRAM[5]={ 70, 82, 65, 77, (png_byte) '\0'};
658 static png_byte mng_IEND[5]={ 73, 69, 78, 68, (png_byte) '\0'};
659 static png_byte mng_IHDR[5]={ 73, 72, 68, 82, (png_byte) '\0'};
660 static png_byte mng_JHDR[5]={ 74, 72, 68, 82, (png_byte) '\0'};
661 static png_byte mng_LOOP[5]={ 76, 79, 79, 80, (png_byte) '\0'};
662 static png_byte mng_MAGN[5]={ 77, 65, 71, 78, (png_byte) '\0'};
663 static png_byte mng_MEND[5]={ 77, 69, 78, 68, (png_byte) '\0'};
664 static png_byte mng_MOVE[5]={ 77, 79, 86, 69, (png_byte) '\0'};
665 static png_byte mng_PAST[5]={ 80, 65, 83, 84, (png_byte) '\0'};
666 static png_byte mng_PLTE[5]={ 80, 76, 84, 69, (png_byte) '\0'};
667 static png_byte mng_SAVE[5]={ 83, 65, 86, 69, (png_byte) '\0'};
668 static png_byte mng_SEEK[5]={ 83, 69, 69, 75, (png_byte) '\0'};
669 static png_byte mng_SHOW[5]={ 83, 72, 79, 87, (png_byte) '\0'};
670 static png_byte mng_TERM[5]={ 84, 69, 82, 77, (png_byte) '\0'};
671 static png_byte mng_bKGD[5]={ 98, 75, 71, 68, (png_byte) '\0'};
672 static png_byte mng_cHRM[5]={ 99, 72, 82, 77, (png_byte) '\0'};
673 static png_byte mng_gAMA[5]={103, 65, 77, 65, (png_byte) '\0'};
674 static png_byte mng_iCCP[5]={105, 67, 67, 80, (png_byte) '\0'};
675 static png_byte mng_nEED[5]={110, 69, 69, 68, (png_byte) '\0'};
676 static png_byte mng_pHYg[5]={112, 72, 89, 103, (png_byte) '\0'};
677 static png_byte mng_vpAg[5]={118, 112, 65, 103, (png_byte) '\0'};
678 static png_byte mng_pHYs[5]={112, 72, 89, 115, (png_byte) '\0'};
679 static png_byte mng_sBIT[5]={115, 66, 73, 84, (png_byte) '\0'};
680 static png_byte mng_sRGB[5]={115, 82, 71, 66, (png_byte) '\0'};
681 static png_byte mng_tRNS[5]={116, 82, 78, 83, (png_byte) '\0'};
683 #if defined(JNG_SUPPORTED)
684 static png_byte mng_IDAT[5]={ 73, 68, 65, 84, (png_byte) '\0'};
685 static png_byte mng_JDAT[5]={ 74, 68, 65, 84, (png_byte) '\0'};
686 static png_byte mng_JDAA[5]={ 74, 68, 65, 65, (png_byte) '\0'};
687 static png_byte mng_JdAA[5]={ 74, 100, 65, 65, (png_byte) '\0'};
688 static png_byte mng_JSEP[5]={ 74, 83, 69, 80, (png_byte) '\0'};
689 static png_byte mng_oFFs[5]={111, 70, 70, 115, (png_byte) '\0'};
693 Other known chunks that are not yet supported by ImageMagick:
694 static png_byte mng_hIST[5]={104, 73, 83, 84, (png_byte) '\0'};
695 static png_byte mng_iCCP[5]={105, 67, 67, 80, (png_byte) '\0'};
696 static png_byte mng_iTXt[5]={105, 84, 88, 116, (png_byte) '\0'};
697 static png_byte mng_sPLT[5]={115, 80, 76, 84, (png_byte) '\0'};
698 static png_byte mng_sTER[5]={115, 84, 69, 82, (png_byte) '\0'};
699 static png_byte mng_tEXt[5]={116, 69, 88, 116, (png_byte) '\0'};
700 static png_byte mng_tIME[5]={116, 73, 77, 69, (png_byte) '\0'};
701 static png_byte mng_zTXt[5]={122, 84, 88, 116, (png_byte) '\0'};
704 typedef struct _MngBox
713 typedef struct _MngPair
720 #ifdef MNG_OBJECT_BUFFERS
721 typedef struct _MngBuffer
753 typedef struct _MngInfo
756 #ifdef MNG_OBJECT_BUFFERS
758 *ob[MNG_MAX_OBJECTS];
769 #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
770 bytes_in_read_buffer,
776 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
777 defined(PNG_MNG_FEATURES_SUPPORTED)
789 have_saved_bkgd_index,
790 have_write_global_chrm,
791 have_write_global_gama,
792 have_write_global_plte,
793 have_write_global_srgb,
807 x_off[MNG_MAX_OBJECTS],
808 y_off[MNG_MAX_OBJECTS];
814 object_clip[MNG_MAX_OBJECTS];
817 /* These flags could be combined into one byte */
818 exists[MNG_MAX_OBJECTS],
819 frozen[MNG_MAX_OBJECTS],
821 invisible[MNG_MAX_OBJECTS],
822 viewable[MNG_MAX_OBJECTS];
834 #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
852 global_x_pixels_per_unit,
853 global_y_pixels_per_unit,
863 global_phys_unit_type,
878 write_png_compression_level,
879 write_png_compression_strategy,
880 write_png_compression_filter,
887 #ifdef MNG_BASI_SUPPORTED
895 basi_compression_method,
897 basi_interlace_method,
920 /* Added at version 6.6.6-7 */
928 /* ping_exclude_iTXt, */
935 ping_exclude_zCCP, /* hex-encoded iCCP */
937 ping_preserve_colormap;
943 Forward declarations.
945 static MagickBooleanType
946 WritePNGImage(const ImageInfo *,Image *,ExceptionInfo *);
948 static MagickBooleanType
949 WriteMNGImage(const ImageInfo *,Image *,ExceptionInfo *);
951 #if defined(JNG_SUPPORTED)
952 static MagickBooleanType
953 WriteJNGImage(const ImageInfo *,Image *,ExceptionInfo *);
956 #if PNG_LIBPNG_VER > 10011
959 #if (MAGICKCORE_QUANTUM_DEPTH >= 16)
960 static MagickBooleanType
961 LosslessReduceDepthOK(Image *image,ExceptionInfo *exception)
963 /* Reduce bit depth if it can be reduced losslessly from 16+ to 8.
965 * This is true if the high byte and the next highest byte of
966 * each sample of the image, the colormap, and the background color
967 * are equal to each other. We check this by seeing if the samples
968 * are unchanged when we scale them down to 8 and back up to Quantum.
970 * We don't use the method GetImageDepth() because it doesn't check
971 * background and doesn't handle PseudoClass specially.
974 #define QuantumToCharToQuantumEqQuantum(quantum) \
975 ((ScaleCharToQuantum((unsigned char) ScaleQuantumToChar(quantum))) == quantum)
978 ok_to_reduce=MagickFalse;
980 if (image->depth >= 16)
987 QuantumToCharToQuantumEqQuantum(image->background_color.red) &&
988 QuantumToCharToQuantumEqQuantum(image->background_color.green) &&
989 QuantumToCharToQuantumEqQuantum(image->background_color.blue) ?
990 MagickTrue : MagickFalse;
992 if (ok_to_reduce != MagickFalse && image->storage_class == PseudoClass)
996 for (indx=0; indx < (ssize_t) image->colors; indx++)
999 QuantumToCharToQuantumEqQuantum(
1000 image->colormap[indx].red) &&
1001 QuantumToCharToQuantumEqQuantum(
1002 image->colormap[indx].green) &&
1003 QuantumToCharToQuantumEqQuantum(
1004 image->colormap[indx].blue)) ?
1005 MagickTrue : MagickFalse;
1007 if (ok_to_reduce == MagickFalse)
1012 if ((ok_to_reduce != MagickFalse) &&
1013 (image->storage_class != PseudoClass))
1021 for (y=0; y < (ssize_t) image->rows; y++)
1023 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1025 if (p == (const Quantum *) NULL)
1027 ok_to_reduce = MagickFalse;
1031 for (x=(ssize_t) image->columns-1; x >= 0; x--)
1034 QuantumToCharToQuantumEqQuantum(GetPixelRed(image,p)) &&
1035 QuantumToCharToQuantumEqQuantum(GetPixelGreen(image,p)) &&
1036 QuantumToCharToQuantumEqQuantum(GetPixelBlue(image,p)) ?
1037 MagickTrue : MagickFalse;
1039 if (ok_to_reduce == MagickFalse)
1042 p+=GetPixelChannels(image);
1049 if (ok_to_reduce != MagickFalse)
1051 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1052 " OK to reduce PNG bit depth to 8 without loss of info");
1056 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1057 " Not OK to reduce PNG bit depth to 8 without loss of info");
1061 return ok_to_reduce;
1063 #endif /* MAGICKCORE_QUANTUM_DEPTH >= 16 */
1065 static const char* PngColorTypeToString(const unsigned int color_type)
1068 *result = "Unknown";
1072 case PNG_COLOR_TYPE_GRAY:
1075 case PNG_COLOR_TYPE_GRAY_ALPHA:
1076 result = "Gray+Alpha";
1078 case PNG_COLOR_TYPE_PALETTE:
1081 case PNG_COLOR_TYPE_RGB:
1084 case PNG_COLOR_TYPE_RGB_ALPHA:
1085 result = "RGB+Alpha";
1093 Magick_RenderingIntent_to_PNG_RenderingIntent(const RenderingIntent intent)
1097 case PerceptualIntent:
1100 case RelativeIntent:
1103 case SaturationIntent:
1106 case AbsoluteIntent:
1114 static RenderingIntent
1115 Magick_RenderingIntent_from_PNG_RenderingIntent(const int ping_intent)
1117 switch (ping_intent)
1120 return PerceptualIntent;
1123 return RelativeIntent;
1126 return SaturationIntent;
1129 return AbsoluteIntent;
1132 return UndefinedIntent;
1137 Magick_RenderingIntentString_from_PNG_RenderingIntent(const int ping_intent)
1139 switch (ping_intent)
1142 return "Perceptual Intent";
1145 return "Relative Intent";
1148 return "Saturation Intent";
1151 return "Absolute Intent";
1154 return "Undefined Intent";
1158 static inline ssize_t MagickMax(const ssize_t x,const ssize_t y)
1167 Magick_ColorType_from_PNG_ColorType(const int ping_colortype)
1169 switch (ping_colortype)
1187 return "UndefinedColorType";
1192 static inline ssize_t MagickMin(const ssize_t x,const ssize_t y)
1199 #endif /* PNG_LIBPNG_VER > 10011 */
1200 #endif /* MAGICKCORE_PNG_DELEGATE */
1203 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1211 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1213 % IsMNG() returns MagickTrue if the image format type, identified by the
1214 % magick string, is MNG.
1216 % The format of the IsMNG method is:
1218 % MagickBooleanType IsMNG(const unsigned char *magick,const size_t length)
1220 % A description of each parameter follows:
1222 % o magick: compare image format pattern against these bytes.
1224 % o length: Specifies the length of the magick string.
1228 static MagickBooleanType IsMNG(const unsigned char *magick,const size_t length)
1231 return(MagickFalse);
1233 if (memcmp(magick,"\212MNG\r\n\032\n",8) == 0)
1236 return(MagickFalse);
1240 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1248 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1250 % IsJNG() returns MagickTrue if the image format type, identified by the
1251 % magick string, is JNG.
1253 % The format of the IsJNG method is:
1255 % MagickBooleanType IsJNG(const unsigned char *magick,const size_t length)
1257 % A description of each parameter follows:
1259 % o magick: compare image format pattern against these bytes.
1261 % o length: Specifies the length of the magick string.
1265 static MagickBooleanType IsJNG(const unsigned char *magick,const size_t length)
1268 return(MagickFalse);
1270 if (memcmp(magick,"\213JNG\r\n\032\n",8) == 0)
1273 return(MagickFalse);
1277 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1285 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1287 % IsPNG() returns MagickTrue if the image format type, identified by the
1288 % magick string, is PNG.
1290 % The format of the IsPNG method is:
1292 % MagickBooleanType IsPNG(const unsigned char *magick,const size_t length)
1294 % A description of each parameter follows:
1296 % o magick: compare image format pattern against these bytes.
1298 % o length: Specifies the length of the magick string.
1301 static MagickBooleanType IsPNG(const unsigned char *magick,const size_t length)
1304 return(MagickFalse);
1306 if (memcmp(magick,"\211PNG\r\n\032\n",8) == 0)
1309 return(MagickFalse);
1312 #if defined(MAGICKCORE_PNG_DELEGATE)
1313 #if defined(__cplusplus) || defined(c_plusplus)
1317 #if (PNG_LIBPNG_VER > 10011)
1318 static size_t WriteBlobMSBULong(Image *image,const size_t value)
1323 assert(image != (Image *) NULL);
1324 assert(image->signature == MagickSignature);
1325 buffer[0]=(unsigned char) (value >> 24);
1326 buffer[1]=(unsigned char) (value >> 16);
1327 buffer[2]=(unsigned char) (value >> 8);
1328 buffer[3]=(unsigned char) value;
1329 return((size_t) WriteBlob(image,4,buffer));
1332 static void PNGLong(png_bytep p,png_uint_32 value)
1334 *p++=(png_byte) ((value >> 24) & 0xff);
1335 *p++=(png_byte) ((value >> 16) & 0xff);
1336 *p++=(png_byte) ((value >> 8) & 0xff);
1337 *p++=(png_byte) (value & 0xff);
1340 #if defined(JNG_SUPPORTED)
1341 static void PNGsLong(png_bytep p,png_int_32 value)
1343 *p++=(png_byte) ((value >> 24) & 0xff);
1344 *p++=(png_byte) ((value >> 16) & 0xff);
1345 *p++=(png_byte) ((value >> 8) & 0xff);
1346 *p++=(png_byte) (value & 0xff);
1350 static void PNGShort(png_bytep p,png_uint_16 value)
1352 *p++=(png_byte) ((value >> 8) & 0xff);
1353 *p++=(png_byte) (value & 0xff);
1356 static void PNGType(png_bytep p,png_bytep type)
1358 (void) CopyMagickMemory(p,type,4*sizeof(png_byte));
1361 static void LogPNGChunk(MagickBooleanType logging, png_bytep type,
1364 if (logging != MagickFalse)
1365 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1366 " Writing %c%c%c%c chunk, length: %.20g",
1367 type[0],type[1],type[2],type[3],(double) length);
1369 #endif /* PNG_LIBPNG_VER > 10011 */
1371 #if defined(__cplusplus) || defined(c_plusplus)
1375 #if PNG_LIBPNG_VER > 10011
1377 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1381 % R e a d P N G I m a g e %
1385 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1387 % ReadPNGImage() reads a Portable Network Graphics (PNG) or
1388 % Multiple-image Network Graphics (MNG) image file and returns it. It
1389 % allocates the memory necessary for the new Image structure and returns a
1390 % pointer to the new image or set of images.
1392 % MNG support written by Glenn Randers-Pehrson, glennrp@image...
1394 % The format of the ReadPNGImage method is:
1396 % Image *ReadPNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
1398 % A description of each parameter follows:
1400 % o image_info: the image info.
1402 % o exception: return any errors or warnings in this structure.
1404 % To do, more or less in chronological order (as of version 5.5.2,
1405 % November 26, 2002 -- glennrp -- see also "To do" under WriteMNGImage):
1407 % Get 16-bit cheap transparency working.
1409 % (At this point, PNG decoding is supposed to be in full MNG-LC compliance)
1411 % Preserve all unknown and not-yet-handled known chunks found in input
1412 % PNG file and copy them into output PNG files according to the PNG
1415 % (At this point, PNG encoding should be in full MNG compliance)
1417 % Provide options for choice of background to use when the MNG BACK
1418 % chunk is not present or is not mandatory (i.e., leave transparent,
1419 % user specified, MNG BACK, PNG bKGD)
1421 % Implement LOOP/ENDL [done, but could do discretionary loops more
1422 % efficiently by linking in the duplicate frames.].
1424 % Decode and act on the MHDR simplicity profile (offer option to reject
1425 % files or attempt to process them anyway when the profile isn't LC or VLC).
1427 % Upgrade to full MNG without Delta-PNG.
1429 % o BACK [done a while ago except for background image ID]
1430 % o MOVE [done 15 May 1999]
1431 % o CLIP [done 15 May 1999]
1432 % o DISC [done 19 May 1999]
1433 % o SAVE [partially done 19 May 1999 (marks objects frozen)]
1434 % o SEEK [partially done 19 May 1999 (discard function only)]
1438 % o MNG-level tEXt/iTXt/zTXt
1443 % o iTXt (wait for libpng implementation).
1445 % Use the scene signature to discover when an identical scene is
1446 % being reused, and just point to the original image->exception instead
1447 % of storing another set of pixels. This not specific to MNG
1448 % but could be applied generally.
1450 % Upgrade to full MNG with Delta-PNG.
1452 % JNG tEXt/iTXt/zTXt
1454 % We will not attempt to read files containing the CgBI chunk.
1455 % They are really Xcode files meant for display on the iPhone.
1456 % These are not valid PNG files and it is impossible to recover
1457 % the original PNG from files that have been converted to Xcode-PNG,
1458 % since irretrievable loss of color data has occurred due to the
1459 % use of premultiplied alpha.
1462 #if defined(__cplusplus) || defined(c_plusplus)
1467 This the function that does the actual reading of data. It is
1468 the same as the one supplied in libpng, except that it receives the
1469 datastream from the ReadBlob() function instead of standard input.
1471 static void png_get_data(png_structp png_ptr,png_bytep data,png_size_t length)
1476 image=(Image *) png_get_io_ptr(png_ptr);
1482 check=(png_size_t) ReadBlob(image,(size_t) length,data);
1483 if (check != length)
1488 (void) FormatLocaleString(msg,MaxTextExtent,
1489 "Expected %.20g bytes; found %.20g bytes",(double) length,
1491 png_warning(png_ptr,msg);
1492 png_error(png_ptr,"Read Exception");
1497 #if !defined(PNG_READ_EMPTY_PLTE_SUPPORTED) && \
1498 !defined(PNG_MNG_FEATURES_SUPPORTED)
1499 /* We use mng_get_data() instead of png_get_data() if we have a libpng
1500 * older than libpng-1.0.3a, which was the first to allow the empty
1501 * PLTE, or a newer libpng in which PNG_MNG_FEATURES_SUPPORTED was
1502 * ifdef'ed out. Earlier versions would crash if the bKGD chunk was
1503 * encountered after an empty PLTE, so we have to look ahead for bKGD
1504 * chunks and remove them from the datastream that is passed to libpng,
1505 * and store their contents for later use.
1507 static void mng_get_data(png_structp png_ptr,png_bytep data,png_size_t length)
1522 mng_info=(MngInfo *) png_get_io_ptr(png_ptr);
1523 image=(Image *) mng_info->image;
1524 while (mng_info->bytes_in_read_buffer && length)
1526 data[i]=mng_info->read_buffer[i];
1527 mng_info->bytes_in_read_buffer--;
1533 check=(png_size_t) ReadBlob(image,(size_t) length,(char *) data);
1535 if (check != length)
1536 png_error(png_ptr,"Read Exception");
1540 if ((data[0] == 0) && (data[1] == 0) && (data[2] == 0) &&
1543 check=(png_size_t) ReadBlob(image,(size_t) length,
1544 (char *) mng_info->read_buffer);
1545 mng_info->read_buffer[4]=0;
1546 mng_info->bytes_in_read_buffer=4;
1547 if (memcmp(mng_info->read_buffer,mng_PLTE,4) == 0)
1548 mng_info->found_empty_plte=MagickTrue;
1549 if (memcmp(mng_info->read_buffer,mng_IEND,4) == 0)
1551 mng_info->found_empty_plte=MagickFalse;
1552 mng_info->have_saved_bkgd_index=MagickFalse;
1556 if ((data[0] == 0) && (data[1] == 0) && (data[2] == 0) &&
1559 check=(png_size_t) ReadBlob(image,(size_t) length,
1560 (char *) mng_info->read_buffer);
1561 mng_info->read_buffer[4]=0;
1562 mng_info->bytes_in_read_buffer=4;
1563 if (memcmp(mng_info->read_buffer,mng_bKGD,4) == 0)
1564 if (mng_info->found_empty_plte)
1567 Skip the bKGD data byte and CRC.
1570 ReadBlob(image,5,(char *) mng_info->read_buffer);
1571 check=(png_size_t) ReadBlob(image,(size_t) length,
1572 (char *) mng_info->read_buffer);
1573 mng_info->saved_bkgd_index=mng_info->read_buffer[0];
1574 mng_info->have_saved_bkgd_index=MagickTrue;
1575 mng_info->bytes_in_read_buffer=0;
1583 static void png_put_data(png_structp png_ptr,png_bytep data,png_size_t length)
1588 image=(Image *) png_get_io_ptr(png_ptr);
1594 check=(png_size_t) WriteBlob(image,(size_t) length,data);
1596 if (check != length)
1597 png_error(png_ptr,"WriteBlob Failed");
1601 static void png_flush_data(png_structp png_ptr)
1606 #ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
1607 static int PalettesAreEqual(Image *a,Image *b)
1612 if ((a == (Image *) NULL) || (b == (Image *) NULL))
1613 return((int) MagickFalse);
1615 if (a->storage_class != PseudoClass || b->storage_class != PseudoClass)
1616 return((int) MagickFalse);
1618 if (a->colors != b->colors)
1619 return((int) MagickFalse);
1621 for (i=0; i < (ssize_t) a->colors; i++)
1623 if ((a->colormap[i].red != b->colormap[i].red) ||
1624 (a->colormap[i].green != b->colormap[i].green) ||
1625 (a->colormap[i].blue != b->colormap[i].blue))
1626 return((int) MagickFalse);
1629 return((int) MagickTrue);
1633 static void MngInfoDiscardObject(MngInfo *mng_info,int i)
1635 if (i && (i < MNG_MAX_OBJECTS) && (mng_info != (MngInfo *) NULL) &&
1636 mng_info->exists[i] && !mng_info->frozen[i])
1638 #ifdef MNG_OBJECT_BUFFERS
1639 if (mng_info->ob[i] != (MngBuffer *) NULL)
1641 if (mng_info->ob[i]->reference_count > 0)
1642 mng_info->ob[i]->reference_count--;
1644 if (mng_info->ob[i]->reference_count == 0)
1646 if (mng_info->ob[i]->image != (Image *) NULL)
1647 mng_info->ob[i]->image=DestroyImage(mng_info->ob[i]->image);
1649 mng_info->ob[i]=DestroyString(mng_info->ob[i]);
1652 mng_info->ob[i]=(MngBuffer *) NULL;
1654 mng_info->exists[i]=MagickFalse;
1655 mng_info->invisible[i]=MagickFalse;
1656 mng_info->viewable[i]=MagickFalse;
1657 mng_info->frozen[i]=MagickFalse;
1658 mng_info->x_off[i]=0;
1659 mng_info->y_off[i]=0;
1660 mng_info->object_clip[i].left=0;
1661 mng_info->object_clip[i].right=(ssize_t) PNG_UINT_31_MAX;
1662 mng_info->object_clip[i].top=0;
1663 mng_info->object_clip[i].bottom=(ssize_t) PNG_UINT_31_MAX;
1667 static void MngInfoFreeStruct(MngInfo *mng_info,
1668 MagickBooleanType *have_mng_structure)
1670 if (*have_mng_structure != MagickFalse && (mng_info != (MngInfo *) NULL))
1675 for (i=1; i < MNG_MAX_OBJECTS; i++)
1676 MngInfoDiscardObject(mng_info,i);
1678 if (mng_info->global_plte != (png_colorp) NULL)
1679 mng_info->global_plte=(png_colorp)
1680 RelinquishMagickMemory(mng_info->global_plte);
1682 mng_info=(MngInfo *) RelinquishMagickMemory(mng_info);
1683 *have_mng_structure=MagickFalse;
1687 static MngBox mng_minimum_box(MngBox box1,MngBox box2)
1693 if (box.left < box2.left)
1696 if (box.top < box2.top)
1699 if (box.right > box2.right)
1700 box.right=box2.right;
1702 if (box.bottom > box2.bottom)
1703 box.bottom=box2.bottom;
1708 static MngBox mng_read_box(MngBox previous_box,char delta_type,unsigned char *p)
1714 Read clipping boundaries from DEFI, CLIP, FRAM, or PAST chunk.
1716 box.left=(ssize_t) ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]);
1717 box.right=(ssize_t) ((p[4] << 24) | (p[5] << 16) | (p[6] << 8) | p[7]);
1718 box.top=(ssize_t) ((p[8] << 24) | (p[9] << 16) | (p[10] << 8) | p[11]);
1719 box.bottom=(ssize_t) ((p[12] << 24) | (p[13] << 16) | (p[14] << 8) | p[15]);
1720 if (delta_type != 0)
1722 box.left+=previous_box.left;
1723 box.right+=previous_box.right;
1724 box.top+=previous_box.top;
1725 box.bottom+=previous_box.bottom;
1731 static MngPair mng_read_pair(MngPair previous_pair,int delta_type,
1737 Read two ssize_ts from CLON, MOVE or PAST chunk
1739 pair.a=(long) ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]);
1740 pair.b=(long) ((p[4] << 24) | (p[5] << 16) | (p[6] << 8) | p[7]);
1742 if (delta_type != 0)
1744 pair.a+=previous_pair.a;
1745 pair.b+=previous_pair.b;
1751 static long mng_get_long(unsigned char *p)
1753 return((long) ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]));
1756 typedef struct _PNGErrorInfo
1765 static void MagickPNGErrorHandler(png_struct *ping,png_const_charp message)
1776 error_info=(PNGErrorInfo *) png_get_error_ptr(ping);
1777 image=error_info->image;
1778 exception=error_info->exception;
1780 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1781 " libpng-%s error: %s", PNG_LIBPNG_VER_STRING,message);
1783 (void) ThrowMagickException(exception,GetMagickModule(),CoderError,message,
1784 "`%s'",image->filename);
1786 #if (PNG_LIBPNG_VER < 10500)
1787 /* A warning about deprecated use of jmpbuf here is unavoidable if you
1788 * are building with libpng-1.4.x and can be ignored.
1790 longjmp(ping->jmpbuf,1);
1792 png_longjmp(ping,1);
1796 static void MagickPNGWarningHandler(png_struct *ping,png_const_charp message)
1807 if (LocaleCompare(message, "Missing PLTE before tRNS") == 0)
1808 png_error(ping, message);
1810 error_info=(PNGErrorInfo *) png_get_error_ptr(ping);
1811 image=error_info->image;
1812 exception=error_info->exception;
1813 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1814 " libpng-%s warning: %s", PNG_LIBPNG_VER_STRING,message);
1816 (void) ThrowMagickException(exception,GetMagickModule(),CoderWarning,
1817 message,"`%s'",image->filename);
1820 #ifdef PNG_USER_MEM_SUPPORTED
1821 #if PNG_LIBPNG_VER >= 14000
1822 static png_voidp Magick_png_malloc(png_structp png_ptr,png_alloc_size_t size)
1824 static png_voidp Magick_png_malloc(png_structp png_ptr,png_size_t size)
1828 return((png_voidp) AcquireMagickMemory((size_t) size));
1832 Free a pointer. It is removed from the list at the same time.
1834 static png_free_ptr Magick_png_free(png_structp png_ptr,png_voidp ptr)
1837 ptr=RelinquishMagickMemory(ptr);
1838 return((png_free_ptr) NULL);
1842 #if defined(__cplusplus) || defined(c_plusplus)
1847 Magick_png_read_raw_profile(png_struct *ping,Image *image,
1848 const ImageInfo *image_info, png_textp text,int ii,ExceptionInfo *exception)
1853 register unsigned char
1867 unhex[103]={0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,
1868 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,
1869 0,0,0,0,0,0,0,0,0,1, 2,3,4,5,6,7,8,9,0,0,
1870 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,
1871 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,10,11,12,
1875 /* look for newline */
1879 /* look for length */
1880 while (*sp == '\0' || *sp == ' ' || *sp == '\n')
1883 length=(png_uint_32) StringToLong(sp);
1885 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1886 " length: %lu",(unsigned long) length);
1888 while (*sp != ' ' && *sp != '\n')
1891 /* allocate space */
1894 png_warning(ping,"invalid profile length");
1895 return(MagickFalse);
1898 profile=BlobToStringInfo((const void *) NULL,length);
1900 if (profile == (StringInfo *) NULL)
1902 png_warning(ping, "unable to copy profile");
1903 return(MagickFalse);
1906 /* copy profile, skipping white space and column 1 "=" signs */
1907 dp=GetStringInfoDatum(profile);
1910 for (i=0; i < (ssize_t) nibbles; i++)
1912 while (*sp < '0' || (*sp > '9' && *sp < 'a') || *sp > 'f')
1916 png_warning(ping, "ran out of profile data");
1917 profile=DestroyStringInfo(profile);
1918 return(MagickFalse);
1924 *dp=(unsigned char) (16*unhex[(int) *sp++]);
1927 (*dp++)+=unhex[(int) *sp++];
1930 We have already read "Raw profile type.
1932 (void) SetImageProfile(image,&text[ii].key[17],profile,exception);
1933 profile=DestroyStringInfo(profile);
1935 if (image_info->verbose)
1936 (void) printf(" Found a generic profile, type %s\n",&text[ii].key[17]);
1941 #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
1942 static int read_vpag_chunk_callback(png_struct *ping, png_unknown_chunkp chunk)
1948 /* The unknown chunk structure contains the chunk data:
1953 Note that libpng has already taken care of the CRC handling.
1956 LogMagickEvent(CoderEvent,GetMagickModule(),
1957 " read_vpag_chunk: found %c%c%c%c chunk",
1958 chunk->name[0],chunk->name[1],chunk->name[2],chunk->name[3]);
1960 if (chunk->name[0] != 118 || chunk->name[1] != 112 ||
1961 chunk->name[2] != 65 ||chunk-> name[3] != 103)
1962 return(0); /* Did not recognize */
1964 /* recognized vpAg */
1966 if (chunk->size != 9)
1967 return(-1); /* Error return */
1969 if (chunk->data[8] != 0)
1970 return(0); /* ImageMagick requires pixel units */
1972 image=(Image *) png_get_user_chunk_ptr(ping);
1974 image->page.width=(size_t) ((chunk->data[0] << 24) |
1975 (chunk->data[1] << 16) | (chunk->data[2] << 8) | chunk->data[3]);
1977 image->page.height=(size_t) ((chunk->data[4] << 24) |
1978 (chunk->data[5] << 16) | (chunk->data[6] << 8) | chunk->data[7]);
1980 /* Return one of the following: */
1981 /* return(-n); chunk had an error */
1982 /* return(0); did not recognize */
1983 /* return(n); success */
1991 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1995 % R e a d O n e P N G I m a g e %
1999 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2001 % ReadOnePNGImage() reads a Portable Network Graphics (PNG) image file
2002 % (minus the 8-byte signature) and returns it. It allocates the memory
2003 % necessary for the new Image structure and returns a pointer to the new
2006 % The format of the ReadOnePNGImage method is:
2008 % Image *ReadOnePNGImage(MngInfo *mng_info, const ImageInfo *image_info,
2009 % ExceptionInfo *exception)
2011 % A description of each parameter follows:
2013 % o mng_info: Specifies a pointer to a MngInfo structure.
2015 % o image_info: the image info.
2017 % o exception: return any errors or warnings in this structure.
2020 static Image *ReadOnePNGImage(MngInfo *mng_info,
2021 const ImageInfo *image_info, ExceptionInfo *exception)
2023 /* Read one PNG image */
2025 /* To do: Read the tIME chunk into the date:modify property */
2026 /* To do: Read the tEXt/Creation Time chunk into the date:create property */
2039 intent, /* "PNG Rendering intent", which is ICC intent + 1 */
2049 ping_interlace_method,
2050 ping_compression_method,
2064 ping_found_sRGB_cHRM,
2103 register unsigned char
2121 *volatile ping_pixels;
2123 #ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED
2124 png_byte unused_chunks[]=
2126 104, 73, 83, 84, (png_byte) '\0', /* hIST */
2127 105, 84, 88, 116, (png_byte) '\0', /* iTXt */
2128 112, 67, 65, 76, (png_byte) '\0', /* pCAL */
2129 115, 67, 65, 76, (png_byte) '\0', /* sCAL */
2130 115, 80, 76, 84, (png_byte) '\0', /* sPLT */
2131 116, 73, 77, 69, (png_byte) '\0', /* tIME */
2132 #ifdef PNG_APNG_SUPPORTED /* libpng was built with APNG patch; */
2133 /* ignore the APNG chunks */
2134 97, 99, 84, 76, (png_byte) '\0', /* acTL */
2135 102, 99, 84, 76, (png_byte) '\0', /* fcTL */
2136 102, 100, 65, 84, (png_byte) '\0', /* fdAT */
2141 logging=LogMagickEvent(CoderEvent,GetMagickModule(),
2142 " Enter ReadOnePNGImage()");
2144 /* Define these outside of the following "if logging()" block so they will
2145 * show in debuggers.
2148 (void) ConcatenateMagickString(im_vers,
2149 MagickLibVersionText,32);
2150 (void) ConcatenateMagickString(im_vers,
2151 MagickLibAddendum,32);
2154 (void) ConcatenateMagickString(libpng_vers,
2155 PNG_LIBPNG_VER_STRING,32);
2157 (void) ConcatenateMagickString(libpng_runv,
2158 png_get_libpng_ver(NULL),32);
2161 (void) ConcatenateMagickString(zlib_vers,
2164 (void) ConcatenateMagickString(zlib_runv,
2169 LogMagickEvent(CoderEvent,GetMagickModule()," IM version = %s",
2171 LogMagickEvent(CoderEvent,GetMagickModule()," Libpng version = %s",
2173 if (LocaleCompare(libpng_vers,libpng_runv) != 0)
2175 LogMagickEvent(CoderEvent,GetMagickModule()," running with %s",
2178 LogMagickEvent(CoderEvent,GetMagickModule()," Zlib version = %s",
2180 if (LocaleCompare(zlib_vers,zlib_runv) != 0)
2182 LogMagickEvent(CoderEvent,GetMagickModule()," running with %s",
2187 #if (PNG_LIBPNG_VER < 10200)
2188 if (image_info->verbose)
2189 printf("Your PNG library (libpng-%s) is rather old.\n",
2190 PNG_LIBPNG_VER_STRING);
2193 #if (PNG_LIBPNG_VER >= 10400)
2194 # ifndef PNG_TRANSFORM_GRAY_TO_RGB /* Added at libpng-1.4.0beta67 */
2195 if (image_info->verbose)
2197 printf("Your PNG library (libpng-%s) is an old beta version.\n",
2198 PNG_LIBPNG_VER_STRING);
2199 printf("Please update it.\n");
2205 quantum_info = (QuantumInfo *) NULL;
2206 image=mng_info->image;
2208 if (logging != MagickFalse)
2210 (void)LogMagickEvent(CoderEvent,GetMagickModule(),
2211 " Before reading:");
2213 (void)LogMagickEvent(CoderEvent,GetMagickModule(),
2214 " image->alpha_trait=%d",(int) image->alpha_trait);
2216 (void)LogMagickEvent(CoderEvent,GetMagickModule(),
2217 " image->rendering_intent=%d",(int) image->rendering_intent);
2219 (void)LogMagickEvent(CoderEvent,GetMagickModule(),
2220 " image->colorspace=%d",(int) image->colorspace);
2222 (void)LogMagickEvent(CoderEvent,GetMagickModule(),
2223 " image->gamma=%f", image->gamma);
2225 intent=Magick_RenderingIntent_to_PNG_RenderingIntent(image->rendering_intent);
2227 /* Set to an out-of-range color unless tRNS chunk is present */
2228 transparent_color.red=65537;
2229 transparent_color.green=65537;
2230 transparent_color.blue=65537;
2231 transparent_color.alpha=65537;
2236 num_raw_profiles = 0;
2238 ping_found_cHRM = MagickFalse;
2239 ping_found_gAMA = MagickFalse;
2240 ping_found_iCCP = MagickFalse;
2241 ping_found_sRGB = MagickFalse;
2244 Allocate the PNG structures
2246 #ifdef PNG_USER_MEM_SUPPORTED
2247 error_info.image=image;
2248 error_info.exception=exception;
2249 ping=png_create_read_struct_2(PNG_LIBPNG_VER_STRING,&error_info,
2250 MagickPNGErrorHandler,MagickPNGWarningHandler, NULL,
2251 (png_malloc_ptr) Magick_png_malloc,(png_free_ptr) Magick_png_free);
2253 ping=png_create_read_struct(PNG_LIBPNG_VER_STRING,&error_info,
2254 MagickPNGErrorHandler,MagickPNGWarningHandler);
2256 if (ping == (png_struct *) NULL)
2257 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2259 ping_info=png_create_info_struct(ping);
2261 if (ping_info == (png_info *) NULL)
2263 png_destroy_read_struct(&ping,(png_info **) NULL,(png_info **) NULL);
2264 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2267 end_info=png_create_info_struct(ping);
2269 if (end_info == (png_info *) NULL)
2271 png_destroy_read_struct(&ping,&ping_info,(png_info **) NULL);
2272 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2275 ping_pixels=(unsigned char *) NULL;
2277 if (setjmp(png_jmpbuf(ping)))
2280 PNG image is corrupt.
2282 png_destroy_read_struct(&ping,&ping_info,&end_info);
2284 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
2285 UnlockSemaphoreInfo(ping_semaphore);
2288 if (ping_pixels != (unsigned char *) NULL)
2289 ping_pixels=(unsigned char *) RelinquishMagickMemory(ping_pixels);
2291 if (logging != MagickFalse)
2292 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2293 " exit ReadOnePNGImage() with error.");
2295 if (image != (Image *) NULL)
2297 InheritException(exception,exception);
2301 return(GetFirstImageInList(image));
2304 /* { For navigation to end of SETJMP-protected block. Within this
2305 * block, use png_error() instead of Throwing an Exception, to ensure
2306 * that libpng is able to clean up, and that the semaphore is unlocked.
2309 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
2310 LockSemaphoreInfo(ping_semaphore);
2314 Prepare PNG for reading.
2317 mng_info->image_found++;
2318 png_set_sig_bytes(ping,8);
2320 if (LocaleCompare(image_info->magick,"MNG") == 0)
2322 #if defined(PNG_MNG_FEATURES_SUPPORTED)
2323 (void) png_permit_mng_features(ping,PNG_ALL_MNG_FEATURES);
2324 png_set_read_fn(ping,image,png_get_data);
2326 #if defined(PNG_READ_EMPTY_PLTE_SUPPORTED)
2327 png_permit_empty_plte(ping,MagickTrue);
2328 png_set_read_fn(ping,image,png_get_data);
2330 mng_info->image=image;
2331 mng_info->bytes_in_read_buffer=0;
2332 mng_info->found_empty_plte=MagickFalse;
2333 mng_info->have_saved_bkgd_index=MagickFalse;
2334 png_set_read_fn(ping,mng_info,mng_get_data);
2340 png_set_read_fn(ping,image,png_get_data);
2342 #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
2343 /* Ignore unused chunks and all unknown chunks except for vpAg */
2344 #if PNG_LIBPNG_VER < 10700 /* Avoid libpng16 warning */
2345 png_set_keep_unknown_chunks(ping, 2, NULL, 0);
2347 png_set_keep_unknown_chunks(ping, 1, NULL, 0);
2349 png_set_keep_unknown_chunks(ping, 2, mng_vpAg, 1);
2350 png_set_keep_unknown_chunks(ping, 1, unused_chunks,
2351 (int)sizeof(unused_chunks)/5);
2352 /* Callback for other unknown chunks */
2353 png_set_read_user_chunk_fn(ping, image, read_vpag_chunk_callback);
2356 #ifdef PNG_SET_USER_LIMITS_SUPPORTED
2357 # if (PNG_LIBPNG_VER >= 10400)
2358 /* Limit the size of the chunk storage cache used for sPLT, text,
2359 * and unknown chunks.
2361 png_set_chunk_cache_max(ping, 32767);
2365 #ifdef PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED
2366 /* Disable new libpng-1.5.10 feature */
2367 png_set_check_for_invalid_index (ping, 0);
2370 #if (PNG_LIBPNG_VER < 10400)
2371 # if defined(PNG_USE_PNGGCCRD) && defined(PNG_ASSEMBLER_CODE_SUPPORTED) && \
2372 (PNG_LIBPNG_VER >= 10200) && (PNG_LIBPNG_VER < 10220) && defined(__i386__)
2373 /* Disable thread-unsafe features of pnggccrd */
2374 if (png_access_version_number() >= 10200)
2376 png_uint_32 mmx_disable_mask=0;
2377 png_uint_32 asm_flags;
2379 mmx_disable_mask |= ( PNG_ASM_FLAG_MMX_READ_COMBINE_ROW \
2380 | PNG_ASM_FLAG_MMX_READ_FILTER_SUB \
2381 | PNG_ASM_FLAG_MMX_READ_FILTER_AVG \
2382 | PNG_ASM_FLAG_MMX_READ_FILTER_PAETH );
2383 asm_flags=png_get_asm_flags(ping);
2384 png_set_asm_flags(ping, asm_flags & ~mmx_disable_mask);
2389 png_read_info(ping,ping_info);
2391 png_get_IHDR(ping,ping_info,&ping_width,&ping_height,
2392 &ping_bit_depth,&ping_color_type,
2393 &ping_interlace_method,&ping_compression_method,
2394 &ping_filter_method);
2396 ping_file_depth = ping_bit_depth;
2398 /* Save bit-depth and color-type in case we later want to write a PNG00 */
2403 (void) FormatLocaleString(msg,MaxTextExtent,"%d",(int) ping_color_type);
2404 (void) SetImageProperty(image,"png:IHDR.color-type-orig ",msg,exception);
2406 (void) FormatLocaleString(msg,MaxTextExtent,"%d",(int) ping_bit_depth);
2407 (void) SetImageProperty(image,"png:IHDR.bit-depth-orig ",msg,exception);
2410 (void) png_get_tRNS(ping, ping_info, &ping_trans_alpha, &ping_num_trans,
2413 (void) png_get_bKGD(ping, ping_info, &ping_background);
2415 if (ping_bit_depth < 8)
2417 png_set_packing(ping);
2421 image->depth=ping_bit_depth;
2422 image->depth=GetImageQuantumDepth(image,MagickFalse);
2423 image->interlace=ping_interlace_method != 0 ? PNGInterlace : NoInterlace;
2425 if (((int) ping_color_type == PNG_COLOR_TYPE_GRAY) ||
2426 ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA))
2428 image->rendering_intent=UndefinedIntent;
2429 intent=Magick_RenderingIntent_to_PNG_RenderingIntent(UndefinedIntent);
2431 (void) ResetMagickMemory(&image->chromaticity,0,
2432 sizeof(image->chromaticity));
2435 if (logging != MagickFalse)
2437 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2438 " PNG width: %.20g, height: %.20g",
2439 (double) ping_width, (double) ping_height);
2441 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2442 " PNG color_type: %d, bit_depth: %d",
2443 ping_color_type, ping_bit_depth);
2445 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2446 " PNG compression_method: %d",
2447 ping_compression_method);
2449 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2450 " PNG interlace_method: %d, filter_method: %d",
2451 ping_interlace_method,ping_filter_method);
2454 if (png_get_valid(ping,ping_info,PNG_INFO_gAMA))
2456 ping_found_gAMA=MagickTrue;
2457 if (logging != MagickFalse)
2458 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2459 " Found PNG gAMA chunk.");
2462 if (png_get_valid(ping,ping_info,PNG_INFO_cHRM))
2464 ping_found_cHRM=MagickTrue;
2465 if (logging != MagickFalse)
2466 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2467 " Found PNG cHRM chunk.");
2470 if (png_get_valid(ping,ping_info,PNG_INFO_iCCP))
2472 ping_found_iCCP=MagickTrue;
2473 if (logging != MagickFalse)
2474 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2475 " Found PNG iCCP chunk.");
2478 if (png_get_valid(ping,ping_info,PNG_INFO_sRGB))
2480 ping_found_sRGB=MagickTrue;
2481 if (logging != MagickFalse)
2482 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2483 " Found PNG sRGB chunk.");
2486 #ifdef PNG_READ_iCCP_SUPPORTED
2487 if (png_get_valid(ping,ping_info,PNG_INFO_iCCP))
2492 #if (PNG_LIBPNG_VER < 10500)
2506 (void) png_get_iCCP(ping,ping_info,&name,(int *) &compression,&info,
2509 if (profile_length != 0)
2514 if (logging != MagickFalse)
2515 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2516 " Reading PNG iCCP chunk.");
2517 profile=BlobToStringInfo(info,profile_length);
2518 if (profile == (StringInfo *) NULL)
2520 png_warning(ping, "ICC profile is NULL");
2521 profile=DestroyStringInfo(profile);
2525 (void) SetImageProfile(image,"icc",profile,exception);
2526 profile=DestroyStringInfo(profile);
2531 #if defined(PNG_READ_sRGB_SUPPORTED)
2533 if (mng_info->have_global_srgb)
2535 image->rendering_intent=Magick_RenderingIntent_from_PNG_RenderingIntent
2536 (mng_info->global_srgb_intent);
2539 if (png_get_sRGB(ping,ping_info,&intent))
2541 image->rendering_intent=Magick_RenderingIntent_from_PNG_RenderingIntent
2544 if (logging != MagickFalse)
2545 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2546 " Reading PNG sRGB chunk: rendering_intent: %d",intent);
2551 if (!png_get_gAMA(ping,ping_info,&file_gamma))
2552 if (mng_info->have_global_gama)
2553 png_set_gAMA(ping,ping_info,mng_info->global_gamma);
2555 if (png_get_gAMA(ping,ping_info,&file_gamma))
2557 image->gamma=(float) file_gamma;
2558 if (logging != MagickFalse)
2559 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2560 " Reading PNG gAMA chunk: gamma: %f",file_gamma);
2564 if (!png_get_valid(ping,ping_info,PNG_INFO_cHRM))
2566 if (mng_info->have_global_chrm != MagickFalse)
2568 (void) png_set_cHRM(ping,ping_info,
2569 mng_info->global_chrm.white_point.x,
2570 mng_info->global_chrm.white_point.y,
2571 mng_info->global_chrm.red_primary.x,
2572 mng_info->global_chrm.red_primary.y,
2573 mng_info->global_chrm.green_primary.x,
2574 mng_info->global_chrm.green_primary.y,
2575 mng_info->global_chrm.blue_primary.x,
2576 mng_info->global_chrm.blue_primary.y);
2580 if (png_get_valid(ping,ping_info,PNG_INFO_cHRM))
2582 (void) png_get_cHRM(ping,ping_info,
2583 &image->chromaticity.white_point.x,
2584 &image->chromaticity.white_point.y,
2585 &image->chromaticity.red_primary.x,
2586 &image->chromaticity.red_primary.y,
2587 &image->chromaticity.green_primary.x,
2588 &image->chromaticity.green_primary.y,
2589 &image->chromaticity.blue_primary.x,
2590 &image->chromaticity.blue_primary.y);
2592 if (image->chromaticity.red_primary.x>0.6399f &&
2593 image->chromaticity.red_primary.x<0.6401f &&
2594 image->chromaticity.red_primary.y>0.3299f &&
2595 image->chromaticity.red_primary.y<0.3301f &&
2596 image->chromaticity.green_primary.x>0.2999f &&
2597 image->chromaticity.green_primary.x<0.3001f &&
2598 image->chromaticity.green_primary.y>0.5999f &&
2599 image->chromaticity.green_primary.y<0.6001f &&
2600 image->chromaticity.blue_primary.x>0.1499f &&
2601 image->chromaticity.blue_primary.x<0.1501f &&
2602 image->chromaticity.blue_primary.y>0.0599f &&
2603 image->chromaticity.blue_primary.y<0.0601f &&
2604 image->chromaticity.white_point.x>0.3126f &&
2605 image->chromaticity.white_point.x<0.3128f &&
2606 image->chromaticity.white_point.y>0.3289f &&
2607 image->chromaticity.white_point.y<0.3291f)
2608 ping_found_sRGB_cHRM=MagickTrue;
2610 ping_found_cHRM=MagickTrue;
2613 if (image->rendering_intent != UndefinedIntent)
2615 if (ping_found_sRGB != MagickTrue &&
2616 (ping_found_gAMA != MagickTrue ||
2617 (image->gamma > .45 && image->gamma < .46)) &&
2618 (ping_found_cHRM != MagickTrue ||
2619 ping_found_sRGB_cHRM == MagickTrue) &&
2620 ping_found_iCCP != MagickTrue)
2622 png_set_sRGB(ping,ping_info,
2623 Magick_RenderingIntent_to_PNG_RenderingIntent
2624 (image->rendering_intent));
2625 if (ping_found_gAMA != MagickTrue)
2626 png_set_gAMA(ping,ping_info,1.000f/2.200f);
2627 file_gamma=1.000f/2.200f;
2628 ping_found_sRGB=MagickTrue;
2629 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2630 " Setting sRGB and gAMA as if in input");
2634 #if defined(PNG_oFFs_SUPPORTED)
2635 if (png_get_valid(ping,ping_info,PNG_INFO_oFFs))
2637 image->page.x=(ssize_t) png_get_x_offset_pixels(ping, ping_info);
2638 image->page.y=(ssize_t) png_get_y_offset_pixels(ping, ping_info);
2640 if (logging != MagickFalse)
2641 if (image->page.x || image->page.y)
2642 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2643 " Reading PNG oFFs chunk: x: %.20g, y: %.20g.",(double)
2644 image->page.x,(double) image->page.y);
2647 #if defined(PNG_pHYs_SUPPORTED)
2648 if (!png_get_valid(ping,ping_info,PNG_INFO_pHYs))
2650 if (mng_info->have_global_phys)
2652 png_set_pHYs(ping,ping_info,
2653 mng_info->global_x_pixels_per_unit,
2654 mng_info->global_y_pixels_per_unit,
2655 mng_info->global_phys_unit_type);
2659 if (png_get_valid(ping,ping_info,PNG_INFO_pHYs))
2662 Set image resolution.
2664 (void) png_get_pHYs(ping,ping_info,&x_resolution,&y_resolution,
2666 image->resolution.x=(double) x_resolution;
2667 image->resolution.y=(double) y_resolution;
2669 if (unit_type == PNG_RESOLUTION_METER)
2671 image->units=PixelsPerCentimeterResolution;
2672 image->resolution.x=(double) x_resolution/100.0;
2673 image->resolution.y=(double) y_resolution/100.0;
2676 if (logging != MagickFalse)
2677 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2678 " Reading PNG pHYs chunk: xres: %.20g, yres: %.20g, units: %d.",
2679 (double) x_resolution,(double) y_resolution,unit_type);
2683 if (png_get_valid(ping,ping_info,PNG_INFO_PLTE))
2688 (void) png_get_PLTE(ping,ping_info,&palette,&number_colors);
2690 if ((number_colors == 0) &&
2691 ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE))
2693 if (mng_info->global_plte_length)
2695 png_set_PLTE(ping,ping_info,mng_info->global_plte,
2696 (int) mng_info->global_plte_length);
2698 if (!png_get_valid(ping,ping_info,PNG_INFO_tRNS))
2700 if (mng_info->global_trns_length)
2703 "global tRNS has more entries than global PLTE");
2707 png_set_tRNS(ping,ping_info,mng_info->global_trns,
2708 (int) mng_info->global_trns_length,NULL);
2711 #ifdef PNG_READ_bKGD_SUPPORTED
2713 #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
2714 mng_info->have_saved_bkgd_index ||
2716 png_get_valid(ping,ping_info,PNG_INFO_bKGD))
2721 #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
2722 if (mng_info->have_saved_bkgd_index)
2723 background.index=mng_info->saved_bkgd_index;
2725 if (png_get_valid(ping, ping_info, PNG_INFO_bKGD))
2726 background.index=ping_background->index;
2728 background.red=(png_uint_16)
2729 mng_info->global_plte[background.index].red;
2731 background.green=(png_uint_16)
2732 mng_info->global_plte[background.index].green;
2734 background.blue=(png_uint_16)
2735 mng_info->global_plte[background.index].blue;
2737 background.gray=(png_uint_16)
2738 mng_info->global_plte[background.index].green;
2740 png_set_bKGD(ping,ping_info,&background);
2745 png_error(ping,"No global PLTE in file");
2749 #ifdef PNG_READ_bKGD_SUPPORTED
2750 if (mng_info->have_global_bkgd &&
2751 (!png_get_valid(ping,ping_info,PNG_INFO_bKGD)))
2752 image->background_color=mng_info->mng_global_bkgd;
2754 if (png_get_valid(ping,ping_info,PNG_INFO_bKGD))
2760 Set image background color.
2762 if (logging != MagickFalse)
2763 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2764 " Reading PNG bKGD chunk.");
2766 /* Scale background components to 16-bit, then scale
2769 if (logging != MagickFalse)
2770 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2771 " raw ping_background=(%d,%d,%d).",ping_background->red,
2772 ping_background->green,ping_background->blue);
2776 if (ping_file_depth == 1)
2779 else if (ping_file_depth == 2)
2782 else if (ping_file_depth == 4)
2785 if (ping_file_depth <= 8)
2788 ping_background->red *= bkgd_scale;
2789 ping_background->green *= bkgd_scale;
2790 ping_background->blue *= bkgd_scale;
2792 if (logging != MagickFalse)
2794 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2795 " bkgd_scale=%d.",bkgd_scale);
2797 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2798 " ping_background=(%d,%d,%d).",ping_background->red,
2799 ping_background->green,ping_background->blue);
2802 image->background_color.red=
2803 ScaleShortToQuantum(ping_background->red);
2805 image->background_color.green=
2806 ScaleShortToQuantum(ping_background->green);
2808 image->background_color.blue=
2809 ScaleShortToQuantum(ping_background->blue);
2811 image->background_color.alpha=OpaqueAlpha;
2813 if (logging != MagickFalse)
2814 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2815 " image->background_color=(%.20g,%.20g,%.20g).",
2816 (double) image->background_color.red,
2817 (double) image->background_color.green,
2818 (double) image->background_color.blue);
2820 #endif /* PNG_READ_bKGD_SUPPORTED */
2822 if (png_get_valid(ping,ping_info,PNG_INFO_tRNS))
2825 Image has a tRNS chunk.
2833 if (logging != MagickFalse)
2834 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2835 " Reading PNG tRNS chunk.");
2837 max_sample = (int) ((one << ping_file_depth) - 1);
2839 if ((ping_color_type == PNG_COLOR_TYPE_GRAY &&
2840 (int)ping_trans_color->gray > max_sample) ||
2841 (ping_color_type == PNG_COLOR_TYPE_RGB &&
2842 ((int)ping_trans_color->red > max_sample ||
2843 (int)ping_trans_color->green > max_sample ||
2844 (int)ping_trans_color->blue > max_sample)))
2846 if (logging != MagickFalse)
2847 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2848 " Ignoring PNG tRNS chunk with out-of-range sample.");
2849 png_free_data(ping, ping_info, PNG_FREE_TRNS, 0);
2850 png_set_invalid(ping,ping_info,PNG_INFO_tRNS);
2851 image->alpha_trait=UndefinedPixelTrait;
2858 scale_to_short = 65535L/((1UL << ping_file_depth)-1);
2860 /* Scale transparent_color to short */
2861 transparent_color.red= scale_to_short*ping_trans_color->red;
2862 transparent_color.green= scale_to_short*ping_trans_color->green;
2863 transparent_color.blue= scale_to_short*ping_trans_color->blue;
2864 transparent_color.alpha= scale_to_short*ping_trans_color->gray;
2866 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
2868 if (logging != MagickFalse)
2870 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2871 " Raw tRNS graylevel is %d.",ping_trans_color->gray);
2873 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2874 " scaled graylevel is %.20g.",transparent_color.alpha);
2876 transparent_color.red=transparent_color.alpha;
2877 transparent_color.green=transparent_color.alpha;
2878 transparent_color.blue=transparent_color.alpha;
2882 #if defined(PNG_READ_sBIT_SUPPORTED)
2883 if (mng_info->have_global_sbit)
2885 if (!png_get_valid(ping,ping_info,PNG_INFO_sBIT))
2886 png_set_sBIT(ping,ping_info,&mng_info->global_sbit);
2889 num_passes=png_set_interlace_handling(ping);
2891 png_read_update_info(ping,ping_info);
2893 ping_rowbytes=png_get_rowbytes(ping,ping_info);
2896 Initialize image structure.
2898 mng_info->image_box.left=0;
2899 mng_info->image_box.right=(ssize_t) ping_width;
2900 mng_info->image_box.top=0;
2901 mng_info->image_box.bottom=(ssize_t) ping_height;
2902 if (mng_info->mng_type == 0)
2904 mng_info->mng_width=ping_width;
2905 mng_info->mng_height=ping_height;
2906 mng_info->frame=mng_info->image_box;
2907 mng_info->clip=mng_info->image_box;
2912 image->page.y=mng_info->y_off[mng_info->object_id];
2915 image->compression=ZipCompression;
2916 image->columns=ping_width;
2917 image->rows=ping_height;
2919 if (((int) ping_color_type == PNG_COLOR_TYPE_GRAY) ||
2920 ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA))
2922 if ((!png_get_valid(ping,ping_info,PNG_INFO_gAMA) ||
2923 image->gamma == 1.0) && ping_found_sRGB != MagickTrue)
2925 /* Set image->gamma to 1.0, image->rendering_intent to Undefined,
2926 * image->colorspace to GRAY, and reset image->chromaticity.
2928 SetImageColorspace(image,GRAYColorspace,exception);
2932 (void)LogMagickEvent(CoderEvent,GetMagickModule(),
2933 " image->colorspace=%d",(int) image->colorspace);
2935 if (((int) ping_color_type == PNG_COLOR_TYPE_PALETTE) ||
2936 ((int) ping_bit_depth < 16 &&
2937 (int) ping_color_type == PNG_COLOR_TYPE_GRAY))
2942 image->storage_class=PseudoClass;
2944 image->colors=one << ping_file_depth;
2945 #if (MAGICKCORE_QUANTUM_DEPTH == 8)
2946 if (image->colors > 256)
2949 if (image->colors > 65536L)
2950 image->colors=65536L;
2952 if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
2957 (void) png_get_PLTE(ping,ping_info,&palette,&number_colors);
2958 image->colors=(size_t) number_colors;
2960 if (logging != MagickFalse)
2961 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2962 " Reading PNG PLTE chunk: number_colors: %d.",number_colors);
2966 if (image->storage_class == PseudoClass)
2969 Initialize image colormap.
2971 if (AcquireImageColormap(image,image->colors,exception) == MagickFalse)
2972 png_error(ping,"Memory allocation failed");
2974 if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
2979 (void) png_get_PLTE(ping,ping_info,&palette,&number_colors);
2981 for (i=0; i < (ssize_t) number_colors; i++)
2983 image->colormap[i].red=ScaleCharToQuantum(palette[i].red);
2984 image->colormap[i].green=ScaleCharToQuantum(palette[i].green);
2985 image->colormap[i].blue=ScaleCharToQuantum(palette[i].blue);
2988 for ( ; i < (ssize_t) image->colors; i++)
2990 image->colormap[i].red=0;
2991 image->colormap[i].green=0;
2992 image->colormap[i].blue=0;
3001 scale=(QuantumRange/((1UL << ping_file_depth)-1));
3006 for (i=0; i < (ssize_t) image->colors; i++)
3008 image->colormap[i].red=(Quantum) (i*scale);
3009 image->colormap[i].green=(Quantum) (i*scale);
3010 image->colormap[i].blue=(Quantum) (i*scale);
3015 /* Set some properties for reporting by "identify" */
3020 /* encode ping_width, ping_height, ping_file_depth, ping_color_type,
3021 ping_interlace_method in value */
3023 (void) FormatLocaleString(msg,MaxTextExtent,
3024 "%d, %d",(int) ping_width, (int) ping_height);
3025 (void) SetImageProperty(image,"png:IHDR.width,height ",msg,exception);
3027 (void) FormatLocaleString(msg,MaxTextExtent,"%d",(int) ping_file_depth);
3028 (void) SetImageProperty(image,"png:IHDR.bit_depth ",msg,exception);
3030 (void) FormatLocaleString(msg,MaxTextExtent,"%d (%s)",
3031 (int) ping_color_type,
3032 Magick_ColorType_from_PNG_ColorType((int)ping_color_type));
3033 (void) SetImageProperty(image,"png:IHDR.color_type ",msg,exception);
3035 if (ping_interlace_method == 0)
3037 (void) FormatLocaleString(msg,MaxTextExtent,"%d (Not interlaced)",
3038 (int) ping_interlace_method);
3040 else if (ping_interlace_method == 1)
3042 (void) FormatLocaleString(msg,MaxTextExtent,"%d (Adam7 method)",
3043 (int) ping_interlace_method);
3047 (void) FormatLocaleString(msg,MaxTextExtent,"%d (Unknown method)",
3048 (int) ping_interlace_method);
3050 (void) SetImageProperty(image,"png:IHDR.interlace_method",msg,exception);
3052 if (number_colors != 0)
3054 (void) FormatLocaleString(msg,MaxTextExtent,"%d",
3055 (int) number_colors);
3056 (void) SetImageProperty(image,"png:PLTE.number_colors ",msg,
3062 Read image scanlines.
3064 if (image->delay != 0)
3065 mng_info->scenes_found++;
3067 if ((mng_info->mng_type == 0 && (image->ping != MagickFalse)) || (
3068 (image_info->number_scenes != 0) && (mng_info->scenes_found > (ssize_t)
3069 (image_info->first_scene+image_info->number_scenes))))
3071 /* This happens later in non-ping decodes */
3072 if (png_get_valid(ping,ping_info,PNG_INFO_tRNS))
3073 image->storage_class=DirectClass;
3075 if (logging != MagickFalse)
3076 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3077 " Skipping PNG image data for scene %.20g",(double)
3078 mng_info->scenes_found-1);
3079 png_destroy_read_struct(&ping,&ping_info,&end_info);
3081 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
3082 UnlockSemaphoreInfo(ping_semaphore);
3085 if (logging != MagickFalse)
3086 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3087 " exit ReadOnePNGImage().");
3092 if (logging != MagickFalse)
3093 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3094 " Reading PNG IDAT chunk(s)");
3097 ping_pixels=(unsigned char *) AcquireQuantumMemory(image->rows,
3098 ping_rowbytes*sizeof(*ping_pixels));
3101 ping_pixels=(unsigned char *) AcquireQuantumMemory(ping_rowbytes,
3102 sizeof(*ping_pixels));
3104 if (ping_pixels == (unsigned char *) NULL)
3105 png_error(ping,"Memory allocation failed");
3107 if (logging != MagickFalse)
3108 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3109 " Converting PNG pixels to pixel packets");
3111 Convert PNG pixels to pixel packets.
3113 quantum_info=AcquireQuantumInfo(image_info,image);
3115 if (quantum_info == (QuantumInfo *) NULL)
3116 png_error(ping,"Failed to allocate quantum_info");
3118 (void) SetQuantumEndian(image,quantum_info,MSBEndian);
3123 found_transparent_pixel;
3125 found_transparent_pixel=MagickFalse;
3127 if (image->storage_class == DirectClass)
3129 for (pass=0; pass < num_passes; pass++)
3132 Convert image to DirectClass pixel packets.
3134 image->alpha_trait=(((int) ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA) ||
3135 ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) ||
3136 (png_get_valid(ping,ping_info,PNG_INFO_tRNS))) ?
3137 BlendPixelTrait : UndefinedPixelTrait;
3139 for (y=0; y < (ssize_t) image->rows; y++)
3142 row_offset=ping_rowbytes*y;
3147 png_read_row(ping,ping_pixels+row_offset,NULL);
3149 if (pass < num_passes-1)
3152 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
3154 if (q == (Quantum *) NULL)
3157 if ((int) ping_color_type == PNG_COLOR_TYPE_GRAY)
3158 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
3159 GrayQuantum,ping_pixels+row_offset,exception);
3161 else if ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
3162 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
3163 GrayAlphaQuantum,ping_pixels+row_offset,exception);
3165 else if ((int) ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA)
3166 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
3167 RGBAQuantum,ping_pixels+row_offset,exception);
3169 else if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
3170 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
3171 IndexQuantum,ping_pixels+row_offset,exception);
3173 else /* ping_color_type == PNG_COLOR_TYPE_RGB */
3174 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
3175 RGBQuantum,ping_pixels+row_offset,exception);
3177 if (found_transparent_pixel == MagickFalse)
3179 /* Is there a transparent pixel in the row? */
3180 if (y== 0 && logging != MagickFalse)
3181 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3182 " Looking for cheap transparent pixel");
3184 for (x=(ssize_t) image->columns-1; x >= 0; x--)
3186 if ((ping_color_type == PNG_COLOR_TYPE_RGBA ||
3187 ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) &&
3188 (GetPixelAlpha(image,q) != OpaqueAlpha))
3190 if (logging != MagickFalse)
3191 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3194 found_transparent_pixel = MagickTrue;
3197 if ((ping_color_type == PNG_COLOR_TYPE_RGB ||
3198 ping_color_type == PNG_COLOR_TYPE_GRAY) &&
3199 (ScaleQuantumToShort(GetPixelRed(image,q)) ==
3200 transparent_color.red &&
3201 ScaleQuantumToShort(GetPixelGreen(image,q)) ==
3202 transparent_color.green &&
3203 ScaleQuantumToShort(GetPixelBlue(image,q)) ==
3204 transparent_color.blue))
3206 if (logging != MagickFalse)
3207 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3209 found_transparent_pixel = MagickTrue;
3212 q+=GetPixelChannels(image);
3216 if ((image->previous == (Image *) NULL) && (num_passes == 1))
3218 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
3221 if (status == MagickFalse)
3224 if (SyncAuthenticPixels(image,exception) == MagickFalse)
3228 if ((image->previous == (Image *) NULL) && (num_passes != 1))
3230 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
3231 if (status == MagickFalse)
3237 else /* image->storage_class != DirectClass */
3239 for (pass=0; pass < num_passes; pass++)
3248 Convert grayscale image to PseudoClass pixel packets.
3250 if (logging != MagickFalse)
3251 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3252 " Converting grayscale pixels to pixel packets");
3254 image->alpha_trait=ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA ?
3255 BlendPixelTrait : UndefinedPixelTrait;
3257 quantum_scanline=(Quantum *) AcquireQuantumMemory(image->columns,
3258 (image->alpha_trait == BlendPixelTrait? 2 : 1)*
3259 sizeof(*quantum_scanline));
3261 if (quantum_scanline == (Quantum *) NULL)
3262 png_error(ping,"Memory allocation failed");
3264 for (y=0; y < (ssize_t) image->rows; y++)
3270 row_offset=ping_rowbytes*y;
3275 png_read_row(ping,ping_pixels+row_offset,NULL);
3277 if (pass < num_passes-1)
3280 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
3282 if (q == (Quantum *) NULL)
3285 p=ping_pixels+row_offset;
3288 switch (ping_bit_depth)
3293 if (ping_color_type == 4)
3294 for (x=(ssize_t) image->columns-1; x >= 0; x--)
3298 alpha=ScaleCharToQuantum((unsigned char)*p++);
3300 SetPixelAlpha(image,alpha,q);
3302 if (alpha != OpaqueAlpha)
3303 found_transparent_pixel = MagickTrue;
3305 q+=GetPixelChannels(image);
3309 for (x=(ssize_t) image->columns-1; x >= 0; x--)
3317 for (x=(ssize_t) image->columns-1; x >= 0; x--)
3319 #if (MAGICKCORE_QUANTUM_DEPTH == 16) || (MAGICKCORE_QUANTUM_DEPTH == 32)
3323 if (image->colors > 256)
3324 quantum=((*p++) << 8);
3330 *r=ScaleShortToQuantum(quantum);
3333 if (ping_color_type == 4)
3335 if (image->colors > 256)
3336 quantum=((*p++) << 8);
3342 alpha=ScaleShortToQuantum(quantum);
3343 SetPixelAlpha(image,alpha,q);
3345 if (alpha != OpaqueAlpha)
3346 found_transparent_pixel = MagickTrue;
3348 q+=GetPixelChannels(image);
3351 #else /* MAGICKCORE_QUANTUM_DEPTH == 8 */
3353 p++; /* strip low byte */
3355 if (ping_color_type == 4)
3357 SetPixelAlpha(image,*p++,q);
3359 if (GetPixelAlpha(image,q) != OpaqueAlpha)
3360 found_transparent_pixel = MagickTrue;
3363 q+=GetPixelChannels(image);
3376 Transfer image scanline.
3380 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
3382 if (q == (Quantum *) NULL)
3384 for (x=0; x < (ssize_t) image->columns; x++)
3386 SetPixelIndex(image,*r++,q);
3387 q+=GetPixelChannels(image);
3390 if (SyncAuthenticPixels(image,exception) == MagickFalse)
3393 if ((image->previous == (Image *) NULL) && (num_passes == 1))
3395 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
3398 if (status == MagickFalse)
3403 if ((image->previous == (Image *) NULL) && (num_passes != 1))
3405 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
3407 if (status == MagickFalse)
3411 quantum_scanline=(Quantum *) RelinquishMagickMemory(quantum_scanline);
3414 image->alpha_trait=found_transparent_pixel ? BlendPixelTrait :
3415 UndefinedPixelTrait;
3417 if (logging != MagickFalse)
3419 if (found_transparent_pixel != MagickFalse)
3420 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3421 " Found transparent pixel");
3424 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3425 " No transparent pixel was found");
3427 ping_color_type&=0x03;
3432 if (quantum_info != (QuantumInfo *) NULL)
3433 quantum_info=DestroyQuantumInfo(quantum_info);
3435 if (image->storage_class == PseudoClass)
3440 alpha_trait=image->alpha_trait;
3441 image->alpha_trait=UndefinedPixelTrait;
3442 (void) SyncImage(image,exception);
3443 image->alpha_trait=alpha_trait;
3446 png_read_end(ping,end_info);
3448 if (image_info->number_scenes != 0 && mng_info->scenes_found-1 <
3449 (ssize_t) image_info->first_scene && image->delay != 0)
3451 png_destroy_read_struct(&ping,&ping_info,&end_info);
3452 ping_pixels=(unsigned char *) RelinquishMagickMemory(ping_pixels);
3454 (void) SetImageBackgroundColor(image,exception);
3455 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
3456 UnlockSemaphoreInfo(ping_semaphore);
3458 if (logging != MagickFalse)
3459 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3460 " exit ReadOnePNGImage() early.");
3464 if (png_get_valid(ping,ping_info,PNG_INFO_tRNS))
3470 Image has a transparent background.
3472 storage_class=image->storage_class;
3473 image->alpha_trait=BlendPixelTrait;
3475 /* Balfour fix from imagemagick discourse server, 5 Feb 2010 */
3477 if (storage_class == PseudoClass)
3479 if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
3481 for (x=0; x < ping_num_trans; x++)
3483 image->colormap[x].alpha_trait=BlendPixelTrait;
3484 image->colormap[x].alpha =
3485 ScaleCharToQuantum((unsigned char)ping_trans_alpha[x]);
3489 else if (ping_color_type == PNG_COLOR_TYPE_GRAY)
3491 for (x=0; x < (int) image->colors; x++)
3493 if (ScaleQuantumToShort(image->colormap[x].red) ==
3494 transparent_color.alpha)
3496 image->colormap[x].alpha_trait=BlendPixelTrait;
3497 image->colormap[x].alpha = (Quantum) TransparentAlpha;
3501 (void) SyncImage(image,exception);
3504 #if 1 /* Should have already been done above, but glennrp problem P10
3509 for (y=0; y < (ssize_t) image->rows; y++)
3511 image->storage_class=storage_class;
3512 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
3514 if (q == (Quantum *) NULL)
3518 /* Caution: on a Q8 build, this does not distinguish between
3519 * 16-bit colors that differ only in the low byte
3521 for (x=(ssize_t) image->columns-1; x >= 0; x--)
3523 if (ScaleQuantumToShort(GetPixelRed(image,q)) ==
3524 transparent_color.red &&
3525 ScaleQuantumToShort(GetPixelGreen(image,q)) ==
3526 transparent_color.green &&
3527 ScaleQuantumToShort(GetPixelBlue(image,q)) ==
3528 transparent_color.blue)
3530 SetPixelAlpha(image,TransparentAlpha,q);
3533 #if 0 /* I have not found a case where this is needed. */
3536 SetPixelAlpha(image,q)=(Quantum) OpaqueAlpha;
3540 q+=GetPixelChannels(image);
3543 if (SyncAuthenticPixels(image,exception) == MagickFalse)
3549 image->storage_class=DirectClass;
3552 for (j = 0; j < 2; j++)
3555 status = png_get_text(ping,ping_info,&text,&num_text) != 0 ?
3556 MagickTrue : MagickFalse;
3558 status = png_get_text(ping,end_info,&text,&num_text) != 0 ?
3559 MagickTrue : MagickFalse;
3561 if (status != MagickFalse)
3562 for (i=0; i < (ssize_t) num_text; i++)
3564 /* Check for a profile */
3566 if (logging != MagickFalse)
3567 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3568 " Reading PNG text chunk");
3570 if (memcmp(text[i].key, "Raw profile type ",17) == 0)
3572 (void) Magick_png_read_raw_profile(ping,image,image_info,text,
3582 length=text[i].text_length;
3583 value=(char *) AcquireQuantumMemory(length+MaxTextExtent,
3585 if (value == (char *) NULL)
3587 png_error(ping,"Memory allocation failed");
3591 (void) ConcatenateMagickString(value,text[i].text,length+2);
3593 /* Don't save "density" or "units" property if we have a pHYs
3596 if (!png_get_valid(ping,ping_info,PNG_INFO_pHYs) ||
3597 (LocaleCompare(text[i].key,"density") != 0 &&
3598 LocaleCompare(text[i].key,"units") != 0))
3599 (void) SetImageProperty(image,text[i].key,value,exception);
3601 if (logging != MagickFalse)
3603 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3604 " length: %lu",(unsigned long) length);
3605 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3606 " Keyword: %s",text[i].key);
3609 value=DestroyString(value);
3612 num_text_total += num_text;
3615 #ifdef MNG_OBJECT_BUFFERS
3617 Store the object if necessary.
3619 if (object_id && !mng_info->frozen[object_id])
3621 if (mng_info->ob[object_id] == (MngBuffer *) NULL)
3624 create a new object buffer.
3626 mng_info->ob[object_id]=(MngBuffer *)
3627 AcquireMagickMemory(sizeof(MngBuffer));
3629 if (mng_info->ob[object_id] != (MngBuffer *) NULL)
3631 mng_info->ob[object_id]->image=(Image *) NULL;
3632 mng_info->ob[object_id]->reference_count=1;
3636 if ((mng_info->ob[object_id] == (MngBuffer *) NULL) ||
3637 mng_info->ob[object_id]->frozen)
3639 if (mng_info->ob[object_id] == (MngBuffer *) NULL)
3640 png_error(ping,"Memory allocation failed");
3642 if (mng_info->ob[object_id]->frozen)
3643 png_error(ping,"Cannot overwrite frozen MNG object buffer");
3649 if (mng_info->ob[object_id]->image != (Image *) NULL)
3650 mng_info->ob[object_id]->image=DestroyImage
3651 (mng_info->ob[object_id]->image);
3653 mng_info->ob[object_id]->image=CloneImage(image,0,0,MagickTrue,
3656 if (mng_info->ob[object_id]->image != (Image *) NULL)
3657 mng_info->ob[object_id]->image->file=(FILE *) NULL;
3660 png_error(ping, "Cloning image for object buffer failed");
3662 if (ping_width > 250000L || ping_height > 250000L)
3663 png_error(ping,"PNG Image dimensions are too large.");
3665 mng_info->ob[object_id]->width=ping_width;
3666 mng_info->ob[object_id]->height=ping_height;
3667 mng_info->ob[object_id]->color_type=ping_color_type;
3668 mng_info->ob[object_id]->sample_depth=ping_bit_depth;
3669 mng_info->ob[object_id]->interlace_method=ping_interlace_method;
3670 mng_info->ob[object_id]->compression_method=
3671 ping_compression_method;
3672 mng_info->ob[object_id]->filter_method=ping_filter_method;
3674 if (png_get_valid(ping,ping_info,PNG_INFO_PLTE))
3680 Copy the PLTE to the object buffer.
3682 png_get_PLTE(ping,ping_info,&plte,&number_colors);
3683 mng_info->ob[object_id]->plte_length=number_colors;
3685 for (i=0; i < number_colors; i++)
3687 mng_info->ob[object_id]->plte[i]=plte[i];
3692 mng_info->ob[object_id]->plte_length=0;
3697 /* Set image->alpha_trait to MagickTrue if the input colortype supports
3698 * alpha or if a valid tRNS chunk is present, no matter whether there
3699 * is actual transparency present.
3701 image->alpha_trait=(((int) ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA) ||
3702 ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) ||
3703 (png_get_valid(ping,ping_info,PNG_INFO_tRNS))) ?
3704 BlendPixelTrait : UndefinedPixelTrait;
3706 #if 0 /* I'm not sure what's wrong here but it does not work. */
3707 if (image->alpha_trait == BlendPixelTrait)
3709 if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
3710 (void) SetImageType(image,GrayscaleMatteType,exception);
3712 else if (ping_color_type == PNG_COLOR_TYPE_PALETTE)
3713 (void) SetImageType(image,PaletteMatteType,exception);
3716 (void) SetImageType(image,TrueColorMatteType,exception);
3721 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
3722 (void) SetImageType(image,GrayscaleType,exception);
3724 else if (ping_color_type == PNG_COLOR_TYPE_PALETTE)
3725 (void) SetImageType(image,PaletteType,exception);
3728 (void) SetImageType(image,TrueColorType,exception);
3732 /* Set more properties for identify to retrieve */
3737 if (num_text_total != 0)
3739 /* libpng doesn't tell us whether they were tEXt, zTXt, or iTXt */
3740 (void) FormatLocaleString(msg,MaxTextExtent,
3741 "%d tEXt/zTXt/iTXt chunks were found", num_text_total);
3742 (void) SetImageProperty(image,"png:text ",msg,
3746 if (num_raw_profiles != 0)
3748 (void) FormatLocaleString(msg,MaxTextExtent,
3749 "%d were found", num_raw_profiles);
3750 (void) SetImageProperty(image,"png:text-encoded profiles",msg,
3754 if (ping_found_cHRM != MagickFalse)
3756 (void) FormatLocaleString(msg,MaxTextExtent,"%s",
3757 "chunk was found (see Chromaticity, above)");
3758 (void) SetImageProperty(image,"png:cHRM ",msg,
3762 if (png_get_valid(ping,ping_info,PNG_INFO_bKGD))
3764 (void) FormatLocaleString(msg,MaxTextExtent,"%s",
3765 "chunk was found (see Background color, above)");
3766 (void) SetImageProperty(image,"png:bKGD ",msg,
3770 (void) FormatLocaleString(msg,MaxTextExtent,"%s",
3773 #if defined(PNG_iCCP_SUPPORTED)
3774 if (ping_found_iCCP != MagickFalse)
3775 (void) SetImageProperty(image,"png:iCCP ",msg,
3779 if (png_get_valid(ping,ping_info,PNG_INFO_tRNS))
3780 (void) SetImageProperty(image,"png:tRNS ",msg,
3783 #if defined(PNG_sRGB_SUPPORTED)
3784 if (ping_found_sRGB != MagickFalse)
3786 (void) FormatLocaleString(msg,MaxTextExtent,
3789 Magick_RenderingIntentString_from_PNG_RenderingIntent(intent));
3790 (void) SetImageProperty(image,"png:sRGB ",msg,
3795 if (ping_found_gAMA != MagickFalse)
3797 (void) FormatLocaleString(msg,MaxTextExtent,
3798 "gamma=%.8g (See Gamma, above)",
3800 (void) SetImageProperty(image,"png:gAMA ",msg,
3804 #if defined(PNG_pHYs_SUPPORTED)
3805 if (png_get_valid(ping,ping_info,PNG_INFO_pHYs))
3807 (void) FormatLocaleString(msg,MaxTextExtent,
3808 "x_res=%.10g, y_res=%.10g, units=%d",
3809 (double) x_resolution,(double) y_resolution, unit_type);
3810 (void) SetImageProperty(image,"png:pHYs ",msg,
3815 #if defined(PNG_oFFs_SUPPORTED)
3816 if (png_get_valid(ping,ping_info,PNG_INFO_oFFs))
3818 (void) FormatLocaleString(msg,MaxTextExtent,"x_off=%.20g, y_off=%.20g",
3819 (double) image->page.x,(double) image->page.y);
3820 (void) SetImageProperty(image,"png:oFFs ",msg,
3825 if ((image->page.width != 0 && image->page.width != image->columns) ||
3826 (image->page.height != 0 && image->page.height != image->rows))
3828 (void) FormatLocaleString(msg,MaxTextExtent,
3829 "width=%.20g, height=%.20g",
3830 (double) image->page.width,(double) image->page.height);
3831 (void) SetImageProperty(image,"png:vpAg ",msg,
3837 Relinquish resources.
3839 png_destroy_read_struct(&ping,&ping_info,&end_info);
3841 ping_pixels=(unsigned char *) RelinquishMagickMemory(ping_pixels);
3843 if (logging != MagickFalse)
3844 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3845 " exit ReadOnePNGImage()");
3847 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
3848 UnlockSemaphoreInfo(ping_semaphore);
3851 /* } for navigation to beginning of SETJMP-protected block, revert to
3852 * Throwing an Exception when an error occurs.
3857 /* end of reading one PNG image */
3860 static Image *ReadPNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
3875 magic_number[MaxTextExtent];
3883 assert(image_info != (const ImageInfo *) NULL);
3884 assert(image_info->signature == MagickSignature);
3886 if (image_info->debug != MagickFalse)
3887 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
3888 image_info->filename);
3890 assert(exception != (ExceptionInfo *) NULL);
3891 assert(exception->signature == MagickSignature);
3892 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter ReadPNGImage()");
3893 image=AcquireImage(image_info,exception);
3894 mng_info=(MngInfo *) NULL;
3895 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
3897 if (status == MagickFalse)
3898 ThrowReaderException(FileOpenError,"UnableToOpenFile");
3901 Verify PNG signature.
3903 count=ReadBlob(image,8,(unsigned char *) magic_number);
3905 if (count < 8 || memcmp(magic_number,"\211PNG\r\n\032\n",8) != 0)
3906 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
3909 Allocate a MngInfo structure.
3911 have_mng_structure=MagickFalse;
3912 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
3914 if (mng_info == (MngInfo *) NULL)
3915 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
3918 Initialize members of the MngInfo structure.
3920 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
3921 mng_info->image=image;
3922 have_mng_structure=MagickTrue;
3925 image=ReadOnePNGImage(mng_info,image_info,exception);
3926 MngInfoFreeStruct(mng_info,&have_mng_structure);
3928 if (image == (Image *) NULL)
3930 if (previous != (Image *) NULL)
3932 if (previous->signature != MagickSignature)
3933 ThrowReaderException(CorruptImageError,"CorruptImage");
3935 (void) CloseBlob(previous);
3936 (void) DestroyImageList(previous);
3939 if (logging != MagickFalse)
3940 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3941 "exit ReadPNGImage() with error");
3943 return((Image *) NULL);
3946 (void) CloseBlob(image);
3948 if ((image->columns == 0) || (image->rows == 0))
3950 if (logging != MagickFalse)
3951 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3952 "exit ReadPNGImage() with error.");
3954 ThrowReaderException(CorruptImageError,"CorruptImage");
3957 if ((IssRGBColorspace(image->colorspace) != MagickFalse) &&
3958 ((image->gamma < .45) || (image->gamma > .46)) &&
3959 !(image->chromaticity.red_primary.x>0.6399f &&
3960 image->chromaticity.red_primary.x<0.6401f &&
3961 image->chromaticity.red_primary.y>0.3299f &&
3962 image->chromaticity.red_primary.y<0.3301f &&
3963 image->chromaticity.green_primary.x>0.2999f &&
3964 image->chromaticity.green_primary.x<0.3001f &&
3965 image->chromaticity.green_primary.y>0.5999f &&
3966 image->chromaticity.green_primary.y<0.6001f &&
3967 image->chromaticity.blue_primary.x>0.1499f &&
3968 image->chromaticity.blue_primary.x<0.1501f &&
3969 image->chromaticity.blue_primary.y>0.0599f &&
3970 image->chromaticity.blue_primary.y<0.0601f &&
3971 image->chromaticity.white_point.x>0.3126f &&
3972 image->chromaticity.white_point.x<0.3128f &&
3973 image->chromaticity.white_point.y>0.3289f &&
3974 image->chromaticity.white_point.y<0.3291f))
3975 SetImageColorspace(image,RGBColorspace,exception);
3977 if (logging != MagickFalse)
3978 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3979 " page.w: %.20g, page.h: %.20g,page.x: %.20g, page.y: %.20g.",
3980 (double) image->page.width,(double) image->page.height,
3981 (double) image->page.x,(double) image->page.y);
3983 if (logging != MagickFalse)
3984 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit ReadPNGImage()");
3991 #if defined(JNG_SUPPORTED)
3993 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3997 % R e a d O n e J N G I m a g e %
4001 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4003 % ReadOneJNGImage() reads a JPEG Network Graphics (JNG) image file
4004 % (minus the 8-byte signature) and returns it. It allocates the memory
4005 % necessary for the new Image structure and returns a pointer to the new
4008 % JNG support written by Glenn Randers-Pehrson, glennrp@image...
4010 % The format of the ReadOneJNGImage method is:
4012 % Image *ReadOneJNGImage(MngInfo *mng_info, const ImageInfo *image_info,
4013 % ExceptionInfo *exception)
4015 % A description of each parameter follows:
4017 % o mng_info: Specifies a pointer to a MngInfo structure.
4019 % o image_info: the image info.
4021 % o exception: return any errors or warnings in this structure.
4024 static Image *ReadOneJNGImage(MngInfo *mng_info,
4025 const ImageInfo *image_info, ExceptionInfo *exception)
4052 jng_image_sample_depth,
4053 jng_image_compression_method,
4054 jng_image_interlace_method,
4055 jng_alpha_sample_depth,
4056 jng_alpha_compression_method,
4057 jng_alpha_filter_method,
4058 jng_alpha_interlace_method;
4060 register const Quantum
4070 register unsigned char
4081 jng_alpha_compression_method=0;
4082 jng_alpha_sample_depth=8;
4086 alpha_image=(Image *) NULL;
4087 color_image=(Image *) NULL;
4088 alpha_image_info=(ImageInfo *) NULL;
4089 color_image_info=(ImageInfo *) NULL;
4091 logging=LogMagickEvent(CoderEvent,GetMagickModule(),
4092 " Enter ReadOneJNGImage()");
4094 image=mng_info->image;
4096 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
4099 Allocate next image structure.
4101 if (logging != MagickFalse)
4102 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4103 " AcquireNextImage()");
4105 AcquireNextImage(image_info,image,exception);
4107 if (GetNextImageInList(image) == (Image *) NULL)
4108 return((Image *) NULL);
4110 image=SyncNextImageInList(image);
4112 mng_info->image=image;
4115 Signature bytes have already been read.
4118 read_JSEP=MagickFalse;
4119 reading_idat=MagickFalse;
4120 skip_to_iend=MagickFalse;
4124 type[MaxTextExtent];
4133 Read a new JNG chunk.
4135 status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
4136 2*GetBlobSize(image));
4138 if (status == MagickFalse)
4142 (void) ConcatenateMagickString(type,"errr",MaxTextExtent);
4143 length=ReadBlobMSBLong(image);
4144 count=(unsigned int) ReadBlob(image,4,(unsigned char *) type);
4146 if (logging != MagickFalse)
4147 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4148 " Reading JNG chunk type %c%c%c%c, length: %.20g",
4149 type[0],type[1],type[2],type[3],(double) length);
4151 if (length > PNG_UINT_31_MAX || count == 0)
4152 ThrowReaderException(CorruptImageError,"CorruptImage");
4155 chunk=(unsigned char *) NULL;
4159 chunk=(unsigned char *) AcquireQuantumMemory(length,sizeof(*chunk));
4161 if (chunk == (unsigned char *) NULL)
4162 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
4164 for (i=0; i < (ssize_t) length; i++)
4165 chunk[i]=(unsigned char) ReadBlobByte(image);
4170 (void) ReadBlobMSBLong(image); /* read crc word */
4175 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4180 if (memcmp(type,mng_JHDR,4) == 0)
4184 jng_width=(size_t) ((p[0] << 24) | (p[1] << 16) |
4185 (p[2] << 8) | p[3]);
4186 jng_height=(size_t) ((p[4] << 24) | (p[5] << 16) |
4187 (p[6] << 8) | p[7]);
4188 jng_color_type=p[8];
4189 jng_image_sample_depth=p[9];
4190 jng_image_compression_method=p[10];
4191 jng_image_interlace_method=p[11];
4193 image->interlace=jng_image_interlace_method != 0 ? PNGInterlace :
4196 jng_alpha_sample_depth=p[12];
4197 jng_alpha_compression_method=p[13];
4198 jng_alpha_filter_method=p[14];
4199 jng_alpha_interlace_method=p[15];
4201 if (logging != MagickFalse)
4203 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4204 " jng_width: %16lu",(unsigned long) jng_width);
4206 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4207 " jng_width: %16lu",(unsigned long) jng_height);
4209 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4210 " jng_color_type: %16d",jng_color_type);
4212 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4213 " jng_image_sample_depth: %3d",
4214 jng_image_sample_depth);
4216 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4217 " jng_image_compression_method:%3d",
4218 jng_image_compression_method);
4220 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4221 " jng_image_interlace_method: %3d",
4222 jng_image_interlace_method);
4224 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4225 " jng_alpha_sample_depth: %3d",
4226 jng_alpha_sample_depth);
4228 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4229 " jng_alpha_compression_method:%3d",
4230 jng_alpha_compression_method);
4232 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4233 " jng_alpha_filter_method: %3d",
4234 jng_alpha_filter_method);
4236 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4237 " jng_alpha_interlace_method: %3d",
4238 jng_alpha_interlace_method);
4243 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4249 if ((reading_idat == MagickFalse) && (read_JSEP == MagickFalse) &&
4250 ((memcmp(type,mng_JDAT,4) == 0) || (memcmp(type,mng_JdAA,4) == 0) ||
4251 (memcmp(type,mng_IDAT,4) == 0) || (memcmp(type,mng_JDAA,4) == 0)))
4254 o create color_image
4255 o open color_blob, attached to color_image
4256 o if (color type has alpha)
4257 open alpha_blob, attached to alpha_image
4260 color_image_info=(ImageInfo *)AcquireMagickMemory(sizeof(ImageInfo));
4262 if (color_image_info == (ImageInfo *) NULL)
4263 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
4265 GetImageInfo(color_image_info);
4266 color_image=AcquireImage(color_image_info,exception);
4268 if (color_image == (Image *) NULL)
4269 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
4271 if (logging != MagickFalse)
4272 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4273 " Creating color_blob.");
4275 (void) AcquireUniqueFilename(color_image->filename);
4276 status=OpenBlob(color_image_info,color_image,WriteBinaryBlobMode,
4279 if (status == MagickFalse)
4280 return((Image *) NULL);
4282 if ((image_info->ping == MagickFalse) && (jng_color_type >= 12))
4284 alpha_image_info=(ImageInfo *)
4285 AcquireMagickMemory(sizeof(ImageInfo));
4287 if (alpha_image_info == (ImageInfo *) NULL)
4288 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
4290 GetImageInfo(alpha_image_info);
4291 alpha_image=AcquireImage(alpha_image_info,exception);
4293 if (alpha_image == (Image *) NULL)
4295 alpha_image=DestroyImage(alpha_image);
4296 ThrowReaderException(ResourceLimitError,
4297 "MemoryAllocationFailed");
4300 if (logging != MagickFalse)
4301 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4302 " Creating alpha_blob.");
4304 (void) AcquireUniqueFilename(alpha_image->filename);
4305 status=OpenBlob(alpha_image_info,alpha_image,WriteBinaryBlobMode,
4308 if (status == MagickFalse)
4309 return((Image *) NULL);
4311 if (jng_alpha_compression_method == 0)
4316 if (logging != MagickFalse)
4317 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4318 " Writing IHDR chunk to alpha_blob.");
4320 (void) WriteBlob(alpha_image,8,(const unsigned char *)
4321 "\211PNG\r\n\032\n");
4323 (void) WriteBlobMSBULong(alpha_image,13L);
4324 PNGType(data,mng_IHDR);
4325 LogPNGChunk(logging,mng_IHDR,13L);
4326 PNGLong(data+4,jng_width);
4327 PNGLong(data+8,jng_height);
4328 data[12]=jng_alpha_sample_depth;
4329 data[13]=0; /* color_type gray */
4330 data[14]=0; /* compression method 0 */
4331 data[15]=0; /* filter_method 0 */
4332 data[16]=0; /* interlace_method 0 */
4333 (void) WriteBlob(alpha_image,17,data);
4334 (void) WriteBlobMSBULong(alpha_image,crc32(0,data,17));
4337 reading_idat=MagickTrue;
4340 if (memcmp(type,mng_JDAT,4) == 0)
4342 /* Copy chunk to color_image->blob */
4344 if (logging != MagickFalse)
4345 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4346 " Copying JDAT chunk data to color_blob.");
4348 (void) WriteBlob(color_image,length,chunk);
4351 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4356 if (memcmp(type,mng_IDAT,4) == 0)
4361 /* Copy IDAT header and chunk data to alpha_image->blob */
4363 if (image_info->ping == MagickFalse)
4365 if (logging != MagickFalse)
4366 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4367 " Copying IDAT chunk data to alpha_blob.");
4369 (void) WriteBlobMSBULong(alpha_image,(size_t) length);
4370 PNGType(data,mng_IDAT);
4371 LogPNGChunk(logging,mng_IDAT,length);
4372 (void) WriteBlob(alpha_image,4,data);
4373 (void) WriteBlob(alpha_image,length,chunk);
4374 (void) WriteBlobMSBULong(alpha_image,
4375 crc32(crc32(0,data,4),chunk,(uInt) length));
4379 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4384 if ((memcmp(type,mng_JDAA,4) == 0) || (memcmp(type,mng_JdAA,4) == 0))
4386 /* Copy chunk data to alpha_image->blob */
4388 if (image_info->ping == MagickFalse)
4390 if (logging != MagickFalse)
4391 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4392 " Copying JDAA chunk data to alpha_blob.");
4394 (void) WriteBlob(alpha_image,length,chunk);
4398 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4403 if (memcmp(type,mng_JSEP,4) == 0)
4405 read_JSEP=MagickTrue;
4408 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4413 if (memcmp(type,mng_bKGD,4) == 0)
4417 image->background_color.red=ScaleCharToQuantum(p[1]);
4418 image->background_color.green=image->background_color.red;
4419 image->background_color.blue=image->background_color.red;
4424 image->background_color.red=ScaleCharToQuantum(p[1]);
4425 image->background_color.green=ScaleCharToQuantum(p[3]);
4426 image->background_color.blue=ScaleCharToQuantum(p[5]);
4429 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4433 if (memcmp(type,mng_gAMA,4) == 0)
4436 image->gamma=((float) mng_get_long(p))*0.00001;
4438 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4442 if (memcmp(type,mng_cHRM,4) == 0)
4446 image->chromaticity.white_point.x=0.00001*mng_get_long(p);
4447 image->chromaticity.white_point.y=0.00001*mng_get_long(&p[4]);
4448 image->chromaticity.red_primary.x=0.00001*mng_get_long(&p[8]);
4449 image->chromaticity.red_primary.y=0.00001*mng_get_long(&p[12]);
4450 image->chromaticity.green_primary.x=0.00001*mng_get_long(&p[16]);
4451 image->chromaticity.green_primary.y=0.00001*mng_get_long(&p[20]);
4452 image->chromaticity.blue_primary.x=0.00001*mng_get_long(&p[24]);
4453 image->chromaticity.blue_primary.y=0.00001*mng_get_long(&p[28]);
4456 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4460 if (memcmp(type,mng_sRGB,4) == 0)
4464 image->rendering_intent=
4465 Magick_RenderingIntent_from_PNG_RenderingIntent(p[0]);
4466 image->gamma=1.000f/2.200f;
4467 image->chromaticity.red_primary.x=0.6400f;
4468 image->chromaticity.red_primary.y=0.3300f;
4469 image->chromaticity.green_primary.x=0.3000f;
4470 image->chromaticity.green_primary.y=0.6000f;
4471 image->chromaticity.blue_primary.x=0.1500f;
4472 image->chromaticity.blue_primary.y=0.0600f;
4473 image->chromaticity.white_point.x=0.3127f;
4474 image->chromaticity.white_point.y=0.3290f;
4477 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4481 if (memcmp(type,mng_oFFs,4) == 0)
4485 image->page.x=(ssize_t) mng_get_long(p);
4486 image->page.y=(ssize_t) mng_get_long(&p[4]);
4488 if ((int) p[8] != 0)
4490 image->page.x/=10000;
4491 image->page.y/=10000;
4496 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4501 if (memcmp(type,mng_pHYs,4) == 0)
4505 image->resolution.x=(double) mng_get_long(p);
4506 image->resolution.y=(double) mng_get_long(&p[4]);
4507 if ((int) p[8] == PNG_RESOLUTION_METER)
4509 image->units=PixelsPerCentimeterResolution;
4510 image->resolution.x=image->resolution.x/100.0f;
4511 image->resolution.y=image->resolution.y/100.0f;
4515 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4520 if (memcmp(type,mng_iCCP,4) == 0)
4524 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4531 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4533 if (memcmp(type,mng_IEND,4))
4543 Finish up reading image data:
4545 o read main image from color_blob.
4549 o if (color_type has alpha)
4550 if alpha_encoding is PNG
4551 read secondary image from alpha_blob via ReadPNG
4552 if alpha_encoding is JPEG
4553 read secondary image from alpha_blob via ReadJPEG
4557 o copy intensity of secondary image into
4558 alpha samples of main image.
4560 o destroy the secondary image.
4563 (void) CloseBlob(color_image);
4565 if (logging != MagickFalse)
4566 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4567 " Reading jng_image from color_blob.");
4569 (void) FormatLocaleString(color_image_info->filename,MaxTextExtent,"%s",
4570 color_image->filename);
4572 color_image_info->ping=MagickFalse; /* To do: avoid this */
4573 jng_image=ReadImage(color_image_info,exception);
4575 if (jng_image == (Image *) NULL)
4576 return((Image *) NULL);
4578 (void) RelinquishUniqueFileResource(color_image->filename);
4579 color_image=DestroyImage(color_image);
4580 color_image_info=DestroyImageInfo(color_image_info);
4582 if (jng_image == (Image *) NULL)
4583 return((Image *) NULL);
4585 if (logging != MagickFalse)
4586 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4587 " Copying jng_image pixels to main image.");
4589 image->rows=jng_height;
4590 image->columns=jng_width;
4592 for (y=0; y < (ssize_t) image->rows; y++)
4594 s=GetVirtualPixels(jng_image,0,y,image->columns,1,exception);
4595 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
4596 for (x=(ssize_t) image->columns; x != 0; x--)
4598 SetPixelRed(image,GetPixelRed(jng_image,s),q);
4599 SetPixelGreen(image,GetPixelGreen(jng_image,s),q);
4600 SetPixelBlue(image,GetPixelBlue(jng_image,s),q);
4601 q+=GetPixelChannels(image);
4602 s+=GetPixelChannels(jng_image);
4605 if (SyncAuthenticPixels(image,exception) == MagickFalse)
4609 jng_image=DestroyImage(jng_image);
4611 if (image_info->ping == MagickFalse)
4613 if (jng_color_type >= 12)
4615 if (jng_alpha_compression_method == 0)
4619 (void) WriteBlobMSBULong(alpha_image,0x00000000L);
4620 PNGType(data,mng_IEND);
4621 LogPNGChunk(logging,mng_IEND,0L);
4622 (void) WriteBlob(alpha_image,4,data);
4623 (void) WriteBlobMSBULong(alpha_image,crc32(0,data,4));
4626 (void) CloseBlob(alpha_image);
4628 if (logging != MagickFalse)
4629 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4630 " Reading alpha from alpha_blob.");
4632 (void) FormatLocaleString(alpha_image_info->filename,MaxTextExtent,
4633 "%s",alpha_image->filename);
4635 jng_image=ReadImage(alpha_image_info,exception);
4637 if (jng_image != (Image *) NULL)
4638 for (y=0; y < (ssize_t) image->rows; y++)
4640 s=GetVirtualPixels(jng_image,0,y,image->columns,1,
4642 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
4644 if (image->alpha_trait == BlendPixelTrait)
4645 for (x=(ssize_t) image->columns; x != 0; x--)
4647 SetPixelAlpha(image,GetPixelRed(jng_image,s),q);
4648 q+=GetPixelChannels(image);
4649 s+=GetPixelChannels(jng_image);
4653 for (x=(ssize_t) image->columns; x != 0; x--)
4655 SetPixelAlpha(image,GetPixelRed(jng_image,s),q);
4656 if (GetPixelAlpha(image,q) != OpaqueAlpha)
4657 image->alpha_trait=BlendPixelTrait;
4658 q+=GetPixelChannels(image);
4659 s+=GetPixelChannels(jng_image);
4662 if (SyncAuthenticPixels(image,exception) == MagickFalse)
4665 (void) RelinquishUniqueFileResource(alpha_image->filename);
4666 alpha_image=DestroyImage(alpha_image);
4667 alpha_image_info=DestroyImageInfo(alpha_image_info);
4668 if (jng_image != (Image *) NULL)
4669 jng_image=DestroyImage(jng_image);
4673 /* Read the JNG image. */
4675 if (mng_info->mng_type == 0)
4677 mng_info->mng_width=jng_width;
4678 mng_info->mng_height=jng_height;
4681 if (image->page.width == 0 && image->page.height == 0)
4683 image->page.width=jng_width;
4684 image->page.height=jng_height;
4687 if (image->page.x == 0 && image->page.y == 0)
4689 image->page.x=mng_info->x_off[mng_info->object_id];
4690 image->page.y=mng_info->y_off[mng_info->object_id];
4695 image->page.y=mng_info->y_off[mng_info->object_id];
4698 mng_info->image_found++;
4699 status=SetImageProgress(image,LoadImagesTag,2*TellBlob(image),
4700 2*GetBlobSize(image));
4702 if (logging != MagickFalse)
4703 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4704 " exit ReadOneJNGImage()");
4710 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4714 % R e a d J N G I m a g e %
4718 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4720 % ReadJNGImage() reads a JPEG Network Graphics (JNG) image file
4721 % (including the 8-byte signature) and returns it. It allocates the memory
4722 % necessary for the new Image structure and returns a pointer to the new
4725 % JNG support written by Glenn Randers-Pehrson, glennrp@image...
4727 % The format of the ReadJNGImage method is:
4729 % Image *ReadJNGImage(const ImageInfo *image_info, ExceptionInfo
4732 % A description of each parameter follows:
4734 % o image_info: the image info.
4736 % o exception: return any errors or warnings in this structure.
4740 static Image *ReadJNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
4755 magic_number[MaxTextExtent];
4763 assert(image_info != (const ImageInfo *) NULL);
4764 assert(image_info->signature == MagickSignature);
4765 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image_info->filename);
4766 assert(exception != (ExceptionInfo *) NULL);
4767 assert(exception->signature == MagickSignature);
4768 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter ReadJNGImage()");
4769 image=AcquireImage(image_info,exception);
4770 mng_info=(MngInfo *) NULL;
4771 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
4773 if (status == MagickFalse)
4774 return((Image *) NULL);
4776 if (LocaleCompare(image_info->magick,"JNG") != 0)
4777 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
4779 /* Verify JNG signature. */
4781 count=(size_t) ReadBlob(image,8,(unsigned char *) magic_number);
4783 if (count < 8 || memcmp(magic_number,"\213JNG\r\n\032\n",8) != 0)
4784 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
4786 /* Allocate a MngInfo structure. */
4788 have_mng_structure=MagickFalse;
4789 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(*mng_info));
4791 if (mng_info == (MngInfo *) NULL)
4792 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
4794 /* Initialize members of the MngInfo structure. */
4796 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
4797 have_mng_structure=MagickTrue;
4799 mng_info->image=image;
4801 image=ReadOneJNGImage(mng_info,image_info,exception);
4802 MngInfoFreeStruct(mng_info,&have_mng_structure);
4804 if (image == (Image *) NULL)
4806 if (IsImageObject(previous) != MagickFalse)
4808 (void) CloseBlob(previous);
4809 (void) DestroyImageList(previous);
4812 if (logging != MagickFalse)
4813 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4814 "exit ReadJNGImage() with error");
4816 return((Image *) NULL);
4818 (void) CloseBlob(image);
4820 if (image->columns == 0 || image->rows == 0)
4822 if (logging != MagickFalse)
4823 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4824 "exit ReadJNGImage() with error");
4826 ThrowReaderException(CorruptImageError,"CorruptImage");
4829 if (logging != MagickFalse)
4830 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit ReadJNGImage()");
4836 static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
4839 page_geometry[MaxTextExtent];
4872 #if defined(MNG_INSERT_LAYERS)
4874 mng_background_color;
4877 register unsigned char
4892 #if defined(MNG_INSERT_LAYERS)
4897 volatile unsigned int
4898 #ifdef MNG_OBJECT_BUFFERS
4899 mng_background_object=0,
4901 mng_type=0; /* 0: PNG or JNG; 1: MNG; 2: MNG-LC; 3: MNG-VLC */
4904 default_frame_timeout,
4906 #if defined(MNG_INSERT_LAYERS)
4912 /* These delays are all measured in image ticks_per_second,
4913 * not in MNG ticks_per_second
4916 default_frame_delay,
4920 #if defined(MNG_INSERT_LAYERS)
4929 previous_fb.bottom=0;
4931 previous_fb.right=0;
4933 default_fb.bottom=0;
4937 /* Open image file. */
4939 assert(image_info != (const ImageInfo *) NULL);
4940 assert(image_info->signature == MagickSignature);
4941 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image_info->filename);
4942 assert(exception != (ExceptionInfo *) NULL);
4943 assert(exception->signature == MagickSignature);
4944 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter ReadMNGImage()");
4945 image=AcquireImage(image_info,exception);
4946 mng_info=(MngInfo *) NULL;
4947 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
4949 if (status == MagickFalse)
4950 return((Image *) NULL);
4952 first_mng_object=MagickFalse;
4954 have_mng_structure=MagickFalse;
4956 /* Allocate a MngInfo structure. */
4958 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
4960 if (mng_info == (MngInfo *) NULL)
4961 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
4963 /* Initialize members of the MngInfo structure. */
4965 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
4966 mng_info->image=image;
4967 have_mng_structure=MagickTrue;
4969 if (LocaleCompare(image_info->magick,"MNG") == 0)
4972 magic_number[MaxTextExtent];
4974 /* Verify MNG signature. */
4975 count=(size_t) ReadBlob(image,8,(unsigned char *) magic_number);
4976 if (memcmp(magic_number,"\212MNG\r\n\032\n",8) != 0)
4977 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
4979 /* Initialize some nonzero members of the MngInfo structure. */
4980 for (i=0; i < MNG_MAX_OBJECTS; i++)
4982 mng_info->object_clip[i].right=(ssize_t) PNG_UINT_31_MAX;
4983 mng_info->object_clip[i].bottom=(ssize_t) PNG_UINT_31_MAX;
4985 mng_info->exists[0]=MagickTrue;
4988 first_mng_object=MagickTrue;
4990 #if defined(MNG_INSERT_LAYERS)
4991 insert_layers=MagickFalse; /* should be False when converting or mogrifying */
4993 default_frame_delay=0;
4994 default_frame_timeout=0;
4997 mng_info->ticks_per_second=1UL*image->ticks_per_second;
4999 skip_to_iend=MagickFalse;
5000 term_chunk_found=MagickFalse;
5001 mng_info->framing_mode=1;
5002 #if defined(MNG_INSERT_LAYERS)
5003 mandatory_back=MagickFalse;
5005 #if defined(MNG_INSERT_LAYERS)
5006 mng_background_color=image->background_color;
5008 default_fb=mng_info->frame;
5009 previous_fb=mng_info->frame;
5013 type[MaxTextExtent];
5015 if (LocaleCompare(image_info->magick,"MNG") == 0)
5024 (void) ConcatenateMagickString(type,"errr",MaxTextExtent);
5025 length=ReadBlobMSBLong(image);
5026 count=(size_t) ReadBlob(image,4,(unsigned char *) type);
5028 if (logging != MagickFalse)
5029 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5030 " Reading MNG chunk type %c%c%c%c, length: %.20g",
5031 type[0],type[1],type[2],type[3],(double) length);
5033 if (length > PNG_UINT_31_MAX)
5037 ThrowReaderException(CorruptImageError,"CorruptImage");
5040 chunk=(unsigned char *) NULL;
5044 chunk=(unsigned char *) AcquireQuantumMemory(length,sizeof(*chunk));
5046 if (chunk == (unsigned char *) NULL)
5047 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
5049 for (i=0; i < (ssize_t) length; i++)
5050 chunk[i]=(unsigned char) ReadBlobByte(image);
5055 (void) ReadBlobMSBLong(image); /* read crc word */
5057 #if !defined(JNG_SUPPORTED)
5058 if (memcmp(type,mng_JHDR,4) == 0)
5060 skip_to_iend=MagickTrue;
5062 if (mng_info->jhdr_warning == 0)
5063 (void) ThrowMagickException(exception,GetMagickModule(),
5064 CoderError,"JNGCompressNotSupported","`%s'",image->filename);
5066 mng_info->jhdr_warning++;
5069 if (memcmp(type,mng_DHDR,4) == 0)
5071 skip_to_iend=MagickTrue;
5073 if (mng_info->dhdr_warning == 0)
5074 (void) ThrowMagickException(exception,GetMagickModule(),
5075 CoderError,"DeltaPNGNotSupported","`%s'",image->filename);
5077 mng_info->dhdr_warning++;
5079 if (memcmp(type,mng_MEND,4) == 0)
5084 if (memcmp(type,mng_IEND,4) == 0)
5085 skip_to_iend=MagickFalse;
5088 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5090 if (logging != MagickFalse)
5091 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5097 if (memcmp(type,mng_MHDR,4) == 0)
5099 mng_info->mng_width=(size_t) ((p[0] << 24) | (p[1] << 16) |
5100 (p[2] << 8) | p[3]);
5102 mng_info->mng_height=(size_t) ((p[4] << 24) | (p[5] << 16) |
5103 (p[6] << 8) | p[7]);
5105 if (logging != MagickFalse)
5107 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5108 " MNG width: %.20g",(double) mng_info->mng_width);
5109 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5110 " MNG height: %.20g",(double) mng_info->mng_height);
5114 mng_info->ticks_per_second=(size_t) mng_get_long(p);
5116 if (mng_info->ticks_per_second == 0)
5117 default_frame_delay=0;
5120 default_frame_delay=1UL*image->ticks_per_second/
5121 mng_info->ticks_per_second;
5123 frame_delay=default_frame_delay;
5129 simplicity=(size_t) mng_get_long(p);
5132 mng_type=1; /* Full MNG */
5134 if ((simplicity != 0) && ((simplicity | 11) == 11))
5135 mng_type=2; /* LC */
5137 if ((simplicity != 0) && ((simplicity | 9) == 9))
5138 mng_type=3; /* VLC */
5140 #if defined(MNG_INSERT_LAYERS)
5142 insert_layers=MagickTrue;
5144 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
5146 /* Allocate next image structure. */
5147 AcquireNextImage(image_info,image,exception);
5149 if (GetNextImageInList(image) == (Image *) NULL)
5150 return((Image *) NULL);
5152 image=SyncNextImageInList(image);
5153 mng_info->image=image;
5156 if ((mng_info->mng_width > 65535L) ||
5157 (mng_info->mng_height > 65535L))
5158 ThrowReaderException(ImageError,"WidthOrHeightExceedsLimit");
5160 (void) FormatLocaleString(page_geometry,MaxTextExtent,
5161 "%.20gx%.20g+0+0",(double) mng_info->mng_width,(double)
5162 mng_info->mng_height);
5164 mng_info->frame.left=0;
5165 mng_info->frame.right=(ssize_t) mng_info->mng_width;
5166 mng_info->frame.top=0;
5167 mng_info->frame.bottom=(ssize_t) mng_info->mng_height;
5168 mng_info->clip=default_fb=previous_fb=mng_info->frame;
5170 for (i=0; i < MNG_MAX_OBJECTS; i++)
5171 mng_info->object_clip[i]=mng_info->frame;
5173 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5177 if (memcmp(type,mng_TERM,4) == 0)
5188 final_delay=(png_uint_32) mng_get_long(&p[2]);
5189 mng_iterations=(png_uint_32) mng_get_long(&p[6]);
5191 if (mng_iterations == PNG_UINT_31_MAX)
5194 image->iterations=mng_iterations;
5195 term_chunk_found=MagickTrue;
5198 if (logging != MagickFalse)
5200 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5201 " repeat=%d",repeat);
5203 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5204 " final_delay=%.20g",(double) final_delay);
5206 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5207 " image->iterations=%.20g",(double) image->iterations);
5210 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5213 if (memcmp(type,mng_DEFI,4) == 0)
5216 (void) ThrowMagickException(exception,GetMagickModule(),
5217 CoderError,"DEFI chunk found in MNG-VLC datastream","`%s'",
5220 object_id=(p[0] << 8) | p[1];
5222 if (mng_type == 2 && object_id != 0)
5223 (void) ThrowMagickException(exception,GetMagickModule(),
5224 CoderError,"Nonzero object_id in MNG-LC datastream","`%s'",
5227 if (object_id > MNG_MAX_OBJECTS)
5230 Instead of using a warning we should allocate a larger
5231 MngInfo structure and continue.
5233 (void) ThrowMagickException(exception,GetMagickModule(),
5234 CoderError,"object id too large","`%s'",image->filename);
5235 object_id=MNG_MAX_OBJECTS;
5238 if (mng_info->exists[object_id])
5239 if (mng_info->frozen[object_id])
5241 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5242 (void) ThrowMagickException(exception,
5243 GetMagickModule(),CoderError,
5244 "DEFI cannot redefine a frozen MNG object","`%s'",
5249 mng_info->exists[object_id]=MagickTrue;
5252 mng_info->invisible[object_id]=p[2];
5255 Extract object offset info.
5259 mng_info->x_off[object_id]=(ssize_t) ((p[4] << 24) |
5260 (p[5] << 16) | (p[6] << 8) | p[7]);
5262 mng_info->y_off[object_id]=(ssize_t) ((p[8] << 24) |
5263 (p[9] << 16) | (p[10] << 8) | p[11]);
5265 if (logging != MagickFalse)
5267 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5268 " x_off[%d]: %.20g",object_id,(double)
5269 mng_info->x_off[object_id]);
5271 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5272 " y_off[%d]: %.20g",object_id,(double)
5273 mng_info->y_off[object_id]);
5278 Extract object clipping info.
5281 mng_info->object_clip[object_id]=mng_read_box(mng_info->frame,0,
5284 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5287 if (memcmp(type,mng_bKGD,4) == 0)
5289 mng_info->have_global_bkgd=MagickFalse;
5293 mng_info->mng_global_bkgd.red=
5294 ScaleShortToQuantum((unsigned short) ((p[0] << 8) | p[1]));
5296 mng_info->mng_global_bkgd.green=
5297 ScaleShortToQuantum((unsigned short) ((p[2] << 8) | p[3]));
5299 mng_info->mng_global_bkgd.blue=
5300 ScaleShortToQuantum((unsigned short) ((p[4] << 8) | p[5]));
5302 mng_info->have_global_bkgd=MagickTrue;
5305 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5308 if (memcmp(type,mng_BACK,4) == 0)
5310 #if defined(MNG_INSERT_LAYERS)
5312 mandatory_back=p[6];
5317 if (mandatory_back && length > 5)
5319 mng_background_color.red=
5320 ScaleShortToQuantum((unsigned short) ((p[0] << 8) | p[1]));
5322 mng_background_color.green=
5323 ScaleShortToQuantum((unsigned short) ((p[2] << 8) | p[3]));
5325 mng_background_color.blue=
5326 ScaleShortToQuantum((unsigned short) ((p[4] << 8) | p[5]));
5328 mng_background_color.alpha=OpaqueAlpha;
5331 #ifdef MNG_OBJECT_BUFFERS
5333 mng_background_object=(p[7] << 8) | p[8];
5336 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5340 if (memcmp(type,mng_PLTE,4) == 0)
5342 /* Read global PLTE. */
5344 if (length && (length < 769))
5346 if (mng_info->global_plte == (png_colorp) NULL)
5347 mng_info->global_plte=(png_colorp) AcquireQuantumMemory(256,
5348 sizeof(*mng_info->global_plte));
5350 for (i=0; i < (ssize_t) (length/3); i++)
5352 mng_info->global_plte[i].red=p[3*i];
5353 mng_info->global_plte[i].green=p[3*i+1];
5354 mng_info->global_plte[i].blue=p[3*i+2];
5357 mng_info->global_plte_length=(unsigned int) (length/3);
5360 for ( ; i < 256; i++)
5362 mng_info->global_plte[i].red=i;
5363 mng_info->global_plte[i].green=i;
5364 mng_info->global_plte[i].blue=i;
5368 mng_info->global_plte_length=256;
5371 mng_info->global_plte_length=0;
5373 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5377 if (memcmp(type,mng_tRNS,4) == 0)
5379 /* read global tRNS */
5382 for (i=0; i < (ssize_t) length; i++)
5383 mng_info->global_trns[i]=p[i];
5386 for ( ; i < 256; i++)
5387 mng_info->global_trns[i]=255;
5389 mng_info->global_trns_length=(unsigned int) length;
5390 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5393 if (memcmp(type,mng_gAMA,4) == 0)
5400 igamma=mng_get_long(p);
5401 mng_info->global_gamma=((float) igamma)*0.00001;
5402 mng_info->have_global_gama=MagickTrue;
5406 mng_info->have_global_gama=MagickFalse;
5408 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5412 if (memcmp(type,mng_cHRM,4) == 0)
5414 /* Read global cHRM */
5418 mng_info->global_chrm.white_point.x=0.00001*mng_get_long(p);
5419 mng_info->global_chrm.white_point.y=0.00001*mng_get_long(&p[4]);
5420 mng_info->global_chrm.red_primary.x=0.00001*mng_get_long(&p[8]);
5421 mng_info->global_chrm.red_primary.y=0.00001*
5422 mng_get_long(&p[12]);
5423 mng_info->global_chrm.green_primary.x=0.00001*
5424 mng_get_long(&p[16]);
5425 mng_info->global_chrm.green_primary.y=0.00001*
5426 mng_get_long(&p[20]);
5427 mng_info->global_chrm.blue_primary.x=0.00001*
5428 mng_get_long(&p[24]);
5429 mng_info->global_chrm.blue_primary.y=0.00001*
5430 mng_get_long(&p[28]);
5431 mng_info->have_global_chrm=MagickTrue;
5434 mng_info->have_global_chrm=MagickFalse;
5436 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5440 if (memcmp(type,mng_sRGB,4) == 0)
5447 mng_info->global_srgb_intent=
5448 Magick_RenderingIntent_from_PNG_RenderingIntent(p[0]);
5449 mng_info->have_global_srgb=MagickTrue;
5452 mng_info->have_global_srgb=MagickFalse;
5454 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5458 if (memcmp(type,mng_iCCP,4) == 0)
5466 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5471 if (memcmp(type,mng_FRAM,4) == 0)
5474 (void) ThrowMagickException(exception,GetMagickModule(),
5475 CoderError,"FRAM chunk found in MNG-VLC datastream","`%s'",
5478 if ((mng_info->framing_mode == 2) || (mng_info->framing_mode == 4))
5479 image->delay=frame_delay;
5481 frame_delay=default_frame_delay;
5482 frame_timeout=default_frame_timeout;
5487 mng_info->framing_mode=p[0];
5489 if (logging != MagickFalse)
5490 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5491 " Framing_mode=%d",mng_info->framing_mode);
5495 /* Note the delay and frame clipping boundaries. */
5497 p++; /* framing mode */
5499 while (*p && ((p-chunk) < (ssize_t) length))
5500 p++; /* frame name */
5502 p++; /* frame name terminator */
5504 if ((p-chunk) < (ssize_t) (length-4))
5511 change_delay=(*p++);
5512 change_timeout=(*p++);
5513 change_clipping=(*p++);
5514 p++; /* change_sync */
5518 frame_delay=1UL*image->ticks_per_second*
5521 if (mng_info->ticks_per_second != 0)
5522 frame_delay/=mng_info->ticks_per_second;
5525 frame_delay=PNG_UINT_31_MAX;
5527 if (change_delay == 2)
5528 default_frame_delay=frame_delay;
5532 if (logging != MagickFalse)
5533 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5534 " Framing_delay=%.20g",(double) frame_delay);
5539 frame_timeout=1UL*image->ticks_per_second*
5542 if (mng_info->ticks_per_second != 0)
5543 frame_timeout/=mng_info->ticks_per_second;
5546 frame_timeout=PNG_UINT_31_MAX;
5548 if (change_delay == 2)
5549 default_frame_timeout=frame_timeout;
5553 if (logging != MagickFalse)
5554 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5555 " Framing_timeout=%.20g",(double) frame_timeout);
5558 if (change_clipping)
5560 fb=mng_read_box(previous_fb,(char) p[0],&p[1]);
5564 if (logging != MagickFalse)
5565 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5566 " Frame_clip: L=%.20g R=%.20g T=%.20g B=%.20g",
5567 (double) fb.left,(double) fb.right,(double) fb.top,
5568 (double) fb.bottom);
5570 if (change_clipping == 2)
5576 mng_info->clip=mng_minimum_box(fb,mng_info->frame);
5578 subframe_width=(size_t) (mng_info->clip.right
5579 -mng_info->clip.left);
5581 subframe_height=(size_t) (mng_info->clip.bottom
5582 -mng_info->clip.top);
5584 Insert a background layer behind the frame if framing_mode is 4.
5586 #if defined(MNG_INSERT_LAYERS)
5587 if (logging != MagickFalse)
5588 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5589 " subframe_width=%.20g, subframe_height=%.20g",(double)
5590 subframe_width,(double) subframe_height);
5592 if (insert_layers && (mng_info->framing_mode == 4) &&
5593 (subframe_width) && (subframe_height))
5595 /* Allocate next image structure. */
5596 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
5598 AcquireNextImage(image_info,image,exception);
5600 if (GetNextImageInList(image) == (Image *) NULL)
5602 image=DestroyImageList(image);
5603 MngInfoFreeStruct(mng_info,&have_mng_structure);
5604 return((Image *) NULL);
5607 image=SyncNextImageInList(image);
5610 mng_info->image=image;
5612 if (term_chunk_found)
5614 image->start_loop=MagickTrue;
5615 image->iterations=mng_iterations;
5616 term_chunk_found=MagickFalse;
5620 image->start_loop=MagickFalse;
5622 image->columns=subframe_width;
5623 image->rows=subframe_height;
5624 image->page.width=subframe_width;
5625 image->page.height=subframe_height;
5626 image->page.x=mng_info->clip.left;
5627 image->page.y=mng_info->clip.top;
5628 image->background_color=mng_background_color;
5629 image->alpha_trait=UndefinedPixelTrait;
5631 (void) SetImageBackgroundColor(image,exception);
5633 if (logging != MagickFalse)
5634 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5635 " Insert backgd layer, L=%.20g, R=%.20g T=%.20g, B=%.20g",
5636 (double) mng_info->clip.left,(double) mng_info->clip.right,
5637 (double) mng_info->clip.top,(double) mng_info->clip.bottom);
5640 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5643 if (memcmp(type,mng_CLIP,4) == 0)
5652 first_object=(p[0] << 8) | p[1];
5653 last_object=(p[2] << 8) | p[3];
5655 for (i=(int) first_object; i <= (int) last_object; i++)
5657 if (mng_info->exists[i] && !mng_info->frozen[i])
5662 box=mng_info->object_clip[i];
5663 mng_info->object_clip[i]=mng_read_box(box,(char) p[4],&p[5]);
5667 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5670 if (memcmp(type,mng_SAVE,4) == 0)
5672 for (i=1; i < MNG_MAX_OBJECTS; i++)
5673 if (mng_info->exists[i])
5675 mng_info->frozen[i]=MagickTrue;
5676 #ifdef MNG_OBJECT_BUFFERS
5677 if (mng_info->ob[i] != (MngBuffer *) NULL)
5678 mng_info->ob[i]->frozen=MagickTrue;
5683 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5688 if ((memcmp(type,mng_DISC,4) == 0) || (memcmp(type,mng_SEEK,4) == 0))
5690 /* Read DISC or SEEK. */
5692 if ((length == 0) || !memcmp(type,mng_SEEK,4))
5694 for (i=1; i < MNG_MAX_OBJECTS; i++)
5695 MngInfoDiscardObject(mng_info,i);
5703 for (j=0; j < (ssize_t) length; j+=2)
5705 i=p[j] << 8 | p[j+1];
5706 MngInfoDiscardObject(mng_info,i);
5711 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5716 if (memcmp(type,mng_MOVE,4) == 0)
5724 first_object=(p[0] << 8) | p[1];
5725 last_object=(p[2] << 8) | p[3];
5726 for (i=(ssize_t) first_object; i <= (ssize_t) last_object; i++)
5728 if (mng_info->exists[i] && !mng_info->frozen[i])
5736 old_pair.a=mng_info->x_off[i];
5737 old_pair.b=mng_info->y_off[i];
5738 new_pair=mng_read_pair(old_pair,(int) p[4],&p[5]);
5739 mng_info->x_off[i]=new_pair.a;
5740 mng_info->y_off[i]=new_pair.b;
5744 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5748 if (memcmp(type,mng_LOOP,4) == 0)
5750 ssize_t loop_iters=1;
5751 loop_level=chunk[0];
5752 mng_info->loop_active[loop_level]=1; /* mark loop active */
5754 /* Record starting point. */
5755 loop_iters=mng_get_long(&chunk[1]);
5757 if (logging != MagickFalse)
5758 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5759 " LOOP level %.20g has %.20g iterations ",(double) loop_level,
5760 (double) loop_iters);
5762 if (loop_iters == 0)
5763 skipping_loop=loop_level;
5767 mng_info->loop_jump[loop_level]=TellBlob(image);
5768 mng_info->loop_count[loop_level]=loop_iters;
5771 mng_info->loop_iteration[loop_level]=0;
5772 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5776 if (memcmp(type,mng_ENDL,4) == 0)
5778 loop_level=chunk[0];
5780 if (skipping_loop > 0)
5782 if (skipping_loop == loop_level)
5785 Found end of zero-iteration loop.
5788 mng_info->loop_active[loop_level]=0;
5794 if (mng_info->loop_active[loop_level] == 1)
5796 mng_info->loop_count[loop_level]--;
5797 mng_info->loop_iteration[loop_level]++;
5799 if (logging != MagickFalse)
5800 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5801 " ENDL: LOOP level %.20g has %.20g remaining iters ",
5802 (double) loop_level,(double)
5803 mng_info->loop_count[loop_level]);
5805 if (mng_info->loop_count[loop_level] != 0)
5807 offset=SeekBlob(image,mng_info->loop_jump[loop_level],
5811 ThrowReaderException(CorruptImageError,
5812 "ImproperImageHeader");
5823 mng_info->loop_active[loop_level]=0;
5825 for (i=0; i < loop_level; i++)
5826 if (mng_info->loop_active[i] == 1)
5827 last_level=(short) i;
5828 loop_level=last_level;
5833 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5837 if (memcmp(type,mng_CLON,4) == 0)
5839 if (mng_info->clon_warning == 0)
5840 (void) ThrowMagickException(exception,GetMagickModule(),
5841 CoderError,"CLON is not implemented yet","`%s'",
5844 mng_info->clon_warning++;
5847 if (memcmp(type,mng_MAGN,4) == 0)
5862 magn_first=(p[0] << 8) | p[1];
5868 magn_last=(p[2] << 8) | p[3];
5871 magn_last=magn_first;
5872 #ifndef MNG_OBJECT_BUFFERS
5873 if (magn_first || magn_last)
5874 if (mng_info->magn_warning == 0)
5876 (void) ThrowMagickException(exception,
5877 GetMagickModule(),CoderError,
5878 "MAGN is not implemented yet for nonzero objects",
5879 "`%s'",image->filename);
5881 mng_info->magn_warning++;
5891 magn_mx=(p[5] << 8) | p[6];
5900 magn_my=(p[7] << 8) | p[8];
5909 magn_ml=(p[9] << 8) | p[10];
5918 magn_mr=(p[11] << 8) | p[12];
5927 magn_mt=(p[13] << 8) | p[14];
5936 magn_mb=(p[15] << 8) | p[16];
5948 magn_methy=magn_methx;
5951 if (magn_methx > 5 || magn_methy > 5)
5952 if (mng_info->magn_warning == 0)
5954 (void) ThrowMagickException(exception,
5955 GetMagickModule(),CoderError,
5956 "Unknown MAGN method in MNG datastream","`%s'",
5959 mng_info->magn_warning++;
5961 #ifdef MNG_OBJECT_BUFFERS
5962 /* Magnify existing objects in the range magn_first to magn_last */
5964 if (magn_first == 0 || magn_last == 0)
5966 /* Save the magnification factors for object 0 */
5967 mng_info->magn_mb=magn_mb;
5968 mng_info->magn_ml=magn_ml;
5969 mng_info->magn_mr=magn_mr;
5970 mng_info->magn_mt=magn_mt;
5971 mng_info->magn_mx=magn_mx;
5972 mng_info->magn_my=magn_my;
5973 mng_info->magn_methx=magn_methx;
5974 mng_info->magn_methy=magn_methy;
5978 if (memcmp(type,mng_PAST,4) == 0)
5980 if (mng_info->past_warning == 0)
5981 (void) ThrowMagickException(exception,GetMagickModule(),
5982 CoderError,"PAST is not implemented yet","`%s'",
5985 mng_info->past_warning++;
5988 if (memcmp(type,mng_SHOW,4) == 0)
5990 if (mng_info->show_warning == 0)
5991 (void) ThrowMagickException(exception,GetMagickModule(),
5992 CoderError,"SHOW is not implemented yet","`%s'",
5995 mng_info->show_warning++;
5998 if (memcmp(type,mng_sBIT,4) == 0)
6001 mng_info->have_global_sbit=MagickFalse;
6005 mng_info->global_sbit.gray=p[0];
6006 mng_info->global_sbit.red=p[0];
6007 mng_info->global_sbit.green=p[1];
6008 mng_info->global_sbit.blue=p[2];
6009 mng_info->global_sbit.alpha=p[3];
6010 mng_info->have_global_sbit=MagickTrue;
6013 if (memcmp(type,mng_pHYs,4) == 0)
6017 mng_info->global_x_pixels_per_unit=
6018 (size_t) mng_get_long(p);
6019 mng_info->global_y_pixels_per_unit=
6020 (size_t) mng_get_long(&p[4]);
6021 mng_info->global_phys_unit_type=p[8];
6022 mng_info->have_global_phys=MagickTrue;
6026 mng_info->have_global_phys=MagickFalse;
6028 if (memcmp(type,mng_pHYg,4) == 0)
6030 if (mng_info->phyg_warning == 0)
6031 (void) ThrowMagickException(exception,GetMagickModule(),
6032 CoderError,"pHYg is not implemented.","`%s'",image->filename);
6034 mng_info->phyg_warning++;
6036 if (memcmp(type,mng_BASI,4) == 0)
6038 skip_to_iend=MagickTrue;
6040 if (mng_info->basi_warning == 0)
6041 (void) ThrowMagickException(exception,GetMagickModule(),
6042 CoderError,"BASI is not implemented yet","`%s'",
6045 mng_info->basi_warning++;
6046 #ifdef MNG_BASI_SUPPORTED
6047 basi_width=(size_t) ((p[0] << 24) | (p[1] << 16) |
6048 (p[2] << 8) | p[3]);
6049 basi_height=(size_t) ((p[4] << 24) | (p[5] << 16) |
6050 (p[6] << 8) | p[7]);
6051 basi_color_type=p[8];
6052 basi_compression_method=p[9];
6053 basi_filter_type=p[10];
6054 basi_interlace_method=p[11];
6056 basi_red=(p[12] << 8) & p[13];
6062 basi_green=(p[14] << 8) & p[15];
6068 basi_blue=(p[16] << 8) & p[17];
6074 basi_alpha=(p[18] << 8) & p[19];
6078 if (basi_sample_depth == 16)
6085 basi_viewable=p[20];
6091 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
6095 if (memcmp(type,mng_IHDR,4)
6096 #if defined(JNG_SUPPORTED)
6097 && memcmp(type,mng_JHDR,4)
6101 /* Not an IHDR or JHDR chunk */
6103 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
6108 if (logging != MagickFalse)
6109 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6110 " Processing %c%c%c%c chunk",type[0],type[1],type[2],type[3]);
6112 mng_info->exists[object_id]=MagickTrue;
6113 mng_info->viewable[object_id]=MagickTrue;
6115 if (mng_info->invisible[object_id])
6117 if (logging != MagickFalse)
6118 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6119 " Skipping invisible object");
6121 skip_to_iend=MagickTrue;
6122 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
6125 #if defined(MNG_INSERT_LAYERS)
6127 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
6129 image_width=(size_t) mng_get_long(p);
6130 image_height=(size_t) mng_get_long(&p[4]);
6132 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
6135 Insert a transparent background layer behind the entire animation
6136 if it is not full screen.
6138 #if defined(MNG_INSERT_LAYERS)
6139 if (insert_layers && mng_type && first_mng_object)
6141 if ((mng_info->clip.left > 0) || (mng_info->clip.top > 0) ||
6142 (image_width < mng_info->mng_width) ||
6143 (mng_info->clip.right < (ssize_t) mng_info->mng_width) ||
6144 (image_height < mng_info->mng_height) ||
6145 (mng_info->clip.bottom < (ssize_t) mng_info->mng_height))
6147 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
6150 Allocate next image structure.
6152 AcquireNextImage(image_info,image,exception);
6154 if (GetNextImageInList(image) == (Image *) NULL)
6156 image=DestroyImageList(image);
6157 MngInfoFreeStruct(mng_info,&have_mng_structure);
6158 return((Image *) NULL);
6161 image=SyncNextImageInList(image);
6163 mng_info->image=image;
6165 if (term_chunk_found)
6167 image->start_loop=MagickTrue;
6168 image->iterations=mng_iterations;
6169 term_chunk_found=MagickFalse;
6173 image->start_loop=MagickFalse;
6175 /* Make a background rectangle. */
6178 image->columns=mng_info->mng_width;
6179 image->rows=mng_info->mng_height;
6180 image->page.width=mng_info->mng_width;
6181 image->page.height=mng_info->mng_height;
6184 image->background_color=mng_background_color;
6185 (void) SetImageBackgroundColor(image,exception);
6186 if (logging != MagickFalse)
6187 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6188 " Inserted transparent background layer, W=%.20g, H=%.20g",
6189 (double) mng_info->mng_width,(double) mng_info->mng_height);
6193 Insert a background layer behind the upcoming image if
6194 framing_mode is 3, and we haven't already inserted one.
6196 if (insert_layers && (mng_info->framing_mode == 3) &&
6197 (subframe_width) && (subframe_height) && (simplicity == 0 ||
6198 (simplicity & 0x08)))
6200 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
6203 Allocate next image structure.
6205 AcquireNextImage(image_info,image,exception);
6207 if (GetNextImageInList(image) == (Image *) NULL)
6209 image=DestroyImageList(image);
6210 MngInfoFreeStruct(mng_info,&have_mng_structure);
6211 return((Image *) NULL);
6214 image=SyncNextImageInList(image);
6217 mng_info->image=image;
6219 if (term_chunk_found)
6221 image->start_loop=MagickTrue;
6222 image->iterations=mng_iterations;
6223 term_chunk_found=MagickFalse;
6227 image->start_loop=MagickFalse;
6230 image->columns=subframe_width;
6231 image->rows=subframe_height;
6232 image->page.width=subframe_width;
6233 image->page.height=subframe_height;
6234 image->page.x=mng_info->clip.left;
6235 image->page.y=mng_info->clip.top;
6236 image->background_color=mng_background_color;
6237 image->alpha_trait=UndefinedPixelTrait;
6238 (void) SetImageBackgroundColor(image,exception);
6240 if (logging != MagickFalse)
6241 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6242 " Insert background layer, L=%.20g, R=%.20g T=%.20g, B=%.20g",
6243 (double) mng_info->clip.left,(double) mng_info->clip.right,
6244 (double) mng_info->clip.top,(double) mng_info->clip.bottom);
6246 #endif /* MNG_INSERT_LAYERS */
6247 first_mng_object=MagickFalse;
6249 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
6252 Allocate next image structure.
6254 AcquireNextImage(image_info,image,exception);
6256 if (GetNextImageInList(image) == (Image *) NULL)
6258 image=DestroyImageList(image);
6259 MngInfoFreeStruct(mng_info,&have_mng_structure);
6260 return((Image *) NULL);
6263 image=SyncNextImageInList(image);
6265 mng_info->image=image;
6266 status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
6267 GetBlobSize(image));
6269 if (status == MagickFalse)
6272 if (term_chunk_found)
6274 image->start_loop=MagickTrue;
6275 term_chunk_found=MagickFalse;
6279 image->start_loop=MagickFalse;
6281 if (mng_info->framing_mode == 1 || mng_info->framing_mode == 3)
6283 image->delay=frame_delay;
6284 frame_delay=default_frame_delay;
6290 image->page.width=mng_info->mng_width;
6291 image->page.height=mng_info->mng_height;
6292 image->page.x=mng_info->x_off[object_id];
6293 image->page.y=mng_info->y_off[object_id];
6294 image->iterations=mng_iterations;
6297 Seek back to the beginning of the IHDR or JHDR chunk's length field.
6300 if (logging != MagickFalse)
6301 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6302 " Seeking back to beginning of %c%c%c%c chunk",type[0],type[1],
6305 offset=SeekBlob(image,-((ssize_t) length+12),SEEK_CUR);
6308 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
6312 mng_info->image=image;
6313 mng_info->mng_type=mng_type;
6314 mng_info->object_id=object_id;
6316 if (memcmp(type,mng_IHDR,4) == 0)
6317 image=ReadOnePNGImage(mng_info,image_info,exception);
6319 #if defined(JNG_SUPPORTED)
6321 image=ReadOneJNGImage(mng_info,image_info,exception);
6324 if (image == (Image *) NULL)
6326 if (IsImageObject(previous) != MagickFalse)
6328 (void) DestroyImageList(previous);
6329 (void) CloseBlob(previous);
6332 MngInfoFreeStruct(mng_info,&have_mng_structure);
6333 return((Image *) NULL);
6336 if (image->columns == 0 || image->rows == 0)
6338 (void) CloseBlob(image);
6339 image=DestroyImageList(image);
6340 MngInfoFreeStruct(mng_info,&have_mng_structure);
6341 return((Image *) NULL);
6344 mng_info->image=image;
6351 if (mng_info->magn_methx || mng_info->magn_methy)
6357 if (logging != MagickFalse)
6358 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6359 " Processing MNG MAGN chunk");
6361 if (mng_info->magn_methx == 1)
6363 magnified_width=mng_info->magn_ml;
6365 if (image->columns > 1)
6366 magnified_width += mng_info->magn_mr;
6368 if (image->columns > 2)
6369 magnified_width += (png_uint_32)
6370 ((image->columns-2)*(mng_info->magn_mx));
6375 magnified_width=(png_uint_32) image->columns;
6377 if (image->columns > 1)
6378 magnified_width += mng_info->magn_ml-1;
6380 if (image->columns > 2)
6381 magnified_width += mng_info->magn_mr-1;
6383 if (image->columns > 3)
6384 magnified_width += (png_uint_32)
6385 ((image->columns-3)*(mng_info->magn_mx-1));
6388 if (mng_info->magn_methy == 1)
6390 magnified_height=mng_info->magn_mt;
6392 if (image->rows > 1)
6393 magnified_height += mng_info->magn_mb;
6395 if (image->rows > 2)
6396 magnified_height += (png_uint_32)
6397 ((image->rows-2)*(mng_info->magn_my));
6402 magnified_height=(png_uint_32) image->rows;
6404 if (image->rows > 1)
6405 magnified_height += mng_info->magn_mt-1;
6407 if (image->rows > 2)
6408 magnified_height += mng_info->magn_mb-1;
6410 if (image->rows > 3)
6411 magnified_height += (png_uint_32)
6412 ((image->rows-3)*(mng_info->magn_my-1));
6415 if (magnified_height > image->rows ||
6416 magnified_width > image->columns)
6443 /* Allocate next image structure. */
6445 if (logging != MagickFalse)
6446 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6447 " Allocate magnified image");
6449 AcquireNextImage(image_info,image,exception);
6451 if (GetNextImageInList(image) == (Image *) NULL)
6453 image=DestroyImageList(image);
6454 MngInfoFreeStruct(mng_info,&have_mng_structure);
6455 return((Image *) NULL);
6458 large_image=SyncNextImageInList(image);
6460 large_image->columns=magnified_width;
6461 large_image->rows=magnified_height;
6463 magn_methx=mng_info->magn_methx;
6464 magn_methy=mng_info->magn_methy;
6466 #if (MAGICKCORE_QUANTUM_DEPTH > 16)
6467 #define QM unsigned short
6468 if (magn_methx != 1 || magn_methy != 1)
6471 Scale pixels to unsigned shorts to prevent
6472 overflow of intermediate values of interpolations
6474 for (y=0; y < (ssize_t) image->rows; y++)
6476 q=GetAuthenticPixels(image,0,y,image->columns,1,
6479 for (x=(ssize_t) image->columns-1; x >= 0; x--)
6481 SetPixelRed(image,ScaleQuantumToShort(
6482 GetPixelRed(image,q)),q);
6483 SetPixelGreen(image,ScaleQuantumToShort(
6484 GetPixelGreen(image,q)),q);
6485 SetPixelBlue(image,ScaleQuantumToShort(
6486 GetPixelBlue(image,q)),q);
6487 SetPixelAlpha(image,ScaleQuantumToShort(
6488 GetPixelAlpha(image,q)),q);
6489 q+=GetPixelChannels(image);
6492 if (SyncAuthenticPixels(image,exception) == MagickFalse)
6500 if (image->alpha_trait == BlendPixelTrait)
6501 (void) SetImageBackgroundColor(large_image,exception);
6505 large_image->background_color.alpha=OpaqueAlpha;
6506 (void) SetImageBackgroundColor(large_image,exception);
6508 if (magn_methx == 4)
6511 if (magn_methx == 5)
6514 if (magn_methy == 4)
6517 if (magn_methy == 5)
6521 /* magnify the rows into the right side of the large image */
6523 if (logging != MagickFalse)
6524 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6525 " Magnify the rows to %.20g",(double) large_image->rows);
6526 m=(ssize_t) mng_info->magn_mt;
6528 length=(size_t) image->columns*GetPixelChannels(image);
6529 next=(Quantum *) AcquireQuantumMemory(length,sizeof(*next));
6530 prev=(Quantum *) AcquireQuantumMemory(length,sizeof(*prev));
6532 if ((prev == (Quantum *) NULL) ||
6533 (next == (Quantum *) NULL))
6535 image=DestroyImageList(image);
6536 MngInfoFreeStruct(mng_info,&have_mng_structure);
6537 ThrowReaderException(ResourceLimitError,
6538 "MemoryAllocationFailed");
6541 n=GetAuthenticPixels(image,0,0,image->columns,1,exception);
6542 (void) CopyMagickMemory(next,n,length);
6544 for (y=0; y < (ssize_t) image->rows; y++)
6547 m=(ssize_t) mng_info->magn_mt;
6549 else if (magn_methy > 1 && y == (ssize_t) image->rows-2)
6550 m=(ssize_t) mng_info->magn_mb;
6552 else if (magn_methy <= 1 && y == (ssize_t) image->rows-1)
6553 m=(ssize_t) mng_info->magn_mb;
6555 else if (magn_methy > 1 && y == (ssize_t) image->rows-1)
6559 m=(ssize_t) mng_info->magn_my;
6565 if (y < (ssize_t) image->rows-1)
6567 n=GetAuthenticPixels(image,0,y+1,image->columns,1,
6569 (void) CopyMagickMemory(next,n,length);
6572 for (i=0; i < m; i++, yy++)
6577 assert(yy < (ssize_t) large_image->rows);
6580 q=GetAuthenticPixels(large_image,0,yy,large_image->columns,
6582 q+=(large_image->columns-image->columns)*
6583 GetPixelChannels(large_image);
6585 for (x=(ssize_t) image->columns-1; x >= 0; x--)
6587 /* To do: get color as function of indexes[x] */
6589 if (image->storage_class == PseudoClass)
6594 if (magn_methy <= 1)
6596 /* replicate previous */
6597 SetPixelRed(large_image,GetPixelRed(image,pixels),q);
6598 SetPixelGreen(large_image,GetPixelGreen(image,
6600 SetPixelBlue(large_image,GetPixelBlue(image,
6602 SetPixelAlpha(large_image,GetPixelAlpha(image,
6606 else if (magn_methy == 2 || magn_methy == 4)
6610 SetPixelRed(large_image,GetPixelRed(image,
6612 SetPixelGreen(large_image,GetPixelGreen(image,
6614 SetPixelBlue(large_image,GetPixelBlue(image,
6616 SetPixelAlpha(large_image,GetPixelAlpha(image,
6623 SetPixelRed(large_image,((QM) (((ssize_t)
6624 (2*i*(GetPixelRed(image,n)
6625 -GetPixelRed(image,pixels)+m))/
6627 +GetPixelRed(image,pixels)))),q);
6628 SetPixelGreen(large_image,((QM) (((ssize_t)
6629 (2*i*(GetPixelGreen(image,n)
6630 -GetPixelGreen(image,pixels)+m))/
6632 +GetPixelGreen(image,pixels)))),q);
6633 SetPixelBlue(large_image,((QM) (((ssize_t)
6634 (2*i*(GetPixelBlue(image,n)
6635 -GetPixelBlue(image,pixels)+m))/
6637 +GetPixelBlue(image,pixels)))),q);
6639 if (image->alpha_trait == BlendPixelTrait)
6640 SetPixelAlpha(large_image, ((QM) (((ssize_t)
6641 (2*i*(GetPixelAlpha(image,n)
6642 -GetPixelAlpha(image,pixels)+m))
6644 GetPixelAlpha(image,pixels)))),q);
6647 if (magn_methy == 4)
6649 /* Replicate nearest */
6650 if (i <= ((m+1) << 1))
6651 SetPixelAlpha(large_image,GetPixelAlpha(image,
6654 SetPixelAlpha(large_image,GetPixelAlpha(image,
6659 else /* if (magn_methy == 3 || magn_methy == 5) */
6661 /* Replicate nearest */
6662 if (i <= ((m+1) << 1))
6664 SetPixelRed(large_image,GetPixelRed(image,
6666 SetPixelGreen(large_image,GetPixelGreen(image,
6668 SetPixelBlue(large_image,GetPixelBlue(image,
6670 SetPixelAlpha(large_image,GetPixelAlpha(image,
6676 SetPixelRed(large_image,GetPixelRed(image,n),q);
6677 SetPixelGreen(large_image,GetPixelGreen(image,n),
6679 SetPixelBlue(large_image,GetPixelBlue(image,n),
6681 SetPixelAlpha(large_image,GetPixelAlpha(image,n),
6685 if (magn_methy == 5)
6687 SetPixelAlpha(large_image,(QM) (((ssize_t) (2*i*
6688 (GetPixelAlpha(image,n)
6689 -GetPixelAlpha(image,pixels))
6690 +m))/((ssize_t) (m*2))
6691 +GetPixelAlpha(image,pixels)),q);
6694 n+=GetPixelChannels(image);
6695 q+=GetPixelChannels(large_image);
6696 pixels+=GetPixelChannels(image);
6699 if (SyncAuthenticPixels(large_image,exception) == 0)
6705 prev=(Quantum *) RelinquishMagickMemory(prev);
6706 next=(Quantum *) RelinquishMagickMemory(next);
6708 length=image->columns;
6710 if (logging != MagickFalse)
6711 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6712 " Delete original image");
6714 DeleteImageFromList(&image);
6718 mng_info->image=image;
6720 /* magnify the columns */
6721 if (logging != MagickFalse)
6722 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6723 " Magnify the columns to %.20g",(double) image->columns);
6725 for (y=0; y < (ssize_t) image->rows; y++)
6730 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
6731 pixels=q+(image->columns-length)*GetPixelChannels(image);
6732 n=pixels+GetPixelChannels(image);
6734 for (x=(ssize_t) (image->columns-length);
6735 x < (ssize_t) image->columns; x++)
6737 /* To do: Rewrite using Get/Set***PixelChannel() */
6739 if (x == (ssize_t) (image->columns-length))
6740 m=(ssize_t) mng_info->magn_ml;
6742 else if (magn_methx > 1 && x == (ssize_t) image->columns-2)
6743 m=(ssize_t) mng_info->magn_mr;
6745 else if (magn_methx <= 1 && x == (ssize_t) image->columns-1)
6746 m=(ssize_t) mng_info->magn_mr;
6748 else if (magn_methx > 1 && x == (ssize_t) image->columns-1)
6752 m=(ssize_t) mng_info->magn_mx;
6754 for (i=0; i < m; i++)
6756 if (magn_methx <= 1)
6758 /* replicate previous */
6759 SetPixelRed(image,GetPixelRed(image,pixels),q);
6760 SetPixelGreen(image,GetPixelGreen(image,pixels),q);
6761 SetPixelBlue(image,GetPixelBlue(image,pixels),q);
6762 SetPixelAlpha(image,GetPixelAlpha(image,pixels),q);
6765 else if (magn_methx == 2 || magn_methx == 4)
6769 SetPixelRed(image,GetPixelRed(image,pixels),q);
6770 SetPixelGreen(image,GetPixelGreen(image,pixels),q);
6771 SetPixelBlue(image,GetPixelBlue(image,pixels),q);
6772 SetPixelAlpha(image,GetPixelAlpha(image,pixels),q);
6775 /* To do: Rewrite using Get/Set***PixelChannel() */
6779 SetPixelRed(image,(QM) ((2*i*(
6780 GetPixelRed(image,n)
6781 -GetPixelRed(image,pixels))+m)
6783 GetPixelRed(image,pixels)),q);
6785 SetPixelGreen(image,(QM) ((2*i*(
6786 GetPixelGreen(image,n)
6787 -GetPixelGreen(image,pixels))+m)
6789 GetPixelGreen(image,pixels)),q);
6791 SetPixelBlue(image,(QM) ((2*i*(
6792 GetPixelBlue(image,n)
6793 -GetPixelBlue(image,pixels))+m)
6795 GetPixelBlue(image,pixels)),q);
6796 if (image->alpha_trait == BlendPixelTrait)
6797 SetPixelAlpha(image,(QM) ((2*i*(
6798 GetPixelAlpha(image,n)
6799 -GetPixelAlpha(image,pixels))+m)
6801 GetPixelAlpha(image,pixels)),q);
6804 if (magn_methx == 4)
6806 /* Replicate nearest */
6807 if (i <= ((m+1) << 1))
6809 SetPixelAlpha(image,
6810 GetPixelAlpha(image,pixels)+0,q);
6814 SetPixelAlpha(image,
6815 GetPixelAlpha(image,n)+0,q);
6820 else /* if (magn_methx == 3 || magn_methx == 5) */
6822 /* Replicate nearest */
6823 if (i <= ((m+1) << 1))
6825 SetPixelRed(image,GetPixelRed(image,pixels),q);
6826 SetPixelGreen(image,GetPixelGreen(image,pixels),q);
6827 SetPixelBlue(image,GetPixelBlue(image,pixels),q);
6828 SetPixelAlpha(image,GetPixelAlpha(image,pixels),q);
6833 SetPixelRed(image,GetPixelRed(image,n),q);
6834 SetPixelGreen(image,GetPixelGreen(image,n),q);
6835 SetPixelBlue(image,GetPixelBlue(image,n),q);
6836 SetPixelAlpha(image,GetPixelAlpha(image,n),q);
6839 if (magn_methx == 5)
6842 SetPixelAlpha(image,
6843 (QM) ((2*i*( GetPixelAlpha(image,n)
6844 -GetPixelAlpha(image,pixels))+m)/
6846 +GetPixelAlpha(image,pixels)),q);
6849 q+=GetPixelChannels(image);
6851 n+=GetPixelChannels(image);
6852 p+=GetPixelChannels(image);
6855 if (SyncAuthenticPixels(image,exception) == MagickFalse)
6858 #if (MAGICKCORE_QUANTUM_DEPTH > 16)
6859 if (magn_methx != 1 || magn_methy != 1)
6862 Rescale pixels to Quantum
6864 for (y=0; y < (ssize_t) image->rows; y++)
6866 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
6868 for (x=(ssize_t) image->columns-1; x >= 0; x--)
6870 SetPixelRed(image,ScaleShortToQuantum(
6871 GetPixelRed(image,q)),q);
6872 SetPixelGreen(image,ScaleShortToQuantum(
6873 GetPixelGreen(image,q)),q);
6874 SetPixelBlue(image,ScaleShortToQuantum(
6875 GetPixelBlue(image,q)),q);
6876 SetPixelAlpha(image,ScaleShortToQuantum(
6877 GetPixelAlpha(image,q)),q);
6878 q+=GetPixelChannels(image);
6881 if (SyncAuthenticPixels(image,exception) == MagickFalse)
6886 if (logging != MagickFalse)
6887 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6888 " Finished MAGN processing");
6893 Crop_box is with respect to the upper left corner of the MNG.
6895 crop_box.left=mng_info->image_box.left+mng_info->x_off[object_id];
6896 crop_box.right=mng_info->image_box.right+mng_info->x_off[object_id];
6897 crop_box.top=mng_info->image_box.top+mng_info->y_off[object_id];
6898 crop_box.bottom=mng_info->image_box.bottom+mng_info->y_off[object_id];
6899 crop_box=mng_minimum_box(crop_box,mng_info->clip);
6900 crop_box=mng_minimum_box(crop_box,mng_info->frame);
6901 crop_box=mng_minimum_box(crop_box,mng_info->object_clip[object_id]);
6902 if ((crop_box.left != (mng_info->image_box.left
6903 +mng_info->x_off[object_id])) ||
6904 (crop_box.right != (mng_info->image_box.right
6905 +mng_info->x_off[object_id])) ||
6906 (crop_box.top != (mng_info->image_box.top
6907 +mng_info->y_off[object_id])) ||
6908 (crop_box.bottom != (mng_info->image_box.bottom
6909 +mng_info->y_off[object_id])))
6911 if (logging != MagickFalse)
6912 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6913 " Crop the PNG image");
6915 if ((crop_box.left < crop_box.right) &&
6916 (crop_box.top < crop_box.bottom))
6925 Crop_info is with respect to the upper left corner of
6928 crop_info.x=(crop_box.left-mng_info->x_off[object_id]);
6929 crop_info.y=(crop_box.top-mng_info->y_off[object_id]);
6930 crop_info.width=(size_t) (crop_box.right-crop_box.left);
6931 crop_info.height=(size_t) (crop_box.bottom-crop_box.top);
6932 image->page.width=image->columns;
6933 image->page.height=image->rows;
6936 im=CropImage(image,&crop_info,exception);
6938 if (im != (Image *) NULL)
6940 image->columns=im->columns;
6941 image->rows=im->rows;
6942 im=DestroyImage(im);
6943 image->page.width=image->columns;
6944 image->page.height=image->rows;
6945 image->page.x=crop_box.left;
6946 image->page.y=crop_box.top;
6953 No pixels in crop area. The MNG spec still requires
6954 a layer, though, so make a single transparent pixel in
6955 the top left corner.
6960 (void) SetImageBackgroundColor(image,exception);
6961 image->page.width=1;
6962 image->page.height=1;
6967 #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
6968 image=mng_info->image;
6972 #if (MAGICKCORE_QUANTUM_DEPTH > 16)
6973 /* PNG does not handle depths greater than 16 so reduce it even
6976 if (image->depth > 16)
6980 #if (MAGICKCORE_QUANTUM_DEPTH > 8)
6981 if (image->depth > 8)
6983 /* To do: fill low byte properly */
6987 if (LosslessReduceDepthOK(image,exception) != MagickFalse)
6991 if (image_info->number_scenes != 0)
6993 if (mng_info->scenes_found >
6994 (ssize_t) (image_info->first_scene+image_info->number_scenes))
6998 if (logging != MagickFalse)
6999 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7000 " Finished reading image datastream.");
7002 } while (LocaleCompare(image_info->magick,"MNG") == 0);
7004 (void) CloseBlob(image);
7006 if (logging != MagickFalse)
7007 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7008 " Finished reading all image datastreams.");
7010 #if defined(MNG_INSERT_LAYERS)
7011 if (insert_layers && !mng_info->image_found && (mng_info->mng_width) &&
7012 (mng_info->mng_height))
7015 Insert a background layer if nothing else was found.
7017 if (logging != MagickFalse)
7018 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7019 " No images found. Inserting a background layer.");
7021 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
7024 Allocate next image structure.
7026 AcquireNextImage(image_info,image,exception);
7027 if (GetNextImageInList(image) == (Image *) NULL)
7029 image=DestroyImageList(image);
7030 MngInfoFreeStruct(mng_info,&have_mng_structure);
7032 if (logging != MagickFalse)
7033 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7034 " Allocation failed, returning NULL.");
7036 return((Image *) NULL);
7038 image=SyncNextImageInList(image);
7040 image->columns=mng_info->mng_width;
7041 image->rows=mng_info->mng_height;
7042 image->page.width=mng_info->mng_width;
7043 image->page.height=mng_info->mng_height;
7046 image->background_color=mng_background_color;
7047 image->alpha_trait=UndefinedPixelTrait;
7049 if (image_info->ping == MagickFalse)
7050 (void) SetImageBackgroundColor(image,exception);
7052 mng_info->image_found++;
7055 image->iterations=mng_iterations;
7057 if (mng_iterations == 1)
7058 image->start_loop=MagickTrue;
7060 while (GetPreviousImageInList(image) != (Image *) NULL)
7063 if (image_count > 10*mng_info->image_found)
7065 if (logging != MagickFalse)
7066 (void) LogMagickEvent(CoderEvent,GetMagickModule()," No beginning");
7068 (void) ThrowMagickException(exception,GetMagickModule(),
7069 CoderError,"Linked list is corrupted, beginning of list not found",
7070 "`%s'",image_info->filename);
7072 return((Image *) NULL);
7075 image=GetPreviousImageInList(image);
7077 if (GetNextImageInList(image) == (Image *) NULL)
7079 if (logging != MagickFalse)
7080 (void) LogMagickEvent(CoderEvent,GetMagickModule()," Corrupt list");
7082 (void) ThrowMagickException(exception,GetMagickModule(),
7083 CoderError,"Linked list is corrupted; next_image is NULL","`%s'",
7084 image_info->filename);
7088 if (mng_info->ticks_per_second && mng_info->image_found > 1 &&
7089 GetNextImageInList(image) ==
7092 if (logging != MagickFalse)
7093 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7094 " First image null");
7096 (void) ThrowMagickException(exception,GetMagickModule(),
7097 CoderError,"image->next for first image is NULL but shouldn't be.",
7098 "`%s'",image_info->filename);
7101 if (mng_info->image_found == 0)
7103 if (logging != MagickFalse)
7104 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7105 " No visible images found.");
7107 (void) ThrowMagickException(exception,GetMagickModule(),
7108 CoderError,"No visible images in file","`%s'",image_info->filename);
7110 if (image != (Image *) NULL)
7111 image=DestroyImageList(image);
7113 MngInfoFreeStruct(mng_info,&have_mng_structure);
7114 return((Image *) NULL);
7117 if (mng_info->ticks_per_second)
7118 final_delay=1UL*MagickMax(image->ticks_per_second,1L)*
7119 final_delay/mng_info->ticks_per_second;
7122 image->start_loop=MagickTrue;
7124 /* Find final nonzero image delay */
7125 final_image_delay=0;
7127 while (GetNextImageInList(image) != (Image *) NULL)
7130 final_image_delay=image->delay;
7132 image=GetNextImageInList(image);
7135 if (final_delay < final_image_delay)
7136 final_delay=final_image_delay;
7138 image->delay=final_delay;
7140 if (logging != MagickFalse)
7141 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7142 " image->delay=%.20g, final_delay=%.20g",(double) image->delay,
7143 (double) final_delay);
7145 if (logging != MagickFalse)
7151 image=GetFirstImageInList(image);
7153 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7154 " Before coalesce:");
7156 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7157 " scene 0 delay=%.20g",(double) image->delay);
7159 while (GetNextImageInList(image) != (Image *) NULL)
7161 image=GetNextImageInList(image);
7162 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7163 " scene %.20g delay=%.20g",(double) scene++,(double) image->delay);
7167 image=GetFirstImageInList(image);
7168 #ifdef MNG_COALESCE_LAYERS
7178 if (logging != MagickFalse)
7179 (void) LogMagickEvent(CoderEvent,GetMagickModule()," Coalesce Images");
7182 next_image=CoalesceImages(image,exception);
7184 if (next_image == (Image *) NULL)
7185 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
7187 image=DestroyImageList(image);
7190 for (next=image; next != (Image *) NULL; next=next_image)
7192 next->page.width=mng_info->mng_width;
7193 next->page.height=mng_info->mng_height;
7196 next->scene=scene++;
7197 next_image=GetNextImageInList(next);
7199 if (next_image == (Image *) NULL)
7202 if (next->delay == 0)
7205 next_image->previous=GetPreviousImageInList(next);
7206 if (GetPreviousImageInList(next) == (Image *) NULL)
7209 next->previous->next=next_image;
7210 next=DestroyImage(next);
7216 while (GetNextImageInList(image) != (Image *) NULL)
7217 image=GetNextImageInList(image);
7219 image->dispose=BackgroundDispose;
7221 if (logging != MagickFalse)
7227 image=GetFirstImageInList(image);
7229 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7230 " After coalesce:");
7232 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7233 " scene 0 delay=%.20g dispose=%.20g",(double) image->delay,
7234 (double) image->dispose);
7236 while (GetNextImageInList(image) != (Image *) NULL)
7238 image=GetNextImageInList(image);
7240 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7241 " scene %.20g delay=%.20g dispose=%.20g",(double) scene++,
7242 (double) image->delay,(double) image->dispose);
7246 image=GetFirstImageInList(image);
7247 MngInfoFreeStruct(mng_info,&have_mng_structure);
7248 have_mng_structure=MagickFalse;
7250 if (logging != MagickFalse)
7251 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit ReadMNGImage()");
7253 return(GetFirstImageInList(image));
7255 #else /* PNG_LIBPNG_VER > 10011 */
7256 static Image *ReadPNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
7258 printf("Your PNG library is too old: You have libpng-%s\n",
7259 PNG_LIBPNG_VER_STRING);
7261 (void) ThrowMagickException(exception,GetMagickModule(),CoderError,
7262 "PNG library is too old","`%s'",image_info->filename);
7264 return(Image *) NULL;
7267 static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
7269 return(ReadPNGImage(image_info,exception));
7271 #endif /* PNG_LIBPNG_VER > 10011 */
7275 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7279 % R e g i s t e r P N G I m a g e %
7283 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7285 % RegisterPNGImage() adds properties for the PNG image format to
7286 % the list of supported formats. The properties include the image format
7287 % tag, a method to read and/or write the format, whether the format
7288 % supports the saving of more than one frame to the same file or blob,
7289 % whether the format supports native in-memory I/O, and a brief
7290 % description of the format.
7292 % The format of the RegisterPNGImage method is:
7294 % size_t RegisterPNGImage(void)
7297 ModuleExport size_t RegisterPNGImage(void)
7300 version[MaxTextExtent];
7308 "See http://www.libpng.org/ for details about the PNG format."
7313 "See http://www.libpng.org/pub/mng/ for details about the JNG\n"
7319 "See http://www.libpng.org/pub/mng/ for details about the MNG\n"
7325 #if defined(PNG_LIBPNG_VER_STRING)
7326 (void) ConcatenateMagickString(version,"libpng ",MaxTextExtent);
7327 (void) ConcatenateMagickString(version,PNG_LIBPNG_VER_STRING,MaxTextExtent);
7329 if (LocaleCompare(PNG_LIBPNG_VER_STRING,png_get_header_ver(NULL)) != 0)
7331 (void) ConcatenateMagickString(version,",",MaxTextExtent);
7332 (void) ConcatenateMagickString(version,png_get_libpng_ver(NULL),
7337 entry=SetMagickInfo("MNG");
7338 entry->seekable_stream=MagickTrue; /* To do: eliminate this. */
7340 #if defined(MAGICKCORE_PNG_DELEGATE)
7341 entry->decoder=(DecodeImageHandler *) ReadMNGImage;
7342 entry->encoder=(EncodeImageHandler *) WriteMNGImage;
7345 entry->magick=(IsImageFormatHandler *) IsMNG;
7346 entry->description=ConstantString("Multiple-image Network Graphics");
7348 if (*version != '\0')
7349 entry->version=ConstantString(version);
7351 entry->module=ConstantString("PNG");
7352 entry->note=ConstantString(MNGNote);
7353 (void) RegisterMagickInfo(entry);
7355 entry=SetMagickInfo("PNG");
7357 #if defined(MAGICKCORE_PNG_DELEGATE)
7358 entry->decoder=(DecodeImageHandler *) ReadPNGImage;
7359 entry->encoder=(EncodeImageHandler *) WritePNGImage;
7362 entry->magick=(IsImageFormatHandler *) IsPNG;
7363 entry->adjoin=MagickFalse;
7364 entry->description=ConstantString("Portable Network Graphics");
7365 entry->module=ConstantString("PNG");
7367 if (*version != '\0')
7368 entry->version=ConstantString(version);
7370 entry->note=ConstantString(PNGNote);
7371 (void) RegisterMagickInfo(entry);
7373 entry=SetMagickInfo("PNG8");
7375 #if defined(MAGICKCORE_PNG_DELEGATE)
7376 entry->decoder=(DecodeImageHandler *) ReadPNGImage;
7377 entry->encoder=(EncodeImageHandler *) WritePNGImage;
7380 entry->magick=(IsImageFormatHandler *) IsPNG;
7381 entry->adjoin=MagickFalse;
7382 entry->description=ConstantString(
7383 "8-bit indexed with optional binary transparency");
7384 entry->module=ConstantString("PNG");
7385 (void) RegisterMagickInfo(entry);
7387 entry=SetMagickInfo("PNG24");
7390 #if defined(ZLIB_VERSION)
7391 (void) ConcatenateMagickString(version,"zlib ",MaxTextExtent);
7392 (void) ConcatenateMagickString(version,ZLIB_VERSION,MaxTextExtent);
7394 if (LocaleCompare(ZLIB_VERSION,zlib_version) != 0)
7396 (void) ConcatenateMagickString(version,",",MaxTextExtent);
7397 (void) ConcatenateMagickString(version,zlib_version,MaxTextExtent);
7401 if (*version != '\0')
7402 entry->version=ConstantString(version);
7404 #if defined(MAGICKCORE_PNG_DELEGATE)
7405 entry->decoder=(DecodeImageHandler *) ReadPNGImage;
7406 entry->encoder=(EncodeImageHandler *) WritePNGImage;
7409 entry->magick=(IsImageFormatHandler *) IsPNG;
7410 entry->adjoin=MagickFalse;
7411 entry->description=ConstantString("opaque or binary transparent 24-bit RGB");
7412 entry->module=ConstantString("PNG");
7413 (void) RegisterMagickInfo(entry);
7415 entry=SetMagickInfo("PNG32");
7417 #if defined(MAGICKCORE_PNG_DELEGATE)
7418 entry->decoder=(DecodeImageHandler *) ReadPNGImage;
7419 entry->encoder=(EncodeImageHandler *) WritePNGImage;
7422 entry->magick=(IsImageFormatHandler *) IsPNG;
7423 entry->adjoin=MagickFalse;
7424 entry->description=ConstantString("opaque or transparent 32-bit RGBA");
7425 entry->module=ConstantString("PNG");
7426 (void) RegisterMagickInfo(entry);
7428 entry=SetMagickInfo("PNG48");
7430 #if defined(MAGICKCORE_PNG_DELEGATE)
7431 entry->decoder=(DecodeImageHandler *) ReadPNGImage;
7432 entry->encoder=(EncodeImageHandler *) WritePNGImage;
7435 entry->magick=(IsImageFormatHandler *) IsPNG;
7436 entry->adjoin=MagickFalse;
7437 entry->description=ConstantString("opaque or binary transparent 48-bit RGB");
7438 entry->module=ConstantString("PNG");
7439 (void) RegisterMagickInfo(entry);
7441 entry=SetMagickInfo("PNG64");
7443 #if defined(MAGICKCORE_PNG_DELEGATE)
7444 entry->decoder=(DecodeImageHandler *) ReadPNGImage;
7445 entry->encoder=(EncodeImageHandler *) WritePNGImage;
7448 entry->magick=(IsImageFormatHandler *) IsPNG;
7449 entry->adjoin=MagickFalse;
7450 entry->description=ConstantString("opaque or transparent 64-bit RGBA");
7451 entry->module=ConstantString("PNG");
7452 (void) RegisterMagickInfo(entry);
7454 entry=SetMagickInfo("PNG00");
7456 #if defined(MAGICKCORE_PNG_DELEGATE)
7457 entry->decoder=(DecodeImageHandler *) ReadPNGImage;
7458 entry->encoder=(EncodeImageHandler *) WritePNGImage;
7461 entry->magick=(IsImageFormatHandler *) IsPNG;
7462 entry->adjoin=MagickFalse;
7463 entry->description=ConstantString(
7464 "PNG inheriting bit-depth and color-type from original");
7465 entry->module=ConstantString("PNG");
7466 (void) RegisterMagickInfo(entry);
7468 entry=SetMagickInfo("JNG");
7470 #if defined(JNG_SUPPORTED)
7471 #if defined(MAGICKCORE_PNG_DELEGATE)
7472 entry->decoder=(DecodeImageHandler *) ReadJNGImage;
7473 entry->encoder=(EncodeImageHandler *) WriteJNGImage;
7477 entry->magick=(IsImageFormatHandler *) IsJNG;
7478 entry->adjoin=MagickFalse;
7479 entry->description=ConstantString("JPEG Network Graphics");
7480 entry->module=ConstantString("PNG");
7481 entry->note=ConstantString(JNGNote);
7482 (void) RegisterMagickInfo(entry);
7484 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
7485 ping_semaphore=AllocateSemaphoreInfo();
7488 return(MagickImageCoderSignature);
7492 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7496 % U n r e g i s t e r P N G I m a g e %
7500 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7502 % UnregisterPNGImage() removes format registrations made by the
7503 % PNG module from the list of supported formats.
7505 % The format of the UnregisterPNGImage method is:
7507 % UnregisterPNGImage(void)
7510 ModuleExport void UnregisterPNGImage(void)
7512 (void) UnregisterMagickInfo("MNG");
7513 (void) UnregisterMagickInfo("PNG");
7514 (void) UnregisterMagickInfo("PNG8");
7515 (void) UnregisterMagickInfo("PNG24");
7516 (void) UnregisterMagickInfo("PNG32");
7517 (void) UnregisterMagickInfo("PNG48");
7518 (void) UnregisterMagickInfo("PNG64");
7519 (void) UnregisterMagickInfo("PNG00");
7520 (void) UnregisterMagickInfo("JNG");
7522 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
7523 if (ping_semaphore != (SemaphoreInfo *) NULL)
7524 DestroySemaphoreInfo(&ping_semaphore);
7528 #if defined(MAGICKCORE_PNG_DELEGATE)
7529 #if PNG_LIBPNG_VER > 10011
7531 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7535 % W r i t e M N G I m a g e %
7539 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7541 % WriteMNGImage() writes an image in the Portable Network Graphics
7542 % Group's "Multiple-image Network Graphics" encoded image format.
7544 % MNG support written by Glenn Randers-Pehrson, glennrp@image...
7546 % The format of the WriteMNGImage method is:
7548 % MagickBooleanType WriteMNGImage(const ImageInfo *image_info,
7549 % Image *image,ExceptionInfo *exception)
7551 % A description of each parameter follows.
7553 % o image_info: the image info.
7555 % o image: The image.
7557 % o exception: return any errors or warnings in this structure.
7559 % To do (as of version 5.5.2, November 26, 2002 -- glennrp -- see also
7560 % "To do" under ReadPNGImage):
7562 % Preserve all unknown and not-yet-handled known chunks found in input
7563 % PNG file and copy them into output PNG files according to the PNG
7566 % Write the iCCP chunk at MNG level when (icc profile length > 0)
7568 % Improve selection of color type (use indexed-colour or indexed-colour
7569 % with tRNS when 256 or fewer unique RGBA values are present).
7571 % Figure out what to do with "dispose=<restore-to-previous>" (dispose == 3)
7572 % This will be complicated if we limit ourselves to generating MNG-LC
7573 % files. For now we ignore disposal method 3 and simply overlay the next
7576 % Check for identical PLTE's or PLTE/tRNS combinations and use a
7577 % global MNG PLTE or PLTE/tRNS combination when appropriate.
7578 % [mostly done 15 June 1999 but still need to take care of tRNS]
7580 % Check for identical sRGB and replace with a global sRGB (and remove
7581 % gAMA/cHRM if sRGB is found; check for identical gAMA/cHRM and
7582 % replace with global gAMA/cHRM (or with sRGB if appropriate; replace
7583 % local gAMA/cHRM with local sRGB if appropriate).
7585 % Check for identical sBIT chunks and write global ones.
7587 % Provide option to skip writing the signature tEXt chunks.
7589 % Use signatures to detect identical objects and reuse the first
7590 % instance of such objects instead of writing duplicate objects.
7592 % Use a smaller-than-32k value of compression window size when
7595 % Encode JNG datastreams. Mostly done as of 5.5.2; need to write
7596 % ancillary text chunks and save profiles.
7598 % Provide an option to force LC files (to ensure exact framing rate)
7601 % Provide an option to force VLC files instead of LC, even when offsets
7602 % are present. This will involve expanding the embedded images with a
7603 % transparent region at the top and/or left.
7607 Magick_png_write_raw_profile(const ImageInfo *image_info,png_struct *ping,
7608 png_info *ping_info, unsigned char *profile_type, unsigned char
7609 *profile_description, unsigned char *profile_data, png_uint_32 length)
7628 hex[16]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
7630 if (LocaleNCompare((char *) profile_type+1, "ng-chunk-",9) == 0)
7633 if (image_info->verbose)
7635 (void) printf("writing raw profile: type=%s, length=%.20g\n",
7636 (char *) profile_type, (double) length);
7639 #if PNG_LIBPNG_VER >= 14000
7640 text=(png_textp) png_malloc(ping,(png_alloc_size_t) sizeof(png_text));
7642 text=(png_textp) png_malloc(ping,(png_size_t) sizeof(png_text));
7644 description_length=(png_uint_32) strlen((const char *) profile_description);
7645 allocated_length=(png_uint_32) (length*2 + (length >> 5) + 20
7646 + description_length);
7647 #if PNG_LIBPNG_VER >= 14000
7648 text[0].text=(png_charp) png_malloc(ping,
7649 (png_alloc_size_t) allocated_length);
7650 text[0].key=(png_charp) png_malloc(ping, (png_alloc_size_t) 80);
7652 text[0].text=(png_charp) png_malloc(ping, (png_size_t) allocated_length);
7653 text[0].key=(png_charp) png_malloc(ping, (png_size_t) 80);
7655 text[0].key[0]='\0';
7656 (void) ConcatenateMagickString(text[0].key,
7657 "Raw profile type ",MaxTextExtent);
7658 (void) ConcatenateMagickString(text[0].key,(const char *) profile_type,62);
7662 (void) CopyMagickString(dp,(const char *) profile_description,
7664 dp+=description_length;
7666 (void) FormatLocaleString(dp,allocated_length-
7667 (png_size_t) (dp-text[0].text),"%8lu ",(unsigned long) length);
7670 for (i=0; i < (ssize_t) length; i++)
7674 *(dp++)=(char) hex[((*sp >> 4) & 0x0f)];
7675 *(dp++)=(char) hex[((*sp++ ) & 0x0f)];
7680 text[0].text_length=(png_size_t) (dp-text[0].text);
7681 text[0].compression=image_info->compression == NoCompression ||
7682 (image_info->compression == UndefinedCompression &&
7683 text[0].text_length < 128) ? -1 : 0;
7685 if (text[0].text_length <= allocated_length)
7686 png_set_text(ping,ping_info,text,1);
7688 png_free(ping,text[0].text);
7689 png_free(ping,text[0].key);
7690 png_free(ping,text);
7693 static MagickBooleanType Magick_png_write_chunk_from_profile(Image *image,
7694 const char *string, MagickBooleanType logging)
7707 ResetImageProfileIterator(image);
7709 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
7711 profile=GetImageProfile(image,name);
7713 if (profile != (const StringInfo *) NULL)
7718 if (LocaleNCompare(name,string,11) == 0)
7720 if (logging != MagickFalse)
7721 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7722 " Found %s profile",name);
7724 ping_profile=CloneStringInfo(profile);
7725 data=GetStringInfoDatum(ping_profile),
7726 length=(png_uint_32) GetStringInfoLength(ping_profile);
7731 (void) WriteBlobMSBULong(image,length-5); /* data length */
7732 (void) WriteBlob(image,length-1,data+1);
7733 (void) WriteBlobMSBULong(image,crc32(0,data+1,(uInt) length-1));
7734 ping_profile=DestroyStringInfo(ping_profile);
7738 name=GetNextImageProfile(image);
7745 /* Write one PNG image */
7746 static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
7747 const ImageInfo *IMimage_info,Image *IMimage,ExceptionInfo *exception)
7771 ping_trans_alpha[256];
7799 ping_have_cheap_transparency,
7810 /* ping_exclude_EXIF, */
7813 /* ping_exclude_iTXt, */
7818 /* ping_exclude_tRNS, */
7820 ping_exclude_zCCP, /* hex-encoded iCCP */
7823 ping_preserve_colormap,
7824 ping_need_colortype_warning,
7842 *volatile ping_pixels;
7855 ping_interlace_method,
7856 ping_compression_method,
7873 number_semitransparent,
7875 ping_pHYs_unit_type;
7878 ping_pHYs_x_resolution,
7879 ping_pHYs_y_resolution;
7881 logging=LogMagickEvent(CoderEvent,GetMagickModule(),
7882 " Enter WriteOnePNGImage()");
7884 image = CloneImage(IMimage,0,0,MagickFalse,exception);
7885 image_info=(ImageInfo *) CloneImageInfo(IMimage_info);
7886 if (image_info == (ImageInfo *) NULL)
7887 ThrowWriterException(ResourceLimitError, "MemoryAllocationFailed");
7889 /* Define these outside of the following "if logging()" block so they will
7890 * show in debuggers.
7893 (void) ConcatenateMagickString(im_vers,
7894 MagickLibVersionText,MaxTextExtent);
7895 (void) ConcatenateMagickString(im_vers,
7896 MagickLibAddendum,MaxTextExtent);
7899 (void) ConcatenateMagickString(libpng_vers,
7900 PNG_LIBPNG_VER_STRING,32);
7902 (void) ConcatenateMagickString(libpng_runv,
7903 png_get_libpng_ver(NULL),32);
7906 (void) ConcatenateMagickString(zlib_vers,
7909 (void) ConcatenateMagickString(zlib_runv,
7914 LogMagickEvent(CoderEvent,GetMagickModule()," IM version = %s",
7916 LogMagickEvent(CoderEvent,GetMagickModule()," Libpng version = %s",
7918 if (LocaleCompare(libpng_vers,libpng_runv) != 0)
7920 LogMagickEvent(CoderEvent,GetMagickModule()," running with %s",
7923 LogMagickEvent(CoderEvent,GetMagickModule()," Zlib version = %s",
7925 if (LocaleCompare(zlib_vers,zlib_runv) != 0)
7927 LogMagickEvent(CoderEvent,GetMagickModule()," running with %s",
7932 /* Initialize some stuff */
7935 ping_interlace_method=0,
7936 ping_compression_method=0,
7937 ping_filter_method=0,
7940 ping_background.red = 0;
7941 ping_background.green = 0;
7942 ping_background.blue = 0;
7943 ping_background.gray = 0;
7944 ping_background.index = 0;
7946 ping_trans_color.red=0;
7947 ping_trans_color.green=0;
7948 ping_trans_color.blue=0;
7949 ping_trans_color.gray=0;
7951 ping_pHYs_unit_type = 0;
7952 ping_pHYs_x_resolution = 0;
7953 ping_pHYs_y_resolution = 0;
7955 ping_have_blob=MagickFalse;
7956 ping_have_color=MagickTrue;
7957 ping_have_non_bw=MagickTrue;
7958 ping_have_PLTE=MagickFalse;
7959 ping_have_bKGD=MagickFalse;
7960 ping_have_pHYs=MagickFalse;
7961 ping_have_tRNS=MagickFalse;
7963 ping_exclude_bKGD=mng_info->ping_exclude_bKGD;
7964 ping_exclude_cHRM=mng_info->ping_exclude_cHRM;
7965 ping_exclude_date=mng_info->ping_exclude_date;
7966 /* ping_exclude_EXIF=mng_info->ping_exclude_EXIF; */
7967 ping_exclude_gAMA=mng_info->ping_exclude_gAMA;
7968 ping_exclude_iCCP=mng_info->ping_exclude_iCCP;
7969 /* ping_exclude_iTXt=mng_info->ping_exclude_iTXt; */
7970 ping_exclude_oFFs=mng_info->ping_exclude_oFFs;
7971 ping_exclude_pHYs=mng_info->ping_exclude_pHYs;
7972 ping_exclude_sRGB=mng_info->ping_exclude_sRGB;
7973 ping_exclude_tEXt=mng_info->ping_exclude_tEXt;
7974 /* ping_exclude_tRNS=mng_info->ping_exclude_tRNS; */
7975 ping_exclude_vpAg=mng_info->ping_exclude_vpAg;
7976 ping_exclude_zCCP=mng_info->ping_exclude_zCCP; /* hex-encoded iCCP in zTXt */
7977 ping_exclude_zTXt=mng_info->ping_exclude_zTXt;
7979 ping_preserve_colormap = mng_info->ping_preserve_colormap;
7980 ping_need_colortype_warning = MagickFalse;
7982 /* Recognize the ICC sRGB profile and convert it to the sRGB chunk,
7983 * i.e., eliminate the ICC profile and set image->rendering_intent.
7984 * Note that this will not involve any changes to the actual pixels
7985 * but merely passes information to applications that read the resulting
7988 if (ping_exclude_sRGB == MagickFalse)
7996 ResetImageProfileIterator(image);
7997 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
7999 profile=GetImageProfile(image,name);
8001 if (profile != (StringInfo *) NULL)
8003 if ((LocaleCompare(name,"ICC") == 0) ||
8004 (LocaleCompare(name,"ICM") == 0))
8009 /* 0: not a known sRGB profile
8010 * 1: HP-Microsoft sRGB v2
8011 * 2: ICC sRGB v4 perceptual
8012 * 3: ICC sRGB v2 perceptual no black-compensation
8015 check_crc[4] = {0, 0xf29e526dUL, 0xbbef7812UL, 0x427ebb21UL},
8016 check_len[4] = {0, 3144, 60960, 3052};
8025 length=(png_uint_32) GetStringInfoLength(profile);
8027 for (icheck=3; icheck > 0; icheck--)
8029 if (length == check_len[icheck])
8031 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8032 " Got a %lu-byte ICC profile (potentially sRGB)",
8033 (unsigned long) length);
8035 data=GetStringInfoDatum(profile);
8036 profile_crc=crc32(0,data,length);
8038 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8039 " with crc=%8x",(unsigned int) profile_crc);
8041 if (profile_crc == check_crc[icheck])
8043 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8045 if (image->rendering_intent==UndefinedIntent)
8046 image->rendering_intent=PerceptualIntent;
8052 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8053 " Got a %lu-byte ICC profile",
8054 (unsigned long) length);
8057 name=GetNextImageProfile(image);
8062 number_semitransparent = 0;
8063 number_transparent = 0;
8065 if (logging != MagickFalse)
8067 if (image->storage_class == UndefinedClass)
8068 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8069 " storage_class=UndefinedClass");
8070 if (image->storage_class == DirectClass)
8071 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8072 " storage_class=DirectClass");
8073 if (image->storage_class == PseudoClass)
8074 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8075 " storage_class=PseudoClass");
8078 if (image->storage_class == PseudoClass &&
8079 (mng_info->write_png8 || mng_info->write_png24 || mng_info->write_png32 ||
8080 mng_info->write_png48 || mng_info->write_png64 ||
8081 (mng_info->write_png_colortype != 1 &&
8082 mng_info->write_png_colortype != 5)))
8084 (void) SyncImage(image,exception);
8085 image->storage_class = DirectClass;
8088 if (ping_preserve_colormap == MagickFalse)
8090 if (image->storage_class != PseudoClass && image->colormap != NULL)
8092 /* Free the bogus colormap; it can cause trouble later */
8093 if (logging != MagickFalse)
8094 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8095 " Freeing bogus colormap");
8096 (void) RelinquishMagickMemory(image->colormap);
8097 image->colormap=NULL;
8101 if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
8102 (void) TransformImageColorspace(image,sRGBColorspace,exception);
8105 Sometimes we get PseudoClass images whose RGB values don't match
8106 the colors in the colormap. This code syncs the RGB values.
8108 if (image->depth <= 8 && image->taint && image->storage_class == PseudoClass)
8109 (void) SyncImage(image,exception);
8111 #if (MAGICKCORE_QUANTUM_DEPTH == 8)
8112 if (image->depth > 8)
8114 if (logging != MagickFalse)
8115 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8116 " Reducing PNG bit depth to 8 since this is a Q8 build.");
8122 /* Respect the -depth option */
8123 if (image->depth < MAGICKCORE_QUANTUM_DEPTH)
8128 if (image->depth > 8)
8130 #if MAGICKCORE_QUANTUM_DEPTH > 16
8131 /* Scale to 16-bit */
8132 LBR16PacketRGBO(image->background_color);
8134 for (y=0; y < (ssize_t) image->rows; y++)
8136 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8138 if (r == (Quantum *) NULL)
8141 for (x=0; x < (ssize_t) image->columns; x++)
8144 r+=GetPixelChannels(image);
8147 if (SyncAuthenticPixels(image,exception) == MagickFalse)
8151 if (image->storage_class == PseudoClass && image->colormap != NULL)
8153 for (i=0; i < (ssize_t) image->colors; i++)
8155 LBR16PacketRGBO(image->colormap[i]);
8158 #endif /* MAGICKCORE_QUANTUM_DEPTH > 16 */
8161 else if (image->depth > 4)
8163 #if MAGICKCORE_QUANTUM_DEPTH > 8
8164 /* Scale to 8-bit */
8165 LBR08PacketRGBO(image->background_color);
8167 for (y=0; y < (ssize_t) image->rows; y++)
8169 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8171 if (r == (Quantum *) NULL)
8174 for (x=0; x < (ssize_t) image->columns; x++)
8177 r+=GetPixelChannels(image);
8180 if (SyncAuthenticPixels(image,exception) == MagickFalse)
8184 if (image->storage_class == PseudoClass && image->colormap != NULL)
8186 for (i=0; i < (ssize_t) image->colors; i++)
8188 LBR08PacketRGBO(image->colormap[i]);
8191 #endif /* MAGICKCORE_QUANTUM_DEPTH > 8 */
8194 if (image->depth > 2)
8196 /* Scale to 4-bit */
8197 LBR04PacketRGBO(image->background_color);
8199 for (y=0; y < (ssize_t) image->rows; y++)
8201 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8203 if (r == (Quantum *) NULL)
8206 for (x=0; x < (ssize_t) image->columns; x++)
8209 r+=GetPixelChannels(image);
8212 if (SyncAuthenticPixels(image,exception) == MagickFalse)
8216 if (image->storage_class == PseudoClass && image->colormap != NULL)
8218 for (i=0; i < (ssize_t) image->colors; i++)
8220 LBR04PacketRGBO(image->colormap[i]);
8225 else if (image->depth > 1)
8227 /* Scale to 2-bit */
8228 LBR02PacketRGBO(image->background_color);
8230 for (y=0; y < (ssize_t) image->rows; y++)
8232 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8234 if (r == (Quantum *) NULL)
8237 for (x=0; x < (ssize_t) image->columns; x++)
8240 r+=GetPixelChannels(image);
8243 if (SyncAuthenticPixels(image,exception) == MagickFalse)
8247 if (image->storage_class == PseudoClass && image->colormap != NULL)
8249 for (i=0; i < (ssize_t) image->colors; i++)
8251 LBR02PacketRGBO(image->colormap[i]);
8257 /* Scale to 1-bit */
8258 LBR01PacketRGBO(image->background_color);
8260 for (y=0; y < (ssize_t) image->rows; y++)
8262 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8264 if (r == (Quantum *) NULL)
8267 for (x=0; x < (ssize_t) image->columns; x++)
8270 r+=GetPixelChannels(image);
8273 if (SyncAuthenticPixels(image,exception) == MagickFalse)
8277 if (image->storage_class == PseudoClass && image->colormap != NULL)
8279 for (i=0; i < (ssize_t) image->colors; i++)
8281 LBR01PacketRGBO(image->colormap[i]);
8287 /* To do: set to next higher multiple of 8 */
8288 if (image->depth < 8)
8291 #if (MAGICKCORE_QUANTUM_DEPTH > 16)
8292 /* PNG does not handle depths greater than 16 so reduce it even
8295 if (image->depth > 8)
8299 #if (MAGICKCORE_QUANTUM_DEPTH > 8)
8300 if (image->depth > 8)
8302 /* To do: fill low byte properly */
8306 if (image->depth == 16 && mng_info->write_png_depth != 16)
8307 if (mng_info->write_png8 || LosslessReduceDepthOK(image,exception) != MagickFalse)
8311 if (image->storage_class != PseudoClass && mng_info->write_png_colortype &&
8312 (mng_info->write_png_colortype > 4 || (mng_info->write_png_depth >= 8 &&
8313 mng_info->write_png_colortype < 4 &&
8314 image->alpha_trait != BlendPixelTrait)))
8316 /* Avoid the expensive BUILD_PALETTE operation if we're sure that we
8317 * are not going to need the result.
8319 image_colors = (int) image->colors;
8320 number_opaque = (int) image->colors;
8321 if (mng_info->write_png_colortype == 1 ||
8322 mng_info->write_png_colortype == 5)
8323 ping_have_color=MagickFalse;
8325 ping_have_color=MagickTrue;
8326 ping_have_non_bw=MagickFalse;
8328 if (image->alpha_trait == BlendPixelTrait)
8330 number_transparent = 2;
8331 number_semitransparent = 1;
8336 number_transparent = 0;
8337 number_semitransparent = 0;
8345 * Normally we run this just once, but in the case of writing PNG8
8346 * we reduce the transparency to binary and run again, then if there
8347 * are still too many colors we reduce to a simple 4-4-4-1, then 3-3-3-1
8348 * RGBA palette and run again, and then to a simple 3-3-2-1 RGBA
8349 * palette. Then (To do) we take care of a final reduction that is only
8350 * needed if there are still 256 colors present and one of them has both
8351 * transparent and opaque instances.
8354 tried_332 = MagickFalse;
8355 tried_333 = MagickFalse;
8356 tried_444 = MagickFalse;
8361 * Sometimes we get DirectClass images that have 256 colors or fewer.
8362 * This code will build a colormap.
8364 * Also, sometimes we get PseudoClass images with an out-of-date
8365 * colormap. This code will replace the colormap with a new one.
8366 * Sometimes we get PseudoClass images that have more than 256 colors.
8367 * This code will delete the colormap and change the image to
8370 * If image->alpha_trait is MagickFalse, we ignore the alpha channel
8371 * even though it sometimes contains left-over non-opaque values.
8373 * Also we gather some information (number of opaque, transparent,
8374 * and semitransparent pixels, and whether the image has any non-gray
8375 * pixels or only black-and-white pixels) that we might need later.
8377 * Even if the user wants to force GrayAlpha or RGBA (colortype 4 or 6)
8378 * we need to check for bogus non-opaque values, at least.
8386 semitransparent[260],
8389 register const Quantum
8396 if (logging != MagickFalse)
8397 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8398 " Enter BUILD_PALETTE:");
8400 if (logging != MagickFalse)
8402 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8403 " image->columns=%.20g",(double) image->columns);
8404 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8405 " image->rows=%.20g",(double) image->rows);
8406 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8407 " image->alpha_trait=%.20g",(double) image->alpha_trait);
8408 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8409 " image->depth=%.20g",(double) image->depth);
8411 if (image->storage_class == PseudoClass && image->colormap != NULL)
8413 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8414 " Original colormap:");
8415 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8416 " i (red,green,blue,alpha)");
8418 for (i=0; i < 256; i++)
8420 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8421 " %d (%d,%d,%d,%d)",
8423 (int) image->colormap[i].red,
8424 (int) image->colormap[i].green,
8425 (int) image->colormap[i].blue,
8426 (int) image->colormap[i].alpha);
8429 for (i=image->colors - 10; i < (ssize_t) image->colors; i++)
8433 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8434 " %d (%d,%d,%d,%d)",
8436 (int) image->colormap[i].red,
8437 (int) image->colormap[i].green,
8438 (int) image->colormap[i].blue,
8439 (int) image->colormap[i].alpha);
8444 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8445 " image->colors=%d",(int) image->colors);
8447 if (image->colors == 0)
8448 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8449 " (zero means unknown)");
8451 if (ping_preserve_colormap == MagickFalse)
8452 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8453 " Regenerate the colormap");
8458 number_semitransparent = 0;
8459 number_transparent = 0;
8461 for (y=0; y < (ssize_t) image->rows; y++)
8463 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8465 if (q == (Quantum *) NULL)
8468 for (x=0; x < (ssize_t) image->columns; x++)
8470 if (image->alpha_trait != BlendPixelTrait ||
8471 GetPixelAlpha(image,q) == OpaqueAlpha)
8473 if (number_opaque < 259)
8475 if (number_opaque == 0)
8477 GetPixelInfoPixel(image, q, opaque);
8478 opaque[0].alpha=OpaqueAlpha;
8482 for (i=0; i< (ssize_t) number_opaque; i++)
8484 if (IsPixelEquivalent(image,q, opaque+i))
8488 if (i == (ssize_t) number_opaque && number_opaque < 259)
8491 GetPixelInfoPixel(image, q, opaque+i);
8492 opaque[i].alpha=OpaqueAlpha;
8496 else if (GetPixelAlpha(image,q) == TransparentAlpha)
8498 if (number_transparent < 259)
8500 if (number_transparent == 0)
8502 GetPixelInfoPixel(image, q, transparent);
8503 ping_trans_color.red=(unsigned short)
8504 GetPixelRed(image,q);
8505 ping_trans_color.green=(unsigned short)
8506 GetPixelGreen(image,q);
8507 ping_trans_color.blue=(unsigned short)
8508 GetPixelBlue(image,q);
8509 ping_trans_color.gray=(unsigned short)
8510 GetPixelGray(image,q);
8511 number_transparent = 1;
8514 for (i=0; i< (ssize_t) number_transparent; i++)
8516 if (IsPixelEquivalent(image,q, transparent+i))
8520 if (i == (ssize_t) number_transparent &&
8521 number_transparent < 259)
8523 number_transparent++;
8524 GetPixelInfoPixel(image,q,transparent+i);
8530 if (number_semitransparent < 259)
8532 if (number_semitransparent == 0)
8534 GetPixelInfoPixel(image,q,semitransparent);
8535 number_semitransparent = 1;
8538 for (i=0; i< (ssize_t) number_semitransparent; i++)
8540 if (IsPixelEquivalent(image,q, semitransparent+i)
8541 && GetPixelAlpha(image,q) ==
8542 semitransparent[i].alpha)
8546 if (i == (ssize_t) number_semitransparent &&
8547 number_semitransparent < 259)
8549 number_semitransparent++;
8550 GetPixelInfoPixel(image, q, semitransparent+i);
8554 q+=GetPixelChannels(image);
8558 if (mng_info->write_png8 == MagickFalse &&
8559 ping_exclude_bKGD == MagickFalse)
8561 /* Add the background color to the palette, if it
8562 * isn't already there.
8564 if (logging != MagickFalse)
8566 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8567 " Check colormap for background (%d,%d,%d)",
8568 (int) image->background_color.red,
8569 (int) image->background_color.green,
8570 (int) image->background_color.blue);
8572 for (i=0; i<number_opaque; i++)
8574 if (opaque[i].red == image->background_color.red &&
8575 opaque[i].green == image->background_color.green &&
8576 opaque[i].blue == image->background_color.blue)
8579 if (number_opaque < 259 && i == number_opaque)
8581 opaque[i] = image->background_color;
8582 ping_background.index = i;
8584 if (logging != MagickFalse)
8586 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8587 " background_color index is %d",(int) i);
8591 else if (logging != MagickFalse)
8592 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8593 " No room in the colormap to add background color");
8596 image_colors=number_opaque+number_transparent+number_semitransparent;
8598 if (mng_info->write_png8 != MagickFalse && image_colors > 256)
8600 /* No room for the background color; remove it. */
8605 if (logging != MagickFalse)
8607 if (image_colors > 256)
8608 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8609 " image has more than 256 colors");
8612 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8613 " image has %d colors",image_colors);
8616 if (ping_preserve_colormap != MagickFalse)
8619 if (mng_info->write_png_colortype != 7) /* We won't need this info */
8621 ping_have_color=MagickFalse;
8622 ping_have_non_bw=MagickFalse;
8624 if ((IssRGBCompatibleColorspace(image->colorspace) == MagickFalse) ||
8625 (IssRGBColorspace(image->colorspace) != MagickFalse))
8627 ping_have_color=MagickTrue;
8628 ping_have_non_bw=MagickTrue;
8631 if(image_colors > 256)
8633 for (y=0; y < (ssize_t) image->rows; y++)
8635 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8637 if (q == (Quantum *) NULL)
8641 for (x=0; x < (ssize_t) image->columns; x++)
8643 if (GetPixelRed(image,s) != GetPixelGreen(image,s) ||
8644 GetPixelRed(image,s) != GetPixelBlue(image,s))
8646 ping_have_color=MagickTrue;
8647 ping_have_non_bw=MagickTrue;
8650 s+=GetPixelChannels(image);
8653 if (ping_have_color != MagickFalse)
8656 /* Worst case is black-and-white; we are looking at every
8660 if (ping_have_non_bw == MagickFalse)
8663 for (x=0; x < (ssize_t) image->columns; x++)
8665 if (GetPixelRed(image,s) != 0 &&
8666 GetPixelRed(image,s) != QuantumRange)
8668 ping_have_non_bw=MagickTrue;
8671 s+=GetPixelChannels(image);
8678 if (image_colors < 257)
8684 * Initialize image colormap.
8687 if (logging != MagickFalse)
8688 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8689 " Sort the new colormap");
8691 /* Sort palette, transparent first */;
8695 for (i=0; i<number_transparent; i++)
8696 colormap[n++] = transparent[i];
8698 for (i=0; i<number_semitransparent; i++)
8699 colormap[n++] = semitransparent[i];
8701 for (i=0; i<number_opaque; i++)
8702 colormap[n++] = opaque[i];
8704 ping_background.index +=
8705 (number_transparent + number_semitransparent);
8707 /* image_colors < 257; search the colormap instead of the pixels
8708 * to get ping_have_color and ping_have_non_bw
8712 if (ping_have_color == MagickFalse)
8714 if (colormap[i].red != colormap[i].green ||
8715 colormap[i].red != colormap[i].blue)
8717 ping_have_color=MagickTrue;
8718 ping_have_non_bw=MagickTrue;
8723 if (ping_have_non_bw == MagickFalse)
8725 if (colormap[i].red != 0 && colormap[i].red != QuantumRange)
8726 ping_have_non_bw=MagickTrue;
8730 if ((mng_info->ping_exclude_tRNS == MagickFalse ||
8731 (number_transparent == 0 && number_semitransparent == 0)) &&
8732 (((mng_info->write_png_colortype-1) ==
8733 PNG_COLOR_TYPE_PALETTE) ||
8734 (mng_info->write_png_colortype == 0)))
8736 if (logging != MagickFalse)
8738 if (n != (ssize_t) image_colors)
8739 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8740 " image_colors (%d) and n (%d) don't match",
8743 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8744 " AcquireImageColormap");
8747 image->colors = image_colors;
8749 if (AcquireImageColormap(image,image_colors,exception) ==
8751 ThrowWriterException(ResourceLimitError,
8752 "MemoryAllocationFailed");
8754 for (i=0; i< (ssize_t) image_colors; i++)
8755 image->colormap[i] = colormap[i];
8757 if (logging != MagickFalse)
8759 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8760 " image->colors=%d (%d)",
8761 (int) image->colors, image_colors);
8763 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8764 " Update the pixel indexes");
8767 /* Sync the pixel indices with the new colormap */
8769 for (y=0; y < (ssize_t) image->rows; y++)
8771 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8773 if (q == (Quantum *) NULL)
8776 for (x=0; x < (ssize_t) image->columns; x++)
8778 for (i=0; i< (ssize_t) image_colors; i++)
8780 if ((image->alpha_trait != BlendPixelTrait ||
8781 image->colormap[i].alpha == GetPixelAlpha(image,q)) &&
8782 image->colormap[i].red == GetPixelRed(image,q) &&
8783 image->colormap[i].green == GetPixelGreen(image,q) &&
8784 image->colormap[i].blue == GetPixelBlue(image,q))
8786 SetPixelIndex(image,i,q);
8790 q+=GetPixelChannels(image);
8793 if (SyncAuthenticPixels(image,exception) == MagickFalse)
8799 if (logging != MagickFalse)
8801 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8802 " image->colors=%d", (int) image->colors);
8804 if (image->colormap != NULL)
8806 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8807 " i (red,green,blue,alpha)");
8809 for (i=0; i < (ssize_t) image->colors; i++)
8811 if (i < 300 || i >= (ssize_t) image->colors - 10)
8813 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8814 " %d (%d,%d,%d,%d)",
8816 (int) image->colormap[i].red,
8817 (int) image->colormap[i].green,
8818 (int) image->colormap[i].blue,
8819 (int) image->colormap[i].alpha);
8824 if (number_transparent < 257)
8825 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8826 " number_transparent = %d",
8827 number_transparent);
8830 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8831 " number_transparent > 256");
8833 if (number_opaque < 257)
8834 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8835 " number_opaque = %d",
8839 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8840 " number_opaque > 256");
8842 if (number_semitransparent < 257)
8843 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8844 " number_semitransparent = %d",
8845 number_semitransparent);
8848 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8849 " number_semitransparent > 256");
8851 if (ping_have_non_bw == MagickFalse)
8852 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8853 " All pixels and the background are black or white");
8855 else if (ping_have_color == MagickFalse)
8856 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8857 " All pixels and the background are gray");
8860 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8861 " At least one pixel or the background is non-gray");
8863 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8864 " Exit BUILD_PALETTE:");
8867 if (mng_info->write_png8 == MagickFalse)
8870 /* Make any reductions necessary for the PNG8 format */
8871 if (image_colors <= 256 &&
8872 image_colors != 0 && image->colormap != NULL &&
8873 number_semitransparent == 0 &&
8874 number_transparent <= 1)
8877 /* PNG8 can't have semitransparent colors so we threshold the
8878 * opacity to 0 or OpaqueOpacity, and PNG8 can only have one
8879 * transparent color so if more than one is transparent we merge
8880 * them into image->background_color.
8882 if (number_semitransparent != 0 || number_transparent > 1)
8884 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8885 " Thresholding the alpha channel to binary");
8887 for (y=0; y < (ssize_t) image->rows; y++)
8889 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8891 if (r == (Quantum *) NULL)
8894 for (x=0; x < (ssize_t) image->columns; x++)
8896 if (GetPixelAlpha(image,r) < OpaqueAlpha/2)
8898 SetPixelInfoPixel(image,&image->background_color,r);
8899 SetPixelAlpha(image,TransparentAlpha,r);
8902 SetPixelAlpha(image,OpaqueAlpha,r);
8903 r+=GetPixelChannels(image);
8906 if (SyncAuthenticPixels(image,exception) == MagickFalse)
8909 if (image_colors != 0 && image_colors <= 256 &&
8910 image->colormap != NULL)
8911 for (i=0; i<image_colors; i++)
8912 image->colormap[i].alpha =
8913 (image->colormap[i].alpha > TransparentAlpha/2 ?
8914 TransparentAlpha : OpaqueAlpha);
8919 /* PNG8 can't have more than 256 colors so we quantize the pixels and
8920 * background color to the 4-4-4-1, 3-3-3-1 or 3-3-2-1 palette. If the
8921 * image is mostly gray, the 4-4-4-1 palette is likely to end up with 256
8924 if (tried_444 == MagickFalse && (image_colors == 0 || image_colors > 256))
8926 if (logging != MagickFalse)
8927 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8928 " Quantizing the background color to 4-4-4");
8930 tried_444 = MagickTrue;
8932 LBR04PacketRGB(image->background_color);
8934 if (logging != MagickFalse)
8935 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8936 " Quantizing the pixel colors to 4-4-4");
8938 if (image->colormap == NULL)
8940 for (y=0; y < (ssize_t) image->rows; y++)
8942 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8944 if (r == (Quantum *) NULL)
8947 for (x=0; x < (ssize_t) image->columns; x++)
8949 if (GetPixelAlpha(image,r) == OpaqueAlpha)
8951 r+=GetPixelChannels(image);
8954 if (SyncAuthenticPixels(image,exception) == MagickFalse)
8959 else /* Should not reach this; colormap already exists and
8962 if (logging != MagickFalse)
8963 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8964 " Quantizing the colormap to 4-4-4");
8966 for (i=0; i<image_colors; i++)
8968 LBR04PacketRGB(image->colormap[i]);
8974 if (tried_333 == MagickFalse && (image_colors == 0 || image_colors > 256))
8976 if (logging != MagickFalse)
8977 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8978 " Quantizing the background color to 3-3-3");
8980 tried_333 = MagickTrue;
8982 LBR03PacketRGB(image->background_color);
8984 if (logging != MagickFalse)
8985 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8986 " Quantizing the pixel colors to 3-3-3-1");
8988 if (image->colormap == NULL)
8990 for (y=0; y < (ssize_t) image->rows; y++)
8992 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8994 if (r == (Quantum *) NULL)
8997 for (x=0; x < (ssize_t) image->columns; x++)
8999 if (GetPixelAlpha(image,r) == OpaqueAlpha)
9001 r+=GetPixelChannels(image);
9004 if (SyncAuthenticPixels(image,exception) == MagickFalse)
9009 else /* Should not reach this; colormap already exists and
9012 if (logging != MagickFalse)
9013 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9014 " Quantizing the colormap to 3-3-3-1");
9015 for (i=0; i<image_colors; i++)
9017 LBR03PacketRGB(image->colormap[i]);
9023 if (tried_332 == MagickFalse && (image_colors == 0 || image_colors > 256))
9025 if (logging != MagickFalse)
9026 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9027 " Quantizing the background color to 3-3-2");
9029 tried_332 = MagickTrue;
9031 /* Red and green were already done so we only quantize the blue
9035 LBR02PacketBlue(image->background_color);
9037 if (logging != MagickFalse)
9038 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9039 " Quantizing the pixel colors to 3-3-2-1");
9041 if (image->colormap == NULL)
9043 for (y=0; y < (ssize_t) image->rows; y++)
9045 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
9047 if (r == (Quantum *) NULL)
9050 for (x=0; x < (ssize_t) image->columns; x++)
9052 if (GetPixelAlpha(image,r) == OpaqueAlpha)
9054 r+=GetPixelChannels(image);
9057 if (SyncAuthenticPixels(image,exception) == MagickFalse)
9062 else /* Should not reach this; colormap already exists and
9065 if (logging != MagickFalse)
9066 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9067 " Quantizing the colormap to 3-3-2-1");
9068 for (i=0; i<image_colors; i++)
9070 LBR02PacketBlue(image->colormap[i]);
9077 if (image_colors == 0 || image_colors > 256)
9079 /* Take care of special case with 256 colors + 1 transparent
9080 * color. We don't need to quantize to 2-3-2-1; we only need to
9081 * eliminate one color, so we'll merge the two darkest red
9082 * colors (0x49, 0, 0) -> (0x24, 0, 0).
9084 if (ScaleQuantumToChar(image->background_color.red) == 0x49 &&
9085 ScaleQuantumToChar(image->background_color.green) == 0x00 &&
9086 ScaleQuantumToChar(image->background_color.blue) == 0x00)
9088 image->background_color.red=ScaleCharToQuantum(0x24);
9091 if (image->colormap == NULL)
9093 for (y=0; y < (ssize_t) image->rows; y++)
9095 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
9097 if (r == (Quantum *) NULL)
9100 for (x=0; x < (ssize_t) image->columns; x++)
9102 if (ScaleQuantumToChar(GetPixelRed(image,r)) == 0x49 &&
9103 ScaleQuantumToChar(GetPixelGreen(image,r)) == 0x00 &&
9104 ScaleQuantumToChar(GetPixelBlue(image,r)) == 0x00 &&
9105 GetPixelAlpha(image,r) == OpaqueAlpha)
9107 SetPixelRed(image,ScaleCharToQuantum(0x24),r);
9109 r+=GetPixelChannels(image);
9112 if (SyncAuthenticPixels(image,exception) == MagickFalse)
9120 for (i=0; i<image_colors; i++)
9122 if (ScaleQuantumToChar(image->colormap[i].red) == 0x49 &&
9123 ScaleQuantumToChar(image->colormap[i].green) == 0x00 &&
9124 ScaleQuantumToChar(image->colormap[i].blue) == 0x00)
9126 image->colormap[i].red=ScaleCharToQuantum(0x24);
9133 /* END OF BUILD_PALETTE */
9135 /* If we are excluding the tRNS chunk and there is transparency,
9136 * then we must write a Gray-Alpha (color-type 4) or RGBA (color-type 6)
9139 if (mng_info->ping_exclude_tRNS != MagickFalse &&
9140 (number_transparent != 0 || number_semitransparent != 0))
9142 unsigned int colortype=mng_info->write_png_colortype;
9144 if (ping_have_color == MagickFalse)
9145 mng_info->write_png_colortype = 5;
9148 mng_info->write_png_colortype = 7;
9150 if (colortype != 0 &&
9151 mng_info->write_png_colortype != colortype)
9152 ping_need_colortype_warning=MagickTrue;
9156 /* See if cheap transparency is possible. It is only possible
9157 * when there is a single transparent color, no semitransparent
9158 * color, and no opaque color that has the same RGB components
9159 * as the transparent color. We only need this information if
9160 * we are writing a PNG with colortype 0 or 2, and we have not
9161 * excluded the tRNS chunk.
9163 if (number_transparent == 1 &&
9164 mng_info->write_png_colortype < 4)
9166 ping_have_cheap_transparency = MagickTrue;
9168 if (number_semitransparent != 0)
9169 ping_have_cheap_transparency = MagickFalse;
9171 else if (image_colors == 0 || image_colors > 256 ||
9172 image->colormap == NULL)
9174 register const Quantum
9177 for (y=0; y < (ssize_t) image->rows; y++)
9179 q=GetVirtualPixels(image,0,y,image->columns,1, exception);
9181 if (q == (Quantum *) NULL)
9184 for (x=0; x < (ssize_t) image->columns; x++)
9186 if (GetPixelAlpha(image,q) != TransparentAlpha &&
9187 (unsigned short) GetPixelRed(image,q) ==
9188 ping_trans_color.red &&
9189 (unsigned short) GetPixelGreen(image,q) ==
9190 ping_trans_color.green &&
9191 (unsigned short) GetPixelBlue(image,q) ==
9192 ping_trans_color.blue)
9194 ping_have_cheap_transparency = MagickFalse;
9198 q+=GetPixelChannels(image);
9201 if (ping_have_cheap_transparency == MagickFalse)
9207 /* Assuming that image->colormap[0] is the one transparent color
9208 * and that all others are opaque.
9210 if (image_colors > 1)
9211 for (i=1; i<image_colors; i++)
9212 if (image->colormap[i].red == image->colormap[0].red &&
9213 image->colormap[i].green == image->colormap[0].green &&
9214 image->colormap[i].blue == image->colormap[0].blue)
9216 ping_have_cheap_transparency = MagickFalse;
9221 if (logging != MagickFalse)
9223 if (ping_have_cheap_transparency == MagickFalse)
9224 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9225 " Cheap transparency is not possible.");
9228 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9229 " Cheap transparency is possible.");
9233 ping_have_cheap_transparency = MagickFalse;
9235 image_depth=image->depth;
9237 quantum_info = (QuantumInfo *) NULL;
9239 image_colors=(int) image->colors;
9240 image_matte=image->alpha_trait == BlendPixelTrait ? MagickTrue : MagickFalse;
9242 mng_info->IsPalette=image->storage_class == PseudoClass &&
9243 image_colors <= 256 && image->colormap != NULL;
9245 if ((mng_info->write_png_colortype == 4 || mng_info->write_png8) &&
9246 (image->colors == 0 || image->colormap == NULL))
9248 image_info=DestroyImageInfo(image_info);
9249 image=DestroyImage(image);
9250 (void) ThrowMagickException(exception,GetMagickModule(),CoderError,
9251 "Cannot write PNG8 or color-type 3; colormap is NULL",
9252 "`%s'",IMimage->filename);
9253 return(MagickFalse);
9257 Allocate the PNG structures
9259 #ifdef PNG_USER_MEM_SUPPORTED
9260 error_info.image=image;
9261 error_info.exception=exception;
9262 ping=png_create_write_struct_2(PNG_LIBPNG_VER_STRING,&error_info,
9263 MagickPNGErrorHandler,MagickPNGWarningHandler,(void *) NULL,
9264 (png_malloc_ptr) Magick_png_malloc,(png_free_ptr) Magick_png_free);
9267 ping=png_create_write_struct(PNG_LIBPNG_VER_STRING,&error_info,
9268 MagickPNGErrorHandler,MagickPNGWarningHandler);
9271 if (ping == (png_struct *) NULL)
9272 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
9274 ping_info=png_create_info_struct(ping);
9276 if (ping_info == (png_info *) NULL)
9278 png_destroy_write_struct(&ping,(png_info **) NULL);
9279 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
9282 png_set_write_fn(ping,image,png_put_data,png_flush_data);
9283 ping_pixels=(unsigned char *) NULL;
9285 if (setjmp(png_jmpbuf(ping)))
9291 if (image_info->verbose)
9292 (void) printf("PNG write has failed.\n");
9294 png_destroy_write_struct(&ping,&ping_info);
9295 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
9296 UnlockSemaphoreInfo(ping_semaphore);
9299 if (ping_pixels != (unsigned char *) NULL)
9300 ping_pixels=(unsigned char *) RelinquishMagickMemory(ping_pixels);
9302 if (quantum_info != (QuantumInfo *) NULL)
9303 quantum_info=DestroyQuantumInfo(quantum_info);
9305 if (ping_have_blob != MagickFalse)
9306 (void) CloseBlob(image);
9307 image_info=DestroyImageInfo(image_info);
9308 image=DestroyImage(image);
9309 return(MagickFalse);
9312 /* { For navigation to end of SETJMP-protected block. Within this
9313 * block, use png_error() instead of Throwing an Exception, to ensure
9314 * that libpng is able to clean up, and that the semaphore is unlocked.
9317 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
9318 LockSemaphoreInfo(ping_semaphore);
9322 Prepare PNG for writing.
9325 #if defined(PNG_MNG_FEATURES_SUPPORTED)
9326 if (mng_info->write_mng)
9328 (void) png_permit_mng_features(ping,PNG_ALL_MNG_FEATURES);
9329 # ifdef PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED
9330 /* Disable new libpng-1.5.10 feature when writing a MNG because
9331 * zero-length PLTE is OK
9333 png_set_check_for_invalid_index (ping, 0);
9338 # ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
9339 if (mng_info->write_mng)
9340 png_permit_empty_plte(ping,MagickTrue);
9347 ping_width=(png_uint_32) image->columns;
9348 ping_height=(png_uint_32) image->rows;
9350 if (mng_info->write_png8 || mng_info->write_png24 || mng_info->write_png32)
9353 if (mng_info->write_png48 || mng_info->write_png64)
9356 if (mng_info->write_png_depth != 0)
9357 image_depth=mng_info->write_png_depth;
9359 /* Adjust requested depth to next higher valid depth if necessary */
9360 if (image_depth > 8)
9363 if ((image_depth > 4) && (image_depth < 8))
9366 if (image_depth == 3)
9369 if (logging != MagickFalse)
9371 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9372 " width=%.20g",(double) ping_width);
9373 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9374 " height=%.20g",(double) ping_height);
9375 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9376 " image_matte=%.20g",(double) image->alpha_trait);
9377 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9378 " image->depth=%.20g",(double) image->depth);
9379 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9380 " Tentative ping_bit_depth=%.20g",(double) image_depth);
9383 save_image_depth=image_depth;
9384 ping_bit_depth=(png_byte) save_image_depth;
9387 #if defined(PNG_pHYs_SUPPORTED)
9388 if (ping_exclude_pHYs == MagickFalse)
9390 if ((image->resolution.x != 0) && (image->resolution.y != 0) &&
9391 (!mng_info->write_mng || !mng_info->equal_physs))
9393 if (logging != MagickFalse)
9394 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9395 " Setting up pHYs chunk");
9397 if (image->units == PixelsPerInchResolution)
9399 ping_pHYs_unit_type=PNG_RESOLUTION_METER;
9400 ping_pHYs_x_resolution=
9401 (png_uint_32) ((100.0*image->resolution.x+0.5)/2.54);
9402 ping_pHYs_y_resolution=
9403 (png_uint_32) ((100.0*image->resolution.y+0.5)/2.54);
9406 else if (image->units == PixelsPerCentimeterResolution)
9408 ping_pHYs_unit_type=PNG_RESOLUTION_METER;
9409 ping_pHYs_x_resolution=(png_uint_32) (100.0*image->resolution.x+0.5);
9410 ping_pHYs_y_resolution=(png_uint_32) (100.0*image->resolution.y+0.5);
9415 ping_pHYs_unit_type=PNG_RESOLUTION_UNKNOWN;
9416 ping_pHYs_x_resolution=(png_uint_32) image->resolution.x;
9417 ping_pHYs_y_resolution=(png_uint_32) image->resolution.y;
9420 if (logging != MagickFalse)
9421 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9422 " Set up PNG pHYs chunk: xres: %.20g, yres: %.20g, units: %d.",
9423 (double) ping_pHYs_x_resolution,(double) ping_pHYs_y_resolution,
9424 (int) ping_pHYs_unit_type);
9425 ping_have_pHYs = MagickTrue;
9430 if (ping_exclude_bKGD == MagickFalse)
9432 if ((!mng_info->adjoin || !mng_info->equal_backgrounds))
9438 if (ping_bit_depth == 8)
9441 if (ping_bit_depth == 4)
9444 if (ping_bit_depth == 2)
9447 if (ping_bit_depth == 1)
9450 ping_background.red=(png_uint_16)
9451 (ScaleQuantumToShort(image->background_color.red) & mask);
9453 ping_background.green=(png_uint_16)
9454 (ScaleQuantumToShort(image->background_color.green) & mask);
9456 ping_background.blue=(png_uint_16)
9457 (ScaleQuantumToShort(image->background_color.blue) & mask);
9459 ping_background.gray=(png_uint_16) ping_background.green;
9462 if (logging != MagickFalse)
9464 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9465 " Setting up bKGD chunk (1)");
9466 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9467 " background_color index is %d",
9468 (int) ping_background.index);
9470 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9471 " ping_bit_depth=%d",ping_bit_depth);
9474 ping_have_bKGD = MagickTrue;
9478 Select the color type.
9483 if (mng_info->IsPalette && mng_info->write_png8)
9486 /* To do: make this a function cause it's used twice, except
9487 for reducing the sample depth from 8. */
9489 number_colors=image_colors;
9491 ping_have_tRNS=MagickFalse;
9496 ping_color_type=(png_byte) PNG_COLOR_TYPE_PALETTE;
9498 if (logging != MagickFalse)
9499 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9500 " Setting up PLTE chunk with %d colors (%d)",
9501 number_colors, image_colors);
9503 for (i=0; i < (ssize_t) number_colors; i++)
9505 palette[i].red=ScaleQuantumToChar(image->colormap[i].red);
9506 palette[i].green=ScaleQuantumToChar(image->colormap[i].green);
9507 palette[i].blue=ScaleQuantumToChar(image->colormap[i].blue);
9508 if (logging != MagickFalse)
9509 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9510 #if MAGICKCORE_QUANTUM_DEPTH == 8
9511 " %3ld (%3d,%3d,%3d)",
9513 " %5ld (%5d,%5d,%5d)",
9515 (long) i,palette[i].red,palette[i].green,palette[i].blue);
9519 ping_have_PLTE=MagickTrue;
9520 image_depth=ping_bit_depth;
9523 if (matte != MagickFalse)
9526 Identify which colormap entry is transparent.
9528 assert(number_colors <= 256);
9529 assert(image->colormap != NULL);
9531 for (i=0; i < (ssize_t) number_transparent; i++)
9532 ping_trans_alpha[i]=0;
9535 ping_num_trans=(unsigned short) (number_transparent +
9536 number_semitransparent);
9538 if (ping_num_trans == 0)
9539 ping_have_tRNS=MagickFalse;
9542 ping_have_tRNS=MagickTrue;
9545 if (ping_exclude_bKGD == MagickFalse)
9548 * Identify which colormap entry is the background color.
9551 for (i=0; i < (ssize_t) MagickMax(1L*number_colors-1L,1L); i++)
9552 if (IsPNGColorEqual(ping_background,image->colormap[i]))
9555 ping_background.index=(png_byte) i;
9557 if (logging != MagickFalse)
9559 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9560 " background_color index is %d",
9561 (int) ping_background.index);
9564 } /* end of write_png8 */
9566 else if (mng_info->write_png_colortype == 1)
9568 image_matte=MagickFalse;
9569 ping_color_type=(png_byte) PNG_COLOR_TYPE_GRAY;
9572 else if (mng_info->write_png24 || mng_info->write_png48 ||
9573 mng_info->write_png_colortype == 3)
9575 image_matte=MagickFalse;
9576 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB;
9579 else if (mng_info->write_png32 || mng_info->write_png64 ||
9580 mng_info->write_png_colortype == 7)
9582 image_matte=MagickTrue;
9583 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB_ALPHA;
9586 else /* mng_info->write_pngNN not specified */
9588 image_depth=ping_bit_depth;
9590 if (mng_info->write_png_colortype != 0)
9592 ping_color_type=(png_byte) mng_info->write_png_colortype-1;
9594 if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA ||
9595 ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA)
9596 image_matte=MagickTrue;
9599 image_matte=MagickFalse;
9601 if (logging != MagickFalse)
9602 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9603 " PNG colortype %d was specified:",(int) ping_color_type);
9606 else /* write_png_colortype not specified */
9608 if (logging != MagickFalse)
9609 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9610 " Selecting PNG colortype:");
9612 ping_color_type=(png_byte) ((matte != MagickFalse)?
9613 PNG_COLOR_TYPE_RGB_ALPHA:PNG_COLOR_TYPE_RGB);
9615 if (image_info->type == TrueColorType)
9617 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB;
9618 image_matte=MagickFalse;
9621 if (image_info->type == TrueColorMatteType)
9623 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB_ALPHA;
9624 image_matte=MagickTrue;
9627 if (image_info->type == PaletteType ||
9628 image_info->type == PaletteMatteType)
9629 ping_color_type=(png_byte) PNG_COLOR_TYPE_PALETTE;
9631 if (mng_info->write_png_colortype == 0 &&
9632 (image_info->type == UndefinedType ||
9633 image_info->type == OptimizeType))
9635 if (ping_have_color == MagickFalse)
9637 if (image_matte == MagickFalse)
9639 ping_color_type=(png_byte) PNG_COLOR_TYPE_GRAY;
9640 image_matte=MagickFalse;
9645 ping_color_type=(png_byte) PNG_COLOR_TYPE_GRAY_ALPHA;
9646 image_matte=MagickTrue;
9651 if (image_matte == MagickFalse)
9653 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB;
9654 image_matte=MagickFalse;
9659 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGBA;
9660 image_matte=MagickTrue;
9667 if (logging != MagickFalse)
9668 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9669 " Selected PNG colortype=%d",ping_color_type);
9671 if (ping_bit_depth < 8)
9673 if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA ||
9674 ping_color_type == PNG_COLOR_TYPE_RGB ||
9675 ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA)
9679 old_bit_depth=ping_bit_depth;
9681 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
9683 if (image->alpha_trait != BlendPixelTrait && ping_have_non_bw == MagickFalse)
9687 if (ping_color_type == PNG_COLOR_TYPE_PALETTE)
9692 if (image->colors == 0)
9695 png_error(ping,"image has 0 colors");
9698 while ((int) (one << ping_bit_depth) < (ssize_t) image_colors)
9699 ping_bit_depth <<= 1;
9702 if (logging != MagickFalse)
9704 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9705 " Number of colors: %.20g",(double) image_colors);
9707 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9708 " Tentative PNG bit depth: %d",ping_bit_depth);
9711 if (ping_bit_depth < (int) mng_info->write_png_depth)
9712 ping_bit_depth = mng_info->write_png_depth;
9715 image_depth=ping_bit_depth;
9717 if (logging != MagickFalse)
9719 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9720 " Tentative PNG color type: %s (%.20g)",
9721 PngColorTypeToString(ping_color_type),
9722 (double) ping_color_type);
9724 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9725 " image_info->type: %.20g",(double) image_info->type);
9727 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9728 " image_depth: %.20g",(double) image_depth);
9730 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9732 " image->depth: %.20g",(double) image->depth);
9734 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9735 " ping_bit_depth: %.20g",(double) ping_bit_depth);
9738 if (matte != MagickFalse)
9740 if (mng_info->IsPalette)
9742 if (mng_info->write_png_colortype == 0)
9744 ping_color_type=PNG_COLOR_TYPE_GRAY_ALPHA;
9746 if (ping_have_color != MagickFalse)
9747 ping_color_type=PNG_COLOR_TYPE_RGBA;
9751 * Determine if there is any transparent color.
9753 if (number_transparent + number_semitransparent == 0)
9756 No transparent pixels are present. Change 4 or 6 to 0 or 2.
9759 image_matte=MagickFalse;
9761 if (mng_info->write_png_colortype == 0)
9762 ping_color_type&=0x03;
9772 if (ping_bit_depth == 8)
9775 if (ping_bit_depth == 4)
9778 if (ping_bit_depth == 2)
9781 if (ping_bit_depth == 1)
9784 ping_trans_color.red=(png_uint_16)
9785 (ScaleQuantumToShort(image->colormap[0].red) & mask);
9787 ping_trans_color.green=(png_uint_16)
9788 (ScaleQuantumToShort(image->colormap[0].green) & mask);
9790 ping_trans_color.blue=(png_uint_16)
9791 (ScaleQuantumToShort(image->colormap[0].blue) & mask);
9793 ping_trans_color.gray=(png_uint_16)
9794 (ScaleQuantumToShort(GetPixelInfoIntensity(
9795 image->colormap)) & mask);
9797 ping_trans_color.index=(png_byte) 0;
9799 ping_have_tRNS=MagickTrue;
9802 if (ping_have_tRNS != MagickFalse)
9805 * Determine if there is one and only one transparent color
9806 * and if so if it is fully transparent.
9808 if (ping_have_cheap_transparency == MagickFalse)
9809 ping_have_tRNS=MagickFalse;
9812 if (ping_have_tRNS != MagickFalse)
9814 if (mng_info->write_png_colortype == 0)
9815 ping_color_type &= 0x03; /* changes 4 or 6 to 0 or 2 */
9817 if (image_depth == 8)
9819 ping_trans_color.red&=0xff;
9820 ping_trans_color.green&=0xff;
9821 ping_trans_color.blue&=0xff;
9822 ping_trans_color.gray&=0xff;
9828 if (image_depth == 8)
9830 ping_trans_color.red&=0xff;
9831 ping_trans_color.green&=0xff;
9832 ping_trans_color.blue&=0xff;
9833 ping_trans_color.gray&=0xff;
9840 if (ping_have_tRNS != MagickFalse)
9841 image_matte=MagickFalse;
9843 if ((mng_info->IsPalette) &&
9844 mng_info->write_png_colortype-1 != PNG_COLOR_TYPE_PALETTE &&
9845 ping_have_color == MagickFalse &&
9846 (image_matte == MagickFalse || image_depth >= 8))
9850 if (image_matte != MagickFalse)
9851 ping_color_type=PNG_COLOR_TYPE_GRAY_ALPHA;
9853 else if (mng_info->write_png_colortype-1 != PNG_COLOR_TYPE_GRAY_ALPHA)
9855 ping_color_type=PNG_COLOR_TYPE_GRAY;
9857 if (save_image_depth == 16 && image_depth == 8)
9859 if (logging != MagickFalse)
9861 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9862 " Scaling ping_trans_color (0)");
9864 ping_trans_color.gray*=0x0101;
9868 if (image_depth > MAGICKCORE_QUANTUM_DEPTH)
9869 image_depth=MAGICKCORE_QUANTUM_DEPTH;
9871 if ((image_colors == 0) ||
9872 ((ssize_t) (image_colors-1) > (ssize_t) MaxColormapSize))
9873 image_colors=(int) (one << image_depth);
9875 if (image_depth > 8)
9881 if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
9883 if(!mng_info->write_png_depth)
9887 while ((int) (one << ping_bit_depth)
9888 < (ssize_t) image_colors)
9889 ping_bit_depth <<= 1;
9893 else if (ping_color_type ==
9894 PNG_COLOR_TYPE_GRAY && image_colors < 17 &&
9895 mng_info->IsPalette)
9897 /* Check if grayscale is reducible */
9900 depth_4_ok=MagickTrue,
9901 depth_2_ok=MagickTrue,
9902 depth_1_ok=MagickTrue;
9904 for (i=0; i < (ssize_t) image_colors; i++)
9909 intensity=ScaleQuantumToChar(image->colormap[i].red);
9911 if ((intensity & 0x0f) != ((intensity & 0xf0) >> 4))
9912 depth_4_ok=depth_2_ok=depth_1_ok=MagickFalse;
9913 else if ((intensity & 0x03) != ((intensity & 0x0c) >> 2))
9914 depth_2_ok=depth_1_ok=MagickFalse;
9915 else if ((intensity & 0x01) != ((intensity & 0x02) >> 1))
9916 depth_1_ok=MagickFalse;
9919 if (depth_1_ok && mng_info->write_png_depth <= 1)
9922 else if (depth_2_ok && mng_info->write_png_depth <= 2)
9925 else if (depth_4_ok && mng_info->write_png_depth <= 4)
9930 image_depth=ping_bit_depth;
9935 if (mng_info->IsPalette)
9937 number_colors=image_colors;
9939 if (image_depth <= 8)
9944 ping_color_type=(png_byte) PNG_COLOR_TYPE_PALETTE;
9946 if (!(mng_info->have_write_global_plte && matte == MagickFalse))
9948 for (i=0; i < (ssize_t) number_colors; i++)
9950 palette[i].red=ScaleQuantumToChar(image->colormap[i].red);
9951 palette[i].green=ScaleQuantumToChar(image->colormap[i].green);
9952 palette[i].blue=ScaleQuantumToChar(image->colormap[i].blue);
9955 if (logging != MagickFalse)
9956 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9957 " Setting up PLTE chunk with %d colors",
9960 ping_have_PLTE=MagickTrue;
9963 /* color_type is PNG_COLOR_TYPE_PALETTE */
9964 if (mng_info->write_png_depth == 0)
9972 while ((one << ping_bit_depth) < (size_t) number_colors)
9973 ping_bit_depth <<= 1;
9978 if (matte != MagickFalse)
9981 * Set up trans_colors array.
9983 assert(number_colors <= 256);
9985 ping_num_trans=(unsigned short) (number_transparent +
9986 number_semitransparent);
9988 if (ping_num_trans == 0)
9989 ping_have_tRNS=MagickFalse;
9993 if (logging != MagickFalse)
9995 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9996 " Scaling ping_trans_color (1)");
9998 ping_have_tRNS=MagickTrue;
10000 for (i=0; i < ping_num_trans; i++)
10002 ping_trans_alpha[i]= (png_byte)
10003 ScaleQuantumToChar(image->colormap[i].alpha);
10013 if (image_depth < 8)
10016 if ((save_image_depth == 16) && (image_depth == 8))
10018 if (logging != MagickFalse)
10020 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10021 " Scaling ping_trans_color from (%d,%d,%d)",
10022 (int) ping_trans_color.red,
10023 (int) ping_trans_color.green,
10024 (int) ping_trans_color.blue);
10027 ping_trans_color.red*=0x0101;
10028 ping_trans_color.green*=0x0101;
10029 ping_trans_color.blue*=0x0101;
10030 ping_trans_color.gray*=0x0101;
10032 if (logging != MagickFalse)
10034 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10036 (int) ping_trans_color.red,
10037 (int) ping_trans_color.green,
10038 (int) ping_trans_color.blue);
10043 if (ping_bit_depth < (ssize_t) mng_info->write_png_depth)
10044 ping_bit_depth = (ssize_t) mng_info->write_png_depth;
10047 Adjust background and transparency samples in sub-8-bit grayscale files.
10049 if (ping_bit_depth < 8 && ping_color_type ==
10050 PNG_COLOR_TYPE_GRAY)
10058 maxval=(png_uint_16) ((one << ping_bit_depth)-1);
10060 if (ping_exclude_bKGD == MagickFalse)
10063 ping_background.gray=(png_uint_16) ((maxval/65535.)*
10064 (ScaleQuantumToShort(((GetPixelInfoIntensity(
10065 &image->background_color))) +.5)));
10067 if (logging != MagickFalse)
10068 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10069 " Setting up bKGD chunk (2)");
10070 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10071 " background_color index is %d",
10072 (int) ping_background.index);
10074 ping_have_bKGD = MagickTrue;
10077 if (logging != MagickFalse)
10078 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10079 " Scaling ping_trans_color.gray from %d",
10080 (int)ping_trans_color.gray);
10082 ping_trans_color.gray=(png_uint_16) ((maxval/255.)*(
10083 ping_trans_color.gray)+.5);
10085 if (logging != MagickFalse)
10086 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10087 " to %d", (int)ping_trans_color.gray);
10090 if (ping_exclude_bKGD == MagickFalse)
10092 if (mng_info->IsPalette && (int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
10095 Identify which colormap entry is the background color.
10098 number_colors=image_colors;
10100 for (i=0; i < (ssize_t) MagickMax(1L*number_colors,1L); i++)
10101 if (IsPNGColorEqual(image->background_color,image->colormap[i]))
10104 ping_background.index=(png_byte) i;
10106 if (logging != MagickFalse)
10108 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10109 " Setting up bKGD chunk with index=%d",(int) i);
10112 if (i < (ssize_t) number_colors)
10114 ping_have_bKGD = MagickTrue;
10116 if (logging != MagickFalse)
10118 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10119 " background =(%d,%d,%d)",
10120 (int) ping_background.red,
10121 (int) ping_background.green,
10122 (int) ping_background.blue);
10126 else /* Can't happen */
10128 if (logging != MagickFalse)
10129 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10130 " No room in PLTE to add bKGD color");
10131 ping_have_bKGD = MagickFalse;
10136 if (logging != MagickFalse)
10137 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10138 " PNG color type: %s (%d)", PngColorTypeToString(ping_color_type),
10141 Initialize compression level and filtering.
10143 if (logging != MagickFalse)
10145 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10146 " Setting up deflate compression");
10148 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10149 " Compression buffer size: 32768");
10152 png_set_compression_buffer_size(ping,32768L);
10154 if (logging != MagickFalse)
10155 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10156 " Compression mem level: 9");
10158 png_set_compression_mem_level(ping, 9);
10160 /* Untangle the "-quality" setting:
10162 Undefined is 0; the default is used.
10167 0: Use Z_HUFFMAN_ONLY strategy with the
10168 zlib default compression level
10170 1-9: the zlib compression level
10174 0-4: the PNG filter method
10176 5: libpng adaptive filtering if compression level > 5
10177 libpng filter type "none" if compression level <= 5
10178 or if image is grayscale or palette
10180 6: libpng adaptive filtering
10182 7: "LOCO" filtering (intrapixel differing) if writing
10183 a MNG, othewise "none". Did not work in IM-6.7.0-9
10184 and earlier because of a missing "else".
10186 8: Z_RLE strategy, all filters
10187 Unused prior to IM-6.7.0-10, was same as 6
10189 9: Z_RLE strategy, no PNG filters
10190 Unused prior to IM-6.7.0-10, was same as 6
10192 Note that using the -quality option, not all combinations of
10193 PNG filter type, zlib compression level, and zlib compression
10194 strategy are possible. This will be addressed soon in a
10195 release that accomodates "-define png:compression-strategy", etc.
10199 quality=image->quality == UndefinedCompressionQuality ? 75UL :
10204 if (mng_info->write_png_compression_strategy == 0)
10205 mng_info->write_png_compression_strategy = Z_HUFFMAN_ONLY+1;
10208 else if (mng_info->write_png_compression_level == 0)
10213 level=(int) MagickMin((ssize_t) quality/10,9);
10215 mng_info->write_png_compression_level = level+1;
10218 if (mng_info->write_png_compression_strategy == 0)
10220 if ((quality %10) == 8 || (quality %10) == 9)
10221 #ifdef Z_RLE /* Z_RLE was added to zlib-1.2.0 */
10222 mng_info->write_png_compression_strategy=Z_RLE+1;
10224 mng_info->write_png_compression_strategy = Z_DEFAULT_STRATEGY+1;
10228 if (mng_info->write_png_compression_filter == 0)
10229 mng_info->write_png_compression_filter=((int) quality % 10) + 1;
10231 if (logging != MagickFalse)
10233 if (mng_info->write_png_compression_level)
10234 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10235 " Compression level: %d",
10236 (int) mng_info->write_png_compression_level-1);
10238 if (mng_info->write_png_compression_strategy)
10239 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10240 " Compression strategy: %d",
10241 (int) mng_info->write_png_compression_strategy-1);
10243 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10244 " Setting up filtering");
10246 if (mng_info->write_png_compression_filter == 6)
10247 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10248 " Base filter method: ADAPTIVE");
10249 else if (mng_info->write_png_compression_filter == 0 ||
10250 mng_info->write_png_compression_filter == 1)
10251 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10252 " Base filter method: NONE");
10254 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10255 " Base filter method: %d",
10256 (int) mng_info->write_png_compression_filter-1);
10259 if (mng_info->write_png_compression_level != 0)
10260 png_set_compression_level(ping,mng_info->write_png_compression_level-1);
10262 if (mng_info->write_png_compression_filter == 6)
10264 if (((int) ping_color_type == PNG_COLOR_TYPE_GRAY) ||
10265 ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE) ||
10267 png_set_filter(ping,PNG_FILTER_TYPE_BASE,PNG_NO_FILTERS);
10269 png_set_filter(ping,PNG_FILTER_TYPE_BASE,PNG_ALL_FILTERS);
10271 else if (mng_info->write_png_compression_filter == 7 ||
10272 mng_info->write_png_compression_filter == 10)
10273 png_set_filter(ping,PNG_FILTER_TYPE_BASE,PNG_ALL_FILTERS);
10275 else if (mng_info->write_png_compression_filter == 8)
10277 #if defined(PNG_MNG_FEATURES_SUPPORTED) && defined(PNG_INTRAPIXEL_DIFFERENCING)
10278 if (mng_info->write_mng)
10280 if (((int) ping_color_type == PNG_COLOR_TYPE_RGB) ||
10281 ((int) ping_color_type == PNG_COLOR_TYPE_RGBA))
10282 ping_filter_method=PNG_INTRAPIXEL_DIFFERENCING;
10285 png_set_filter(ping,PNG_FILTER_TYPE_BASE,PNG_NO_FILTERS);
10288 else if (mng_info->write_png_compression_filter == 9)
10289 png_set_filter(ping,PNG_FILTER_TYPE_BASE,PNG_NO_FILTERS);
10291 else if (mng_info->write_png_compression_filter != 0)
10292 png_set_filter(ping,PNG_FILTER_TYPE_BASE,
10293 mng_info->write_png_compression_filter-1);
10295 if (mng_info->write_png_compression_strategy != 0)
10296 png_set_compression_strategy(ping,
10297 mng_info->write_png_compression_strategy-1);
10299 ping_interlace_method=image_info->interlace != NoInterlace;
10301 if (mng_info->write_mng)
10302 png_set_sig_bytes(ping,8);
10304 /* Bail out if cannot meet defined png:bit-depth or png:color-type */
10306 if (mng_info->write_png_colortype != 0)
10308 if (mng_info->write_png_colortype-1 == PNG_COLOR_TYPE_GRAY)
10309 if (ping_have_color != MagickFalse)
10311 ping_color_type = PNG_COLOR_TYPE_RGB;
10313 if (ping_bit_depth < 8)
10317 if (mng_info->write_png_colortype-1 == PNG_COLOR_TYPE_GRAY_ALPHA)
10318 if (ping_have_color != MagickFalse)
10319 ping_color_type = PNG_COLOR_TYPE_RGB_ALPHA;
10322 if (ping_need_colortype_warning != MagickFalse ||
10323 ((mng_info->write_png_depth &&
10324 (int) mng_info->write_png_depth != ping_bit_depth) ||
10325 (mng_info->write_png_colortype &&
10326 ((int) mng_info->write_png_colortype-1 != ping_color_type &&
10327 mng_info->write_png_colortype != 7 &&
10328 !(mng_info->write_png_colortype == 5 && ping_color_type == 0)))))
10330 if (logging != MagickFalse)
10332 if (ping_need_colortype_warning != MagickFalse)
10334 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10335 " Image has transparency but tRNS chunk was excluded");
10338 if (mng_info->write_png_depth)
10340 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10341 " Defined png:bit-depth=%u, Computed depth=%u",
10342 mng_info->write_png_depth,
10346 if (mng_info->write_png_colortype)
10348 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10349 " Defined png:color-type=%u, Computed color type=%u",
10350 mng_info->write_png_colortype-1,
10356 "Cannot write image with defined png:bit-depth or png:color-type.");
10359 if (image_matte != MagickFalse && image->alpha_trait != BlendPixelTrait)
10361 /* Add an opaque matte channel */
10362 image->alpha_trait = BlendPixelTrait;
10363 (void) SetImageAlpha(image,OpaqueAlpha,exception);
10365 if (logging != MagickFalse)
10366 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10367 " Added an opaque matte channel");
10370 if (number_transparent != 0 || number_semitransparent != 0)
10372 if (ping_color_type < 4)
10374 ping_have_tRNS=MagickTrue;
10375 if (logging != MagickFalse)
10376 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10377 " Setting ping_have_tRNS=MagickTrue.");
10381 if (logging != MagickFalse)
10382 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10383 " Writing PNG header chunks");
10385 png_set_IHDR(ping,ping_info,ping_width,ping_height,
10386 ping_bit_depth,ping_color_type,
10387 ping_interlace_method,ping_compression_method,
10388 ping_filter_method);
10390 if (ping_color_type == 3 && ping_have_PLTE != MagickFalse)
10392 png_set_PLTE(ping,ping_info,palette,number_colors);
10394 if (logging != MagickFalse)
10396 for (i=0; i< (ssize_t) number_colors; i++)
10398 if (i < ping_num_trans)
10399 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10400 " PLTE[%d] = (%d,%d,%d), tRNS[%d] = (%d)",
10402 (int) palette[i].red,
10403 (int) palette[i].green,
10404 (int) palette[i].blue,
10406 (int) ping_trans_alpha[i]);
10408 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10409 " PLTE[%d] = (%d,%d,%d)",
10411 (int) palette[i].red,
10412 (int) palette[i].green,
10413 (int) palette[i].blue);
10418 /* Only write the iCCP chunk if we are not writing the sRGB chunk. */
10419 if (ping_exclude_sRGB != MagickFalse ||
10420 (!png_get_valid(ping,ping_info,PNG_INFO_sRGB)))
10422 if ((ping_exclude_tEXt == MagickFalse ||
10423 ping_exclude_zTXt == MagickFalse) &&
10424 (ping_exclude_iCCP == MagickFalse || ping_exclude_zCCP == MagickFalse))
10426 ResetImageProfileIterator(image);
10427 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
10429 profile=GetImageProfile(image,name);
10431 if (profile != (StringInfo *) NULL)
10433 #ifdef PNG_WRITE_iCCP_SUPPORTED
10434 if ((LocaleCompare(name,"ICC") == 0) ||
10435 (LocaleCompare(name,"ICM") == 0))
10438 if (ping_exclude_iCCP == MagickFalse)
10440 png_set_iCCP(ping,ping_info,(png_charp) name,0,
10441 #if (PNG_LIBPNG_VER < 10500)
10442 (png_charp) GetStringInfoDatum(profile),
10444 (png_const_bytep) GetStringInfoDatum(profile),
10446 (png_uint_32) GetStringInfoLength(profile));
10452 if (ping_exclude_zCCP == MagickFalse)
10454 Magick_png_write_raw_profile(image_info,ping,ping_info,
10455 (unsigned char *) name,(unsigned char *) name,
10456 GetStringInfoDatum(profile),
10457 (png_uint_32) GetStringInfoLength(profile));
10461 if (logging != MagickFalse)
10462 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10463 " Setting up text chunk with %s profile",name);
10465 name=GetNextImageProfile(image);
10470 #if defined(PNG_WRITE_sRGB_SUPPORTED)
10471 if ((mng_info->have_write_global_srgb == 0) &&
10472 (png_get_valid(ping,ping_info,PNG_INFO_sRGB)))
10474 if (ping_exclude_sRGB == MagickFalse)
10477 Note image rendering intent.
10479 if (logging != MagickFalse)
10480 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10481 " Setting up sRGB chunk");
10483 (void) png_set_sRGB(ping,ping_info,(
10484 Magick_RenderingIntent_to_PNG_RenderingIntent(
10485 image->rendering_intent)));
10489 if ((!mng_info->write_mng) || (!png_get_valid(ping,ping_info,PNG_INFO_sRGB)))
10492 if (ping_exclude_gAMA == MagickFalse &&
10493 (ping_exclude_sRGB == MagickFalse ||
10494 (image->gamma < .45 || image->gamma > .46)))
10496 if ((mng_info->have_write_global_gama == 0) && (image->gamma != 0.0))
10500 To do: check for cHRM+gAMA == sRGB, and write sRGB instead.
10502 if (logging != MagickFalse)
10503 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10504 " Setting up gAMA chunk");
10506 png_set_gAMA(ping,ping_info,image->gamma);
10510 if (ping_exclude_cHRM == MagickFalse)
10512 if ((mng_info->have_write_global_chrm == 0) &&
10513 (image->chromaticity.red_primary.x != 0.0))
10516 Note image chromaticity.
10517 To do: check for cHRM+gAMA == sRGB, and write sRGB instead.
10525 wp=image->chromaticity.white_point;
10526 rp=image->chromaticity.red_primary;
10527 gp=image->chromaticity.green_primary;
10528 bp=image->chromaticity.blue_primary;
10530 if (logging != MagickFalse)
10531 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10532 " Setting up cHRM chunk");
10534 png_set_cHRM(ping,ping_info,wp.x,wp.y,rp.x,rp.y,gp.x,gp.y,
10540 if (ping_exclude_bKGD == MagickFalse)
10542 if (ping_have_bKGD != MagickFalse)
10544 png_set_bKGD(ping,ping_info,&ping_background);
10547 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10548 " Setting up bKGD chunk");
10549 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10550 " background color = (%d,%d,%d)",
10551 (int) ping_background.red,
10552 (int) ping_background.green,
10553 (int) ping_background.blue);
10554 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10555 " index = %d, gray=%d",
10556 (int) ping_background.index,
10557 (int) ping_background.gray);
10562 if (ping_exclude_pHYs == MagickFalse)
10564 if (ping_have_pHYs != MagickFalse)
10566 png_set_pHYs(ping,ping_info,
10567 ping_pHYs_x_resolution,
10568 ping_pHYs_y_resolution,
10569 ping_pHYs_unit_type);
10573 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10574 " Setting up pHYs chunk");
10575 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10576 " x_resolution=%lu",
10577 (unsigned long) ping_pHYs_x_resolution);
10578 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10579 " y_resolution=%lu",
10580 (unsigned long) ping_pHYs_y_resolution);
10581 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10583 (unsigned long) ping_pHYs_unit_type);
10588 #if defined(PNG_oFFs_SUPPORTED)
10589 if (ping_exclude_oFFs == MagickFalse)
10591 if (image->page.x || image->page.y)
10593 png_set_oFFs(ping,ping_info,(png_int_32) image->page.x,
10594 (png_int_32) image->page.y, 0);
10596 if (logging != MagickFalse)
10597 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10598 " Setting up oFFs chunk with x=%d, y=%d, units=0",
10599 (int) image->page.x, (int) image->page.y);
10604 if (mng_info->need_blob != MagickFalse)
10606 if (OpenBlob(image_info,image,WriteBinaryBlobMode,exception) ==
10608 png_error(ping,"WriteBlob Failed");
10610 ping_have_blob=MagickTrue;
10613 png_write_info_before_PLTE(ping, ping_info);
10615 if (ping_have_tRNS != MagickFalse && ping_color_type < 4)
10617 if (logging != MagickFalse)
10619 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10620 " Calling png_set_tRNS with num_trans=%d",ping_num_trans);
10623 if (ping_color_type == 3)
10624 (void) png_set_tRNS(ping, ping_info,
10631 (void) png_set_tRNS(ping, ping_info,
10634 &ping_trans_color);
10636 if (logging != MagickFalse)
10638 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10639 " tRNS color =(%d,%d,%d)",
10640 (int) ping_trans_color.red,
10641 (int) ping_trans_color.green,
10642 (int) ping_trans_color.blue);
10647 /* write any png-chunk-b profiles */
10648 (void) Magick_png_write_chunk_from_profile(image,"PNG-chunk-b",logging);
10650 png_write_info(ping,ping_info);
10652 /* write any PNG-chunk-m profiles */
10653 (void) Magick_png_write_chunk_from_profile(image,"PNG-chunk-m",logging);
10655 if (ping_exclude_vpAg == MagickFalse)
10657 if ((image->page.width != 0 && image->page.width != image->columns) ||
10658 (image->page.height != 0 && image->page.height != image->rows))
10663 (void) WriteBlobMSBULong(image,9L); /* data length=8 */
10664 PNGType(chunk,mng_vpAg);
10665 LogPNGChunk(logging,mng_vpAg,9L);
10666 PNGLong(chunk+4,(png_uint_32) image->page.width);
10667 PNGLong(chunk+8,(png_uint_32) image->page.height);
10668 chunk[12]=0; /* unit = pixels */
10669 (void) WriteBlob(image,13,chunk);
10670 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
10674 #if (PNG_LIBPNG_VER == 10206)
10675 /* avoid libpng-1.2.6 bug by setting PNG_HAVE_IDAT flag */
10676 #define PNG_HAVE_IDAT 0x04
10677 ping->mode |= PNG_HAVE_IDAT;
10678 #undef PNG_HAVE_IDAT
10681 png_set_packing(ping);
10685 rowbytes=image->columns;
10686 if (image_depth > 8)
10688 switch (ping_color_type)
10690 case PNG_COLOR_TYPE_RGB:
10694 case PNG_COLOR_TYPE_GRAY_ALPHA:
10698 case PNG_COLOR_TYPE_RGBA:
10706 if (logging != MagickFalse)
10708 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10709 " Writing PNG image data");
10711 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10712 " Allocating %.20g bytes of memory for pixels",(double) rowbytes);
10714 ping_pixels=(unsigned char *) AcquireQuantumMemory(rowbytes,
10715 sizeof(*ping_pixels));
10717 if (ping_pixels == (unsigned char *) NULL)
10718 png_error(ping,"Allocation of memory for pixels failed");
10721 Initialize image scanlines.
10723 quantum_info=AcquireQuantumInfo(image_info,image);
10724 if (quantum_info == (QuantumInfo *) NULL)
10725 png_error(ping,"Memory allocation for quantum_info failed");
10726 quantum_info->format=UndefinedQuantumFormat;
10727 quantum_info->depth=image_depth;
10728 (void) SetQuantumEndian(image,quantum_info,MSBEndian);
10729 num_passes=png_set_interlace_handling(ping);
10731 if ((!mng_info->write_png8 && !mng_info->write_png24 &&
10732 !mng_info->write_png48 && !mng_info->write_png64 &&
10733 !mng_info->write_png32) &&
10734 (mng_info->IsPalette ||
10735 (image_info->type == BilevelType)) &&
10736 image_matte == MagickFalse &&
10737 ping_have_non_bw == MagickFalse)
10739 /* Palette, Bilevel, or Opaque Monochrome */
10740 register const Quantum
10743 quantum_info->depth=8;
10744 for (pass=0; pass < num_passes; pass++)
10747 Convert PseudoClass image to a PNG monochrome image.
10749 for (y=0; y < (ssize_t) image->rows; y++)
10751 if (logging != MagickFalse && y == 0)
10752 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10753 " Writing row of pixels (0)");
10755 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
10757 if (p == (const Quantum *) NULL)
10760 if (mng_info->IsPalette)
10762 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10763 quantum_info,GrayQuantum,ping_pixels,exception);
10764 if (mng_info->write_png_colortype-1 == PNG_COLOR_TYPE_PALETTE &&
10765 mng_info->write_png_depth &&
10766 mng_info->write_png_depth != old_bit_depth)
10768 /* Undo pixel scaling */
10769 for (i=0; i < (ssize_t) image->columns; i++)
10770 *(ping_pixels+i)=(unsigned char) (*(ping_pixels+i)
10771 >> (8-old_bit_depth));
10777 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10778 quantum_info,RedQuantum,ping_pixels,exception);
10781 if (mng_info->write_png_colortype-1 != PNG_COLOR_TYPE_PALETTE)
10782 for (i=0; i < (ssize_t) image->columns; i++)
10783 *(ping_pixels+i)=(unsigned char) ((*(ping_pixels+i) > 127) ?
10786 if (logging != MagickFalse && y == 0)
10787 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10788 " Writing row of pixels (1)");
10790 png_write_row(ping,ping_pixels);
10792 if (image->previous == (Image *) NULL)
10794 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
10795 if (status == MagickFalse)
10801 else /* Not Palette, Bilevel, or Opaque Monochrome */
10803 if ((!mng_info->write_png8 && !mng_info->write_png24 &&
10804 !mng_info->write_png48 && !mng_info->write_png64 &&
10805 !mng_info->write_png32) && (image_matte != MagickFalse ||
10806 (ping_bit_depth >= MAGICKCORE_QUANTUM_DEPTH)) &&
10807 (mng_info->IsPalette) && ping_have_color == MagickFalse)
10809 register const Quantum
10812 for (pass=0; pass < num_passes; pass++)
10815 for (y=0; y < (ssize_t) image->rows; y++)
10817 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
10819 if (p == (const Quantum *) NULL)
10822 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
10824 if (mng_info->IsPalette)
10825 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10826 quantum_info,GrayQuantum,ping_pixels,exception);
10829 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10830 quantum_info,RedQuantum,ping_pixels,exception);
10832 if (logging != MagickFalse && y == 0)
10833 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10834 " Writing GRAY PNG pixels (2)");
10837 else /* PNG_COLOR_TYPE_GRAY_ALPHA */
10839 if (logging != MagickFalse && y == 0)
10840 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10841 " Writing GRAY_ALPHA PNG pixels (2)");
10843 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10844 quantum_info,GrayAlphaQuantum,ping_pixels,exception);
10847 if (logging != MagickFalse && y == 0)
10848 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10849 " Writing row of pixels (2)");
10851 png_write_row(ping,ping_pixels);
10854 if (image->previous == (Image *) NULL)
10856 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
10857 if (status == MagickFalse)
10865 register const Quantum
10868 for (pass=0; pass < num_passes; pass++)
10870 if ((image_depth > 8) ||
10871 mng_info->write_png24 ||
10872 mng_info->write_png32 ||
10873 mng_info->write_png48 ||
10874 mng_info->write_png64 ||
10875 (!mng_info->write_png8 && !mng_info->IsPalette))
10877 for (y=0; y < (ssize_t) image->rows; y++)
10879 p=GetVirtualPixels(image,0,y,image->columns,1, exception);
10881 if (p == (const Quantum *) NULL)
10884 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
10886 if (image->storage_class == DirectClass)
10887 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10888 quantum_info,RedQuantum,ping_pixels,exception);
10891 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10892 quantum_info,GrayQuantum,ping_pixels,exception);
10895 else if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
10897 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10898 quantum_info,GrayAlphaQuantum,ping_pixels,
10901 if (logging != MagickFalse && y == 0)
10902 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10903 " Writing GRAY_ALPHA PNG pixels (3)");
10906 else if (image_matte != MagickFalse)
10907 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10908 quantum_info,RGBAQuantum,ping_pixels,exception);
10911 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10912 quantum_info,RGBQuantum,ping_pixels,exception);
10914 if (logging != MagickFalse && y == 0)
10915 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10916 " Writing row of pixels (3)");
10918 png_write_row(ping,ping_pixels);
10923 /* not ((image_depth > 8) ||
10924 mng_info->write_png24 || mng_info->write_png32 ||
10925 mng_info->write_png48 || mng_info->write_png64 ||
10926 (!mng_info->write_png8 && !mng_info->IsPalette))
10929 if ((ping_color_type != PNG_COLOR_TYPE_GRAY) &&
10930 (ping_color_type != PNG_COLOR_TYPE_GRAY_ALPHA))
10932 if (logging != MagickFalse)
10933 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10934 " pass %d, Image Is not GRAY or GRAY_ALPHA",pass);
10936 quantum_info->depth=8;
10940 for (y=0; y < (ssize_t) image->rows; y++)
10942 if (logging != MagickFalse && y == 0)
10943 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10944 " pass %d, Image Is RGB, 16-bit GRAY, or GRAY_ALPHA",pass);
10946 p=GetVirtualPixels(image,0,y,image->columns,1, exception);
10948 if (p == (const Quantum *) NULL)
10951 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
10953 quantum_info->depth=image->depth;
10955 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10956 quantum_info,GrayQuantum,ping_pixels,exception);
10959 else if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
10961 if (logging != MagickFalse && y == 0)
10962 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10963 " Writing GRAY_ALPHA PNG pixels (4)");
10965 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10966 quantum_info,GrayAlphaQuantum,ping_pixels,
10972 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10973 quantum_info,IndexQuantum,ping_pixels,exception);
10975 if (logging != MagickFalse && y <= 2)
10977 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10978 " Writing row of non-gray pixels (4)");
10980 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10981 " ping_pixels[0]=%d,ping_pixels[1]=%d",
10982 (int)ping_pixels[0],(int)ping_pixels[1]);
10985 png_write_row(ping,ping_pixels);
10989 if (image->previous == (Image *) NULL)
10991 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
10992 if (status == MagickFalse)
10999 if (quantum_info != (QuantumInfo *) NULL)
11000 quantum_info=DestroyQuantumInfo(quantum_info);
11002 if (logging != MagickFalse)
11004 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11005 " Wrote PNG image data");
11007 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11008 " Width: %.20g",(double) ping_width);
11010 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11011 " Height: %.20g",(double) ping_height);
11013 if (mng_info->write_png_depth)
11015 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11016 " Defined png:bit-depth: %d",mng_info->write_png_depth);
11019 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11020 " PNG bit-depth written: %d",ping_bit_depth);
11022 if (mng_info->write_png_colortype)
11024 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11025 " Defined png:color-type: %d",mng_info->write_png_colortype-1);
11028 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11029 " PNG color-type written: %d",ping_color_type);
11031 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11032 " PNG Interlace method: %d",ping_interlace_method);
11035 Generate text chunks after IDAT.
11037 if (ping_exclude_tEXt == MagickFalse || ping_exclude_zTXt == MagickFalse)
11039 ResetImagePropertyIterator(image);
11040 property=GetNextImageProperty(image);
11041 while (property != (const char *) NULL)
11046 value=GetImageProperty(image,property,exception);
11048 /* Don't write any "png:" properties; those are just for "identify" */
11049 if (LocaleNCompare(property,"png:",4) != 0 &&
11051 /* Suppress density and units if we wrote a pHYs chunk */
11052 (ping_exclude_pHYs != MagickFalse ||
11053 LocaleCompare(property,"density") != 0 ||
11054 LocaleCompare(property,"units") != 0) &&
11056 /* Suppress the IM-generated Date:create and Date:modify */
11057 (ping_exclude_date == MagickFalse ||
11058 LocaleNCompare(property, "Date:",5) != 0))
11060 if (value != (const char *) NULL)
11063 #if PNG_LIBPNG_VER >= 14000
11064 text=(png_textp) png_malloc(ping,
11065 (png_alloc_size_t) sizeof(png_text));
11067 text=(png_textp) png_malloc(ping,(png_size_t) sizeof(png_text));
11069 text[0].key=(char *) property;
11070 text[0].text=(char *) value;
11071 text[0].text_length=strlen(value);
11073 if (ping_exclude_tEXt != MagickFalse)
11074 text[0].compression=PNG_TEXT_COMPRESSION_zTXt;
11076 else if (ping_exclude_zTXt != MagickFalse)
11077 text[0].compression=PNG_TEXT_COMPRESSION_NONE;
11081 text[0].compression=image_info->compression == NoCompression ||
11082 (image_info->compression == UndefinedCompression &&
11083 text[0].text_length < 128) ? PNG_TEXT_COMPRESSION_NONE :
11084 PNG_TEXT_COMPRESSION_zTXt ;
11087 if (logging != MagickFalse)
11089 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11090 " Setting up text chunk");
11092 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11093 " keyword: '%s'",text[0].key);
11096 png_set_text(ping,ping_info,text,1);
11097 png_free(ping,text);
11100 property=GetNextImageProperty(image);
11104 /* write any PNG-chunk-e profiles */
11105 (void) Magick_png_write_chunk_from_profile(image,"PNG-chunk-e",logging);
11107 if (logging != MagickFalse)
11108 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11109 " Writing PNG end info");
11111 png_write_end(ping,ping_info);
11113 if (mng_info->need_fram && (int) image->dispose == BackgroundDispose)
11115 if (mng_info->page.x || mng_info->page.y ||
11116 (ping_width != mng_info->page.width) ||
11117 (ping_height != mng_info->page.height))
11123 Write FRAM 4 with clipping boundaries followed by FRAM 1.
11125 (void) WriteBlobMSBULong(image,27L); /* data length=27 */
11126 PNGType(chunk,mng_FRAM);
11127 LogPNGChunk(logging,mng_FRAM,27L);
11129 chunk[5]=0; /* frame name separator (no name) */
11130 chunk[6]=1; /* flag for changing delay, for next frame only */
11131 chunk[7]=0; /* flag for changing frame timeout */
11132 chunk[8]=1; /* flag for changing frame clipping for next frame */
11133 chunk[9]=0; /* flag for changing frame sync_id */
11134 PNGLong(chunk+10,(png_uint_32) (0L)); /* temporary 0 delay */
11135 chunk[14]=0; /* clipping boundaries delta type */
11136 PNGLong(chunk+15,(png_uint_32) (mng_info->page.x)); /* left cb */
11138 (png_uint_32) (mng_info->page.x + ping_width));
11139 PNGLong(chunk+23,(png_uint_32) (mng_info->page.y)); /* top cb */
11141 (png_uint_32) (mng_info->page.y + ping_height));
11142 (void) WriteBlob(image,31,chunk);
11143 (void) WriteBlobMSBULong(image,crc32(0,chunk,31));
11144 mng_info->old_framing_mode=4;
11145 mng_info->framing_mode=1;
11149 mng_info->framing_mode=3;
11151 if (mng_info->write_mng && !mng_info->need_fram &&
11152 ((int) image->dispose == 3))
11153 png_error(ping, "Cannot convert GIF with disposal method 3 to MNG-LC");
11156 Free PNG resources.
11159 png_destroy_write_struct(&ping,&ping_info);
11161 ping_pixels=(unsigned char *) RelinquishMagickMemory(ping_pixels);
11163 if (ping_have_blob != MagickFalse)
11164 (void) CloseBlob(image);
11166 image_info=DestroyImageInfo(image_info);
11167 image=DestroyImage(image);
11169 /* Store bit depth actually written */
11170 s[0]=(char) ping_bit_depth;
11173 (void) SetImageProperty(IMimage,"png:bit-depth-written",s,exception);
11175 if (logging != MagickFalse)
11176 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11177 " exit WriteOnePNGImage()");
11179 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
11180 UnlockSemaphoreInfo(ping_semaphore);
11183 /* } for navigation to beginning of SETJMP-protected block. Revert to
11184 * Throwing an Exception when an error occurs.
11187 return(MagickTrue);
11188 /* End write one PNG image */
11193 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11197 % W r i t e P N G I m a g e %
11201 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11203 % WritePNGImage() writes a Portable Network Graphics (PNG) or
11204 % Multiple-image Network Graphics (MNG) image file.
11206 % MNG support written by Glenn Randers-Pehrson, glennrp@image...
11208 % The format of the WritePNGImage method is:
11210 % MagickBooleanType WritePNGImage(const ImageInfo *image_info,
11211 % Image *image,ExceptionInfo *exception)
11213 % A description of each parameter follows:
11215 % o image_info: the image info.
11217 % o image: The image.
11219 % o exception: return any errors or warnings in this structure.
11221 % Returns MagickTrue on success, MagickFalse on failure.
11223 % Communicating with the PNG encoder:
11225 % While the datastream written is always in PNG format and normally would
11226 % be given the "png" file extension, this method also writes the following
11227 % pseudo-formats which are subsets of png:
11229 % o PNG8: An 8-bit indexed PNG datastream is written. If the image has
11230 % a depth greater than 8, the depth is reduced. If transparency
11231 % is present, the tRNS chunk must only have values 0 and 255
11232 % (i.e., transparency is binary: fully opaque or fully
11233 % transparent). If other values are present they will be
11234 % 50%-thresholded to binary transparency. If more than 256
11235 % colors are present, they will be quantized to the 4-4-4-1,
11236 % 3-3-3-1, or 3-3-2-1 palette. The underlying RGB color
11237 % of any resulting fully-transparent pixels is changed to
11238 % the image's background color.
11240 % If you want better quantization or dithering of the colors
11241 % or alpha than that, you need to do it before calling the
11242 % PNG encoder. The pixels contain 8-bit indices even if
11243 % they could be represented with 1, 2, or 4 bits. Grayscale
11244 % images will be written as indexed PNG files even though the
11245 % PNG grayscale type might be slightly more efficient. Please
11246 % note that writing to the PNG8 format may result in loss
11247 % of color and alpha data.
11249 % o PNG24: An 8-bit per sample RGB PNG datastream is written. The tRNS
11250 % chunk can be present to convey binary transparency by naming
11251 % one of the colors as transparent. The only loss incurred
11252 % is reduction of sample depth to 8. If the image has more
11253 % than one transparent color, has semitransparent pixels, or
11254 % has an opaque pixel with the same RGB components as the
11255 % transparent color, an image is not written.
11257 % o PNG32: An 8-bit per sample RGBA PNG is written. Partial
11258 % transparency is permitted, i.e., the alpha sample for
11259 % each pixel can have any value from 0 to 255. The alpha
11260 % channel is present even if the image is fully opaque.
11261 % The only loss in data is the reduction of the sample depth
11264 % o PNG48: A 16-bit per sample RGB PNG datastream is written. The tRNS
11265 % chunk can be present to convey binary transparency by naming
11266 % one of the colors as transparent. If the image has more
11267 % than one transparent color, has semitransparent pixels, or
11268 % has an opaque pixel with the same RGB components as the
11269 % transparent color, an image is not written.
11271 % o PNG64: A 16-bit per sample RGBA PNG is written. Partial
11272 % transparency is permitted, i.e., the alpha sample for
11273 % each pixel can have any value from 0 to 65535. The alpha
11274 % channel is present even if the image is fully opaque.
11276 % o PNG00: A PNG that inherits its colortype and bit-depth from the input
11277 % image, if the input was a PNG, is written. If these values
11278 % cannot be found, then "PNG00" falls back to the regular "PNG"
11281 % o -define: For more precise control of the PNG output, you can use the
11282 % Image options "png:bit-depth" and "png:color-type". These
11283 % can be set from the commandline with "-define" and also
11284 % from the application programming interfaces. The options
11285 % are case-independent and are converted to lowercase before
11286 % being passed to this encoder.
11288 % png:color-type can be 0, 2, 3, 4, or 6.
11290 % When png:color-type is 0 (Grayscale), png:bit-depth can
11291 % be 1, 2, 4, 8, or 16.
11293 % When png:color-type is 2 (RGB), png:bit-depth can
11296 % When png:color-type is 3 (Indexed), png:bit-depth can
11297 % be 1, 2, 4, or 8. This refers to the number of bits
11298 % used to store the index. The color samples always have
11299 % bit-depth 8 in indexed PNG files.
11301 % When png:color-type is 4 (Gray-Matte) or 6 (RGB-Matte),
11302 % png:bit-depth can be 8 or 16.
11304 % If the image cannot be written without loss with the
11305 % requested bit-depth and color-type, a PNG file will not
11306 % be written, a warning will be issued, and the encoder will
11307 % return MagickFalse.
11309 % Since image encoders should not be responsible for the "heavy lifting",
11310 % the user should make sure that ImageMagick has already reduced the
11311 % image depth and number of colors and limit transparency to binary
11312 % transparency prior to attempting to write the image with depth, color,
11313 % or transparency limitations.
11315 % Note that another definition, "png:bit-depth-written" exists, but it
11316 % is not intended for external use. It is only used internally by the
11317 % PNG encoder to inform the JNG encoder of the depth of the alpha channel.
11319 % It is possible to request that the PNG encoder write previously-formatted
11320 % ancillary chunks in the output PNG file, using the "-profile" commandline
11321 % option as shown below or by setting the profile via a programming
11324 % -profile PNG-chunk-x:<file>
11326 % where x is a location flag and <file> is a file containing the chunk
11327 % name in the first 4 bytes, then a colon (":"), followed by the chunk data.
11328 % This encoder will compute the chunk length and CRC, so those must not
11329 % be included in the file.
11331 % "x" can be "b" (before PLTE), "m" (middle, i.e., between PLTE and IDAT),
11332 % or "e" (end, i.e., after IDAT). If you want to write multiple chunks
11333 % of the same type, then add a short unique string after the "x" to prevent
11334 % subsequent profiles from overwriting the preceding ones, e.g.,
11336 % -profile PNG-chunk-b01:file01 -profile PNG-chunk-b02:file02
11338 % As of version 6.6.6 the following optimizations are always done:
11340 % o 32-bit depth is reduced to 16.
11341 % o 16-bit depth is reduced to 8 if all pixels contain samples whose
11342 % high byte and low byte are identical.
11343 % o Palette is sorted to remove unused entries and to put a
11344 % transparent color first, if BUILD_PNG_PALETTE is defined.
11345 % o Opaque matte channel is removed when writing an indexed PNG.
11346 % o Grayscale images are reduced to 1, 2, or 4 bit depth if
11347 % this can be done without loss and a larger bit depth N was not
11348 % requested via the "-define png:bit-depth=N" option.
11349 % o If matte channel is present but only one transparent color is
11350 % present, RGB+tRNS is written instead of RGBA
11351 % o Opaque matte channel is removed (or added, if color-type 4 or 6
11352 % was requested when converting an opaque image).
11354 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11356 static MagickBooleanType WritePNGImage(const ImageInfo *image_info,
11357 Image *image,ExceptionInfo *exception)
11362 have_mng_structure,
11378 assert(image_info != (const ImageInfo *) NULL);
11379 assert(image_info->signature == MagickSignature);
11380 assert(image != (Image *) NULL);
11381 assert(image->signature == MagickSignature);
11382 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
11383 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter WritePNGImage()");
11385 Allocate a MngInfo structure.
11387 have_mng_structure=MagickFalse;
11388 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
11390 if (mng_info == (MngInfo *) NULL)
11391 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
11394 Initialize members of the MngInfo structure.
11396 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
11397 mng_info->image=image;
11398 mng_info->equal_backgrounds=MagickTrue;
11399 have_mng_structure=MagickTrue;
11401 /* See if user has requested a specific PNG subformat */
11403 mng_info->write_png8=LocaleCompare(image_info->magick,"PNG8") == 0;
11404 mng_info->write_png24=LocaleCompare(image_info->magick,"PNG24") == 0;
11405 mng_info->write_png32=LocaleCompare(image_info->magick,"PNG32") == 0;
11406 mng_info->write_png48=LocaleCompare(image_info->magick,"PNG48") == 0;
11407 mng_info->write_png64=LocaleCompare(image_info->magick,"PNG64") == 0;
11409 value=GetImageOption(image_info,"png:format");
11411 if (value != (char *) NULL)
11413 mng_info->write_png8 = MagickFalse;
11414 mng_info->write_png24 = MagickFalse;
11415 mng_info->write_png32 = MagickFalse;
11416 mng_info->write_png48 = MagickFalse;
11417 mng_info->write_png64 = MagickFalse;
11419 if (LocaleCompare(value,"png8") == 0)
11420 mng_info->write_png8 = MagickTrue;
11422 else if (LocaleCompare(value,"png24") == 0)
11423 mng_info->write_png24 = MagickTrue;
11425 else if (LocaleCompare(value,"png32") == 0)
11426 mng_info->write_png32 = MagickTrue;
11428 else if (LocaleCompare(value,"png48") == 0)
11429 mng_info->write_png48 = MagickTrue;
11431 else if (LocaleCompare(value,"png64") == 0)
11432 mng_info->write_png64 = MagickTrue;
11435 if (LocaleCompare(value,"png00") == 0)
11437 /* Retrieve png:IHDR.bit-depth-orig and png:IHDR.color-type-orig
11438 Note that whitespace at the end of the property names must match
11439 that in the corresponding SetImageProperty() calls.
11441 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11442 " Format=%s",value);
11444 value=GetImageProperty(image,"png:IHDR.bit-depth-orig ",exception);
11446 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11447 " png00 inherited bit depth=%s",value);
11449 if (value != (char *) NULL)
11451 if (LocaleCompare(value,"1") == 0)
11452 mng_info->write_png_depth = 1;
11454 else if (LocaleCompare(value,"1") == 0)
11455 mng_info->write_png_depth = 2;
11457 else if (LocaleCompare(value,"2") == 0)
11458 mng_info->write_png_depth = 4;
11460 else if (LocaleCompare(value,"8") == 0)
11461 mng_info->write_png_depth = 8;
11463 else if (LocaleCompare(value,"16") == 0)
11464 mng_info->write_png_depth = 16;
11467 value=GetImageProperty(image,"png:IHDR.color-type-orig ",exception);
11469 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11470 " png00 inherited color type=%s",value);
11472 if (value != (char *) NULL)
11474 if (LocaleCompare(value,"0") == 0)
11475 mng_info->write_png_colortype = 1;
11477 else if (LocaleCompare(value,"2") == 0)
11478 mng_info->write_png_colortype = 3;
11480 else if (LocaleCompare(value,"3") == 0)
11481 mng_info->write_png_colortype = 4;
11483 else if (LocaleCompare(value,"4") == 0)
11484 mng_info->write_png_colortype = 5;
11486 else if (LocaleCompare(value,"6") == 0)
11487 mng_info->write_png_colortype = 7;
11491 if (mng_info->write_png8)
11493 mng_info->write_png_colortype = /* 3 */ 4;
11494 mng_info->write_png_depth = 8;
11498 if (mng_info->write_png24)
11500 mng_info->write_png_colortype = /* 2 */ 3;
11501 mng_info->write_png_depth = 8;
11504 if (image->alpha_trait == BlendPixelTrait)
11505 (void) SetImageType(image,TrueColorMatteType,exception);
11508 (void) SetImageType(image,TrueColorType,exception);
11510 (void) SyncImage(image,exception);
11513 if (mng_info->write_png32)
11515 mng_info->write_png_colortype = /* 6 */ 7;
11516 mng_info->write_png_depth = 8;
11519 if (image->alpha_trait == BlendPixelTrait)
11520 (void) SetImageType(image,TrueColorMatteType,exception);
11523 (void) SetImageType(image,TrueColorType,exception);
11525 (void) SyncImage(image,exception);
11528 if (mng_info->write_png48)
11530 mng_info->write_png_colortype = /* 2 */ 3;
11531 mng_info->write_png_depth = 16;
11534 if (image->alpha_trait == BlendPixelTrait)
11535 (void) SetImageType(image,TrueColorMatteType,exception);
11538 (void) SetImageType(image,TrueColorType,exception);
11540 (void) SyncImage(image,exception);
11543 if (mng_info->write_png64)
11545 mng_info->write_png_colortype = /* 6 */ 7;
11546 mng_info->write_png_depth = 16;
11549 if (image->alpha_trait == BlendPixelTrait)
11550 (void) SetImageType(image,TrueColorMatteType,exception);
11553 (void) SetImageType(image,TrueColorType,exception);
11555 (void) SyncImage(image,exception);
11558 value=GetImageOption(image_info,"png:bit-depth");
11560 if (value != (char *) NULL)
11562 if (LocaleCompare(value,"1") == 0)
11563 mng_info->write_png_depth = 1;
11565 else if (LocaleCompare(value,"2") == 0)
11566 mng_info->write_png_depth = 2;
11568 else if (LocaleCompare(value,"4") == 0)
11569 mng_info->write_png_depth = 4;
11571 else if (LocaleCompare(value,"8") == 0)
11572 mng_info->write_png_depth = 8;
11574 else if (LocaleCompare(value,"16") == 0)
11575 mng_info->write_png_depth = 16;
11578 (void) ThrowMagickException(exception,
11579 GetMagickModule(),CoderWarning,
11580 "ignoring invalid defined png:bit-depth",
11583 if (logging != MagickFalse)
11584 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11585 " png:bit-depth=%d was defined.\n",mng_info->write_png_depth);
11588 value=GetImageOption(image_info,"png:color-type");
11590 if (value != (char *) NULL)
11592 /* We must store colortype+1 because 0 is a valid colortype */
11593 if (LocaleCompare(value,"0") == 0)
11594 mng_info->write_png_colortype = 1;
11596 else if (LocaleCompare(value,"1") == 0)
11597 mng_info->write_png_colortype = 2;
11599 else if (LocaleCompare(value,"2") == 0)
11600 mng_info->write_png_colortype = 3;
11602 else if (LocaleCompare(value,"3") == 0)
11603 mng_info->write_png_colortype = 4;
11605 else if (LocaleCompare(value,"4") == 0)
11606 mng_info->write_png_colortype = 5;
11608 else if (LocaleCompare(value,"6") == 0)
11609 mng_info->write_png_colortype = 7;
11612 (void) ThrowMagickException(exception,
11613 GetMagickModule(),CoderWarning,
11614 "ignoring invalid defined png:color-type",
11617 if (logging != MagickFalse)
11618 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11619 " png:color-type=%d was defined.\n",mng_info->write_png_colortype-1);
11622 /* Check for chunks to be excluded:
11624 * The default is to not exclude any known chunks except for any
11625 * listed in the "unused_chunks" array, above.
11627 * Chunks can be listed for exclusion via a "png:exclude-chunk"
11628 * define (in the image properties or in the image artifacts)
11629 * or via a mng_info member. For convenience, in addition
11630 * to or instead of a comma-separated list of chunks, the
11631 * "exclude-chunk" string can be simply "all" or "none".
11633 * The exclude-chunk define takes priority over the mng_info.
11635 * A "png:include-chunk" define takes priority over both the
11636 * mng_info and the "png:exclude-chunk" define. Like the
11637 * "exclude-chunk" string, it can define "all" or "none" as
11638 * well as a comma-separated list. Chunks that are unknown to
11639 * ImageMagick are always excluded, regardless of their "copy-safe"
11640 * status according to the PNG specification, and even if they
11641 * appear in the "include-chunk" list. Such defines appearing among
11642 * the image options take priority over those found among the image
11645 * Finally, all chunks listed in the "unused_chunks" array are
11646 * automatically excluded, regardless of the other instructions
11649 * if you exclude sRGB but not gAMA (recommended), then sRGB chunk
11650 * will not be written and the gAMA chunk will only be written if it
11651 * is not between .45 and .46, or approximately (1.0/2.2).
11653 * If you exclude tRNS and the image has transparency, the colortype
11654 * is forced to be 4 or 6 (GRAY_ALPHA or RGB_ALPHA).
11656 * The -strip option causes StripImage() to set the png:include-chunk
11657 * artifact to "none,trns,gama".
11660 mng_info->ping_exclude_bKGD=MagickFalse;
11661 mng_info->ping_exclude_cHRM=MagickFalse;
11662 mng_info->ping_exclude_date=MagickFalse;
11663 mng_info->ping_exclude_EXIF=MagickFalse; /* hex-encoded EXIF in zTXt */
11664 mng_info->ping_exclude_gAMA=MagickFalse;
11665 mng_info->ping_exclude_iCCP=MagickFalse;
11666 /* mng_info->ping_exclude_iTXt=MagickFalse; */
11667 mng_info->ping_exclude_oFFs=MagickFalse;
11668 mng_info->ping_exclude_pHYs=MagickFalse;
11669 mng_info->ping_exclude_sRGB=MagickFalse;
11670 mng_info->ping_exclude_tEXt=MagickFalse;
11671 mng_info->ping_exclude_tRNS=MagickFalse;
11672 mng_info->ping_exclude_vpAg=MagickFalse;
11673 mng_info->ping_exclude_zCCP=MagickFalse; /* hex-encoded iCCP in zTXt */
11674 mng_info->ping_exclude_zTXt=MagickFalse;
11676 mng_info->ping_preserve_colormap=MagickFalse;
11678 value=GetImageArtifact(image,"png:preserve-colormap");
11680 value=GetImageOption(image_info,"png:preserve-colormap");
11682 mng_info->ping_preserve_colormap=MagickTrue;
11684 /* Thes compression-level, compression-strategy, and compression-filter
11685 * defines take precedence over values from the -quality option.
11687 value=GetImageArtifact(image,"png:compression-level");
11689 value=GetImageOption(image_info,"png:compression-level");
11692 /* We have to add 1 to everything because 0 is a valid input,
11693 * and we want to use 0 (the default) to mean undefined.
11695 if (LocaleCompare(value,"0") == 0)
11696 mng_info->write_png_compression_level = 1;
11698 else if (LocaleCompare(value,"1") == 0)
11699 mng_info->write_png_compression_level = 2;
11701 else if (LocaleCompare(value,"2") == 0)
11702 mng_info->write_png_compression_level = 3;
11704 else if (LocaleCompare(value,"3") == 0)
11705 mng_info->write_png_compression_level = 4;
11707 else if (LocaleCompare(value,"4") == 0)
11708 mng_info->write_png_compression_level = 5;
11710 else if (LocaleCompare(value,"5") == 0)
11711 mng_info->write_png_compression_level = 6;
11713 else if (LocaleCompare(value,"6") == 0)
11714 mng_info->write_png_compression_level = 7;
11716 else if (LocaleCompare(value,"7") == 0)
11717 mng_info->write_png_compression_level = 8;
11719 else if (LocaleCompare(value,"8") == 0)
11720 mng_info->write_png_compression_level = 9;
11722 else if (LocaleCompare(value,"9") == 0)
11723 mng_info->write_png_compression_level = 10;
11726 (void) ThrowMagickException(exception,
11727 GetMagickModule(),CoderWarning,
11728 "ignoring invalid defined png:compression-level",
11732 value=GetImageArtifact(image,"png:compression-strategy");
11734 value=GetImageOption(image_info,"png:compression-strategy");
11738 if (LocaleCompare(value,"0") == 0)
11739 mng_info->write_png_compression_strategy = Z_DEFAULT_STRATEGY+1;
11741 else if (LocaleCompare(value,"1") == 0)
11742 mng_info->write_png_compression_strategy = Z_FILTERED+1;
11744 else if (LocaleCompare(value,"2") == 0)
11745 mng_info->write_png_compression_strategy = Z_HUFFMAN_ONLY+1;
11747 else if (LocaleCompare(value,"3") == 0)
11748 #ifdef Z_RLE /* Z_RLE was added to zlib-1.2.0 */
11749 mng_info->write_png_compression_strategy = Z_RLE+1;
11751 mng_info->write_png_compression_strategy = Z_DEFAULT_STRATEGY+1;
11754 else if (LocaleCompare(value,"4") == 0)
11755 #ifdef Z_FIXED /* Z_FIXED was added to zlib-1.2.2.2 */
11756 mng_info->write_png_compression_strategy = Z_FIXED+1;
11758 mng_info->write_png_compression_strategy = Z_DEFAULT_STRATEGY+1;
11762 (void) ThrowMagickException(exception,
11763 GetMagickModule(),CoderWarning,
11764 "ignoring invalid defined png:compression-strategy",
11768 value=GetImageArtifact(image,"png:compression-filter");
11770 value=GetImageOption(image_info,"png:compression-filter");
11774 /* To do: combinations of filters allowed by libpng
11775 * masks 0x08 through 0xf8
11777 * Implement this as a comma-separated list of 0,1,2,3,4,5
11778 * where 5 is a special case meaning PNG_ALL_FILTERS.
11781 if (LocaleCompare(value,"0") == 0)
11782 mng_info->write_png_compression_filter = 1;
11784 else if (LocaleCompare(value,"1") == 0)
11785 mng_info->write_png_compression_filter = 2;
11787 else if (LocaleCompare(value,"2") == 0)
11788 mng_info->write_png_compression_filter = 3;
11790 else if (LocaleCompare(value,"3") == 0)
11791 mng_info->write_png_compression_filter = 4;
11793 else if (LocaleCompare(value,"4") == 0)
11794 mng_info->write_png_compression_filter = 5;
11796 else if (LocaleCompare(value,"5") == 0)
11797 mng_info->write_png_compression_filter = 6;
11800 (void) ThrowMagickException(exception,
11801 GetMagickModule(),CoderWarning,
11802 "ignoring invalid defined png:compression-filter",
11806 excluding=MagickFalse;
11808 for (source=0; source<1; source++)
11812 value=GetImageArtifact(image,"png:exclude-chunk");
11815 value=GetImageArtifact(image,"png:exclude-chunks");
11819 value=GetImageOption(image_info,"png:exclude-chunk");
11822 value=GetImageOption(image_info,"png:exclude-chunks");
11831 excluding=MagickTrue;
11833 if (logging != MagickFalse)
11836 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11837 " png:exclude-chunk=%s found in image artifacts.\n", value);
11839 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11840 " png:exclude-chunk=%s found in image properties.\n", value);
11843 last=strlen(value);
11845 for (i=0; i<(int) last; i+=5)
11848 if (LocaleNCompare(value+i,"all",3) == 0)
11850 mng_info->ping_exclude_bKGD=MagickTrue;
11851 mng_info->ping_exclude_cHRM=MagickTrue;
11852 mng_info->ping_exclude_date=MagickTrue;
11853 mng_info->ping_exclude_EXIF=MagickTrue;
11854 mng_info->ping_exclude_gAMA=MagickTrue;
11855 mng_info->ping_exclude_iCCP=MagickTrue;
11856 /* mng_info->ping_exclude_iTXt=MagickTrue; */
11857 mng_info->ping_exclude_oFFs=MagickTrue;
11858 mng_info->ping_exclude_pHYs=MagickTrue;
11859 mng_info->ping_exclude_sRGB=MagickTrue;
11860 mng_info->ping_exclude_tEXt=MagickTrue;
11861 mng_info->ping_exclude_tRNS=MagickTrue;
11862 mng_info->ping_exclude_vpAg=MagickTrue;
11863 mng_info->ping_exclude_zCCP=MagickTrue;
11864 mng_info->ping_exclude_zTXt=MagickTrue;
11868 if (LocaleNCompare(value+i,"none",4) == 0)
11870 mng_info->ping_exclude_bKGD=MagickFalse;
11871 mng_info->ping_exclude_cHRM=MagickFalse;
11872 mng_info->ping_exclude_date=MagickFalse;
11873 mng_info->ping_exclude_EXIF=MagickFalse;
11874 mng_info->ping_exclude_gAMA=MagickFalse;
11875 mng_info->ping_exclude_iCCP=MagickFalse;
11876 /* mng_info->ping_exclude_iTXt=MagickFalse; */
11877 mng_info->ping_exclude_oFFs=MagickFalse;
11878 mng_info->ping_exclude_pHYs=MagickFalse;
11879 mng_info->ping_exclude_sRGB=MagickFalse;
11880 mng_info->ping_exclude_tEXt=MagickFalse;
11881 mng_info->ping_exclude_tRNS=MagickFalse;
11882 mng_info->ping_exclude_vpAg=MagickFalse;
11883 mng_info->ping_exclude_zCCP=MagickFalse;
11884 mng_info->ping_exclude_zTXt=MagickFalse;
11887 if (LocaleNCompare(value+i,"bkgd",4) == 0)
11888 mng_info->ping_exclude_bKGD=MagickTrue;
11890 if (LocaleNCompare(value+i,"chrm",4) == 0)
11891 mng_info->ping_exclude_cHRM=MagickTrue;
11893 if (LocaleNCompare(value+i,"date",4) == 0)
11894 mng_info->ping_exclude_date=MagickTrue;
11896 if (LocaleNCompare(value+i,"exif",4) == 0)
11897 mng_info->ping_exclude_EXIF=MagickTrue;
11899 if (LocaleNCompare(value+i,"gama",4) == 0)
11900 mng_info->ping_exclude_gAMA=MagickTrue;
11902 if (LocaleNCompare(value+i,"iccp",4) == 0)
11903 mng_info->ping_exclude_iCCP=MagickTrue;
11906 if (LocaleNCompare(value+i,"itxt",4) == 0)
11907 mng_info->ping_exclude_iTXt=MagickTrue;
11910 if (LocaleNCompare(value+i,"gama",4) == 0)
11911 mng_info->ping_exclude_gAMA=MagickTrue;
11913 if (LocaleNCompare(value+i,"offs",4) == 0)
11914 mng_info->ping_exclude_oFFs=MagickTrue;
11916 if (LocaleNCompare(value+i,"phys",4) == 0)
11917 mng_info->ping_exclude_pHYs=MagickTrue;
11919 if (LocaleNCompare(value+i,"srgb",4) == 0)
11920 mng_info->ping_exclude_sRGB=MagickTrue;
11922 if (LocaleNCompare(value+i,"text",4) == 0)
11923 mng_info->ping_exclude_tEXt=MagickTrue;
11925 if (LocaleNCompare(value+i,"trns",4) == 0)
11926 mng_info->ping_exclude_tRNS=MagickTrue;
11928 if (LocaleNCompare(value+i,"vpag",4) == 0)
11929 mng_info->ping_exclude_vpAg=MagickTrue;
11931 if (LocaleNCompare(value+i,"zccp",4) == 0)
11932 mng_info->ping_exclude_zCCP=MagickTrue;
11934 if (LocaleNCompare(value+i,"ztxt",4) == 0)
11935 mng_info->ping_exclude_zTXt=MagickTrue;
11941 for (source=0; source<1; source++)
11945 value=GetImageArtifact(image,"png:include-chunk");
11948 value=GetImageArtifact(image,"png:include-chunks");
11952 value=GetImageOption(image_info,"png:include-chunk");
11955 value=GetImageOption(image_info,"png:include-chunks");
11963 excluding=MagickTrue;
11965 if (logging != MagickFalse)
11968 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11969 " png:include-chunk=%s found in image artifacts.\n", value);
11971 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11972 " png:include-chunk=%s found in image properties.\n", value);
11975 last=strlen(value);
11977 for (i=0; i<(int) last; i+=5)
11979 if (LocaleNCompare(value+i,"all",3) == 0)
11981 mng_info->ping_exclude_bKGD=MagickFalse;
11982 mng_info->ping_exclude_cHRM=MagickFalse;
11983 mng_info->ping_exclude_date=MagickFalse;
11984 mng_info->ping_exclude_EXIF=MagickFalse;
11985 mng_info->ping_exclude_gAMA=MagickFalse;
11986 mng_info->ping_exclude_iCCP=MagickFalse;
11987 /* mng_info->ping_exclude_iTXt=MagickFalse; */
11988 mng_info->ping_exclude_oFFs=MagickFalse;
11989 mng_info->ping_exclude_pHYs=MagickFalse;
11990 mng_info->ping_exclude_sRGB=MagickFalse;
11991 mng_info->ping_exclude_tEXt=MagickFalse;
11992 mng_info->ping_exclude_tRNS=MagickFalse;
11993 mng_info->ping_exclude_vpAg=MagickFalse;
11994 mng_info->ping_exclude_zCCP=MagickFalse;
11995 mng_info->ping_exclude_zTXt=MagickFalse;
11999 if (LocaleNCompare(value+i,"none",4) == 0)
12001 mng_info->ping_exclude_bKGD=MagickTrue;
12002 mng_info->ping_exclude_cHRM=MagickTrue;
12003 mng_info->ping_exclude_date=MagickTrue;
12004 mng_info->ping_exclude_EXIF=MagickTrue;
12005 mng_info->ping_exclude_gAMA=MagickTrue;
12006 mng_info->ping_exclude_iCCP=MagickTrue;
12007 /* mng_info->ping_exclude_iTXt=MagickTrue; */
12008 mng_info->ping_exclude_oFFs=MagickTrue;
12009 mng_info->ping_exclude_pHYs=MagickTrue;
12010 mng_info->ping_exclude_sRGB=MagickTrue;
12011 mng_info->ping_exclude_tEXt=MagickTrue;
12012 mng_info->ping_exclude_tRNS=MagickTrue;
12013 mng_info->ping_exclude_vpAg=MagickTrue;
12014 mng_info->ping_exclude_zCCP=MagickTrue;
12015 mng_info->ping_exclude_zTXt=MagickTrue;
12018 if (LocaleNCompare(value+i,"bkgd",4) == 0)
12019 mng_info->ping_exclude_bKGD=MagickFalse;
12021 if (LocaleNCompare(value+i,"chrm",4) == 0)
12022 mng_info->ping_exclude_cHRM=MagickFalse;
12024 if (LocaleNCompare(value+i,"date",4) == 0)
12025 mng_info->ping_exclude_date=MagickFalse;
12027 if (LocaleNCompare(value+i,"exif",4) == 0)
12028 mng_info->ping_exclude_EXIF=MagickFalse;
12030 if (LocaleNCompare(value+i,"gama",4) == 0)
12031 mng_info->ping_exclude_gAMA=MagickFalse;
12033 if (LocaleNCompare(value+i,"iccp",4) == 0)
12034 mng_info->ping_exclude_iCCP=MagickFalse;
12037 if (LocaleNCompare(value+i,"itxt",4) == 0)
12038 mng_info->ping_exclude_iTXt=MagickFalse;
12041 if (LocaleNCompare(value+i,"gama",4) == 0)
12042 mng_info->ping_exclude_gAMA=MagickFalse;
12044 if (LocaleNCompare(value+i,"offs",4) == 0)
12045 mng_info->ping_exclude_oFFs=MagickFalse;
12047 if (LocaleNCompare(value+i,"phys",4) == 0)
12048 mng_info->ping_exclude_pHYs=MagickFalse;
12050 if (LocaleNCompare(value+i,"srgb",4) == 0)
12051 mng_info->ping_exclude_sRGB=MagickFalse;
12053 if (LocaleNCompare(value+i,"text",4) == 0)
12054 mng_info->ping_exclude_tEXt=MagickFalse;
12056 if (LocaleNCompare(value+i,"trns",4) == 0)
12057 mng_info->ping_exclude_tRNS=MagickFalse;
12059 if (LocaleNCompare(value+i,"vpag",4) == 0)
12060 mng_info->ping_exclude_vpAg=MagickFalse;
12062 if (LocaleNCompare(value+i,"zccp",4) == 0)
12063 mng_info->ping_exclude_zCCP=MagickFalse;
12065 if (LocaleNCompare(value+i,"ztxt",4) == 0)
12066 mng_info->ping_exclude_zTXt=MagickFalse;
12072 if (excluding != MagickFalse && logging != MagickFalse)
12074 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12075 " Chunks to be excluded from the output png:");
12076 if (mng_info->ping_exclude_bKGD != MagickFalse)
12077 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12079 if (mng_info->ping_exclude_cHRM != MagickFalse)
12080 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12082 if (mng_info->ping_exclude_date != MagickFalse)
12083 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12085 if (mng_info->ping_exclude_EXIF != MagickFalse)
12086 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12088 if (mng_info->ping_exclude_gAMA != MagickFalse)
12089 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12091 if (mng_info->ping_exclude_iCCP != MagickFalse)
12092 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12095 if (mng_info->ping_exclude_iTXt != MagickFalse)
12096 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12099 if (mng_info->ping_exclude_oFFs != MagickFalse)
12100 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12102 if (mng_info->ping_exclude_pHYs != MagickFalse)
12103 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12105 if (mng_info->ping_exclude_sRGB != MagickFalse)
12106 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12108 if (mng_info->ping_exclude_tEXt != MagickFalse)
12109 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12111 if (mng_info->ping_exclude_tRNS != MagickFalse)
12112 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12114 if (mng_info->ping_exclude_vpAg != MagickFalse)
12115 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12117 if (mng_info->ping_exclude_zCCP != MagickFalse)
12118 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12120 if (mng_info->ping_exclude_zTXt != MagickFalse)
12121 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12125 mng_info->need_blob = MagickTrue;
12127 status=WriteOnePNGImage(mng_info,image_info,image,exception);
12129 MngInfoFreeStruct(mng_info,&have_mng_structure);
12131 if (logging != MagickFalse)
12132 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit WritePNGImage()");
12137 #if defined(JNG_SUPPORTED)
12139 /* Write one JNG image */
12140 static MagickBooleanType WriteOneJNGImage(MngInfo *mng_info,
12141 const ImageInfo *image_info,Image *image,ExceptionInfo *exception)
12162 jng_alpha_compression_method,
12163 jng_alpha_sample_depth,
12171 logging=LogMagickEvent(CoderEvent,GetMagickModule(),
12172 " Enter WriteOneJNGImage()");
12174 blob=(unsigned char *) NULL;
12175 jpeg_image=(Image *) NULL;
12176 jpeg_image_info=(ImageInfo *) NULL;
12179 transparent=image_info->type==GrayscaleMatteType ||
12180 image_info->type==TrueColorMatteType || image->alpha_trait == BlendPixelTrait;
12182 jng_quality=image_info->quality == 0UL ? 75UL : image_info->quality%1000;
12184 jng_alpha_compression_method=image->compression==JPEGCompression? 8 : 0;
12186 jng_alpha_quality=image_info->quality == 0UL ? 75UL :
12187 image_info->quality;
12189 if (jng_alpha_quality >= 1000)
12190 jng_alpha_quality /= 1000;
12196 /* Create JPEG blob, image, and image_info */
12197 if (logging != MagickFalse)
12198 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12199 " Creating jpeg_image_info for alpha.");
12201 jpeg_image_info=(ImageInfo *) CloneImageInfo(image_info);
12203 if (jpeg_image_info == (ImageInfo *) NULL)
12204 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
12206 if (logging != MagickFalse)
12207 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12208 " Creating jpeg_image.");
12210 jpeg_image=SeparateImage(image,AlphaChannel,exception);
12211 if (jpeg_image == (Image *) NULL)
12212 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
12213 (void) CopyMagickString(jpeg_image->magick,"JPEG",MaxTextExtent);
12214 jpeg_image->alpha_trait=UndefinedPixelTrait;
12215 jpeg_image->quality=jng_alpha_quality;
12216 jpeg_image_info->type=GrayscaleType;
12217 (void) SetImageType(jpeg_image,GrayscaleType,exception);
12218 (void) AcquireUniqueFilename(jpeg_image->filename);
12219 (void) FormatLocaleString(jpeg_image_info->filename,MaxTextExtent,
12220 "%s",jpeg_image->filename);
12224 jng_alpha_compression_method=0;
12226 jng_alpha_sample_depth=0;
12229 /* To do: check bit depth of PNG alpha channel */
12231 /* Check if image is grayscale. */
12232 if (image_info->type != TrueColorMatteType && image_info->type !=
12233 TrueColorType && IsImageGray(image,exception))
12236 if (logging != MagickFalse)
12238 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12239 " JNG Quality = %d",(int) jng_quality);
12240 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12241 " JNG Color Type = %d",jng_color_type);
12244 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12245 " JNG Alpha Compression = %d",jng_alpha_compression_method);
12246 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12247 " JNG Alpha Depth = %d",jng_alpha_sample_depth);
12248 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12249 " JNG Alpha Quality = %d",(int) jng_alpha_quality);
12255 if (jng_alpha_compression_method==0)
12260 /* Encode alpha as a grayscale PNG blob */
12261 status=OpenBlob(jpeg_image_info,jpeg_image,WriteBinaryBlobMode,
12263 if (logging != MagickFalse)
12264 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12265 " Creating PNG blob.");
12268 (void) CopyMagickString(jpeg_image_info->magick,"PNG",MaxTextExtent);
12269 (void) CopyMagickString(jpeg_image->magick,"PNG",MaxTextExtent);
12270 jpeg_image_info->interlace=NoInterlace;
12272 /* Exclude all ancillary chunks */
12273 (void) SetImageArtifact(jpeg_image,"png:exclude-chunks","all");
12275 blob=ImageToBlob(jpeg_image_info,jpeg_image,&length,
12278 /* Retrieve sample depth used */
12279 value=GetImageProperty(jpeg_image,"png:bit-depth-written",exception);
12280 if (value != (char *) NULL)
12281 jng_alpha_sample_depth= (unsigned int) value[0];
12285 /* Encode alpha as a grayscale JPEG blob */
12287 status=OpenBlob(jpeg_image_info,jpeg_image,WriteBinaryBlobMode,
12290 (void) CopyMagickString(jpeg_image_info->magick,"JPEG",MaxTextExtent);
12291 (void) CopyMagickString(jpeg_image->magick,"JPEG",MaxTextExtent);
12292 jpeg_image_info->interlace=NoInterlace;
12293 if (logging != MagickFalse)
12294 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12295 " Creating blob.");
12296 blob=ImageToBlob(jpeg_image_info,jpeg_image,&length,
12298 jng_alpha_sample_depth=8;
12300 if (logging != MagickFalse)
12301 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12302 " Successfully read jpeg_image into a blob, length=%.20g.",
12306 /* Destroy JPEG image and image_info */
12307 jpeg_image=DestroyImage(jpeg_image);
12308 (void) RelinquishUniqueFileResource(jpeg_image_info->filename);
12309 jpeg_image_info=DestroyImageInfo(jpeg_image_info);
12312 /* Write JHDR chunk */
12313 (void) WriteBlobMSBULong(image,16L); /* chunk data length=16 */
12314 PNGType(chunk,mng_JHDR);
12315 LogPNGChunk(logging,mng_JHDR,16L);
12316 PNGLong(chunk+4,(png_uint_32) image->columns);
12317 PNGLong(chunk+8,(png_uint_32) image->rows);
12318 chunk[12]=jng_color_type;
12319 chunk[13]=8; /* sample depth */
12320 chunk[14]=8; /*jng_image_compression_method */
12321 chunk[15]=(unsigned char) (image_info->interlace == NoInterlace ? 0 : 8);
12322 chunk[16]=jng_alpha_sample_depth;
12323 chunk[17]=jng_alpha_compression_method;
12324 chunk[18]=0; /*jng_alpha_filter_method */
12325 chunk[19]=0; /*jng_alpha_interlace_method */
12326 (void) WriteBlob(image,20,chunk);
12327 (void) WriteBlobMSBULong(image,crc32(0,chunk,20));
12328 if (logging != MagickFalse)
12330 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12331 " JNG width:%15lu",(unsigned long) image->columns);
12333 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12334 " JNG height:%14lu",(unsigned long) image->rows);
12336 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12337 " JNG color type:%10d",jng_color_type);
12339 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12340 " JNG sample depth:%8d",8);
12342 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12343 " JNG compression:%9d",8);
12345 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12346 " JNG interlace:%11d",0);
12348 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12349 " JNG alpha depth:%9d",jng_alpha_sample_depth);
12351 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12352 " JNG alpha compression:%3d",jng_alpha_compression_method);
12354 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12355 " JNG alpha filter:%8d",0);
12357 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12358 " JNG alpha interlace:%5d",0);
12361 /* Write any JNG-chunk-b profiles */
12362 (void) Magick_png_write_chunk_from_profile(image,"JNG-chunk-b",logging);
12365 Write leading ancillary chunks
12371 Write JNG bKGD chunk
12382 if (jng_color_type == 8 || jng_color_type == 12)
12386 (void) WriteBlobMSBULong(image,(size_t) (num_bytes-4L));
12387 PNGType(chunk,mng_bKGD);
12388 LogPNGChunk(logging,mng_bKGD,(size_t) (num_bytes-4L));
12389 red=ScaleQuantumToChar(image->background_color.red);
12390 green=ScaleQuantumToChar(image->background_color.green);
12391 blue=ScaleQuantumToChar(image->background_color.blue);
12398 (void) WriteBlob(image,(size_t) num_bytes,chunk);
12399 (void) WriteBlobMSBULong(image,crc32(0,chunk,(uInt) num_bytes));
12402 if ((image->colorspace == sRGBColorspace || image->rendering_intent))
12405 Write JNG sRGB chunk
12407 (void) WriteBlobMSBULong(image,1L);
12408 PNGType(chunk,mng_sRGB);
12409 LogPNGChunk(logging,mng_sRGB,1L);
12411 if (image->rendering_intent != UndefinedIntent)
12412 chunk[4]=(unsigned char)
12413 Magick_RenderingIntent_to_PNG_RenderingIntent(
12414 (image->rendering_intent));
12417 chunk[4]=(unsigned char)
12418 Magick_RenderingIntent_to_PNG_RenderingIntent(
12419 (PerceptualIntent));
12421 (void) WriteBlob(image,5,chunk);
12422 (void) WriteBlobMSBULong(image,crc32(0,chunk,5));
12426 if (image->gamma != 0.0)
12429 Write JNG gAMA chunk
12431 (void) WriteBlobMSBULong(image,4L);
12432 PNGType(chunk,mng_gAMA);
12433 LogPNGChunk(logging,mng_gAMA,4L);
12434 PNGLong(chunk+4,(png_uint_32) (100000*image->gamma+0.5));
12435 (void) WriteBlob(image,8,chunk);
12436 (void) WriteBlobMSBULong(image,crc32(0,chunk,8));
12439 if ((mng_info->equal_chrms == MagickFalse) &&
12440 (image->chromaticity.red_primary.x != 0.0))
12446 Write JNG cHRM chunk
12448 (void) WriteBlobMSBULong(image,32L);
12449 PNGType(chunk,mng_cHRM);
12450 LogPNGChunk(logging,mng_cHRM,32L);
12451 primary=image->chromaticity.white_point;
12452 PNGLong(chunk+4,(png_uint_32) (100000*primary.x+0.5));
12453 PNGLong(chunk+8,(png_uint_32) (100000*primary.y+0.5));
12454 primary=image->chromaticity.red_primary;
12455 PNGLong(chunk+12,(png_uint_32) (100000*primary.x+0.5));
12456 PNGLong(chunk+16,(png_uint_32) (100000*primary.y+0.5));
12457 primary=image->chromaticity.green_primary;
12458 PNGLong(chunk+20,(png_uint_32) (100000*primary.x+0.5));
12459 PNGLong(chunk+24,(png_uint_32) (100000*primary.y+0.5));
12460 primary=image->chromaticity.blue_primary;
12461 PNGLong(chunk+28,(png_uint_32) (100000*primary.x+0.5));
12462 PNGLong(chunk+32,(png_uint_32) (100000*primary.y+0.5));
12463 (void) WriteBlob(image,36,chunk);
12464 (void) WriteBlobMSBULong(image,crc32(0,chunk,36));
12468 if (image->resolution.x && image->resolution.y && !mng_info->equal_physs)
12471 Write JNG pHYs chunk
12473 (void) WriteBlobMSBULong(image,9L);
12474 PNGType(chunk,mng_pHYs);
12475 LogPNGChunk(logging,mng_pHYs,9L);
12476 if (image->units == PixelsPerInchResolution)
12478 PNGLong(chunk+4,(png_uint_32)
12479 (image->resolution.x*100.0/2.54+0.5));
12481 PNGLong(chunk+8,(png_uint_32)
12482 (image->resolution.y*100.0/2.54+0.5));
12489 if (image->units == PixelsPerCentimeterResolution)
12491 PNGLong(chunk+4,(png_uint_32)
12492 (image->resolution.x*100.0+0.5));
12494 PNGLong(chunk+8,(png_uint_32)
12495 (image->resolution.y*100.0+0.5));
12502 PNGLong(chunk+4,(png_uint_32) (image->resolution.x+0.5));
12503 PNGLong(chunk+8,(png_uint_32) (image->resolution.y+0.5));
12507 (void) WriteBlob(image,13,chunk);
12508 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
12511 if (mng_info->write_mng == 0 && (image->page.x || image->page.y))
12514 Write JNG oFFs chunk
12516 (void) WriteBlobMSBULong(image,9L);
12517 PNGType(chunk,mng_oFFs);
12518 LogPNGChunk(logging,mng_oFFs,9L);
12519 PNGsLong(chunk+4,(ssize_t) (image->page.x));
12520 PNGsLong(chunk+8,(ssize_t) (image->page.y));
12522 (void) WriteBlob(image,13,chunk);
12523 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
12525 if (mng_info->write_mng == 0 && (image->page.width || image->page.height))
12527 (void) WriteBlobMSBULong(image,9L); /* data length=8 */
12528 PNGType(chunk,mng_vpAg);
12529 LogPNGChunk(logging,mng_vpAg,9L);
12530 PNGLong(chunk+4,(png_uint_32) image->page.width);
12531 PNGLong(chunk+8,(png_uint_32) image->page.height);
12532 chunk[12]=0; /* unit = pixels */
12533 (void) WriteBlob(image,13,chunk);
12534 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
12540 if (jng_alpha_compression_method==0)
12548 /* Write IDAT chunk header */
12549 if (logging != MagickFalse)
12550 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12551 " Write IDAT chunks from blob, length=%.20g.",(double)
12554 /* Copy IDAT chunks */
12557 for (i=8; i<(ssize_t) length; i+=len+12)
12559 len=(*p<<24)|((*(p+1))<<16)|((*(p+2))<<8)|(*(p+3));
12562 if (*(p)==73 && *(p+1)==68 && *(p+2)==65 && *(p+3)==84) /* IDAT */
12564 /* Found an IDAT chunk. */
12565 (void) WriteBlobMSBULong(image,(size_t) len);
12566 LogPNGChunk(logging,mng_IDAT,(size_t) len);
12567 (void) WriteBlob(image,(size_t) len+4,p);
12568 (void) WriteBlobMSBULong(image,
12569 crc32(0,p,(uInt) len+4));
12574 if (logging != MagickFalse)
12575 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12576 " Skipping %c%c%c%c chunk, length=%.20g.",
12577 *(p),*(p+1),*(p+2),*(p+3),(double) len);
12584 /* Write JDAA chunk header */
12585 if (logging != MagickFalse)
12586 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12587 " Write JDAA chunk, length=%.20g.",(double) length);
12588 (void) WriteBlobMSBULong(image,(size_t) length);
12589 PNGType(chunk,mng_JDAA);
12590 LogPNGChunk(logging,mng_JDAA,length);
12591 /* Write JDAT chunk(s) data */
12592 (void) WriteBlob(image,4,chunk);
12593 (void) WriteBlob(image,length,blob);
12594 (void) WriteBlobMSBULong(image,crc32(crc32(0,chunk,4),blob,
12597 blob=(unsigned char *) RelinquishMagickMemory(blob);
12600 /* Encode image as a JPEG blob */
12601 if (logging != MagickFalse)
12602 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12603 " Creating jpeg_image_info.");
12604 jpeg_image_info=(ImageInfo *) CloneImageInfo(image_info);
12605 if (jpeg_image_info == (ImageInfo *) NULL)
12606 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
12608 if (logging != MagickFalse)
12609 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12610 " Creating jpeg_image.");
12612 jpeg_image=CloneImage(image,0,0,MagickTrue,exception);
12613 if (jpeg_image == (Image *) NULL)
12614 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
12615 (void) CopyMagickString(jpeg_image->magick,"JPEG",MaxTextExtent);
12617 (void) AcquireUniqueFilename(jpeg_image->filename);
12618 (void) FormatLocaleString(jpeg_image_info->filename,MaxTextExtent,"%s",
12619 jpeg_image->filename);
12621 status=OpenBlob(jpeg_image_info,jpeg_image,WriteBinaryBlobMode,
12624 if (logging != MagickFalse)
12625 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12626 " Created jpeg_image, %.20g x %.20g.",(double) jpeg_image->columns,
12627 (double) jpeg_image->rows);
12629 if (jng_color_type == 8 || jng_color_type == 12)
12630 jpeg_image_info->type=GrayscaleType;
12632 jpeg_image_info->quality=jng_quality;
12633 jpeg_image->quality=jng_quality;
12634 (void) CopyMagickString(jpeg_image_info->magick,"JPEG",MaxTextExtent);
12635 (void) CopyMagickString(jpeg_image->magick,"JPEG",MaxTextExtent);
12637 if (logging != MagickFalse)
12638 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12639 " Creating blob.");
12641 blob=ImageToBlob(jpeg_image_info,jpeg_image,&length,exception);
12643 if (logging != MagickFalse)
12645 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12646 " Successfully read jpeg_image into a blob, length=%.20g.",
12649 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12650 " Write JDAT chunk, length=%.20g.",(double) length);
12653 /* Write JDAT chunk(s) */
12654 (void) WriteBlobMSBULong(image,(size_t) length);
12655 PNGType(chunk,mng_JDAT);
12656 LogPNGChunk(logging,mng_JDAT,length);
12657 (void) WriteBlob(image,4,chunk);
12658 (void) WriteBlob(image,length,blob);
12659 (void) WriteBlobMSBULong(image,crc32(crc32(0,chunk,4),blob,(uInt) length));
12661 jpeg_image=DestroyImage(jpeg_image);
12662 (void) RelinquishUniqueFileResource(jpeg_image_info->filename);
12663 jpeg_image_info=DestroyImageInfo(jpeg_image_info);
12664 blob=(unsigned char *) RelinquishMagickMemory(blob);
12666 /* Write any JNG-chunk-e profiles */
12667 (void) Magick_png_write_chunk_from_profile(image,"JNG-chunk-e",logging);
12669 /* Write IEND chunk */
12670 (void) WriteBlobMSBULong(image,0L);
12671 PNGType(chunk,mng_IEND);
12672 LogPNGChunk(logging,mng_IEND,0);
12673 (void) WriteBlob(image,4,chunk);
12674 (void) WriteBlobMSBULong(image,crc32(0,chunk,4));
12676 if (logging != MagickFalse)
12677 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12678 " exit WriteOneJNGImage()");
12685 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12689 % W r i t e J N G I m a g e %
12693 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12695 % WriteJNGImage() writes a JPEG Network Graphics (JNG) image file.
12697 % JNG support written by Glenn Randers-Pehrson, glennrp@image...
12699 % The format of the WriteJNGImage method is:
12701 % MagickBooleanType WriteJNGImage(const ImageInfo *image_info,
12702 % Image *image,ExceptionInfo *exception)
12704 % A description of each parameter follows:
12706 % o image_info: the image info.
12708 % o image: The image.
12710 % o exception: return any errors or warnings in this structure.
12712 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12714 static MagickBooleanType WriteJNGImage(const ImageInfo *image_info,Image *image,
12715 ExceptionInfo *exception)
12718 have_mng_structure,
12728 assert(image_info != (const ImageInfo *) NULL);
12729 assert(image_info->signature == MagickSignature);
12730 assert(image != (Image *) NULL);
12731 assert(image->signature == MagickSignature);
12732 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
12733 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter WriteJNGImage()");
12734 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
12735 if (status == MagickFalse)
12739 Allocate a MngInfo structure.
12741 have_mng_structure=MagickFalse;
12742 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
12743 if (mng_info == (MngInfo *) NULL)
12744 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
12746 Initialize members of the MngInfo structure.
12748 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
12749 mng_info->image=image;
12750 have_mng_structure=MagickTrue;
12752 (void) WriteBlob(image,8,(const unsigned char *) "\213JNG\r\n\032\n");
12754 status=WriteOneJNGImage(mng_info,image_info,image,exception);
12755 (void) CloseBlob(image);
12757 (void) CatchImageException(image);
12758 MngInfoFreeStruct(mng_info,&have_mng_structure);
12759 if (logging != MagickFalse)
12760 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit WriteJNGImage()");
12765 static MagickBooleanType WriteMNGImage(const ImageInfo *image_info,Image *image,
12766 ExceptionInfo *exception)
12775 have_mng_structure,
12778 volatile MagickBooleanType
12790 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
12791 defined(PNG_MNG_FEATURES_SUPPORTED)
12794 all_images_are_gray,
12804 volatile unsigned int
12815 #if (PNG_LIBPNG_VER < 10200)
12816 if (image_info->verbose)
12817 printf("Your PNG library (libpng-%s) is rather old.\n",
12818 PNG_LIBPNG_VER_STRING);
12824 assert(image_info != (const ImageInfo *) NULL);
12825 assert(image_info->signature == MagickSignature);
12826 assert(image != (Image *) NULL);
12827 assert(image->signature == MagickSignature);
12828 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
12829 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter WriteMNGImage()");
12830 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
12831 if (status == MagickFalse)
12835 Allocate a MngInfo structure.
12837 have_mng_structure=MagickFalse;
12838 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
12839 if (mng_info == (MngInfo *) NULL)
12840 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
12842 Initialize members of the MngInfo structure.
12844 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
12845 mng_info->image=image;
12846 have_mng_structure=MagickTrue;
12847 write_mng=LocaleCompare(image_info->magick,"MNG") == 0;
12850 * See if user has requested a specific PNG subformat to be used
12851 * for all of the PNGs in the MNG being written, e.g.,
12853 * convert *.png png8:animation.mng
12855 * To do: check -define png:bit_depth and png:color_type as well,
12856 * or perhaps use mng:bit_depth and mng:color_type instead for
12860 mng_info->write_png8=LocaleCompare(image_info->magick,"PNG8") == 0;
12861 mng_info->write_png24=LocaleCompare(image_info->magick,"PNG24") == 0;
12862 mng_info->write_png32=LocaleCompare(image_info->magick,"PNG32") == 0;
12864 write_jng=MagickFalse;
12865 if (image_info->compression == JPEGCompression)
12866 write_jng=MagickTrue;
12868 mng_info->adjoin=image_info->adjoin &&
12869 (GetNextImageInList(image) != (Image *) NULL) && write_mng;
12871 if (logging != MagickFalse)
12873 /* Log some info about the input */
12877 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12878 " Checking input image(s)");
12880 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12881 " Image_info depth: %.20g",(double) image_info->depth);
12883 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12884 " Type: %d",image_info->type);
12887 for (p=image; p != (Image *) NULL; p=GetNextImageInList(p))
12889 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12890 " Scene: %.20g",(double) scene++);
12892 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12893 " Image depth: %.20g",(double) p->depth);
12895 if (p->alpha_trait == BlendPixelTrait)
12896 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12900 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12903 if (p->storage_class == PseudoClass)
12904 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12905 " Storage class: PseudoClass");
12908 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12909 " Storage class: DirectClass");
12912 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12913 " Number of colors: %.20g",(double) p->colors);
12916 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12917 " Number of colors: unspecified");
12919 if (mng_info->adjoin == MagickFalse)
12924 use_global_plte=MagickFalse;
12925 all_images_are_gray=MagickFalse;
12926 #ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
12927 need_local_plte=MagickTrue;
12929 need_defi=MagickFalse;
12930 need_matte=MagickFalse;
12931 mng_info->framing_mode=1;
12932 mng_info->old_framing_mode=1;
12935 if (image_info->page != (char *) NULL)
12938 Determine image bounding box.
12940 SetGeometry(image,&mng_info->page);
12941 (void) ParseMetaGeometry(image_info->page,&mng_info->page.x,
12942 &mng_info->page.y,&mng_info->page.width,&mng_info->page.height);
12954 mng_info->page=image->page;
12955 need_geom=MagickTrue;
12956 if (mng_info->page.width || mng_info->page.height)
12957 need_geom=MagickFalse;
12959 Check all the scenes.
12961 initial_delay=image->delay;
12962 need_iterations=MagickFalse;
12963 mng_info->equal_chrms=image->chromaticity.red_primary.x != 0.0;
12964 mng_info->equal_physs=MagickTrue,
12965 mng_info->equal_gammas=MagickTrue;
12966 mng_info->equal_srgbs=MagickTrue;
12967 mng_info->equal_backgrounds=MagickTrue;
12969 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
12970 defined(PNG_MNG_FEATURES_SUPPORTED)
12971 all_images_are_gray=MagickTrue;
12972 mng_info->equal_palettes=MagickFalse;
12973 need_local_plte=MagickFalse;
12975 for (next_image=image; next_image != (Image *) NULL; )
12979 if ((next_image->columns+next_image->page.x) > mng_info->page.width)
12980 mng_info->page.width=next_image->columns+next_image->page.x;
12982 if ((next_image->rows+next_image->page.y) > mng_info->page.height)
12983 mng_info->page.height=next_image->rows+next_image->page.y;
12986 if (next_image->page.x || next_image->page.y)
12987 need_defi=MagickTrue;
12989 if (next_image->alpha_trait == BlendPixelTrait)
12990 need_matte=MagickTrue;
12992 if ((int) next_image->dispose >= BackgroundDispose)
12993 if ((next_image->alpha_trait == BlendPixelTrait) ||
12994 next_image->page.x || next_image->page.y ||
12995 ((next_image->columns < mng_info->page.width) &&
12996 (next_image->rows < mng_info->page.height)))
12997 mng_info->need_fram=MagickTrue;
12999 if (next_image->iterations)
13000 need_iterations=MagickTrue;
13002 final_delay=next_image->delay;
13004 if (final_delay != initial_delay || final_delay > 1UL*
13005 next_image->ticks_per_second)
13006 mng_info->need_fram=1;
13008 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
13009 defined(PNG_MNG_FEATURES_SUPPORTED)
13011 check for global palette possibility.
13013 if (image->alpha_trait == BlendPixelTrait)
13014 need_local_plte=MagickTrue;
13016 if (need_local_plte == 0)
13018 if (IsImageGray(image,exception) == MagickFalse)
13019 all_images_are_gray=MagickFalse;
13020 mng_info->equal_palettes=PalettesAreEqual(image,next_image);
13021 if (use_global_plte == 0)
13022 use_global_plte=mng_info->equal_palettes;
13023 need_local_plte=!mng_info->equal_palettes;
13026 if (GetNextImageInList(next_image) != (Image *) NULL)
13028 if (next_image->background_color.red !=
13029 next_image->next->background_color.red ||
13030 next_image->background_color.green !=
13031 next_image->next->background_color.green ||
13032 next_image->background_color.blue !=
13033 next_image->next->background_color.blue)
13034 mng_info->equal_backgrounds=MagickFalse;
13036 if (next_image->gamma != next_image->next->gamma)
13037 mng_info->equal_gammas=MagickFalse;
13039 if (next_image->rendering_intent !=
13040 next_image->next->rendering_intent)
13041 mng_info->equal_srgbs=MagickFalse;
13043 if ((next_image->units != next_image->next->units) ||
13044 (next_image->resolution.x != next_image->next->resolution.x) ||
13045 (next_image->resolution.y != next_image->next->resolution.y))
13046 mng_info->equal_physs=MagickFalse;
13048 if (mng_info->equal_chrms)
13050 if (next_image->chromaticity.red_primary.x !=
13051 next_image->next->chromaticity.red_primary.x ||
13052 next_image->chromaticity.red_primary.y !=
13053 next_image->next->chromaticity.red_primary.y ||
13054 next_image->chromaticity.green_primary.x !=
13055 next_image->next->chromaticity.green_primary.x ||
13056 next_image->chromaticity.green_primary.y !=
13057 next_image->next->chromaticity.green_primary.y ||
13058 next_image->chromaticity.blue_primary.x !=
13059 next_image->next->chromaticity.blue_primary.x ||
13060 next_image->chromaticity.blue_primary.y !=
13061 next_image->next->chromaticity.blue_primary.y ||
13062 next_image->chromaticity.white_point.x !=
13063 next_image->next->chromaticity.white_point.x ||
13064 next_image->chromaticity.white_point.y !=
13065 next_image->next->chromaticity.white_point.y)
13066 mng_info->equal_chrms=MagickFalse;
13070 next_image=GetNextImageInList(next_image);
13072 if (image_count < 2)
13074 mng_info->equal_backgrounds=MagickFalse;
13075 mng_info->equal_chrms=MagickFalse;
13076 mng_info->equal_gammas=MagickFalse;
13077 mng_info->equal_srgbs=MagickFalse;
13078 mng_info->equal_physs=MagickFalse;
13079 use_global_plte=MagickFalse;
13080 #ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
13081 need_local_plte=MagickTrue;
13083 need_iterations=MagickFalse;
13086 if (mng_info->need_fram == MagickFalse)
13089 Only certain framing rates 100/n are exactly representable without
13090 the FRAM chunk but we'll allow some slop in VLC files
13092 if (final_delay == 0)
13094 if (need_iterations != MagickFalse)
13097 It's probably a GIF with loop; don't run it *too* fast.
13099 if (mng_info->adjoin)
13102 (void) ThrowMagickException(exception,GetMagickModule(),
13104 "input has zero delay between all frames; assuming",
13109 mng_info->ticks_per_second=0;
13111 if (final_delay != 0)
13112 mng_info->ticks_per_second=(png_uint_32)
13113 (image->ticks_per_second/final_delay);
13114 if (final_delay > 50)
13115 mng_info->ticks_per_second=2;
13117 if (final_delay > 75)
13118 mng_info->ticks_per_second=1;
13120 if (final_delay > 125)
13121 mng_info->need_fram=MagickTrue;
13123 if (need_defi && final_delay > 2 && (final_delay != 4) &&
13124 (final_delay != 5) && (final_delay != 10) && (final_delay != 20) &&
13125 (final_delay != 25) && (final_delay != 50) && (final_delay !=
13126 1UL*image->ticks_per_second))
13127 mng_info->need_fram=MagickTrue; /* make it exact; cannot be VLC */
13130 if (mng_info->need_fram != MagickFalse)
13131 mng_info->ticks_per_second=1UL*image->ticks_per_second;
13133 If pseudocolor, we should also check to see if all the
13134 palettes are identical and write a global PLTE if they are.
13138 Write the MNG version 1.0 signature and MHDR chunk.
13140 (void) WriteBlob(image,8,(const unsigned char *) "\212MNG\r\n\032\n");
13141 (void) WriteBlobMSBULong(image,28L); /* chunk data length=28 */
13142 PNGType(chunk,mng_MHDR);
13143 LogPNGChunk(logging,mng_MHDR,28L);
13144 PNGLong(chunk+4,(png_uint_32) mng_info->page.width);
13145 PNGLong(chunk+8,(png_uint_32) mng_info->page.height);
13146 PNGLong(chunk+12,mng_info->ticks_per_second);
13147 PNGLong(chunk+16,0L); /* layer count=unknown */
13148 PNGLong(chunk+20,0L); /* frame count=unknown */
13149 PNGLong(chunk+24,0L); /* play time=unknown */
13154 if (need_defi || mng_info->need_fram || use_global_plte)
13155 PNGLong(chunk+28,27L); /* simplicity=LC+JNG */
13158 PNGLong(chunk+28,25L); /* simplicity=VLC+JNG */
13163 if (need_defi || mng_info->need_fram || use_global_plte)
13164 PNGLong(chunk+28,19L); /* simplicity=LC+JNG, no transparency */
13167 PNGLong(chunk+28,17L); /* simplicity=VLC+JNG, no transparency */
13175 if (need_defi || mng_info->need_fram || use_global_plte)
13176 PNGLong(chunk+28,11L); /* simplicity=LC */
13179 PNGLong(chunk+28,9L); /* simplicity=VLC */
13184 if (need_defi || mng_info->need_fram || use_global_plte)
13185 PNGLong(chunk+28,3L); /* simplicity=LC, no transparency */
13188 PNGLong(chunk+28,1L); /* simplicity=VLC, no transparency */
13191 (void) WriteBlob(image,32,chunk);
13192 (void) WriteBlobMSBULong(image,crc32(0,chunk,32));
13193 option=GetImageOption(image_info,"mng:need-cacheoff");
13194 if (option != (const char *) NULL)
13200 Write "nEED CACHEOFF" to turn playback caching off for streaming MNG.
13202 PNGType(chunk,mng_nEED);
13203 length=CopyMagickString((char *) chunk+4,"CACHEOFF",20);
13204 (void) WriteBlobMSBULong(image,(size_t) length);
13205 LogPNGChunk(logging,mng_nEED,(size_t) length);
13207 (void) WriteBlob(image,length,chunk);
13208 (void) WriteBlobMSBULong(image,crc32(0,chunk,(uInt) length));
13210 if ((GetPreviousImageInList(image) == (Image *) NULL) &&
13211 (GetNextImageInList(image) != (Image *) NULL) &&
13212 (image->iterations != 1))
13215 Write MNG TERM chunk
13217 (void) WriteBlobMSBULong(image,10L); /* data length=10 */
13218 PNGType(chunk,mng_TERM);
13219 LogPNGChunk(logging,mng_TERM,10L);
13220 chunk[4]=3; /* repeat animation */
13221 chunk[5]=0; /* show last frame when done */
13222 PNGLong(chunk+6,(png_uint_32) (mng_info->ticks_per_second*
13223 final_delay/MagickMax(image->ticks_per_second,1)));
13225 if (image->iterations == 0)
13226 PNGLong(chunk+10,PNG_UINT_31_MAX);
13229 PNGLong(chunk+10,(png_uint_32) image->iterations);
13231 if (logging != MagickFalse)
13233 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
13234 " TERM delay: %.20g",(double) (mng_info->ticks_per_second*
13235 final_delay/MagickMax(image->ticks_per_second,1)));
13237 if (image->iterations == 0)
13238 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
13239 " TERM iterations: %.20g",(double) PNG_UINT_31_MAX);
13242 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
13243 " Image iterations: %.20g",(double) image->iterations);
13245 (void) WriteBlob(image,14,chunk);
13246 (void) WriteBlobMSBULong(image,crc32(0,chunk,14));
13249 To do: check for cHRM+gAMA == sRGB, and write sRGB instead.
13251 if ((image->colorspace == sRGBColorspace || image->rendering_intent) &&
13252 mng_info->equal_srgbs)
13255 Write MNG sRGB chunk
13257 (void) WriteBlobMSBULong(image,1L);
13258 PNGType(chunk,mng_sRGB);
13259 LogPNGChunk(logging,mng_sRGB,1L);
13261 if (image->rendering_intent != UndefinedIntent)
13262 chunk[4]=(unsigned char)
13263 Magick_RenderingIntent_to_PNG_RenderingIntent(
13264 (image->rendering_intent));
13267 chunk[4]=(unsigned char)
13268 Magick_RenderingIntent_to_PNG_RenderingIntent(
13269 (PerceptualIntent));
13271 (void) WriteBlob(image,5,chunk);
13272 (void) WriteBlobMSBULong(image,crc32(0,chunk,5));
13273 mng_info->have_write_global_srgb=MagickTrue;
13278 if (image->gamma && mng_info->equal_gammas)
13281 Write MNG gAMA chunk
13283 (void) WriteBlobMSBULong(image,4L);
13284 PNGType(chunk,mng_gAMA);
13285 LogPNGChunk(logging,mng_gAMA,4L);
13286 PNGLong(chunk+4,(png_uint_32) (100000*image->gamma+0.5));
13287 (void) WriteBlob(image,8,chunk);
13288 (void) WriteBlobMSBULong(image,crc32(0,chunk,8));
13289 mng_info->have_write_global_gama=MagickTrue;
13291 if (mng_info->equal_chrms)
13297 Write MNG cHRM chunk
13299 (void) WriteBlobMSBULong(image,32L);
13300 PNGType(chunk,mng_cHRM);
13301 LogPNGChunk(logging,mng_cHRM,32L);
13302 primary=image->chromaticity.white_point;
13303 PNGLong(chunk+4,(png_uint_32) (100000*primary.x+0.5));
13304 PNGLong(chunk+8,(png_uint_32) (100000*primary.y+0.5));
13305 primary=image->chromaticity.red_primary;
13306 PNGLong(chunk+12,(png_uint_32) (100000*primary.x+0.5));
13307 PNGLong(chunk+16,(png_uint_32) (100000*primary.y+0.5));
13308 primary=image->chromaticity.green_primary;
13309 PNGLong(chunk+20,(png_uint_32) (100000*primary.x+0.5));
13310 PNGLong(chunk+24,(png_uint_32) (100000*primary.y+0.5));
13311 primary=image->chromaticity.blue_primary;
13312 PNGLong(chunk+28,(png_uint_32) (100000*primary.x+0.5));
13313 PNGLong(chunk+32,(png_uint_32) (100000*primary.y+0.5));
13314 (void) WriteBlob(image,36,chunk);
13315 (void) WriteBlobMSBULong(image,crc32(0,chunk,36));
13316 mng_info->have_write_global_chrm=MagickTrue;
13319 if (image->resolution.x && image->resolution.y && mng_info->equal_physs)
13322 Write MNG pHYs chunk
13324 (void) WriteBlobMSBULong(image,9L);
13325 PNGType(chunk,mng_pHYs);
13326 LogPNGChunk(logging,mng_pHYs,9L);
13328 if (image->units == PixelsPerInchResolution)
13330 PNGLong(chunk+4,(png_uint_32)
13331 (image->resolution.x*100.0/2.54+0.5));
13333 PNGLong(chunk+8,(png_uint_32)
13334 (image->resolution.y*100.0/2.54+0.5));
13341 if (image->units == PixelsPerCentimeterResolution)
13343 PNGLong(chunk+4,(png_uint_32)
13344 (image->resolution.x*100.0+0.5));
13346 PNGLong(chunk+8,(png_uint_32)
13347 (image->resolution.y*100.0+0.5));
13354 PNGLong(chunk+4,(png_uint_32) (image->resolution.x+0.5));
13355 PNGLong(chunk+8,(png_uint_32) (image->resolution.y+0.5));
13359 (void) WriteBlob(image,13,chunk);
13360 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
13363 Write MNG BACK chunk and global bKGD chunk, if the image is transparent
13364 or does not cover the entire frame.
13366 if (write_mng && ((image->alpha_trait == BlendPixelTrait) ||
13367 image->page.x > 0 || image->page.y > 0 || (image->page.width &&
13368 (image->page.width+image->page.x < mng_info->page.width))
13369 || (image->page.height && (image->page.height+image->page.y
13370 < mng_info->page.height))))
13372 (void) WriteBlobMSBULong(image,6L);
13373 PNGType(chunk,mng_BACK);
13374 LogPNGChunk(logging,mng_BACK,6L);
13375 red=ScaleQuantumToShort(image->background_color.red);
13376 green=ScaleQuantumToShort(image->background_color.green);
13377 blue=ScaleQuantumToShort(image->background_color.blue);
13378 PNGShort(chunk+4,red);
13379 PNGShort(chunk+6,green);
13380 PNGShort(chunk+8,blue);
13381 (void) WriteBlob(image,10,chunk);
13382 (void) WriteBlobMSBULong(image,crc32(0,chunk,10));
13383 if (mng_info->equal_backgrounds)
13385 (void) WriteBlobMSBULong(image,6L);
13386 PNGType(chunk,mng_bKGD);
13387 LogPNGChunk(logging,mng_bKGD,6L);
13388 (void) WriteBlob(image,10,chunk);
13389 (void) WriteBlobMSBULong(image,crc32(0,chunk,10));
13393 #ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
13394 if ((need_local_plte == MagickFalse) &&
13395 (image->storage_class == PseudoClass) &&
13396 (all_images_are_gray == MagickFalse))
13402 Write MNG PLTE chunk
13404 data_length=3*image->colors;
13405 (void) WriteBlobMSBULong(image,data_length);
13406 PNGType(chunk,mng_PLTE);
13407 LogPNGChunk(logging,mng_PLTE,data_length);
13409 for (i=0; i < (ssize_t) image->colors; i++)
13411 chunk[4+i*3]=(unsigned char) (ScaleQuantumToChar(
13412 image->colormap[i].red) & 0xff);
13413 chunk[5+i*3]=(unsigned char) (ScaleQuantumToChar(
13414 image->colormap[i].green) & 0xff);
13415 chunk[6+i*3]=(unsigned char) (ScaleQuantumToChar(
13416 image->colormap[i].blue) & 0xff);
13419 (void) WriteBlob(image,data_length+4,chunk);
13420 (void) WriteBlobMSBULong(image,crc32(0,chunk,(uInt) (data_length+4)));
13421 mng_info->have_write_global_plte=MagickTrue;
13427 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
13428 defined(PNG_MNG_FEATURES_SUPPORTED)
13429 mng_info->equal_palettes=MagickFalse;
13433 if (mng_info->adjoin)
13435 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
13436 defined(PNG_MNG_FEATURES_SUPPORTED)
13438 If we aren't using a global palette for the entire MNG, check to
13439 see if we can use one for two or more consecutive images.
13441 if (need_local_plte && use_global_plte && !all_images_are_gray)
13443 if (mng_info->IsPalette)
13446 When equal_palettes is true, this image has the same palette
13447 as the previous PseudoClass image
13449 mng_info->have_write_global_plte=mng_info->equal_palettes;
13450 mng_info->equal_palettes=PalettesAreEqual(image,image->next);
13451 if (mng_info->equal_palettes && !mng_info->have_write_global_plte)
13454 Write MNG PLTE chunk
13459 data_length=3*image->colors;
13460 (void) WriteBlobMSBULong(image,data_length);
13461 PNGType(chunk,mng_PLTE);
13462 LogPNGChunk(logging,mng_PLTE,data_length);
13464 for (i=0; i < (ssize_t) image->colors; i++)
13466 chunk[4+i*3]=ScaleQuantumToChar(image->colormap[i].red);
13467 chunk[5+i*3]=ScaleQuantumToChar(image->colormap[i].green);
13468 chunk[6+i*3]=ScaleQuantumToChar(image->colormap[i].blue);
13471 (void) WriteBlob(image,data_length+4,chunk);
13472 (void) WriteBlobMSBULong(image,crc32(0,chunk,
13473 (uInt) (data_length+4)));
13474 mng_info->have_write_global_plte=MagickTrue;
13478 mng_info->have_write_global_plte=MagickFalse;
13489 previous_x=mng_info->page.x;
13490 previous_y=mng_info->page.y;
13497 mng_info->page=image->page;
13498 if ((mng_info->page.x != previous_x) ||
13499 (mng_info->page.y != previous_y))
13501 (void) WriteBlobMSBULong(image,12L); /* data length=12 */
13502 PNGType(chunk,mng_DEFI);
13503 LogPNGChunk(logging,mng_DEFI,12L);
13504 chunk[4]=0; /* object 0 MSB */
13505 chunk[5]=0; /* object 0 LSB */
13506 chunk[6]=0; /* visible */
13507 chunk[7]=0; /* abstract */
13508 PNGLong(chunk+8,(png_uint_32) mng_info->page.x);
13509 PNGLong(chunk+12,(png_uint_32) mng_info->page.y);
13510 (void) WriteBlob(image,16,chunk);
13511 (void) WriteBlobMSBULong(image,crc32(0,chunk,16));
13516 mng_info->write_mng=write_mng;
13518 if ((int) image->dispose >= 3)
13519 mng_info->framing_mode=3;
13521 if (mng_info->need_fram && mng_info->adjoin &&
13522 ((image->delay != mng_info->delay) ||
13523 (mng_info->framing_mode != mng_info->old_framing_mode)))
13525 if (image->delay == mng_info->delay)
13528 Write a MNG FRAM chunk with the new framing mode.
13530 (void) WriteBlobMSBULong(image,1L); /* data length=1 */
13531 PNGType(chunk,mng_FRAM);
13532 LogPNGChunk(logging,mng_FRAM,1L);
13533 chunk[4]=(unsigned char) mng_info->framing_mode;
13534 (void) WriteBlob(image,5,chunk);
13535 (void) WriteBlobMSBULong(image,crc32(0,chunk,5));
13540 Write a MNG FRAM chunk with the delay.
13542 (void) WriteBlobMSBULong(image,10L); /* data length=10 */
13543 PNGType(chunk,mng_FRAM);
13544 LogPNGChunk(logging,mng_FRAM,10L);
13545 chunk[4]=(unsigned char) mng_info->framing_mode;
13546 chunk[5]=0; /* frame name separator (no name) */
13547 chunk[6]=2; /* flag for changing default delay */
13548 chunk[7]=0; /* flag for changing frame timeout */
13549 chunk[8]=0; /* flag for changing frame clipping */
13550 chunk[9]=0; /* flag for changing frame sync_id */
13551 PNGLong(chunk+10,(png_uint_32)
13552 ((mng_info->ticks_per_second*
13553 image->delay)/MagickMax(image->ticks_per_second,1)));
13554 (void) WriteBlob(image,14,chunk);
13555 (void) WriteBlobMSBULong(image,crc32(0,chunk,14));
13556 mng_info->delay=(png_uint_32) image->delay;
13558 mng_info->old_framing_mode=mng_info->framing_mode;
13561 #if defined(JNG_SUPPORTED)
13562 if (image_info->compression == JPEGCompression)
13567 if (logging != MagickFalse)
13568 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
13569 " Writing JNG object.");
13570 /* To do: specify the desired alpha compression method. */
13571 write_info=CloneImageInfo(image_info);
13572 write_info->compression=UndefinedCompression;
13573 status=WriteOneJNGImage(mng_info,write_info,image,exception);
13574 write_info=DestroyImageInfo(write_info);
13579 if (logging != MagickFalse)
13580 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
13581 " Writing PNG object.");
13583 mng_info->need_blob = MagickFalse;
13584 mng_info->ping_preserve_colormap = MagickFalse;
13586 /* We don't want any ancillary chunks written */
13587 mng_info->ping_exclude_bKGD=MagickTrue;
13588 mng_info->ping_exclude_cHRM=MagickTrue;
13589 mng_info->ping_exclude_date=MagickTrue;
13590 mng_info->ping_exclude_EXIF=MagickTrue;
13591 mng_info->ping_exclude_gAMA=MagickTrue;
13592 mng_info->ping_exclude_iCCP=MagickTrue;
13593 /* mng_info->ping_exclude_iTXt=MagickTrue; */
13594 mng_info->ping_exclude_oFFs=MagickTrue;
13595 mng_info->ping_exclude_pHYs=MagickTrue;
13596 mng_info->ping_exclude_sRGB=MagickTrue;
13597 mng_info->ping_exclude_tEXt=MagickTrue;
13598 mng_info->ping_exclude_tRNS=MagickTrue;
13599 mng_info->ping_exclude_vpAg=MagickTrue;
13600 mng_info->ping_exclude_zCCP=MagickTrue;
13601 mng_info->ping_exclude_zTXt=MagickTrue;
13603 status=WriteOnePNGImage(mng_info,image_info,image,exception);
13606 if (status == MagickFalse)
13608 MngInfoFreeStruct(mng_info,&have_mng_structure);
13609 (void) CloseBlob(image);
13610 return(MagickFalse);
13612 (void) CatchImageException(image);
13613 if (GetNextImageInList(image) == (Image *) NULL)
13615 image=SyncNextImageInList(image);
13616 status=SetImageProgress(image,SaveImagesTag,scene++,
13617 GetImageListLength(image));
13619 if (status == MagickFalse)
13622 } while (mng_info->adjoin);
13626 while (GetPreviousImageInList(image) != (Image *) NULL)
13627 image=GetPreviousImageInList(image);
13629 Write the MEND chunk.
13631 (void) WriteBlobMSBULong(image,0x00000000L);
13632 PNGType(chunk,mng_MEND);
13633 LogPNGChunk(logging,mng_MEND,0L);
13634 (void) WriteBlob(image,4,chunk);
13635 (void) WriteBlobMSBULong(image,crc32(0,chunk,4));
13638 Relinquish resources.
13640 (void) CloseBlob(image);
13641 MngInfoFreeStruct(mng_info,&have_mng_structure);
13643 if (logging != MagickFalse)
13644 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit WriteMNGImage()");
13646 return(MagickTrue);
13648 #else /* PNG_LIBPNG_VER > 10011 */
13650 static MagickBooleanType WritePNGImage(const ImageInfo *image_info,Image *image)
13653 printf("Your PNG library is too old: You have libpng-%s\n",
13654 PNG_LIBPNG_VER_STRING);
13656 ThrowBinaryException(CoderError,"PNG library is too old",
13657 image_info->filename);
13660 static MagickBooleanType WriteMNGImage(const ImageInfo *image_info,Image *image)
13662 return(WritePNGImage(image_info,image));
13664 #endif /* PNG_LIBPNG_VER > 10011 */