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 /* LBR08: Replicate top 8 bits */
427 #define LBR08PacketRed(pixelpacket) \
429 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).red); \
430 (pixelpacket).red=ScaleCharToQuantum((lbr_bits)); \
432 #define LBR08PacketGreen(pixelpacket) \
434 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).green); \
435 (pixelpacket).green=ScaleCharToQuantum((lbr_bits)); \
437 #define LBR08PacketBlue(pixelpacket) \
439 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).blue); \
440 (pixelpacket).blue=ScaleCharToQuantum((lbr_bits)); \
442 #define LBR08PacketAlpha(pixelpacket) \
444 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).alpha); \
445 (pixelpacket).alpha=ScaleCharToQuantum((lbr_bits)); \
448 #define LBR08PacketRGB(pixelpacket) \
450 LBR08PacketRed((pixelpacket)); \
451 LBR08PacketGreen((pixelpacket)); \
452 LBR08PacketBlue((pixelpacket)); \
455 #define LBR08PacketRGBO(pixelpacket) \
457 LBR08PacketRGB((pixelpacket)); \
458 LBR08PacketAlpha((pixelpacket)); \
461 #define LBR08PixelRed(pixel) \
463 unsigned char lbr_bits= \
464 ScaleQuantumToChar(GetPixelRed(image,(pixel))); \
466 ScaleCharToQuantum((lbr_bits)), (pixel)); \
468 #define LBR08PixelGreen(pixel) \
470 unsigned char lbr_bits= \
471 ScaleQuantumToChar(GetPixelGreen(image,(pixel))); \
472 SetPixelGreen(image,\
473 ScaleCharToQuantum((lbr_bits)), (pixel)); \
475 #define LBR08PixelBlue(pixel) \
477 unsigned char lbr_bits= \
478 ScaleQuantumToChar(GetPixelBlue(image,(pixel))); \
480 ScaleCharToQuantum((lbr_bits)), (pixel)); \
482 #define LBR08PixelAlpha(pixel) \
484 unsigned char lbr_bits= \
485 ScaleQuantumToChar(GetPixelAlpha(image,(pixel))); \
486 SetPixelAlpha(image,\
487 ScaleCharToQuantum((lbr_bits)), (pixel)); \
490 #define LBR08PixelRGB(pixel) \
492 LBR08PixelRed((pixel)); \
493 LBR08PixelGreen((pixel)); \
494 LBR08PixelBlue((pixel)); \
497 #define LBR08PixelRGBA(pixel) \
499 LBR08PixelRGB((pixel)); \
500 LBR08PixelAlpha((pixel)); \
504 #if MAGICKCORE_QUANTUM_DEPTH > 16
505 /* LBR16: Replicate top 16 bits */
507 #define LBR16PacketRed(pixelpacket) \
509 unsigned short lbr_bits=ScaleQuantumToShort((pixelpacket).red); \
510 (pixelpacket).red=ScaleShortToQuantum((lbr_bits)); \
512 #define LBR16PacketGreen(pixelpacket) \
514 unsigned short lbr_bits=ScaleQuantumToShort((pixelpacket).green); \
515 (pixelpacket).green=ScaleShortToQuantum((lbr_bits)); \
517 #define LBR16PacketBlue(pixelpacket) \
519 unsigned short lbr_bits=ScaleQuantumToShort((pixelpacket).blue); \
520 (pixelpacket).blue=ScaleShortToQuantum((lbr_bits)); \
522 #define LBR16PacketAlpha(pixelpacket) \
524 unsigned short lbr_bits=ScaleQuantumToShort((pixelpacket).alpha); \
525 (pixelpacket).alpha=ScaleShortToQuantum((lbr_bits)); \
528 #define LBR16PacketRGB(pixelpacket) \
530 LBR16PacketRed((pixelpacket)); \
531 LBR16PacketGreen((pixelpacket)); \
532 LBR16PacketBlue((pixelpacket)); \
535 #define LBR16PacketRGBO(pixelpacket) \
537 LBR16PacketRGB((pixelpacket)); \
538 LBR16PacketAlpha((pixelpacket)); \
541 #define LBR16PixelRed(pixel) \
543 unsigned short lbr_bits= \
544 ScaleQuantumToShort(GetPixelRed(image,(pixel))); \
546 ScaleShortToQuantum((lbr_bits)),(pixel)); \
548 #define LBR16PixelGreen(pixel) \
550 unsigned short lbr_bits= \
551 ScaleQuantumToShort(GetPixelGreen(image,(pixel))); \
552 SetPixelGreen(image,\
553 ScaleShortToQuantum((lbr_bits)),(pixel)); \
555 #define LBR16PixelBlue(pixel) \
557 unsigned short lbr_bits= \
558 ScaleQuantumToShort(GetPixelBlue(image,(pixel))); \
560 ScaleShortToQuantum((lbr_bits)),(pixel)); \
562 #define LBR16PixelAlpha(pixel) \
564 unsigned short lbr_bits= \
565 ScaleQuantumToShort(GetPixelAlpha(image,(pixel))); \
566 SetPixelAlpha(image,\
567 ScaleShortToQuantum((lbr_bits)),(pixel)); \
570 #define LBR16PixelRGB(pixel) \
572 LBR16PixelRed((pixel)); \
573 LBR16PixelGreen((pixel)); \
574 LBR16PixelBlue((pixel)); \
577 #define LBR16PixelRGBA(pixel) \
579 LBR16PixelRGB((pixel)); \
580 LBR16PixelAlpha((pixel)); \
582 #endif /* MAGICKCORE_QUANTUM_DEPTH > 16 */
585 Establish thread safety.
586 setjmp/longjmp is claimed to be safe on these platforms:
587 setjmp/longjmp is alleged to be unsafe on these platforms:
589 #ifndef SETJMP_IS_THREAD_SAFE
590 #define PNG_SETJMP_NOT_THREAD_SAFE
593 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
595 *ping_semaphore = (SemaphoreInfo *) NULL;
599 This temporary until I set up malloc'ed object attributes array.
600 Recompile with MNG_MAX_OBJECTS=65536L to avoid this limit but
603 #define MNG_MAX_OBJECTS 256
606 If this not defined, spec is interpreted strictly. If it is
607 defined, an attempt will be made to recover from some errors,
609 o global PLTE too short
614 Don't try to define PNG_MNG_FEATURES_SUPPORTED here. Make sure
615 it's defined in libpng/pngconf.h, version 1.0.9 or later. It won't work
616 with earlier versions of libpng. From libpng-1.0.3a to libpng-1.0.8,
617 PNG_READ|WRITE_EMPTY_PLTE were used but those have been deprecated in
618 libpng in favor of PNG_MNG_FEATURES_SUPPORTED, so we set them here.
619 PNG_MNG_FEATURES_SUPPORTED is disabled by default in libpng-1.0.9 and
620 will be enabled by default in libpng-1.2.0.
622 #ifdef PNG_MNG_FEATURES_SUPPORTED
623 # ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
624 # define PNG_READ_EMPTY_PLTE_SUPPORTED
626 # ifndef PNG_WRITE_EMPTY_PLTE_SUPPORTED
627 # define PNG_WRITE_EMPTY_PLTE_SUPPORTED
632 Maximum valid size_t in PNG/MNG chunks is (2^31)-1
633 This macro is only defined in libpng-1.0.3 and later.
634 Previously it was PNG_MAX_UINT but that was deprecated in libpng-1.2.6
636 #ifndef PNG_UINT_31_MAX
637 #define PNG_UINT_31_MAX (png_uint_32) 0x7fffffffL
641 Constant strings for known chunk types. If you need to add a chunk,
642 add a string holding the name here. To make the code more
643 portable, we use ASCII numbers like this, not characters.
646 static png_byte mng_MHDR[5]={ 77, 72, 68, 82, (png_byte) '\0'};
647 static png_byte mng_BACK[5]={ 66, 65, 67, 75, (png_byte) '\0'};
648 static png_byte mng_BASI[5]={ 66, 65, 83, 73, (png_byte) '\0'};
649 static png_byte mng_CLIP[5]={ 67, 76, 73, 80, (png_byte) '\0'};
650 static png_byte mng_CLON[5]={ 67, 76, 79, 78, (png_byte) '\0'};
651 static png_byte mng_DEFI[5]={ 68, 69, 70, 73, (png_byte) '\0'};
652 static png_byte mng_DHDR[5]={ 68, 72, 68, 82, (png_byte) '\0'};
653 static png_byte mng_DISC[5]={ 68, 73, 83, 67, (png_byte) '\0'};
654 static png_byte mng_ENDL[5]={ 69, 78, 68, 76, (png_byte) '\0'};
655 static png_byte mng_FRAM[5]={ 70, 82, 65, 77, (png_byte) '\0'};
656 static png_byte mng_IEND[5]={ 73, 69, 78, 68, (png_byte) '\0'};
657 static png_byte mng_IHDR[5]={ 73, 72, 68, 82, (png_byte) '\0'};
658 static png_byte mng_JHDR[5]={ 74, 72, 68, 82, (png_byte) '\0'};
659 static png_byte mng_LOOP[5]={ 76, 79, 79, 80, (png_byte) '\0'};
660 static png_byte mng_MAGN[5]={ 77, 65, 71, 78, (png_byte) '\0'};
661 static png_byte mng_MEND[5]={ 77, 69, 78, 68, (png_byte) '\0'};
662 static png_byte mng_MOVE[5]={ 77, 79, 86, 69, (png_byte) '\0'};
663 static png_byte mng_PAST[5]={ 80, 65, 83, 84, (png_byte) '\0'};
664 static png_byte mng_PLTE[5]={ 80, 76, 84, 69, (png_byte) '\0'};
665 static png_byte mng_SAVE[5]={ 83, 65, 86, 69, (png_byte) '\0'};
666 static png_byte mng_SEEK[5]={ 83, 69, 69, 75, (png_byte) '\0'};
667 static png_byte mng_SHOW[5]={ 83, 72, 79, 87, (png_byte) '\0'};
668 static png_byte mng_TERM[5]={ 84, 69, 82, 77, (png_byte) '\0'};
669 static png_byte mng_bKGD[5]={ 98, 75, 71, 68, (png_byte) '\0'};
670 static png_byte mng_cHRM[5]={ 99, 72, 82, 77, (png_byte) '\0'};
671 static png_byte mng_gAMA[5]={103, 65, 77, 65, (png_byte) '\0'};
672 static png_byte mng_iCCP[5]={105, 67, 67, 80, (png_byte) '\0'};
673 static png_byte mng_nEED[5]={110, 69, 69, 68, (png_byte) '\0'};
674 static png_byte mng_pHYg[5]={112, 72, 89, 103, (png_byte) '\0'};
675 static png_byte mng_vpAg[5]={118, 112, 65, 103, (png_byte) '\0'};
676 static png_byte mng_pHYs[5]={112, 72, 89, 115, (png_byte) '\0'};
677 static png_byte mng_sBIT[5]={115, 66, 73, 84, (png_byte) '\0'};
678 static png_byte mng_sRGB[5]={115, 82, 71, 66, (png_byte) '\0'};
679 static png_byte mng_tRNS[5]={116, 82, 78, 83, (png_byte) '\0'};
681 #if defined(JNG_SUPPORTED)
682 static png_byte mng_IDAT[5]={ 73, 68, 65, 84, (png_byte) '\0'};
683 static png_byte mng_JDAT[5]={ 74, 68, 65, 84, (png_byte) '\0'};
684 static png_byte mng_JDAA[5]={ 74, 68, 65, 65, (png_byte) '\0'};
685 static png_byte mng_JdAA[5]={ 74, 100, 65, 65, (png_byte) '\0'};
686 static png_byte mng_JSEP[5]={ 74, 83, 69, 80, (png_byte) '\0'};
687 static png_byte mng_oFFs[5]={111, 70, 70, 115, (png_byte) '\0'};
691 Other known chunks that are not yet supported by ImageMagick:
692 static png_byte mng_hIST[5]={104, 73, 83, 84, (png_byte) '\0'};
693 static png_byte mng_iCCP[5]={105, 67, 67, 80, (png_byte) '\0'};
694 static png_byte mng_iTXt[5]={105, 84, 88, 116, (png_byte) '\0'};
695 static png_byte mng_sPLT[5]={115, 80, 76, 84, (png_byte) '\0'};
696 static png_byte mng_sTER[5]={115, 84, 69, 82, (png_byte) '\0'};
697 static png_byte mng_tEXt[5]={116, 69, 88, 116, (png_byte) '\0'};
698 static png_byte mng_tIME[5]={116, 73, 77, 69, (png_byte) '\0'};
699 static png_byte mng_zTXt[5]={122, 84, 88, 116, (png_byte) '\0'};
702 typedef struct _MngBox
711 typedef struct _MngPair
718 #ifdef MNG_OBJECT_BUFFERS
719 typedef struct _MngBuffer
751 typedef struct _MngInfo
754 #ifdef MNG_OBJECT_BUFFERS
756 *ob[MNG_MAX_OBJECTS];
767 #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
768 bytes_in_read_buffer,
774 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
775 defined(PNG_MNG_FEATURES_SUPPORTED)
787 have_saved_bkgd_index,
788 have_write_global_chrm,
789 have_write_global_gama,
790 have_write_global_plte,
791 have_write_global_srgb,
805 x_off[MNG_MAX_OBJECTS],
806 y_off[MNG_MAX_OBJECTS];
812 object_clip[MNG_MAX_OBJECTS];
815 /* These flags could be combined into one byte */
816 exists[MNG_MAX_OBJECTS],
817 frozen[MNG_MAX_OBJECTS],
819 invisible[MNG_MAX_OBJECTS],
820 viewable[MNG_MAX_OBJECTS];
832 #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
850 global_x_pixels_per_unit,
851 global_y_pixels_per_unit,
861 global_phys_unit_type,
876 write_png_compression_level,
877 write_png_compression_strategy,
878 write_png_compression_filter,
883 #ifdef MNG_BASI_SUPPORTED
891 basi_compression_method,
893 basi_interlace_method,
916 /* Added at version 6.6.6-7 */
924 /* ping_exclude_iTXt, */
931 ping_exclude_zCCP, /* hex-encoded iCCP */
933 ping_preserve_colormap;
939 Forward declarations.
941 static MagickBooleanType
942 WritePNGImage(const ImageInfo *,Image *,ExceptionInfo *);
944 static MagickBooleanType
945 WriteMNGImage(const ImageInfo *,Image *,ExceptionInfo *);
947 #if defined(JNG_SUPPORTED)
948 static MagickBooleanType
949 WriteJNGImage(const ImageInfo *,Image *,ExceptionInfo *);
952 #if PNG_LIBPNG_VER > 10011
955 #if (MAGICKCORE_QUANTUM_DEPTH >= 16)
956 static MagickBooleanType
957 LosslessReduceDepthOK(Image *image,ExceptionInfo *exception)
959 /* Reduce bit depth if it can be reduced losslessly from 16+ to 8.
961 * This is true if the high byte and the next highest byte of
962 * each sample of the image, the colormap, and the background color
963 * are equal to each other. We check this by seeing if the samples
964 * are unchanged when we scale them down to 8 and back up to Quantum.
966 * We don't use the method GetImageDepth() because it doesn't check
967 * background and doesn't handle PseudoClass specially.
970 #define QuantumToCharToQuantumEqQuantum(quantum) \
971 ((ScaleCharToQuantum((unsigned char) ScaleQuantumToChar(quantum))) == quantum)
974 ok_to_reduce=MagickFalse;
976 if (image->depth >= 16)
983 QuantumToCharToQuantumEqQuantum(image->background_color.red) &&
984 QuantumToCharToQuantumEqQuantum(image->background_color.green) &&
985 QuantumToCharToQuantumEqQuantum(image->background_color.blue) ?
986 MagickTrue : MagickFalse;
988 if (ok_to_reduce != MagickFalse && image->storage_class == PseudoClass)
992 for (indx=0; indx < (ssize_t) image->colors; indx++)
995 QuantumToCharToQuantumEqQuantum(
996 image->colormap[indx].red) &&
997 QuantumToCharToQuantumEqQuantum(
998 image->colormap[indx].green) &&
999 QuantumToCharToQuantumEqQuantum(
1000 image->colormap[indx].blue)) ?
1001 MagickTrue : MagickFalse;
1003 if (ok_to_reduce == MagickFalse)
1008 if ((ok_to_reduce != MagickFalse) &&
1009 (image->storage_class != PseudoClass))
1017 for (y=0; y < (ssize_t) image->rows; y++)
1019 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1021 if (p == (const Quantum *) NULL)
1023 ok_to_reduce = MagickFalse;
1027 for (x=(ssize_t) image->columns-1; x >= 0; x--)
1030 QuantumToCharToQuantumEqQuantum(GetPixelRed(image,p)) &&
1031 QuantumToCharToQuantumEqQuantum(GetPixelGreen(image,p)) &&
1032 QuantumToCharToQuantumEqQuantum(GetPixelBlue(image,p)) ?
1033 MagickTrue : MagickFalse;
1035 if (ok_to_reduce == MagickFalse)
1038 p+=GetPixelChannels(image);
1045 if (ok_to_reduce != MagickFalse)
1047 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1048 " OK to reduce PNG bit depth to 8 without loss of info");
1052 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1053 " Not OK to reduce PNG bit depth to 8 without loss of info");
1057 return ok_to_reduce;
1059 #endif /* MAGICKCORE_QUANTUM_DEPTH >= 16 */
1061 static const char* PngColorTypeToString(const unsigned int color_type)
1064 *result = "Unknown";
1068 case PNG_COLOR_TYPE_GRAY:
1071 case PNG_COLOR_TYPE_GRAY_ALPHA:
1072 result = "Gray+Alpha";
1074 case PNG_COLOR_TYPE_PALETTE:
1077 case PNG_COLOR_TYPE_RGB:
1080 case PNG_COLOR_TYPE_RGB_ALPHA:
1081 result = "RGB+Alpha";
1089 Magick_RenderingIntent_to_PNG_RenderingIntent(const RenderingIntent intent)
1093 case PerceptualIntent:
1096 case RelativeIntent:
1099 case SaturationIntent:
1102 case AbsoluteIntent:
1110 static RenderingIntent
1111 Magick_RenderingIntent_from_PNG_RenderingIntent(const int ping_intent)
1113 switch (ping_intent)
1116 return PerceptualIntent;
1119 return RelativeIntent;
1122 return SaturationIntent;
1125 return AbsoluteIntent;
1128 return UndefinedIntent;
1133 Magick_RenderingIntentString_from_PNG_RenderingIntent(const int ping_intent)
1135 switch (ping_intent)
1138 return "Perceptual Intent";
1141 return "Relative Intent";
1144 return "Saturation Intent";
1147 return "Absolute Intent";
1150 return "Undefined Intent";
1154 static inline ssize_t MagickMax(const ssize_t x,const ssize_t y)
1163 Magick_ColorType_from_PNG_ColorType(const int ping_colortype)
1165 switch (ping_colortype)
1183 return "UndefinedColorType";
1188 static inline ssize_t MagickMin(const ssize_t x,const ssize_t y)
1195 #endif /* PNG_LIBPNG_VER > 10011 */
1196 #endif /* MAGICKCORE_PNG_DELEGATE */
1199 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1207 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1209 % IsMNG() returns MagickTrue if the image format type, identified by the
1210 % magick string, is MNG.
1212 % The format of the IsMNG method is:
1214 % MagickBooleanType IsMNG(const unsigned char *magick,const size_t length)
1216 % A description of each parameter follows:
1218 % o magick: compare image format pattern against these bytes.
1220 % o length: Specifies the length of the magick string.
1224 static MagickBooleanType IsMNG(const unsigned char *magick,const size_t length)
1227 return(MagickFalse);
1229 if (memcmp(magick,"\212MNG\r\n\032\n",8) == 0)
1232 return(MagickFalse);
1236 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1244 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1246 % IsJNG() returns MagickTrue if the image format type, identified by the
1247 % magick string, is JNG.
1249 % The format of the IsJNG method is:
1251 % MagickBooleanType IsJNG(const unsigned char *magick,const size_t length)
1253 % A description of each parameter follows:
1255 % o magick: compare image format pattern against these bytes.
1257 % o length: Specifies the length of the magick string.
1261 static MagickBooleanType IsJNG(const unsigned char *magick,const size_t length)
1264 return(MagickFalse);
1266 if (memcmp(magick,"\213JNG\r\n\032\n",8) == 0)
1269 return(MagickFalse);
1273 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1281 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1283 % IsPNG() returns MagickTrue if the image format type, identified by the
1284 % magick string, is PNG.
1286 % The format of the IsPNG method is:
1288 % MagickBooleanType IsPNG(const unsigned char *magick,const size_t length)
1290 % A description of each parameter follows:
1292 % o magick: compare image format pattern against these bytes.
1294 % o length: Specifies the length of the magick string.
1297 static MagickBooleanType IsPNG(const unsigned char *magick,const size_t length)
1300 return(MagickFalse);
1302 if (memcmp(magick,"\211PNG\r\n\032\n",8) == 0)
1305 return(MagickFalse);
1308 #if defined(MAGICKCORE_PNG_DELEGATE)
1309 #if defined(__cplusplus) || defined(c_plusplus)
1313 #if (PNG_LIBPNG_VER > 10011)
1314 static size_t WriteBlobMSBULong(Image *image,const size_t value)
1319 assert(image != (Image *) NULL);
1320 assert(image->signature == MagickSignature);
1321 buffer[0]=(unsigned char) (value >> 24);
1322 buffer[1]=(unsigned char) (value >> 16);
1323 buffer[2]=(unsigned char) (value >> 8);
1324 buffer[3]=(unsigned char) value;
1325 return((size_t) WriteBlob(image,4,buffer));
1328 static void PNGLong(png_bytep p,png_uint_32 value)
1330 *p++=(png_byte) ((value >> 24) & 0xff);
1331 *p++=(png_byte) ((value >> 16) & 0xff);
1332 *p++=(png_byte) ((value >> 8) & 0xff);
1333 *p++=(png_byte) (value & 0xff);
1336 #if defined(JNG_SUPPORTED)
1337 static void PNGsLong(png_bytep p,png_int_32 value)
1339 *p++=(png_byte) ((value >> 24) & 0xff);
1340 *p++=(png_byte) ((value >> 16) & 0xff);
1341 *p++=(png_byte) ((value >> 8) & 0xff);
1342 *p++=(png_byte) (value & 0xff);
1346 static void PNGShort(png_bytep p,png_uint_16 value)
1348 *p++=(png_byte) ((value >> 8) & 0xff);
1349 *p++=(png_byte) (value & 0xff);
1352 static void PNGType(png_bytep p,png_bytep type)
1354 (void) CopyMagickMemory(p,type,4*sizeof(png_byte));
1357 static void LogPNGChunk(MagickBooleanType logging, png_bytep type,
1360 if (logging != MagickFalse)
1361 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1362 " Writing %c%c%c%c chunk, length: %.20g",
1363 type[0],type[1],type[2],type[3],(double) length);
1365 #endif /* PNG_LIBPNG_VER > 10011 */
1367 #if defined(__cplusplus) || defined(c_plusplus)
1371 #if PNG_LIBPNG_VER > 10011
1373 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1377 % R e a d P N G I m a g e %
1381 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1383 % ReadPNGImage() reads a Portable Network Graphics (PNG) or
1384 % Multiple-image Network Graphics (MNG) image file and returns it. It
1385 % allocates the memory necessary for the new Image structure and returns a
1386 % pointer to the new image or set of images.
1388 % MNG support written by Glenn Randers-Pehrson, glennrp@image...
1390 % The format of the ReadPNGImage method is:
1392 % Image *ReadPNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
1394 % A description of each parameter follows:
1396 % o image_info: the image info.
1398 % o exception: return any errors or warnings in this structure.
1400 % To do, more or less in chronological order (as of version 5.5.2,
1401 % November 26, 2002 -- glennrp -- see also "To do" under WriteMNGImage):
1403 % Get 16-bit cheap transparency working.
1405 % (At this point, PNG decoding is supposed to be in full MNG-LC compliance)
1407 % Preserve all unknown and not-yet-handled known chunks found in input
1408 % PNG file and copy them into output PNG files according to the PNG
1411 % (At this point, PNG encoding should be in full MNG compliance)
1413 % Provide options for choice of background to use when the MNG BACK
1414 % chunk is not present or is not mandatory (i.e., leave transparent,
1415 % user specified, MNG BACK, PNG bKGD)
1417 % Implement LOOP/ENDL [done, but could do discretionary loops more
1418 % efficiently by linking in the duplicate frames.].
1420 % Decode and act on the MHDR simplicity profile (offer option to reject
1421 % files or attempt to process them anyway when the profile isn't LC or VLC).
1423 % Upgrade to full MNG without Delta-PNG.
1425 % o BACK [done a while ago except for background image ID]
1426 % o MOVE [done 15 May 1999]
1427 % o CLIP [done 15 May 1999]
1428 % o DISC [done 19 May 1999]
1429 % o SAVE [partially done 19 May 1999 (marks objects frozen)]
1430 % o SEEK [partially done 19 May 1999 (discard function only)]
1434 % o MNG-level tEXt/iTXt/zTXt
1439 % o iTXt (wait for libpng implementation).
1441 % Use the scene signature to discover when an identical scene is
1442 % being reused, and just point to the original image->exception instead
1443 % of storing another set of pixels. This not specific to MNG
1444 % but could be applied generally.
1446 % Upgrade to full MNG with Delta-PNG.
1448 % JNG tEXt/iTXt/zTXt
1450 % We will not attempt to read files containing the CgBI chunk.
1451 % They are really Xcode files meant for display on the iPhone.
1452 % These are not valid PNG files and it is impossible to recover
1453 % the original PNG from files that have been converted to Xcode-PNG,
1454 % since irretrievable loss of color data has occurred due to the
1455 % use of premultiplied alpha.
1458 #if defined(__cplusplus) || defined(c_plusplus)
1463 This the function that does the actual reading of data. It is
1464 the same as the one supplied in libpng, except that it receives the
1465 datastream from the ReadBlob() function instead of standard input.
1467 static void png_get_data(png_structp png_ptr,png_bytep data,png_size_t length)
1472 image=(Image *) png_get_io_ptr(png_ptr);
1478 check=(png_size_t) ReadBlob(image,(size_t) length,data);
1479 if (check != length)
1484 (void) FormatLocaleString(msg,MaxTextExtent,
1485 "Expected %.20g bytes; found %.20g bytes",(double) length,
1487 png_warning(png_ptr,msg);
1488 png_error(png_ptr,"Read Exception");
1493 #if !defined(PNG_READ_EMPTY_PLTE_SUPPORTED) && \
1494 !defined(PNG_MNG_FEATURES_SUPPORTED)
1495 /* We use mng_get_data() instead of png_get_data() if we have a libpng
1496 * older than libpng-1.0.3a, which was the first to allow the empty
1497 * PLTE, or a newer libpng in which PNG_MNG_FEATURES_SUPPORTED was
1498 * ifdef'ed out. Earlier versions would crash if the bKGD chunk was
1499 * encountered after an empty PLTE, so we have to look ahead for bKGD
1500 * chunks and remove them from the datastream that is passed to libpng,
1501 * and store their contents for later use.
1503 static void mng_get_data(png_structp png_ptr,png_bytep data,png_size_t length)
1518 mng_info=(MngInfo *) png_get_io_ptr(png_ptr);
1519 image=(Image *) mng_info->image;
1520 while (mng_info->bytes_in_read_buffer && length)
1522 data[i]=mng_info->read_buffer[i];
1523 mng_info->bytes_in_read_buffer--;
1529 check=(png_size_t) ReadBlob(image,(size_t) length,(char *) data);
1531 if (check != length)
1532 png_error(png_ptr,"Read Exception");
1536 if ((data[0] == 0) && (data[1] == 0) && (data[2] == 0) &&
1539 check=(png_size_t) ReadBlob(image,(size_t) length,
1540 (char *) mng_info->read_buffer);
1541 mng_info->read_buffer[4]=0;
1542 mng_info->bytes_in_read_buffer=4;
1543 if (memcmp(mng_info->read_buffer,mng_PLTE,4) == 0)
1544 mng_info->found_empty_plte=MagickTrue;
1545 if (memcmp(mng_info->read_buffer,mng_IEND,4) == 0)
1547 mng_info->found_empty_plte=MagickFalse;
1548 mng_info->have_saved_bkgd_index=MagickFalse;
1552 if ((data[0] == 0) && (data[1] == 0) && (data[2] == 0) &&
1555 check=(png_size_t) ReadBlob(image,(size_t) length,
1556 (char *) mng_info->read_buffer);
1557 mng_info->read_buffer[4]=0;
1558 mng_info->bytes_in_read_buffer=4;
1559 if (memcmp(mng_info->read_buffer,mng_bKGD,4) == 0)
1560 if (mng_info->found_empty_plte)
1563 Skip the bKGD data byte and CRC.
1566 ReadBlob(image,5,(char *) mng_info->read_buffer);
1567 check=(png_size_t) ReadBlob(image,(size_t) length,
1568 (char *) mng_info->read_buffer);
1569 mng_info->saved_bkgd_index=mng_info->read_buffer[0];
1570 mng_info->have_saved_bkgd_index=MagickTrue;
1571 mng_info->bytes_in_read_buffer=0;
1579 static void png_put_data(png_structp png_ptr,png_bytep data,png_size_t length)
1584 image=(Image *) png_get_io_ptr(png_ptr);
1590 check=(png_size_t) WriteBlob(image,(size_t) length,data);
1592 if (check != length)
1593 png_error(png_ptr,"WriteBlob Failed");
1597 static void png_flush_data(png_structp png_ptr)
1602 #ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
1603 static int PalettesAreEqual(Image *a,Image *b)
1608 if ((a == (Image *) NULL) || (b == (Image *) NULL))
1609 return((int) MagickFalse);
1611 if (a->storage_class != PseudoClass || b->storage_class != PseudoClass)
1612 return((int) MagickFalse);
1614 if (a->colors != b->colors)
1615 return((int) MagickFalse);
1617 for (i=0; i < (ssize_t) a->colors; i++)
1619 if ((a->colormap[i].red != b->colormap[i].red) ||
1620 (a->colormap[i].green != b->colormap[i].green) ||
1621 (a->colormap[i].blue != b->colormap[i].blue))
1622 return((int) MagickFalse);
1625 return((int) MagickTrue);
1629 static void MngInfoDiscardObject(MngInfo *mng_info,int i)
1631 if (i && (i < MNG_MAX_OBJECTS) && (mng_info != (MngInfo *) NULL) &&
1632 mng_info->exists[i] && !mng_info->frozen[i])
1634 #ifdef MNG_OBJECT_BUFFERS
1635 if (mng_info->ob[i] != (MngBuffer *) NULL)
1637 if (mng_info->ob[i]->reference_count > 0)
1638 mng_info->ob[i]->reference_count--;
1640 if (mng_info->ob[i]->reference_count == 0)
1642 if (mng_info->ob[i]->image != (Image *) NULL)
1643 mng_info->ob[i]->image=DestroyImage(mng_info->ob[i]->image);
1645 mng_info->ob[i]=DestroyString(mng_info->ob[i]);
1648 mng_info->ob[i]=(MngBuffer *) NULL;
1650 mng_info->exists[i]=MagickFalse;
1651 mng_info->invisible[i]=MagickFalse;
1652 mng_info->viewable[i]=MagickFalse;
1653 mng_info->frozen[i]=MagickFalse;
1654 mng_info->x_off[i]=0;
1655 mng_info->y_off[i]=0;
1656 mng_info->object_clip[i].left=0;
1657 mng_info->object_clip[i].right=(ssize_t) PNG_UINT_31_MAX;
1658 mng_info->object_clip[i].top=0;
1659 mng_info->object_clip[i].bottom=(ssize_t) PNG_UINT_31_MAX;
1663 static void MngInfoFreeStruct(MngInfo *mng_info,
1664 MagickBooleanType *have_mng_structure)
1666 if (*have_mng_structure != MagickFalse && (mng_info != (MngInfo *) NULL))
1671 for (i=1; i < MNG_MAX_OBJECTS; i++)
1672 MngInfoDiscardObject(mng_info,i);
1674 if (mng_info->global_plte != (png_colorp) NULL)
1675 mng_info->global_plte=(png_colorp)
1676 RelinquishMagickMemory(mng_info->global_plte);
1678 mng_info=(MngInfo *) RelinquishMagickMemory(mng_info);
1679 *have_mng_structure=MagickFalse;
1683 static MngBox mng_minimum_box(MngBox box1,MngBox box2)
1689 if (box.left < box2.left)
1692 if (box.top < box2.top)
1695 if (box.right > box2.right)
1696 box.right=box2.right;
1698 if (box.bottom > box2.bottom)
1699 box.bottom=box2.bottom;
1704 static MngBox mng_read_box(MngBox previous_box,char delta_type,unsigned char *p)
1710 Read clipping boundaries from DEFI, CLIP, FRAM, or PAST chunk.
1712 box.left=(ssize_t) ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]);
1713 box.right=(ssize_t) ((p[4] << 24) | (p[5] << 16) | (p[6] << 8) | p[7]);
1714 box.top=(ssize_t) ((p[8] << 24) | (p[9] << 16) | (p[10] << 8) | p[11]);
1715 box.bottom=(ssize_t) ((p[12] << 24) | (p[13] << 16) | (p[14] << 8) | p[15]);
1716 if (delta_type != 0)
1718 box.left+=previous_box.left;
1719 box.right+=previous_box.right;
1720 box.top+=previous_box.top;
1721 box.bottom+=previous_box.bottom;
1727 static MngPair mng_read_pair(MngPair previous_pair,int delta_type,
1733 Read two ssize_ts from CLON, MOVE or PAST chunk
1735 pair.a=(long) ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]);
1736 pair.b=(long) ((p[4] << 24) | (p[5] << 16) | (p[6] << 8) | p[7]);
1738 if (delta_type != 0)
1740 pair.a+=previous_pair.a;
1741 pair.b+=previous_pair.b;
1747 static long mng_get_long(unsigned char *p)
1749 return((long) ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]));
1752 typedef struct _PNGErrorInfo
1761 static void MagickPNGErrorHandler(png_struct *ping,png_const_charp message)
1772 error_info=(PNGErrorInfo *) png_get_error_ptr(ping);
1773 image=error_info->image;
1774 exception=error_info->exception;
1776 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1777 " libpng-%s error: %s", PNG_LIBPNG_VER_STRING,message);
1779 (void) ThrowMagickException(exception,GetMagickModule(),CoderError,message,
1780 "`%s'",image->filename);
1782 #if (PNG_LIBPNG_VER < 10500)
1783 /* A warning about deprecated use of jmpbuf here is unavoidable if you
1784 * are building with libpng-1.4.x and can be ignored.
1786 longjmp(ping->jmpbuf,1);
1788 png_longjmp(ping,1);
1792 static void MagickPNGWarningHandler(png_struct *ping,png_const_charp message)
1803 if (LocaleCompare(message, "Missing PLTE before tRNS") == 0)
1804 png_error(ping, message);
1806 error_info=(PNGErrorInfo *) png_get_error_ptr(ping);
1807 image=error_info->image;
1808 exception=error_info->exception;
1809 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1810 " libpng-%s warning: %s", PNG_LIBPNG_VER_STRING,message);
1812 (void) ThrowMagickException(exception,GetMagickModule(),CoderWarning,
1813 message,"`%s'",image->filename);
1816 #ifdef PNG_USER_MEM_SUPPORTED
1817 #if PNG_LIBPNG_VER >= 14000
1818 static png_voidp Magick_png_malloc(png_structp png_ptr,png_alloc_size_t size)
1820 static png_voidp Magick_png_malloc(png_structp png_ptr,png_size_t size)
1824 return((png_voidp) AcquireMagickMemory((size_t) size));
1828 Free a pointer. It is removed from the list at the same time.
1830 static png_free_ptr Magick_png_free(png_structp png_ptr,png_voidp ptr)
1833 ptr=RelinquishMagickMemory(ptr);
1834 return((png_free_ptr) NULL);
1838 #if defined(__cplusplus) || defined(c_plusplus)
1843 Magick_png_read_raw_profile(png_struct *ping,Image *image,
1844 const ImageInfo *image_info, png_textp text,int ii,ExceptionInfo *exception)
1849 register unsigned char
1863 unhex[103]={0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,
1864 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,
1865 0,0,0,0,0,0,0,0,0,1, 2,3,4,5,6,7,8,9,0,0,
1866 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,
1867 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,10,11,12,
1871 /* look for newline */
1875 /* look for length */
1876 while (*sp == '\0' || *sp == ' ' || *sp == '\n')
1879 length=(png_uint_32) StringToLong(sp);
1881 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1882 " length: %lu",(unsigned long) length);
1884 while (*sp != ' ' && *sp != '\n')
1887 /* allocate space */
1890 png_warning(ping,"invalid profile length");
1891 return(MagickFalse);
1894 profile=BlobToStringInfo((const void *) NULL,length);
1896 if (profile == (StringInfo *) NULL)
1898 png_warning(ping, "unable to copy profile");
1899 return(MagickFalse);
1902 /* copy profile, skipping white space and column 1 "=" signs */
1903 dp=GetStringInfoDatum(profile);
1906 for (i=0; i < (ssize_t) nibbles; i++)
1908 while (*sp < '0' || (*sp > '9' && *sp < 'a') || *sp > 'f')
1912 png_warning(ping, "ran out of profile data");
1913 profile=DestroyStringInfo(profile);
1914 return(MagickFalse);
1920 *dp=(unsigned char) (16*unhex[(int) *sp++]);
1923 (*dp++)+=unhex[(int) *sp++];
1926 We have already read "Raw profile type.
1928 (void) SetImageProfile(image,&text[ii].key[17],profile,exception);
1929 profile=DestroyStringInfo(profile);
1931 if (image_info->verbose)
1932 (void) printf(" Found a generic profile, type %s\n",&text[ii].key[17]);
1937 #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
1938 static int read_vpag_chunk_callback(png_struct *ping, png_unknown_chunkp chunk)
1944 /* The unknown chunk structure contains the chunk data:
1949 Note that libpng has already taken care of the CRC handling.
1953 if (chunk->name[0] != 118 || chunk->name[1] != 112 ||
1954 chunk->name[2] != 65 ||chunk-> name[3] != 103)
1955 return(0); /* Did not recognize */
1957 /* recognized vpAg */
1959 if (chunk->size != 9)
1960 return(-1); /* Error return */
1962 if (chunk->data[8] != 0)
1963 return(0); /* ImageMagick requires pixel units */
1965 image=(Image *) png_get_user_chunk_ptr(ping);
1967 image->page.width=(size_t) ((chunk->data[0] << 24) |
1968 (chunk->data[1] << 16) | (chunk->data[2] << 8) | chunk->data[3]);
1970 image->page.height=(size_t) ((chunk->data[4] << 24) |
1971 (chunk->data[5] << 16) | (chunk->data[6] << 8) | chunk->data[7]);
1973 /* Return one of the following: */
1974 /* return(-n); chunk had an error */
1975 /* return(0); did not recognize */
1976 /* return(n); success */
1984 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1988 % R e a d O n e P N G I m a g e %
1992 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1994 % ReadOnePNGImage() reads a Portable Network Graphics (PNG) image file
1995 % (minus the 8-byte signature) and returns it. It allocates the memory
1996 % necessary for the new Image structure and returns a pointer to the new
1999 % The format of the ReadOnePNGImage method is:
2001 % Image *ReadOnePNGImage(MngInfo *mng_info, const ImageInfo *image_info,
2002 % ExceptionInfo *exception)
2004 % A description of each parameter follows:
2006 % o mng_info: Specifies a pointer to a MngInfo structure.
2008 % o image_info: the image info.
2010 % o exception: return any errors or warnings in this structure.
2013 static Image *ReadOnePNGImage(MngInfo *mng_info,
2014 const ImageInfo *image_info, ExceptionInfo *exception)
2016 /* Read one PNG image */
2018 /* To do: Read the tIME chunk into the date:modify property */
2019 /* To do: Read the tEXt/Creation Time chunk into the date:create property */
2025 intent, /* "PNG Rendering intent", which is ICC intent + 1 */
2035 ping_interlace_method,
2036 ping_compression_method,
2088 register unsigned char
2106 *volatile ping_pixels;
2108 #ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED
2109 png_byte unused_chunks[]=
2111 104, 73, 83, 84, (png_byte) '\0', /* hIST */
2112 105, 84, 88, 116, (png_byte) '\0', /* iTXt */
2113 112, 67, 65, 76, (png_byte) '\0', /* pCAL */
2114 115, 67, 65, 76, (png_byte) '\0', /* sCAL */
2115 115, 80, 76, 84, (png_byte) '\0', /* sPLT */
2116 116, 73, 77, 69, (png_byte) '\0', /* tIME */
2117 #ifdef PNG_APNG_SUPPORTED /* libpng was built with APNG patch; */
2118 /* ignore the APNG chunks */
2119 97, 99, 84, 76, (png_byte) '\0', /* acTL */
2120 102, 99, 84, 76, (png_byte) '\0', /* fcTL */
2121 102, 100, 65, 84, (png_byte) '\0', /* fdAT */
2126 logging=LogMagickEvent(CoderEvent,GetMagickModule(),
2127 " Enter ReadOnePNGImage()");
2129 #if (PNG_LIBPNG_VER < 10200)
2130 if (image_info->verbose)
2131 printf("Your PNG library (libpng-%s) is rather old.\n",
2132 PNG_LIBPNG_VER_STRING);
2135 #if (PNG_LIBPNG_VER >= 10400)
2136 # ifndef PNG_TRANSFORM_GRAY_TO_RGB /* Added at libpng-1.4.0beta67 */
2137 if (image_info->verbose)
2139 printf("Your PNG library (libpng-%s) is an old beta version.\n",
2140 PNG_LIBPNG_VER_STRING);
2141 printf("Please update it.\n");
2147 quantum_info = (QuantumInfo *) NULL;
2148 image=mng_info->image;
2150 if (logging != MagickFalse)
2152 (void)LogMagickEvent(CoderEvent,GetMagickModule(),
2153 " image->alpha_trait=%d",(int) image->alpha_trait);
2155 (void)LogMagickEvent(CoderEvent,GetMagickModule(),
2156 " image->rendering_intent=%d",(int) image->rendering_intent);
2158 (void)LogMagickEvent(CoderEvent,GetMagickModule(),
2159 " image->colorspace=%d",(int) image->colorspace);
2161 intent=Magick_RenderingIntent_to_PNG_RenderingIntent(image->rendering_intent);
2163 /* Set to an out-of-range color unless tRNS chunk is present */
2164 transparent_color.red=65537;
2165 transparent_color.green=65537;
2166 transparent_color.blue=65537;
2167 transparent_color.alpha=65537;
2172 num_raw_profiles = 0;
2174 ping_found_cHRM = MagickFalse;
2175 ping_found_gAMA = MagickFalse;
2176 ping_found_iCCP = MagickFalse;
2177 ping_found_sRGB = MagickFalse;
2180 Allocate the PNG structures
2182 #ifdef PNG_USER_MEM_SUPPORTED
2183 error_info.image=image;
2184 error_info.exception=exception;
2185 ping=png_create_read_struct_2(PNG_LIBPNG_VER_STRING,&error_info,
2186 MagickPNGErrorHandler,MagickPNGWarningHandler, NULL,
2187 (png_malloc_ptr) Magick_png_malloc,(png_free_ptr) Magick_png_free);
2189 ping=png_create_read_struct(PNG_LIBPNG_VER_STRING,&error_info,
2190 MagickPNGErrorHandler,MagickPNGWarningHandler);
2192 if (ping == (png_struct *) NULL)
2193 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2195 ping_info=png_create_info_struct(ping);
2197 if (ping_info == (png_info *) NULL)
2199 png_destroy_read_struct(&ping,(png_info **) NULL,(png_info **) NULL);
2200 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2203 end_info=png_create_info_struct(ping);
2205 if (end_info == (png_info *) NULL)
2207 png_destroy_read_struct(&ping,&ping_info,(png_info **) NULL);
2208 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2211 ping_pixels=(unsigned char *) NULL;
2213 if (setjmp(png_jmpbuf(ping)))
2216 PNG image is corrupt.
2218 png_destroy_read_struct(&ping,&ping_info,&end_info);
2220 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
2221 UnlockSemaphoreInfo(ping_semaphore);
2224 if (ping_pixels != (unsigned char *) NULL)
2225 ping_pixels=(unsigned char *) RelinquishMagickMemory(ping_pixels);
2227 if (logging != MagickFalse)
2228 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2229 " exit ReadOnePNGImage() with error.");
2231 if (image != (Image *) NULL)
2233 InheritException(exception,exception);
2237 return(GetFirstImageInList(image));
2240 /* { For navigation to end of SETJMP-protected block. Within this
2241 * block, use png_error() instead of Throwing an Exception, to ensure
2242 * that libpng is able to clean up, and that the semaphore is unlocked.
2245 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
2246 LockSemaphoreInfo(ping_semaphore);
2250 Prepare PNG for reading.
2253 mng_info->image_found++;
2254 png_set_sig_bytes(ping,8);
2256 if (LocaleCompare(image_info->magick,"MNG") == 0)
2258 #if defined(PNG_MNG_FEATURES_SUPPORTED)
2259 (void) png_permit_mng_features(ping,PNG_ALL_MNG_FEATURES);
2260 png_set_read_fn(ping,image,png_get_data);
2262 #if defined(PNG_READ_EMPTY_PLTE_SUPPORTED)
2263 png_permit_empty_plte(ping,MagickTrue);
2264 png_set_read_fn(ping,image,png_get_data);
2266 mng_info->image=image;
2267 mng_info->bytes_in_read_buffer=0;
2268 mng_info->found_empty_plte=MagickFalse;
2269 mng_info->have_saved_bkgd_index=MagickFalse;
2270 png_set_read_fn(ping,mng_info,mng_get_data);
2276 png_set_read_fn(ping,image,png_get_data);
2278 #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
2279 /* Ignore unused chunks and all unknown chunks except for vpAg */
2280 png_set_keep_unknown_chunks(ping, 1, NULL, 0);
2281 png_set_keep_unknown_chunks(ping, 2, mng_vpAg, 1);
2282 png_set_keep_unknown_chunks(ping, 1, unused_chunks,
2283 (int)sizeof(unused_chunks)/5);
2284 /* Callback for other unknown chunks */
2285 png_set_read_user_chunk_fn(ping, image, read_vpag_chunk_callback);
2288 #ifdef PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED
2289 /* Disable new libpng-1.5.10 feature */
2290 png_set_check_for_invalid_index (ping, 0);
2293 #if (PNG_LIBPNG_VER < 10400)
2294 # if defined(PNG_USE_PNGGCCRD) && defined(PNG_ASSEMBLER_CODE_SUPPORTED) && \
2295 (PNG_LIBPNG_VER >= 10200) && (PNG_LIBPNG_VER < 10220) && defined(__i386__)
2296 /* Disable thread-unsafe features of pnggccrd */
2297 if (png_access_version_number() >= 10200)
2299 png_uint_32 mmx_disable_mask=0;
2300 png_uint_32 asm_flags;
2302 mmx_disable_mask |= ( PNG_ASM_FLAG_MMX_READ_COMBINE_ROW \
2303 | PNG_ASM_FLAG_MMX_READ_FILTER_SUB \
2304 | PNG_ASM_FLAG_MMX_READ_FILTER_AVG \
2305 | PNG_ASM_FLAG_MMX_READ_FILTER_PAETH );
2306 asm_flags=png_get_asm_flags(ping);
2307 png_set_asm_flags(ping, asm_flags & ~mmx_disable_mask);
2312 png_read_info(ping,ping_info);
2314 png_get_IHDR(ping,ping_info,&ping_width,&ping_height,
2315 &ping_bit_depth,&ping_color_type,
2316 &ping_interlace_method,&ping_compression_method,
2317 &ping_filter_method);
2319 ping_file_depth = ping_bit_depth;
2321 (void) png_get_tRNS(ping, ping_info, &ping_trans_alpha, &ping_num_trans,
2324 (void) png_get_bKGD(ping, ping_info, &ping_background);
2326 if (ping_bit_depth < 8)
2328 png_set_packing(ping);
2332 image->depth=ping_bit_depth;
2333 image->depth=GetImageQuantumDepth(image,MagickFalse);
2334 image->interlace=ping_interlace_method != 0 ? PNGInterlace : NoInterlace;
2336 if (((int) ping_color_type == PNG_COLOR_TYPE_GRAY) ||
2337 ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA))
2339 image->rendering_intent=UndefinedIntent;
2340 intent=Magick_RenderingIntent_to_PNG_RenderingIntent(UndefinedIntent);
2342 (void) ResetMagickMemory(&image->chromaticity,0,
2343 sizeof(image->chromaticity));
2346 if (logging != MagickFalse)
2348 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2349 " PNG width: %.20g, height: %.20g",
2350 (double) ping_width, (double) ping_height);
2352 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2353 " PNG color_type: %d, bit_depth: %d",
2354 ping_color_type, ping_bit_depth);
2356 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2357 " PNG compression_method: %d",
2358 ping_compression_method);
2360 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2361 " PNG interlace_method: %d, filter_method: %d",
2362 ping_interlace_method,ping_filter_method);
2365 if (png_get_valid(ping,ping_info,PNG_INFO_gAMA))
2367 ping_found_gAMA=MagickTrue;
2368 if (logging != MagickFalse)
2369 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2370 " Found PNG gAMA chunk.");
2373 if (png_get_valid(ping,ping_info,PNG_INFO_cHRM))
2375 ping_found_cHRM=MagickTrue;
2376 if (logging != MagickFalse)
2377 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2378 " Found PNG cHRM chunk.");
2381 if (png_get_valid(ping,ping_info,PNG_INFO_iCCP))
2383 ping_found_iCCP=MagickTrue;
2384 if (logging != MagickFalse)
2385 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2386 " Found PNG iCCP chunk.");
2389 if (png_get_valid(ping,ping_info,PNG_INFO_sRGB))
2391 ping_found_sRGB=MagickTrue;
2392 if (logging != MagickFalse)
2393 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2394 " Found PNG sRGB chunk.");
2397 #ifdef PNG_READ_iCCP_SUPPORTED
2398 if (png_get_valid(ping,ping_info,PNG_INFO_iCCP))
2403 #if (PNG_LIBPNG_VER < 10500)
2417 (void) png_get_iCCP(ping,ping_info,&name,(int *) &compression,&info,
2420 if (profile_length != 0)
2425 if (logging != MagickFalse)
2426 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2427 " Reading PNG iCCP chunk.");
2428 profile=BlobToStringInfo(info,profile_length);
2429 if (profile == (StringInfo *) NULL)
2431 png_warning(ping, "ICC profile is NULL");
2432 profile=DestroyStringInfo(profile);
2436 (void) SetImageProfile(image,"icc",profile,exception);
2437 profile=DestroyStringInfo(profile);
2442 #if defined(PNG_READ_sRGB_SUPPORTED)
2444 if (mng_info->have_global_srgb)
2446 image->rendering_intent=Magick_RenderingIntent_from_PNG_RenderingIntent
2447 (mng_info->global_srgb_intent);
2450 if (png_get_sRGB(ping,ping_info,&intent))
2452 image->rendering_intent=Magick_RenderingIntent_from_PNG_RenderingIntent
2455 if (logging != MagickFalse)
2456 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2457 " Reading PNG sRGB chunk: rendering_intent: %d",intent);
2462 if (!png_get_gAMA(ping,ping_info,&file_gamma))
2463 if (mng_info->have_global_gama)
2464 png_set_gAMA(ping,ping_info,mng_info->global_gamma);
2466 if (png_get_gAMA(ping,ping_info,&file_gamma))
2468 image->gamma=(float) file_gamma;
2469 if (logging != MagickFalse)
2470 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2471 " Reading PNG gAMA chunk: gamma: %f",file_gamma);
2475 if (!png_get_valid(ping,ping_info,PNG_INFO_cHRM))
2477 if (mng_info->have_global_chrm != MagickFalse)
2479 (void) png_set_cHRM(ping,ping_info,
2480 mng_info->global_chrm.white_point.x,
2481 mng_info->global_chrm.white_point.y,
2482 mng_info->global_chrm.red_primary.x,
2483 mng_info->global_chrm.red_primary.y,
2484 mng_info->global_chrm.green_primary.x,
2485 mng_info->global_chrm.green_primary.y,
2486 mng_info->global_chrm.blue_primary.x,
2487 mng_info->global_chrm.blue_primary.y);
2491 if (png_get_valid(ping,ping_info,PNG_INFO_cHRM))
2493 (void) png_get_cHRM(ping,ping_info,
2494 &image->chromaticity.white_point.x,
2495 &image->chromaticity.white_point.y,
2496 &image->chromaticity.red_primary.x,
2497 &image->chromaticity.red_primary.y,
2498 &image->chromaticity.green_primary.x,
2499 &image->chromaticity.green_primary.y,
2500 &image->chromaticity.blue_primary.x,
2501 &image->chromaticity.blue_primary.y);
2505 if (image->rendering_intent != UndefinedIntent)
2507 png_set_sRGB(ping,ping_info,
2508 Magick_RenderingIntent_to_PNG_RenderingIntent
2509 (image->rendering_intent));
2510 png_set_gAMA(ping,ping_info,1.000f/2.200f);
2511 png_set_cHRM(ping,ping_info,
2512 0.6400f, 0.3300f, 0.3000f, 0.6000f,
2513 0.1500f, 0.0600f, 0.3127f, 0.3290f);
2515 #if defined(PNG_oFFs_SUPPORTED)
2516 if (png_get_valid(ping,ping_info,PNG_INFO_oFFs))
2518 image->page.x=(ssize_t) png_get_x_offset_pixels(ping, ping_info);
2519 image->page.y=(ssize_t) png_get_y_offset_pixels(ping, ping_info);
2521 if (logging != MagickFalse)
2522 if (image->page.x || image->page.y)
2523 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2524 " Reading PNG oFFs chunk: x: %.20g, y: %.20g.",(double)
2525 image->page.x,(double) image->page.y);
2528 #if defined(PNG_pHYs_SUPPORTED)
2529 if (!png_get_valid(ping,ping_info,PNG_INFO_pHYs))
2531 if (mng_info->have_global_phys)
2533 png_set_pHYs(ping,ping_info,
2534 mng_info->global_x_pixels_per_unit,
2535 mng_info->global_y_pixels_per_unit,
2536 mng_info->global_phys_unit_type);
2540 if (png_get_valid(ping,ping_info,PNG_INFO_pHYs))
2543 Set image resolution.
2545 (void) png_get_pHYs(ping,ping_info,&x_resolution,&y_resolution,
2547 image->resolution.x=(double) x_resolution;
2548 image->resolution.y=(double) y_resolution;
2550 if (unit_type == PNG_RESOLUTION_METER)
2552 image->units=PixelsPerCentimeterResolution;
2553 image->resolution.x=(double) x_resolution/100.0;
2554 image->resolution.y=(double) y_resolution/100.0;
2557 if (logging != MagickFalse)
2558 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2559 " Reading PNG pHYs chunk: xres: %.20g, yres: %.20g, units: %d.",
2560 (double) x_resolution,(double) y_resolution,unit_type);
2564 if (png_get_valid(ping,ping_info,PNG_INFO_PLTE))
2569 (void) png_get_PLTE(ping,ping_info,&palette,&number_colors);
2571 if ((number_colors == 0) &&
2572 ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE))
2574 if (mng_info->global_plte_length)
2576 png_set_PLTE(ping,ping_info,mng_info->global_plte,
2577 (int) mng_info->global_plte_length);
2579 if (!png_get_valid(ping,ping_info,PNG_INFO_tRNS))
2581 if (mng_info->global_trns_length)
2584 "global tRNS has more entries than global PLTE");
2588 png_set_tRNS(ping,ping_info,mng_info->global_trns,
2589 (int) mng_info->global_trns_length,NULL);
2592 #ifdef PNG_READ_bKGD_SUPPORTED
2594 #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
2595 mng_info->have_saved_bkgd_index ||
2597 png_get_valid(ping,ping_info,PNG_INFO_bKGD))
2602 #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
2603 if (mng_info->have_saved_bkgd_index)
2604 background.index=mng_info->saved_bkgd_index;
2606 if (png_get_valid(ping, ping_info, PNG_INFO_bKGD))
2607 background.index=ping_background->index;
2609 background.red=(png_uint_16)
2610 mng_info->global_plte[background.index].red;
2612 background.green=(png_uint_16)
2613 mng_info->global_plte[background.index].green;
2615 background.blue=(png_uint_16)
2616 mng_info->global_plte[background.index].blue;
2618 background.gray=(png_uint_16)
2619 mng_info->global_plte[background.index].green;
2621 png_set_bKGD(ping,ping_info,&background);
2626 png_error(ping,"No global PLTE in file");
2630 #ifdef PNG_READ_bKGD_SUPPORTED
2631 if (mng_info->have_global_bkgd &&
2632 (!png_get_valid(ping,ping_info,PNG_INFO_bKGD)))
2633 image->background_color=mng_info->mng_global_bkgd;
2635 if (png_get_valid(ping,ping_info,PNG_INFO_bKGD))
2641 Set image background color.
2643 if (logging != MagickFalse)
2644 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2645 " Reading PNG bKGD chunk.");
2647 /* Scale background components to 16-bit, then scale
2650 if (logging != MagickFalse)
2651 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2652 " raw ping_background=(%d,%d,%d).",ping_background->red,
2653 ping_background->green,ping_background->blue);
2657 if (ping_file_depth == 1)
2660 else if (ping_file_depth == 2)
2663 else if (ping_file_depth == 4)
2666 if (ping_file_depth <= 8)
2669 ping_background->red *= bkgd_scale;
2670 ping_background->green *= bkgd_scale;
2671 ping_background->blue *= bkgd_scale;
2673 if (logging != MagickFalse)
2675 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2676 " bkgd_scale=%d.",bkgd_scale);
2678 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2679 " ping_background=(%d,%d,%d).",ping_background->red,
2680 ping_background->green,ping_background->blue);
2683 image->background_color.red=
2684 ScaleShortToQuantum(ping_background->red);
2686 image->background_color.green=
2687 ScaleShortToQuantum(ping_background->green);
2689 image->background_color.blue=
2690 ScaleShortToQuantum(ping_background->blue);
2692 image->background_color.alpha=OpaqueAlpha;
2694 if (logging != MagickFalse)
2695 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2696 " image->background_color=(%.20g,%.20g,%.20g).",
2697 (double) image->background_color.red,
2698 (double) image->background_color.green,
2699 (double) image->background_color.blue);
2701 #endif /* PNG_READ_bKGD_SUPPORTED */
2703 if (png_get_valid(ping,ping_info,PNG_INFO_tRNS))
2706 Image has a tRNS chunk.
2714 if (logging != MagickFalse)
2715 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2716 " Reading PNG tRNS chunk.");
2718 max_sample = (int) ((one << ping_file_depth) - 1);
2720 if ((ping_color_type == PNG_COLOR_TYPE_GRAY &&
2721 (int)ping_trans_color->gray > max_sample) ||
2722 (ping_color_type == PNG_COLOR_TYPE_RGB &&
2723 ((int)ping_trans_color->red > max_sample ||
2724 (int)ping_trans_color->green > max_sample ||
2725 (int)ping_trans_color->blue > max_sample)))
2727 if (logging != MagickFalse)
2728 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2729 " Ignoring PNG tRNS chunk with out-of-range sample.");
2730 png_free_data(ping, ping_info, PNG_FREE_TRNS, 0);
2731 png_set_invalid(ping,ping_info,PNG_INFO_tRNS);
2732 image->alpha_trait=UndefinedPixelTrait;
2739 scale_to_short = 65535L/((1UL << ping_file_depth)-1);
2741 /* Scale transparent_color to short */
2742 transparent_color.red= scale_to_short*ping_trans_color->red;
2743 transparent_color.green= scale_to_short*ping_trans_color->green;
2744 transparent_color.blue= scale_to_short*ping_trans_color->blue;
2745 transparent_color.alpha= scale_to_short*ping_trans_color->gray;
2747 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
2749 if (logging != MagickFalse)
2751 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2752 " Raw tRNS graylevel is %d.",ping_trans_color->gray);
2754 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2755 " scaled graylevel is %.20g.",transparent_color.alpha);
2757 transparent_color.red=transparent_color.alpha;
2758 transparent_color.green=transparent_color.alpha;
2759 transparent_color.blue=transparent_color.alpha;
2763 #if defined(PNG_READ_sBIT_SUPPORTED)
2764 if (mng_info->have_global_sbit)
2766 if (!png_get_valid(ping,ping_info,PNG_INFO_sBIT))
2767 png_set_sBIT(ping,ping_info,&mng_info->global_sbit);
2770 num_passes=png_set_interlace_handling(ping);
2772 png_read_update_info(ping,ping_info);
2774 ping_rowbytes=png_get_rowbytes(ping,ping_info);
2777 Initialize image structure.
2779 mng_info->image_box.left=0;
2780 mng_info->image_box.right=(ssize_t) ping_width;
2781 mng_info->image_box.top=0;
2782 mng_info->image_box.bottom=(ssize_t) ping_height;
2783 if (mng_info->mng_type == 0)
2785 mng_info->mng_width=ping_width;
2786 mng_info->mng_height=ping_height;
2787 mng_info->frame=mng_info->image_box;
2788 mng_info->clip=mng_info->image_box;
2793 image->page.y=mng_info->y_off[mng_info->object_id];
2796 image->compression=ZipCompression;
2797 image->columns=ping_width;
2798 image->rows=ping_height;
2800 if (((int) ping_color_type == PNG_COLOR_TYPE_GRAY) ||
2801 ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA))
2803 if ((!png_get_valid(ping,ping_info,PNG_INFO_gAMA) ||
2804 image->gamma == 1.0) &&
2805 !png_get_valid(ping,ping_info,PNG_INFO_cHRM) &&
2806 !png_get_valid(ping,ping_info,PNG_INFO_sRGB))
2808 /* Set image->gamma to 1.0, image->rendering_intent to Undefined,
2809 * image->colorspace to GRAY, and reset image->chromaticity.
2811 SetImageColorspace(image,GRAYColorspace,exception);
2815 (void)LogMagickEvent(CoderEvent,GetMagickModule(),
2816 " image->colorspace=%d",(int) image->colorspace);
2818 if (((int) ping_color_type == PNG_COLOR_TYPE_PALETTE) ||
2819 ((int) ping_bit_depth < 16 &&
2820 (int) ping_color_type == PNG_COLOR_TYPE_GRAY))
2825 image->storage_class=PseudoClass;
2827 image->colors=one << ping_file_depth;
2828 #if (MAGICKCORE_QUANTUM_DEPTH == 8)
2829 if (image->colors > 256)
2832 if (image->colors > 65536L)
2833 image->colors=65536L;
2835 if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
2840 (void) png_get_PLTE(ping,ping_info,&palette,&number_colors);
2841 image->colors=(size_t) number_colors;
2843 if (logging != MagickFalse)
2844 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2845 " Reading PNG PLTE chunk: number_colors: %d.",number_colors);
2849 if (image->storage_class == PseudoClass)
2852 Initialize image colormap.
2854 if (AcquireImageColormap(image,image->colors,exception) == MagickFalse)
2855 png_error(ping,"Memory allocation failed");
2857 if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
2862 (void) png_get_PLTE(ping,ping_info,&palette,&number_colors);
2864 for (i=0; i < (ssize_t) number_colors; i++)
2866 image->colormap[i].red=ScaleCharToQuantum(palette[i].red);
2867 image->colormap[i].green=ScaleCharToQuantum(palette[i].green);
2868 image->colormap[i].blue=ScaleCharToQuantum(palette[i].blue);
2871 for ( ; i < (ssize_t) image->colors; i++)
2873 image->colormap[i].red=0;
2874 image->colormap[i].green=0;
2875 image->colormap[i].blue=0;
2884 scale=(QuantumRange/((1UL << ping_file_depth)-1));
2889 for (i=0; i < (ssize_t) image->colors; i++)
2891 image->colormap[i].red=(Quantum) (i*scale);
2892 image->colormap[i].green=(Quantum) (i*scale);
2893 image->colormap[i].blue=(Quantum) (i*scale);
2898 /* Set some properties for reporting by "identify" */
2903 /* encode ping_width, ping_height, ping_file_depth, ping_color_type,
2904 ping_interlace_method in value */
2906 (void) FormatLocaleString(msg,MaxTextExtent,
2907 "%d, %d",(int) ping_width, (int) ping_height);
2908 (void) SetImageProperty(image,"png:IHDR.width,height ",msg,exception);
2910 (void) FormatLocaleString(msg,MaxTextExtent,"%d",(int) ping_file_depth);
2911 (void) SetImageProperty(image,"png:IHDR.bit_depth ",msg,exception);
2913 (void) FormatLocaleString(msg,MaxTextExtent,"%d (%s)",
2914 (int) ping_color_type,
2915 Magick_ColorType_from_PNG_ColorType((int)ping_color_type));
2916 (void) SetImageProperty(image,"png:IHDR.color_type ",msg,exception);
2918 if (ping_interlace_method == 0)
2920 (void) FormatLocaleString(msg,MaxTextExtent,"%d (Not interlaced)",
2921 (int) ping_interlace_method);
2923 else if (ping_interlace_method == 1)
2925 (void) FormatLocaleString(msg,MaxTextExtent,"%d (Adam7 method)",
2926 (int) ping_interlace_method);
2930 (void) FormatLocaleString(msg,MaxTextExtent,"%d (Unknown method)",
2931 (int) ping_interlace_method);
2933 (void) SetImageProperty(image,"png:IHDR.interlace_method",msg,exception);
2935 if (number_colors != 0)
2937 (void) FormatLocaleString(msg,MaxTextExtent,"%d",
2938 (int) number_colors);
2939 (void) SetImageProperty(image,"png:PLTE.number_colors ",msg,
2945 Read image scanlines.
2947 if (image->delay != 0)
2948 mng_info->scenes_found++;
2950 if ((mng_info->mng_type == 0 && (image->ping != MagickFalse)) || (
2951 (image_info->number_scenes != 0) && (mng_info->scenes_found > (ssize_t)
2952 (image_info->first_scene+image_info->number_scenes))))
2954 /* This happens later in non-ping decodes */
2955 if (png_get_valid(ping,ping_info,PNG_INFO_tRNS))
2956 image->storage_class=DirectClass;
2958 if (logging != MagickFalse)
2959 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2960 " Skipping PNG image data for scene %.20g",(double)
2961 mng_info->scenes_found-1);
2962 png_destroy_read_struct(&ping,&ping_info,&end_info);
2964 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
2965 UnlockSemaphoreInfo(ping_semaphore);
2968 if (logging != MagickFalse)
2969 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2970 " exit ReadOnePNGImage().");
2975 if (logging != MagickFalse)
2976 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2977 " Reading PNG IDAT chunk(s)");
2980 ping_pixels=(unsigned char *) AcquireQuantumMemory(image->rows,
2981 ping_rowbytes*sizeof(*ping_pixels));
2984 ping_pixels=(unsigned char *) AcquireQuantumMemory(ping_rowbytes,
2985 sizeof(*ping_pixels));
2987 if (ping_pixels == (unsigned char *) NULL)
2988 png_error(ping,"Memory allocation failed");
2990 if (logging != MagickFalse)
2991 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2992 " Converting PNG pixels to pixel packets");
2994 Convert PNG pixels to pixel packets.
2996 quantum_info=AcquireQuantumInfo(image_info,image);
2998 if (quantum_info == (QuantumInfo *) NULL)
2999 png_error(ping,"Failed to allocate quantum_info");
3001 (void) SetQuantumEndian(image,quantum_info,MSBEndian);
3006 found_transparent_pixel;
3008 found_transparent_pixel=MagickFalse;
3010 if (image->storage_class == DirectClass)
3012 for (pass=0; pass < num_passes; pass++)
3015 Convert image to DirectClass pixel packets.
3017 image->alpha_trait=(((int) ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA) ||
3018 ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) ||
3019 (png_get_valid(ping,ping_info,PNG_INFO_tRNS))) ?
3020 BlendPixelTrait : UndefinedPixelTrait;
3022 for (y=0; y < (ssize_t) image->rows; y++)
3025 row_offset=ping_rowbytes*y;
3030 png_read_row(ping,ping_pixels+row_offset,NULL);
3032 if (pass < num_passes-1)
3035 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
3037 if (q == (Quantum *) NULL)
3040 if ((int) ping_color_type == PNG_COLOR_TYPE_GRAY)
3041 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
3042 GrayQuantum,ping_pixels+row_offset,exception);
3044 else if ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
3045 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
3046 GrayAlphaQuantum,ping_pixels+row_offset,exception);
3048 else if ((int) ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA)
3049 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
3050 RGBAQuantum,ping_pixels+row_offset,exception);
3052 else if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
3053 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
3054 IndexQuantum,ping_pixels+row_offset,exception);
3056 else /* ping_color_type == PNG_COLOR_TYPE_RGB */
3057 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
3058 RGBQuantum,ping_pixels+row_offset,exception);
3060 if (found_transparent_pixel == MagickFalse)
3062 /* Is there a transparent pixel in the row? */
3063 if (y== 0 && logging != MagickFalse)
3064 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3065 " Looking for cheap transparent pixel");
3067 for (x=(ssize_t) image->columns-1; x >= 0; x--)
3069 if ((ping_color_type == PNG_COLOR_TYPE_RGBA ||
3070 ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) &&
3071 (GetPixelAlpha(image,q) != OpaqueAlpha))
3073 if (logging != MagickFalse)
3074 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3077 found_transparent_pixel = MagickTrue;
3080 if ((ping_color_type == PNG_COLOR_TYPE_RGB ||
3081 ping_color_type == PNG_COLOR_TYPE_GRAY) &&
3082 (ScaleQuantumToShort(GetPixelRed(image,q)) ==
3083 transparent_color.red &&
3084 ScaleQuantumToShort(GetPixelGreen(image,q)) ==
3085 transparent_color.green &&
3086 ScaleQuantumToShort(GetPixelBlue(image,q)) ==
3087 transparent_color.blue))
3089 if (logging != MagickFalse)
3090 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3092 found_transparent_pixel = MagickTrue;
3095 q+=GetPixelChannels(image);
3099 if ((image->previous == (Image *) NULL) && (num_passes == 1))
3101 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
3104 if (status == MagickFalse)
3107 if (SyncAuthenticPixels(image,exception) == MagickFalse)
3111 if ((image->previous == (Image *) NULL) && (num_passes != 1))
3113 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
3114 if (status == MagickFalse)
3120 else /* image->storage_class != DirectClass */
3122 for (pass=0; pass < num_passes; pass++)
3131 Convert grayscale image to PseudoClass pixel packets.
3133 if (logging != MagickFalse)
3134 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3135 " Converting grayscale pixels to pixel packets");
3137 image->alpha_trait=ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA ?
3138 BlendPixelTrait : UndefinedPixelTrait;
3140 quantum_scanline=(Quantum *) AcquireQuantumMemory(image->columns,
3141 (image->alpha_trait == BlendPixelTrait? 2 : 1)*
3142 sizeof(*quantum_scanline));
3144 if (quantum_scanline == (Quantum *) NULL)
3145 png_error(ping,"Memory allocation failed");
3147 for (y=0; y < (ssize_t) image->rows; y++)
3150 row_offset=ping_rowbytes*y;
3155 png_read_row(ping,ping_pixels+row_offset,NULL);
3157 if (pass < num_passes-1)
3160 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
3162 if (q == (Quantum *) NULL)
3165 p=ping_pixels+row_offset;
3168 switch (ping_bit_depth)
3172 if (ping_color_type == 4)
3173 for (x=(ssize_t) image->columns-1; x >= 0; x--)
3176 SetPixelAlpha(image,ScaleCharToQuantum((unsigned char) *p++),q);
3177 if (GetPixelAlpha(image,q) != OpaqueAlpha)
3178 found_transparent_pixel = MagickTrue;
3179 q+=GetPixelChannels(image);
3183 for (x=(ssize_t) image->columns-1; x >= 0; x--)
3191 for (x=(ssize_t) image->columns-1; x >= 0; x--)
3193 #if (MAGICKCORE_QUANTUM_DEPTH == 16) || (MAGICKCORE_QUANTUM_DEPTH == 32)
3197 if (image->colors > 256)
3198 quantum=((*p++) << 8);
3204 *r=ScaleShortToQuantum(quantum);
3207 if (ping_color_type == 4)
3209 if (image->colors > 256)
3210 quantum=((*p++) << 8);
3215 SetPixelAlpha(image,ScaleShortToQuantum(quantum),q);
3216 if (GetPixelAlpha(image,q) != OpaqueAlpha)
3217 found_transparent_pixel = MagickTrue;
3218 q+=GetPixelChannels(image);
3221 #else /* MAGICKCORE_QUANTUM_DEPTH == 8 */
3223 p++; /* strip low byte */
3225 if (ping_color_type == 4)
3227 SetPixelAlpha(image,*p++,q);
3228 if (GetPixelAlpha(image,q) != OpaqueAlpha)
3229 found_transparent_pixel = MagickTrue;
3231 q+=GetPixelChannels(image);
3244 Transfer image scanline.
3248 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
3250 if (q == (Quantum *) NULL)
3252 for (x=0; x < (ssize_t) image->columns; x++)
3254 SetPixelIndex(image,*r++,q);
3255 q+=GetPixelChannels(image);
3258 if (SyncAuthenticPixels(image,exception) == MagickFalse)
3261 if ((image->previous == (Image *) NULL) && (num_passes == 1))
3263 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
3266 if (status == MagickFalse)
3271 if ((image->previous == (Image *) NULL) && (num_passes != 1))
3273 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
3275 if (status == MagickFalse)
3279 quantum_scanline=(Quantum *) RelinquishMagickMemory(quantum_scanline);
3282 image->alpha_trait=found_transparent_pixel ? BlendPixelTrait :
3283 UndefinedPixelTrait;
3285 if (logging != MagickFalse)
3287 if (found_transparent_pixel != MagickFalse)
3288 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3289 " Found transparent pixel");
3292 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3293 " No transparent pixel was found");
3295 ping_color_type&=0x03;
3300 if (quantum_info != (QuantumInfo *) NULL)
3301 quantum_info=DestroyQuantumInfo(quantum_info);
3303 if (image->storage_class == PseudoClass)
3308 alpha_trait=image->alpha_trait;
3309 image->alpha_trait=UndefinedPixelTrait;
3310 (void) SyncImage(image,exception);
3311 image->alpha_trait=alpha_trait;
3314 png_read_end(ping,end_info);
3316 if (image_info->number_scenes != 0 && mng_info->scenes_found-1 <
3317 (ssize_t) image_info->first_scene && image->delay != 0)
3319 png_destroy_read_struct(&ping,&ping_info,&end_info);
3320 ping_pixels=(unsigned char *) RelinquishMagickMemory(ping_pixels);
3322 (void) SetImageBackgroundColor(image,exception);
3323 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
3324 UnlockSemaphoreInfo(ping_semaphore);
3326 if (logging != MagickFalse)
3327 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3328 " exit ReadOnePNGImage() early.");
3332 if (png_get_valid(ping,ping_info,PNG_INFO_tRNS))
3338 Image has a transparent background.
3340 storage_class=image->storage_class;
3341 image->alpha_trait=BlendPixelTrait;
3343 /* Balfour fix from imagemagick discourse server, 5 Feb 2010 */
3345 if (storage_class == PseudoClass)
3347 if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
3349 for (x=0; x < ping_num_trans; x++)
3351 image->colormap[x].alpha_trait=BlendPixelTrait;
3352 image->colormap[x].alpha =
3353 ScaleCharToQuantum((unsigned char)ping_trans_alpha[x]);
3357 else if (ping_color_type == PNG_COLOR_TYPE_GRAY)
3359 for (x=0; x < (int) image->colors; x++)
3361 if (ScaleQuantumToShort(image->colormap[x].red) ==
3362 transparent_color.alpha)
3364 image->colormap[x].alpha_trait=BlendPixelTrait;
3365 image->colormap[x].alpha = (Quantum) TransparentAlpha;
3369 (void) SyncImage(image,exception);
3372 #if 1 /* Should have already been done above, but glennrp problem P10
3377 for (y=0; y < (ssize_t) image->rows; y++)
3379 image->storage_class=storage_class;
3380 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
3382 if (q == (Quantum *) NULL)
3386 /* Caution: on a Q8 build, this does not distinguish between
3387 * 16-bit colors that differ only in the low byte
3389 for (x=(ssize_t) image->columns-1; x >= 0; x--)
3391 if (ScaleQuantumToShort(GetPixelRed(image,q)) ==
3392 transparent_color.red &&
3393 ScaleQuantumToShort(GetPixelGreen(image,q)) ==
3394 transparent_color.green &&
3395 ScaleQuantumToShort(GetPixelBlue(image,q)) ==
3396 transparent_color.blue)
3398 SetPixelAlpha(image,TransparentAlpha,q);
3401 #if 0 /* I have not found a case where this is needed. */
3404 SetPixelAlpha(image,q)=(Quantum) OpaqueAlpha;
3408 q+=GetPixelChannels(image);
3411 if (SyncAuthenticPixels(image,exception) == MagickFalse)
3417 image->storage_class=DirectClass;
3420 for (j = 0; j < 2; j++)
3423 status = png_get_text(ping,ping_info,&text,&num_text) != 0 ?
3424 MagickTrue : MagickFalse;
3426 status = png_get_text(ping,end_info,&text,&num_text) != 0 ?
3427 MagickTrue : MagickFalse;
3429 if (status != MagickFalse)
3430 for (i=0; i < (ssize_t) num_text; i++)
3432 /* Check for a profile */
3434 if (logging != MagickFalse)
3435 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3436 " Reading PNG text chunk");
3438 if (memcmp(text[i].key, "Raw profile type ",17) == 0)
3440 (void) Magick_png_read_raw_profile(ping,image,image_info,text,
3450 length=text[i].text_length;
3451 value=(char *) AcquireQuantumMemory(length+MaxTextExtent,
3453 if (value == (char *) NULL)
3455 png_error(ping,"Memory allocation failed");
3459 (void) ConcatenateMagickString(value,text[i].text,length+2);
3461 /* Don't save "density" or "units" property if we have a pHYs
3464 if (!png_get_valid(ping,ping_info,PNG_INFO_pHYs) ||
3465 (LocaleCompare(text[i].key,"density") != 0 &&
3466 LocaleCompare(text[i].key,"units") != 0))
3467 (void) SetImageProperty(image,text[i].key,value,exception);
3469 if (logging != MagickFalse)
3471 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3472 " length: %lu",(unsigned long) length);
3473 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3474 " Keyword: %s",text[i].key);
3477 value=DestroyString(value);
3480 num_text_total += num_text;
3483 #ifdef MNG_OBJECT_BUFFERS
3485 Store the object if necessary.
3487 if (object_id && !mng_info->frozen[object_id])
3489 if (mng_info->ob[object_id] == (MngBuffer *) NULL)
3492 create a new object buffer.
3494 mng_info->ob[object_id]=(MngBuffer *)
3495 AcquireMagickMemory(sizeof(MngBuffer));
3497 if (mng_info->ob[object_id] != (MngBuffer *) NULL)
3499 mng_info->ob[object_id]->image=(Image *) NULL;
3500 mng_info->ob[object_id]->reference_count=1;
3504 if ((mng_info->ob[object_id] == (MngBuffer *) NULL) ||
3505 mng_info->ob[object_id]->frozen)
3507 if (mng_info->ob[object_id] == (MngBuffer *) NULL)
3508 png_error(ping,"Memory allocation failed");
3510 if (mng_info->ob[object_id]->frozen)
3511 png_error(ping,"Cannot overwrite frozen MNG object buffer");
3517 if (mng_info->ob[object_id]->image != (Image *) NULL)
3518 mng_info->ob[object_id]->image=DestroyImage
3519 (mng_info->ob[object_id]->image);
3521 mng_info->ob[object_id]->image=CloneImage(image,0,0,MagickTrue,
3524 if (mng_info->ob[object_id]->image != (Image *) NULL)
3525 mng_info->ob[object_id]->image->file=(FILE *) NULL;
3528 png_error(ping, "Cloning image for object buffer failed");
3530 if (ping_width > 250000L || ping_height > 250000L)
3531 png_error(ping,"PNG Image dimensions are too large.");
3533 mng_info->ob[object_id]->width=ping_width;
3534 mng_info->ob[object_id]->height=ping_height;
3535 mng_info->ob[object_id]->color_type=ping_color_type;
3536 mng_info->ob[object_id]->sample_depth=ping_bit_depth;
3537 mng_info->ob[object_id]->interlace_method=ping_interlace_method;
3538 mng_info->ob[object_id]->compression_method=
3539 ping_compression_method;
3540 mng_info->ob[object_id]->filter_method=ping_filter_method;
3542 if (png_get_valid(ping,ping_info,PNG_INFO_PLTE))
3548 Copy the PLTE to the object buffer.
3550 png_get_PLTE(ping,ping_info,&plte,&number_colors);
3551 mng_info->ob[object_id]->plte_length=number_colors;
3553 for (i=0; i < number_colors; i++)
3555 mng_info->ob[object_id]->plte[i]=plte[i];
3560 mng_info->ob[object_id]->plte_length=0;
3565 /* Set image->alpha_trait to MagickTrue if the input colortype supports
3566 * alpha or if a valid tRNS chunk is present, no matter whether there
3567 * is actual transparency present.
3569 image->alpha_trait=(((int) ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA) ||
3570 ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) ||
3571 (png_get_valid(ping,ping_info,PNG_INFO_tRNS))) ?
3572 BlendPixelTrait : UndefinedPixelTrait;
3574 /* Set more properties for identify to retrieve */
3579 if (num_text_total != 0)
3581 /* libpng doesn't tell us whether they were tEXt, zTXt, or iTXt */
3582 (void) FormatLocaleString(msg,MaxTextExtent,
3583 "%d tEXt/zTXt/iTXt chunks were found", num_text_total);
3584 (void) SetImageProperty(image,"png:text ",msg,
3588 if (num_raw_profiles != 0)
3590 (void) FormatLocaleString(msg,MaxTextExtent,
3591 "%d were found", num_raw_profiles);
3592 (void) SetImageProperty(image,"png:text-encoded profiles",msg,
3596 if (ping_found_cHRM != MagickFalse)
3598 (void) FormatLocaleString(msg,MaxTextExtent,"%s",
3599 "chunk was found (see Chromaticity, above)");
3600 (void) SetImageProperty(image,"png:cHRM ",msg,
3604 if (png_get_valid(ping,ping_info,PNG_INFO_bKGD))
3606 (void) FormatLocaleString(msg,MaxTextExtent,"%s",
3607 "chunk was found (see Background color, above)");
3608 (void) SetImageProperty(image,"png:bKGD ",msg,
3612 (void) FormatLocaleString(msg,MaxTextExtent,"%s",
3615 #if defined(PNG_iCCP_SUPPORTED)
3616 if (ping_found_iCCP != MagickFalse)
3617 (void) SetImageProperty(image,"png:iCCP ",msg,
3621 if (png_get_valid(ping,ping_info,PNG_INFO_tRNS))
3622 (void) SetImageProperty(image,"png:tRNS ",msg,
3625 #if defined(PNG_sRGB_SUPPORTED)
3626 if (ping_found_sRGB != MagickFalse)
3628 (void) FormatLocaleString(msg,MaxTextExtent,
3631 Magick_RenderingIntentString_from_PNG_RenderingIntent(intent));
3632 (void) SetImageProperty(image,"png:sRGB ",msg,
3637 if (ping_found_gAMA != MagickFalse)
3639 (void) FormatLocaleString(msg,MaxTextExtent,
3640 "gamma=%.8g (See Gamma, above)",
3642 (void) SetImageProperty(image,"png:gAMA ",msg,
3646 #if defined(PNG_pHYs_SUPPORTED)
3647 if (png_get_valid(ping,ping_info,PNG_INFO_pHYs))
3649 (void) FormatLocaleString(msg,MaxTextExtent,
3650 "x_res=%.10g, y_res=%.10g, units=%d",
3651 (double) x_resolution,(double) y_resolution, unit_type);
3652 (void) SetImageProperty(image,"png:pHYs ",msg,
3657 #if defined(PNG_oFFs_SUPPORTED)
3658 if (png_get_valid(ping,ping_info,PNG_INFO_oFFs))
3660 (void) FormatLocaleString(msg,MaxTextExtent,"x_off=%.20g, y_off=%.20g",
3661 (double) image->page.x,(double) image->page.y);
3662 (void) SetImageProperty(image,"png:oFFs ",msg,
3667 if ((image->page.width != 0 && image->page.width != image->columns) ||
3668 (image->page.height != 0 && image->page.height != image->rows))
3670 (void) FormatLocaleString(msg,MaxTextExtent,
3671 "width=%.20g, height=%.20g",
3672 (double) image->page.width,(double) image->page.height);
3673 (void) SetImageProperty(image,"png:vpAg ",msg,
3679 Relinquish resources.
3681 png_destroy_read_struct(&ping,&ping_info,&end_info);
3683 ping_pixels=(unsigned char *) RelinquishMagickMemory(ping_pixels);
3685 if (logging != MagickFalse)
3686 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3687 " exit ReadOnePNGImage()");
3689 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
3690 UnlockSemaphoreInfo(ping_semaphore);
3693 /* } for navigation to beginning of SETJMP-protected block, revert to
3694 * Throwing an Exception when an error occurs.
3699 /* end of reading one PNG image */
3702 static Image *ReadPNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
3717 magic_number[MaxTextExtent];
3725 assert(image_info != (const ImageInfo *) NULL);
3726 assert(image_info->signature == MagickSignature);
3728 if (image_info->debug != MagickFalse)
3729 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
3730 image_info->filename);
3732 assert(exception != (ExceptionInfo *) NULL);
3733 assert(exception->signature == MagickSignature);
3734 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter ReadPNGImage()");
3735 image=AcquireImage(image_info,exception);
3736 mng_info=(MngInfo *) NULL;
3737 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
3739 if (status == MagickFalse)
3740 ThrowReaderException(FileOpenError,"UnableToOpenFile");
3743 Verify PNG signature.
3745 count=ReadBlob(image,8,(unsigned char *) magic_number);
3747 if (count < 8 || memcmp(magic_number,"\211PNG\r\n\032\n",8) != 0)
3748 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
3751 Allocate a MngInfo structure.
3753 have_mng_structure=MagickFalse;
3754 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
3756 if (mng_info == (MngInfo *) NULL)
3757 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
3760 Initialize members of the MngInfo structure.
3762 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
3763 mng_info->image=image;
3764 have_mng_structure=MagickTrue;
3767 image=ReadOnePNGImage(mng_info,image_info,exception);
3768 MngInfoFreeStruct(mng_info,&have_mng_structure);
3770 if (image == (Image *) NULL)
3772 if (previous != (Image *) NULL)
3774 if (previous->signature != MagickSignature)
3775 ThrowReaderException(CorruptImageError,"CorruptImage");
3777 (void) CloseBlob(previous);
3778 (void) DestroyImageList(previous);
3781 if (logging != MagickFalse)
3782 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3783 "exit ReadPNGImage() with error");
3785 return((Image *) NULL);
3788 (void) CloseBlob(image);
3790 if ((image->columns == 0) || (image->rows == 0))
3792 if (logging != MagickFalse)
3793 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3794 "exit ReadPNGImage() with error.");
3796 ThrowReaderException(CorruptImageError,"CorruptImage");
3799 if ((IssRGBColorspace(image->colorspace) != MagickFalse) &&
3800 ((image->gamma < .45) || (image->gamma > .46)))
3801 SetImageColorspace(image,RGBColorspace,exception);
3803 if (LocaleCompare(image_info->magick,"PNG24") == 0)
3805 (void) SetImageType(image,TrueColorType,exception);
3806 image->alpha_trait=UndefinedPixelTrait;
3809 if (LocaleCompare(image_info->magick,"PNG32") == 0)
3810 (void) SetImageType(image,TrueColorMatteType,exception);
3812 if (logging != MagickFalse)
3813 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3814 " page.w: %.20g, page.h: %.20g,page.x: %.20g, page.y: %.20g.",
3815 (double) image->page.width,(double) image->page.height,
3816 (double) image->page.x,(double) image->page.y);
3818 if (logging != MagickFalse)
3819 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit ReadPNGImage()");
3826 #if defined(JNG_SUPPORTED)
3828 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3832 % R e a d O n e J N G I m a g e %
3836 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3838 % ReadOneJNGImage() reads a JPEG Network Graphics (JNG) image file
3839 % (minus the 8-byte signature) and returns it. It allocates the memory
3840 % necessary for the new Image structure and returns a pointer to the new
3843 % JNG support written by Glenn Randers-Pehrson, glennrp@image...
3845 % The format of the ReadOneJNGImage method is:
3847 % Image *ReadOneJNGImage(MngInfo *mng_info, const ImageInfo *image_info,
3848 % ExceptionInfo *exception)
3850 % A description of each parameter follows:
3852 % o mng_info: Specifies a pointer to a MngInfo structure.
3854 % o image_info: the image info.
3856 % o exception: return any errors or warnings in this structure.
3859 static Image *ReadOneJNGImage(MngInfo *mng_info,
3860 const ImageInfo *image_info, ExceptionInfo *exception)
3887 jng_image_sample_depth,
3888 jng_image_compression_method,
3889 jng_image_interlace_method,
3890 jng_alpha_sample_depth,
3891 jng_alpha_compression_method,
3892 jng_alpha_filter_method,
3893 jng_alpha_interlace_method;
3895 register const Quantum
3905 register unsigned char
3916 jng_alpha_compression_method=0;
3917 jng_alpha_sample_depth=8;
3921 alpha_image=(Image *) NULL;
3922 color_image=(Image *) NULL;
3923 alpha_image_info=(ImageInfo *) NULL;
3924 color_image_info=(ImageInfo *) NULL;
3926 logging=LogMagickEvent(CoderEvent,GetMagickModule(),
3927 " Enter ReadOneJNGImage()");
3929 image=mng_info->image;
3931 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
3934 Allocate next image structure.
3936 if (logging != MagickFalse)
3937 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3938 " AcquireNextImage()");
3940 AcquireNextImage(image_info,image,exception);
3942 if (GetNextImageInList(image) == (Image *) NULL)
3943 return((Image *) NULL);
3945 image=SyncNextImageInList(image);
3947 mng_info->image=image;
3950 Signature bytes have already been read.
3953 read_JSEP=MagickFalse;
3954 reading_idat=MagickFalse;
3955 skip_to_iend=MagickFalse;
3959 type[MaxTextExtent];
3968 Read a new JNG chunk.
3970 status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
3971 2*GetBlobSize(image));
3973 if (status == MagickFalse)
3977 (void) ConcatenateMagickString(type,"errr",MaxTextExtent);
3978 length=ReadBlobMSBLong(image);
3979 count=(unsigned int) ReadBlob(image,4,(unsigned char *) type);
3981 if (logging != MagickFalse)
3982 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3983 " Reading JNG chunk type %c%c%c%c, length: %.20g",
3984 type[0],type[1],type[2],type[3],(double) length);
3986 if (length > PNG_UINT_31_MAX || count == 0)
3987 ThrowReaderException(CorruptImageError,"CorruptImage");
3990 chunk=(unsigned char *) NULL;
3994 chunk=(unsigned char *) AcquireQuantumMemory(length,sizeof(*chunk));
3996 if (chunk == (unsigned char *) NULL)
3997 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
3999 for (i=0; i < (ssize_t) length; i++)
4000 chunk[i]=(unsigned char) ReadBlobByte(image);
4005 (void) ReadBlobMSBLong(image); /* read crc word */
4010 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4015 if (memcmp(type,mng_JHDR,4) == 0)
4019 jng_width=(size_t) ((p[0] << 24) | (p[1] << 16) |
4020 (p[2] << 8) | p[3]);
4021 jng_height=(size_t) ((p[4] << 24) | (p[5] << 16) |
4022 (p[6] << 8) | p[7]);
4023 jng_color_type=p[8];
4024 jng_image_sample_depth=p[9];
4025 jng_image_compression_method=p[10];
4026 jng_image_interlace_method=p[11];
4028 image->interlace=jng_image_interlace_method != 0 ? PNGInterlace :
4031 jng_alpha_sample_depth=p[12];
4032 jng_alpha_compression_method=p[13];
4033 jng_alpha_filter_method=p[14];
4034 jng_alpha_interlace_method=p[15];
4036 if (logging != MagickFalse)
4038 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4039 " jng_width: %16lu",(unsigned long) jng_width);
4041 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4042 " jng_width: %16lu",(unsigned long) jng_height);
4044 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4045 " jng_color_type: %16d",jng_color_type);
4047 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4048 " jng_image_sample_depth: %3d",
4049 jng_image_sample_depth);
4051 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4052 " jng_image_compression_method:%3d",
4053 jng_image_compression_method);
4055 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4056 " jng_image_interlace_method: %3d",
4057 jng_image_interlace_method);
4059 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4060 " jng_alpha_sample_depth: %3d",
4061 jng_alpha_sample_depth);
4063 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4064 " jng_alpha_compression_method:%3d",
4065 jng_alpha_compression_method);
4067 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4068 " jng_alpha_filter_method: %3d",
4069 jng_alpha_filter_method);
4071 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4072 " jng_alpha_interlace_method: %3d",
4073 jng_alpha_interlace_method);
4078 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4084 if ((reading_idat == MagickFalse) && (read_JSEP == MagickFalse) &&
4085 ((memcmp(type,mng_JDAT,4) == 0) || (memcmp(type,mng_JdAA,4) == 0) ||
4086 (memcmp(type,mng_IDAT,4) == 0) || (memcmp(type,mng_JDAA,4) == 0)))
4089 o create color_image
4090 o open color_blob, attached to color_image
4091 o if (color type has alpha)
4092 open alpha_blob, attached to alpha_image
4095 color_image_info=(ImageInfo *)AcquireMagickMemory(sizeof(ImageInfo));
4097 if (color_image_info == (ImageInfo *) NULL)
4098 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
4100 GetImageInfo(color_image_info);
4101 color_image=AcquireImage(color_image_info,exception);
4103 if (color_image == (Image *) NULL)
4104 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
4106 if (logging != MagickFalse)
4107 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4108 " Creating color_blob.");
4110 (void) AcquireUniqueFilename(color_image->filename);
4111 status=OpenBlob(color_image_info,color_image,WriteBinaryBlobMode,
4114 if (status == MagickFalse)
4115 return((Image *) NULL);
4117 if ((image_info->ping == MagickFalse) && (jng_color_type >= 12))
4119 alpha_image_info=(ImageInfo *)
4120 AcquireMagickMemory(sizeof(ImageInfo));
4122 if (alpha_image_info == (ImageInfo *) NULL)
4123 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
4125 GetImageInfo(alpha_image_info);
4126 alpha_image=AcquireImage(alpha_image_info,exception);
4128 if (alpha_image == (Image *) NULL)
4130 alpha_image=DestroyImage(alpha_image);
4131 ThrowReaderException(ResourceLimitError,
4132 "MemoryAllocationFailed");
4135 if (logging != MagickFalse)
4136 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4137 " Creating alpha_blob.");
4139 (void) AcquireUniqueFilename(alpha_image->filename);
4140 status=OpenBlob(alpha_image_info,alpha_image,WriteBinaryBlobMode,
4143 if (status == MagickFalse)
4144 return((Image *) NULL);
4146 if (jng_alpha_compression_method == 0)
4151 if (logging != MagickFalse)
4152 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4153 " Writing IHDR chunk to alpha_blob.");
4155 (void) WriteBlob(alpha_image,8,(const unsigned char *)
4156 "\211PNG\r\n\032\n");
4158 (void) WriteBlobMSBULong(alpha_image,13L);
4159 PNGType(data,mng_IHDR);
4160 LogPNGChunk(logging,mng_IHDR,13L);
4161 PNGLong(data+4,jng_width);
4162 PNGLong(data+8,jng_height);
4163 data[12]=jng_alpha_sample_depth;
4164 data[13]=0; /* color_type gray */
4165 data[14]=0; /* compression method 0 */
4166 data[15]=0; /* filter_method 0 */
4167 data[16]=0; /* interlace_method 0 */
4168 (void) WriteBlob(alpha_image,17,data);
4169 (void) WriteBlobMSBULong(alpha_image,crc32(0,data,17));
4172 reading_idat=MagickTrue;
4175 if (memcmp(type,mng_JDAT,4) == 0)
4177 /* Copy chunk to color_image->blob */
4179 if (logging != MagickFalse)
4180 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4181 " Copying JDAT chunk data to color_blob.");
4183 (void) WriteBlob(color_image,length,chunk);
4186 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4191 if (memcmp(type,mng_IDAT,4) == 0)
4196 /* Copy IDAT header and chunk data to alpha_image->blob */
4198 if (image_info->ping == MagickFalse)
4200 if (logging != MagickFalse)
4201 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4202 " Copying IDAT chunk data to alpha_blob.");
4204 (void) WriteBlobMSBULong(alpha_image,(size_t) length);
4205 PNGType(data,mng_IDAT);
4206 LogPNGChunk(logging,mng_IDAT,length);
4207 (void) WriteBlob(alpha_image,4,data);
4208 (void) WriteBlob(alpha_image,length,chunk);
4209 (void) WriteBlobMSBULong(alpha_image,
4210 crc32(crc32(0,data,4),chunk,(uInt) length));
4214 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4219 if ((memcmp(type,mng_JDAA,4) == 0) || (memcmp(type,mng_JdAA,4) == 0))
4221 /* Copy chunk data to alpha_image->blob */
4223 if (image_info->ping == MagickFalse)
4225 if (logging != MagickFalse)
4226 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4227 " Copying JDAA chunk data to alpha_blob.");
4229 (void) WriteBlob(alpha_image,length,chunk);
4233 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4238 if (memcmp(type,mng_JSEP,4) == 0)
4240 read_JSEP=MagickTrue;
4243 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4248 if (memcmp(type,mng_bKGD,4) == 0)
4252 image->background_color.red=ScaleCharToQuantum(p[1]);
4253 image->background_color.green=image->background_color.red;
4254 image->background_color.blue=image->background_color.red;
4259 image->background_color.red=ScaleCharToQuantum(p[1]);
4260 image->background_color.green=ScaleCharToQuantum(p[3]);
4261 image->background_color.blue=ScaleCharToQuantum(p[5]);
4264 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4268 if (memcmp(type,mng_gAMA,4) == 0)
4271 image->gamma=((float) mng_get_long(p))*0.00001;
4273 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4277 if (memcmp(type,mng_cHRM,4) == 0)
4281 image->chromaticity.white_point.x=0.00001*mng_get_long(p);
4282 image->chromaticity.white_point.y=0.00001*mng_get_long(&p[4]);
4283 image->chromaticity.red_primary.x=0.00001*mng_get_long(&p[8]);
4284 image->chromaticity.red_primary.y=0.00001*mng_get_long(&p[12]);
4285 image->chromaticity.green_primary.x=0.00001*mng_get_long(&p[16]);
4286 image->chromaticity.green_primary.y=0.00001*mng_get_long(&p[20]);
4287 image->chromaticity.blue_primary.x=0.00001*mng_get_long(&p[24]);
4288 image->chromaticity.blue_primary.y=0.00001*mng_get_long(&p[28]);
4291 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4295 if (memcmp(type,mng_sRGB,4) == 0)
4299 image->rendering_intent=
4300 Magick_RenderingIntent_from_PNG_RenderingIntent(p[0]);
4301 image->gamma=1.000f/2.200f;
4302 image->chromaticity.red_primary.x=0.6400f;
4303 image->chromaticity.red_primary.y=0.3300f;
4304 image->chromaticity.green_primary.x=0.3000f;
4305 image->chromaticity.green_primary.y=0.6000f;
4306 image->chromaticity.blue_primary.x=0.1500f;
4307 image->chromaticity.blue_primary.y=0.0600f;
4308 image->chromaticity.white_point.x=0.3127f;
4309 image->chromaticity.white_point.y=0.3290f;
4312 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4316 if (memcmp(type,mng_oFFs,4) == 0)
4320 image->page.x=(ssize_t) mng_get_long(p);
4321 image->page.y=(ssize_t) mng_get_long(&p[4]);
4323 if ((int) p[8] != 0)
4325 image->page.x/=10000;
4326 image->page.y/=10000;
4331 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4336 if (memcmp(type,mng_pHYs,4) == 0)
4340 image->resolution.x=(double) mng_get_long(p);
4341 image->resolution.y=(double) mng_get_long(&p[4]);
4342 if ((int) p[8] == PNG_RESOLUTION_METER)
4344 image->units=PixelsPerCentimeterResolution;
4345 image->resolution.x=image->resolution.x/100.0f;
4346 image->resolution.y=image->resolution.y/100.0f;
4350 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4355 if (memcmp(type,mng_iCCP,4) == 0)
4359 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4366 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4368 if (memcmp(type,mng_IEND,4))
4378 Finish up reading image data:
4380 o read main image from color_blob.
4384 o if (color_type has alpha)
4385 if alpha_encoding is PNG
4386 read secondary image from alpha_blob via ReadPNG
4387 if alpha_encoding is JPEG
4388 read secondary image from alpha_blob via ReadJPEG
4392 o copy intensity of secondary image into
4393 alpha samples of main image.
4395 o destroy the secondary image.
4398 (void) CloseBlob(color_image);
4400 if (logging != MagickFalse)
4401 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4402 " Reading jng_image from color_blob.");
4404 (void) FormatLocaleString(color_image_info->filename,MaxTextExtent,"%s",
4405 color_image->filename);
4407 color_image_info->ping=MagickFalse; /* To do: avoid this */
4408 jng_image=ReadImage(color_image_info,exception);
4410 if (jng_image == (Image *) NULL)
4411 return((Image *) NULL);
4413 (void) RelinquishUniqueFileResource(color_image->filename);
4414 color_image=DestroyImage(color_image);
4415 color_image_info=DestroyImageInfo(color_image_info);
4417 if (jng_image == (Image *) NULL)
4418 return((Image *) NULL);
4420 if (logging != MagickFalse)
4421 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4422 " Copying jng_image pixels to main image.");
4424 image->rows=jng_height;
4425 image->columns=jng_width;
4427 for (y=0; y < (ssize_t) image->rows; y++)
4429 s=GetVirtualPixels(jng_image,0,y,image->columns,1,exception);
4430 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
4431 for (x=(ssize_t) image->columns; x != 0; x--)
4433 SetPixelRed(image,GetPixelRed(jng_image,s),q);
4434 SetPixelGreen(image,GetPixelGreen(jng_image,s),q);
4435 SetPixelBlue(image,GetPixelBlue(jng_image,s),q);
4436 q+=GetPixelChannels(image);
4437 s+=GetPixelChannels(jng_image);
4440 if (SyncAuthenticPixels(image,exception) == MagickFalse)
4444 jng_image=DestroyImage(jng_image);
4446 if (image_info->ping == MagickFalse)
4448 if (jng_color_type >= 12)
4450 if (jng_alpha_compression_method == 0)
4454 (void) WriteBlobMSBULong(alpha_image,0x00000000L);
4455 PNGType(data,mng_IEND);
4456 LogPNGChunk(logging,mng_IEND,0L);
4457 (void) WriteBlob(alpha_image,4,data);
4458 (void) WriteBlobMSBULong(alpha_image,crc32(0,data,4));
4461 (void) CloseBlob(alpha_image);
4463 if (logging != MagickFalse)
4464 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4465 " Reading alpha from alpha_blob.");
4467 (void) FormatLocaleString(alpha_image_info->filename,MaxTextExtent,
4468 "%s",alpha_image->filename);
4470 jng_image=ReadImage(alpha_image_info,exception);
4472 if (jng_image != (Image *) NULL)
4473 for (y=0; y < (ssize_t) image->rows; y++)
4475 s=GetVirtualPixels(jng_image,0,y,image->columns,1,
4477 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
4479 if (image->alpha_trait == BlendPixelTrait)
4480 for (x=(ssize_t) image->columns; x != 0; x--)
4482 SetPixelAlpha(image,GetPixelRed(jng_image,s),q);
4483 q+=GetPixelChannels(image);
4484 s+=GetPixelChannels(jng_image);
4488 for (x=(ssize_t) image->columns; x != 0; x--)
4490 SetPixelAlpha(image,GetPixelRed(jng_image,s),q);
4491 if (GetPixelAlpha(image,q) != OpaqueAlpha)
4492 image->alpha_trait=BlendPixelTrait;
4493 q+=GetPixelChannels(image);
4494 s+=GetPixelChannels(jng_image);
4497 if (SyncAuthenticPixels(image,exception) == MagickFalse)
4500 (void) RelinquishUniqueFileResource(alpha_image->filename);
4501 alpha_image=DestroyImage(alpha_image);
4502 alpha_image_info=DestroyImageInfo(alpha_image_info);
4503 if (jng_image != (Image *) NULL)
4504 jng_image=DestroyImage(jng_image);
4508 /* Read the JNG image. */
4510 if (mng_info->mng_type == 0)
4512 mng_info->mng_width=jng_width;
4513 mng_info->mng_height=jng_height;
4516 if (image->page.width == 0 && image->page.height == 0)
4518 image->page.width=jng_width;
4519 image->page.height=jng_height;
4522 if (image->page.x == 0 && image->page.y == 0)
4524 image->page.x=mng_info->x_off[mng_info->object_id];
4525 image->page.y=mng_info->y_off[mng_info->object_id];
4530 image->page.y=mng_info->y_off[mng_info->object_id];
4533 mng_info->image_found++;
4534 status=SetImageProgress(image,LoadImagesTag,2*TellBlob(image),
4535 2*GetBlobSize(image));
4537 if (logging != MagickFalse)
4538 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4539 " exit ReadOneJNGImage()");
4545 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4549 % R e a d J N G I m a g e %
4553 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4555 % ReadJNGImage() reads a JPEG Network Graphics (JNG) image file
4556 % (including the 8-byte signature) and returns it. It allocates the memory
4557 % necessary for the new Image structure and returns a pointer to the new
4560 % JNG support written by Glenn Randers-Pehrson, glennrp@image...
4562 % The format of the ReadJNGImage method is:
4564 % Image *ReadJNGImage(const ImageInfo *image_info, ExceptionInfo
4567 % A description of each parameter follows:
4569 % o image_info: the image info.
4571 % o exception: return any errors or warnings in this structure.
4575 static Image *ReadJNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
4590 magic_number[MaxTextExtent];
4598 assert(image_info != (const ImageInfo *) NULL);
4599 assert(image_info->signature == MagickSignature);
4600 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image_info->filename);
4601 assert(exception != (ExceptionInfo *) NULL);
4602 assert(exception->signature == MagickSignature);
4603 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter ReadJNGImage()");
4604 image=AcquireImage(image_info,exception);
4605 mng_info=(MngInfo *) NULL;
4606 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
4608 if (status == MagickFalse)
4609 return((Image *) NULL);
4611 if (LocaleCompare(image_info->magick,"JNG") != 0)
4612 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
4614 /* Verify JNG signature. */
4616 count=(size_t) ReadBlob(image,8,(unsigned char *) magic_number);
4618 if (count < 8 || memcmp(magic_number,"\213JNG\r\n\032\n",8) != 0)
4619 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
4621 /* Allocate a MngInfo structure. */
4623 have_mng_structure=MagickFalse;
4624 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(*mng_info));
4626 if (mng_info == (MngInfo *) NULL)
4627 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
4629 /* Initialize members of the MngInfo structure. */
4631 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
4632 have_mng_structure=MagickTrue;
4634 mng_info->image=image;
4636 image=ReadOneJNGImage(mng_info,image_info,exception);
4637 MngInfoFreeStruct(mng_info,&have_mng_structure);
4639 if (image == (Image *) NULL)
4641 if (IsImageObject(previous) != MagickFalse)
4643 (void) CloseBlob(previous);
4644 (void) DestroyImageList(previous);
4647 if (logging != MagickFalse)
4648 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4649 "exit ReadJNGImage() with error");
4651 return((Image *) NULL);
4653 (void) CloseBlob(image);
4655 if (image->columns == 0 || image->rows == 0)
4657 if (logging != MagickFalse)
4658 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4659 "exit ReadJNGImage() with error");
4661 ThrowReaderException(CorruptImageError,"CorruptImage");
4664 if (logging != MagickFalse)
4665 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit ReadJNGImage()");
4671 static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
4674 page_geometry[MaxTextExtent];
4707 #if defined(MNG_INSERT_LAYERS)
4709 mng_background_color;
4712 register unsigned char
4727 #if defined(MNG_INSERT_LAYERS)
4732 volatile unsigned int
4733 #ifdef MNG_OBJECT_BUFFERS
4734 mng_background_object=0,
4736 mng_type=0; /* 0: PNG or JNG; 1: MNG; 2: MNG-LC; 3: MNG-VLC */
4739 default_frame_timeout,
4741 #if defined(MNG_INSERT_LAYERS)
4747 /* These delays are all measured in image ticks_per_second,
4748 * not in MNG ticks_per_second
4751 default_frame_delay,
4755 #if defined(MNG_INSERT_LAYERS)
4764 previous_fb.bottom=0;
4766 previous_fb.right=0;
4768 default_fb.bottom=0;
4772 /* Open image file. */
4774 assert(image_info != (const ImageInfo *) NULL);
4775 assert(image_info->signature == MagickSignature);
4776 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image_info->filename);
4777 assert(exception != (ExceptionInfo *) NULL);
4778 assert(exception->signature == MagickSignature);
4779 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter ReadMNGImage()");
4780 image=AcquireImage(image_info,exception);
4781 mng_info=(MngInfo *) NULL;
4782 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
4784 if (status == MagickFalse)
4785 return((Image *) NULL);
4787 first_mng_object=MagickFalse;
4789 have_mng_structure=MagickFalse;
4791 /* Allocate a MngInfo structure. */
4793 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
4795 if (mng_info == (MngInfo *) NULL)
4796 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
4798 /* Initialize members of the MngInfo structure. */
4800 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
4801 mng_info->image=image;
4802 have_mng_structure=MagickTrue;
4804 if (LocaleCompare(image_info->magick,"MNG") == 0)
4807 magic_number[MaxTextExtent];
4809 /* Verify MNG signature. */
4810 count=(size_t) ReadBlob(image,8,(unsigned char *) magic_number);
4811 if (memcmp(magic_number,"\212MNG\r\n\032\n",8) != 0)
4812 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
4814 /* Initialize some nonzero members of the MngInfo structure. */
4815 for (i=0; i < MNG_MAX_OBJECTS; i++)
4817 mng_info->object_clip[i].right=(ssize_t) PNG_UINT_31_MAX;
4818 mng_info->object_clip[i].bottom=(ssize_t) PNG_UINT_31_MAX;
4820 mng_info->exists[0]=MagickTrue;
4823 first_mng_object=MagickTrue;
4825 #if defined(MNG_INSERT_LAYERS)
4826 insert_layers=MagickFalse; /* should be False when converting or mogrifying */
4828 default_frame_delay=0;
4829 default_frame_timeout=0;
4832 mng_info->ticks_per_second=1UL*image->ticks_per_second;
4834 skip_to_iend=MagickFalse;
4835 term_chunk_found=MagickFalse;
4836 mng_info->framing_mode=1;
4837 #if defined(MNG_INSERT_LAYERS)
4838 mandatory_back=MagickFalse;
4840 #if defined(MNG_INSERT_LAYERS)
4841 mng_background_color=image->background_color;
4843 default_fb=mng_info->frame;
4844 previous_fb=mng_info->frame;
4848 type[MaxTextExtent];
4850 if (LocaleCompare(image_info->magick,"MNG") == 0)
4859 (void) ConcatenateMagickString(type,"errr",MaxTextExtent);
4860 length=ReadBlobMSBLong(image);
4861 count=(size_t) ReadBlob(image,4,(unsigned char *) type);
4863 if (logging != MagickFalse)
4864 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4865 " Reading MNG chunk type %c%c%c%c, length: %.20g",
4866 type[0],type[1],type[2],type[3],(double) length);
4868 if (length > PNG_UINT_31_MAX)
4872 ThrowReaderException(CorruptImageError,"CorruptImage");
4875 chunk=(unsigned char *) NULL;
4879 chunk=(unsigned char *) AcquireQuantumMemory(length,sizeof(*chunk));
4881 if (chunk == (unsigned char *) NULL)
4882 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
4884 for (i=0; i < (ssize_t) length; i++)
4885 chunk[i]=(unsigned char) ReadBlobByte(image);
4890 (void) ReadBlobMSBLong(image); /* read crc word */
4892 #if !defined(JNG_SUPPORTED)
4893 if (memcmp(type,mng_JHDR,4) == 0)
4895 skip_to_iend=MagickTrue;
4897 if (mng_info->jhdr_warning == 0)
4898 (void) ThrowMagickException(exception,GetMagickModule(),
4899 CoderError,"JNGCompressNotSupported","`%s'",image->filename);
4901 mng_info->jhdr_warning++;
4904 if (memcmp(type,mng_DHDR,4) == 0)
4906 skip_to_iend=MagickTrue;
4908 if (mng_info->dhdr_warning == 0)
4909 (void) ThrowMagickException(exception,GetMagickModule(),
4910 CoderError,"DeltaPNGNotSupported","`%s'",image->filename);
4912 mng_info->dhdr_warning++;
4914 if (memcmp(type,mng_MEND,4) == 0)
4919 if (memcmp(type,mng_IEND,4) == 0)
4920 skip_to_iend=MagickFalse;
4923 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4925 if (logging != MagickFalse)
4926 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4932 if (memcmp(type,mng_MHDR,4) == 0)
4934 mng_info->mng_width=(size_t) ((p[0] << 24) | (p[1] << 16) |
4935 (p[2] << 8) | p[3]);
4937 mng_info->mng_height=(size_t) ((p[4] << 24) | (p[5] << 16) |
4938 (p[6] << 8) | p[7]);
4940 if (logging != MagickFalse)
4942 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4943 " MNG width: %.20g",(double) mng_info->mng_width);
4944 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4945 " MNG height: %.20g",(double) mng_info->mng_height);
4949 mng_info->ticks_per_second=(size_t) mng_get_long(p);
4951 if (mng_info->ticks_per_second == 0)
4952 default_frame_delay=0;
4955 default_frame_delay=1UL*image->ticks_per_second/
4956 mng_info->ticks_per_second;
4958 frame_delay=default_frame_delay;
4964 simplicity=(size_t) mng_get_long(p);
4967 mng_type=1; /* Full MNG */
4969 if ((simplicity != 0) && ((simplicity | 11) == 11))
4970 mng_type=2; /* LC */
4972 if ((simplicity != 0) && ((simplicity | 9) == 9))
4973 mng_type=3; /* VLC */
4975 #if defined(MNG_INSERT_LAYERS)
4977 insert_layers=MagickTrue;
4979 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
4981 /* Allocate next image structure. */
4982 AcquireNextImage(image_info,image,exception);
4984 if (GetNextImageInList(image) == (Image *) NULL)
4985 return((Image *) NULL);
4987 image=SyncNextImageInList(image);
4988 mng_info->image=image;
4991 if ((mng_info->mng_width > 65535L) ||
4992 (mng_info->mng_height > 65535L))
4993 ThrowReaderException(ImageError,"WidthOrHeightExceedsLimit");
4995 (void) FormatLocaleString(page_geometry,MaxTextExtent,
4996 "%.20gx%.20g+0+0",(double) mng_info->mng_width,(double)
4997 mng_info->mng_height);
4999 mng_info->frame.left=0;
5000 mng_info->frame.right=(ssize_t) mng_info->mng_width;
5001 mng_info->frame.top=0;
5002 mng_info->frame.bottom=(ssize_t) mng_info->mng_height;
5003 mng_info->clip=default_fb=previous_fb=mng_info->frame;
5005 for (i=0; i < MNG_MAX_OBJECTS; i++)
5006 mng_info->object_clip[i]=mng_info->frame;
5008 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5012 if (memcmp(type,mng_TERM,4) == 0)
5023 final_delay=(png_uint_32) mng_get_long(&p[2]);
5024 mng_iterations=(png_uint_32) mng_get_long(&p[6]);
5026 if (mng_iterations == PNG_UINT_31_MAX)
5029 image->iterations=mng_iterations;
5030 term_chunk_found=MagickTrue;
5033 if (logging != MagickFalse)
5035 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5036 " repeat=%d",repeat);
5038 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5039 " final_delay=%.20g",(double) final_delay);
5041 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5042 " image->iterations=%.20g",(double) image->iterations);
5045 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5048 if (memcmp(type,mng_DEFI,4) == 0)
5051 (void) ThrowMagickException(exception,GetMagickModule(),
5052 CoderError,"DEFI chunk found in MNG-VLC datastream","`%s'",
5055 object_id=(p[0] << 8) | p[1];
5057 if (mng_type == 2 && object_id != 0)
5058 (void) ThrowMagickException(exception,GetMagickModule(),
5059 CoderError,"Nonzero object_id in MNG-LC datastream","`%s'",
5062 if (object_id > MNG_MAX_OBJECTS)
5065 Instead of using a warning we should allocate a larger
5066 MngInfo structure and continue.
5068 (void) ThrowMagickException(exception,GetMagickModule(),
5069 CoderError,"object id too large","`%s'",image->filename);
5070 object_id=MNG_MAX_OBJECTS;
5073 if (mng_info->exists[object_id])
5074 if (mng_info->frozen[object_id])
5076 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5077 (void) ThrowMagickException(exception,
5078 GetMagickModule(),CoderError,
5079 "DEFI cannot redefine a frozen MNG object","`%s'",
5084 mng_info->exists[object_id]=MagickTrue;
5087 mng_info->invisible[object_id]=p[2];
5090 Extract object offset info.
5094 mng_info->x_off[object_id]=(ssize_t) ((p[4] << 24) |
5095 (p[5] << 16) | (p[6] << 8) | p[7]);
5097 mng_info->y_off[object_id]=(ssize_t) ((p[8] << 24) |
5098 (p[9] << 16) | (p[10] << 8) | p[11]);
5100 if (logging != MagickFalse)
5102 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5103 " x_off[%d]: %.20g",object_id,(double)
5104 mng_info->x_off[object_id]);
5106 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5107 " y_off[%d]: %.20g",object_id,(double)
5108 mng_info->y_off[object_id]);
5113 Extract object clipping info.
5116 mng_info->object_clip[object_id]=mng_read_box(mng_info->frame,0,
5119 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5122 if (memcmp(type,mng_bKGD,4) == 0)
5124 mng_info->have_global_bkgd=MagickFalse;
5128 mng_info->mng_global_bkgd.red=
5129 ScaleShortToQuantum((unsigned short) ((p[0] << 8) | p[1]));
5131 mng_info->mng_global_bkgd.green=
5132 ScaleShortToQuantum((unsigned short) ((p[2] << 8) | p[3]));
5134 mng_info->mng_global_bkgd.blue=
5135 ScaleShortToQuantum((unsigned short) ((p[4] << 8) | p[5]));
5137 mng_info->have_global_bkgd=MagickTrue;
5140 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5143 if (memcmp(type,mng_BACK,4) == 0)
5145 #if defined(MNG_INSERT_LAYERS)
5147 mandatory_back=p[6];
5152 if (mandatory_back && length > 5)
5154 mng_background_color.red=
5155 ScaleShortToQuantum((unsigned short) ((p[0] << 8) | p[1]));
5157 mng_background_color.green=
5158 ScaleShortToQuantum((unsigned short) ((p[2] << 8) | p[3]));
5160 mng_background_color.blue=
5161 ScaleShortToQuantum((unsigned short) ((p[4] << 8) | p[5]));
5163 mng_background_color.alpha=OpaqueAlpha;
5166 #ifdef MNG_OBJECT_BUFFERS
5168 mng_background_object=(p[7] << 8) | p[8];
5171 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5175 if (memcmp(type,mng_PLTE,4) == 0)
5177 /* Read global PLTE. */
5179 if (length && (length < 769))
5181 if (mng_info->global_plte == (png_colorp) NULL)
5182 mng_info->global_plte=(png_colorp) AcquireQuantumMemory(256,
5183 sizeof(*mng_info->global_plte));
5185 for (i=0; i < (ssize_t) (length/3); i++)
5187 mng_info->global_plte[i].red=p[3*i];
5188 mng_info->global_plte[i].green=p[3*i+1];
5189 mng_info->global_plte[i].blue=p[3*i+2];
5192 mng_info->global_plte_length=(unsigned int) (length/3);
5195 for ( ; i < 256; i++)
5197 mng_info->global_plte[i].red=i;
5198 mng_info->global_plte[i].green=i;
5199 mng_info->global_plte[i].blue=i;
5203 mng_info->global_plte_length=256;
5206 mng_info->global_plte_length=0;
5208 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5212 if (memcmp(type,mng_tRNS,4) == 0)
5214 /* read global tRNS */
5217 for (i=0; i < (ssize_t) length; i++)
5218 mng_info->global_trns[i]=p[i];
5221 for ( ; i < 256; i++)
5222 mng_info->global_trns[i]=255;
5224 mng_info->global_trns_length=(unsigned int) length;
5225 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5228 if (memcmp(type,mng_gAMA,4) == 0)
5235 igamma=mng_get_long(p);
5236 mng_info->global_gamma=((float) igamma)*0.00001;
5237 mng_info->have_global_gama=MagickTrue;
5241 mng_info->have_global_gama=MagickFalse;
5243 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5247 if (memcmp(type,mng_cHRM,4) == 0)
5249 /* Read global cHRM */
5253 mng_info->global_chrm.white_point.x=0.00001*mng_get_long(p);
5254 mng_info->global_chrm.white_point.y=0.00001*mng_get_long(&p[4]);
5255 mng_info->global_chrm.red_primary.x=0.00001*mng_get_long(&p[8]);
5256 mng_info->global_chrm.red_primary.y=0.00001*
5257 mng_get_long(&p[12]);
5258 mng_info->global_chrm.green_primary.x=0.00001*
5259 mng_get_long(&p[16]);
5260 mng_info->global_chrm.green_primary.y=0.00001*
5261 mng_get_long(&p[20]);
5262 mng_info->global_chrm.blue_primary.x=0.00001*
5263 mng_get_long(&p[24]);
5264 mng_info->global_chrm.blue_primary.y=0.00001*
5265 mng_get_long(&p[28]);
5266 mng_info->have_global_chrm=MagickTrue;
5269 mng_info->have_global_chrm=MagickFalse;
5271 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5275 if (memcmp(type,mng_sRGB,4) == 0)
5282 mng_info->global_srgb_intent=
5283 Magick_RenderingIntent_from_PNG_RenderingIntent(p[0]);
5284 mng_info->have_global_srgb=MagickTrue;
5287 mng_info->have_global_srgb=MagickFalse;
5289 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5293 if (memcmp(type,mng_iCCP,4) == 0)
5301 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5306 if (memcmp(type,mng_FRAM,4) == 0)
5309 (void) ThrowMagickException(exception,GetMagickModule(),
5310 CoderError,"FRAM chunk found in MNG-VLC datastream","`%s'",
5313 if ((mng_info->framing_mode == 2) || (mng_info->framing_mode == 4))
5314 image->delay=frame_delay;
5316 frame_delay=default_frame_delay;
5317 frame_timeout=default_frame_timeout;
5322 mng_info->framing_mode=p[0];
5324 if (logging != MagickFalse)
5325 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5326 " Framing_mode=%d",mng_info->framing_mode);
5330 /* Note the delay and frame clipping boundaries. */
5332 p++; /* framing mode */
5334 while (*p && ((p-chunk) < (ssize_t) length))
5335 p++; /* frame name */
5337 p++; /* frame name terminator */
5339 if ((p-chunk) < (ssize_t) (length-4))
5346 change_delay=(*p++);
5347 change_timeout=(*p++);
5348 change_clipping=(*p++);
5349 p++; /* change_sync */
5353 frame_delay=1UL*image->ticks_per_second*
5356 if (mng_info->ticks_per_second != 0)
5357 frame_delay/=mng_info->ticks_per_second;
5360 frame_delay=PNG_UINT_31_MAX;
5362 if (change_delay == 2)
5363 default_frame_delay=frame_delay;
5367 if (logging != MagickFalse)
5368 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5369 " Framing_delay=%.20g",(double) frame_delay);
5374 frame_timeout=1UL*image->ticks_per_second*
5377 if (mng_info->ticks_per_second != 0)
5378 frame_timeout/=mng_info->ticks_per_second;
5381 frame_timeout=PNG_UINT_31_MAX;
5383 if (change_delay == 2)
5384 default_frame_timeout=frame_timeout;
5388 if (logging != MagickFalse)
5389 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5390 " Framing_timeout=%.20g",(double) frame_timeout);
5393 if (change_clipping)
5395 fb=mng_read_box(previous_fb,(char) p[0],&p[1]);
5399 if (logging != MagickFalse)
5400 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5401 " Frame_clip: L=%.20g R=%.20g T=%.20g B=%.20g",
5402 (double) fb.left,(double) fb.right,(double) fb.top,
5403 (double) fb.bottom);
5405 if (change_clipping == 2)
5411 mng_info->clip=mng_minimum_box(fb,mng_info->frame);
5413 subframe_width=(size_t) (mng_info->clip.right
5414 -mng_info->clip.left);
5416 subframe_height=(size_t) (mng_info->clip.bottom
5417 -mng_info->clip.top);
5419 Insert a background layer behind the frame if framing_mode is 4.
5421 #if defined(MNG_INSERT_LAYERS)
5422 if (logging != MagickFalse)
5423 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5424 " subframe_width=%.20g, subframe_height=%.20g",(double)
5425 subframe_width,(double) subframe_height);
5427 if (insert_layers && (mng_info->framing_mode == 4) &&
5428 (subframe_width) && (subframe_height))
5430 /* Allocate next image structure. */
5431 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
5433 AcquireNextImage(image_info,image,exception);
5435 if (GetNextImageInList(image) == (Image *) NULL)
5437 image=DestroyImageList(image);
5438 MngInfoFreeStruct(mng_info,&have_mng_structure);
5439 return((Image *) NULL);
5442 image=SyncNextImageInList(image);
5445 mng_info->image=image;
5447 if (term_chunk_found)
5449 image->start_loop=MagickTrue;
5450 image->iterations=mng_iterations;
5451 term_chunk_found=MagickFalse;
5455 image->start_loop=MagickFalse;
5457 image->columns=subframe_width;
5458 image->rows=subframe_height;
5459 image->page.width=subframe_width;
5460 image->page.height=subframe_height;
5461 image->page.x=mng_info->clip.left;
5462 image->page.y=mng_info->clip.top;
5463 image->background_color=mng_background_color;
5464 image->alpha_trait=UndefinedPixelTrait;
5466 (void) SetImageBackgroundColor(image,exception);
5468 if (logging != MagickFalse)
5469 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5470 " Insert backgd layer, L=%.20g, R=%.20g T=%.20g, B=%.20g",
5471 (double) mng_info->clip.left,(double) mng_info->clip.right,
5472 (double) mng_info->clip.top,(double) mng_info->clip.bottom);
5475 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5478 if (memcmp(type,mng_CLIP,4) == 0)
5487 first_object=(p[0] << 8) | p[1];
5488 last_object=(p[2] << 8) | p[3];
5490 for (i=(int) first_object; i <= (int) last_object; i++)
5492 if (mng_info->exists[i] && !mng_info->frozen[i])
5497 box=mng_info->object_clip[i];
5498 mng_info->object_clip[i]=mng_read_box(box,(char) p[4],&p[5]);
5502 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5505 if (memcmp(type,mng_SAVE,4) == 0)
5507 for (i=1; i < MNG_MAX_OBJECTS; i++)
5508 if (mng_info->exists[i])
5510 mng_info->frozen[i]=MagickTrue;
5511 #ifdef MNG_OBJECT_BUFFERS
5512 if (mng_info->ob[i] != (MngBuffer *) NULL)
5513 mng_info->ob[i]->frozen=MagickTrue;
5518 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5523 if ((memcmp(type,mng_DISC,4) == 0) || (memcmp(type,mng_SEEK,4) == 0))
5525 /* Read DISC or SEEK. */
5527 if ((length == 0) || !memcmp(type,mng_SEEK,4))
5529 for (i=1; i < MNG_MAX_OBJECTS; i++)
5530 MngInfoDiscardObject(mng_info,i);
5538 for (j=0; j < (ssize_t) length; j+=2)
5540 i=p[j] << 8 | p[j+1];
5541 MngInfoDiscardObject(mng_info,i);
5546 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5551 if (memcmp(type,mng_MOVE,4) == 0)
5559 first_object=(p[0] << 8) | p[1];
5560 last_object=(p[2] << 8) | p[3];
5561 for (i=(ssize_t) first_object; i <= (ssize_t) last_object; i++)
5563 if (mng_info->exists[i] && !mng_info->frozen[i])
5571 old_pair.a=mng_info->x_off[i];
5572 old_pair.b=mng_info->y_off[i];
5573 new_pair=mng_read_pair(old_pair,(int) p[4],&p[5]);
5574 mng_info->x_off[i]=new_pair.a;
5575 mng_info->y_off[i]=new_pair.b;
5579 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5583 if (memcmp(type,mng_LOOP,4) == 0)
5585 ssize_t loop_iters=1;
5586 loop_level=chunk[0];
5587 mng_info->loop_active[loop_level]=1; /* mark loop active */
5589 /* Record starting point. */
5590 loop_iters=mng_get_long(&chunk[1]);
5592 if (logging != MagickFalse)
5593 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5594 " LOOP level %.20g has %.20g iterations ",(double) loop_level,
5595 (double) loop_iters);
5597 if (loop_iters == 0)
5598 skipping_loop=loop_level;
5602 mng_info->loop_jump[loop_level]=TellBlob(image);
5603 mng_info->loop_count[loop_level]=loop_iters;
5606 mng_info->loop_iteration[loop_level]=0;
5607 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5611 if (memcmp(type,mng_ENDL,4) == 0)
5613 loop_level=chunk[0];
5615 if (skipping_loop > 0)
5617 if (skipping_loop == loop_level)
5620 Found end of zero-iteration loop.
5623 mng_info->loop_active[loop_level]=0;
5629 if (mng_info->loop_active[loop_level] == 1)
5631 mng_info->loop_count[loop_level]--;
5632 mng_info->loop_iteration[loop_level]++;
5634 if (logging != MagickFalse)
5635 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5636 " ENDL: LOOP level %.20g has %.20g remaining iters ",
5637 (double) loop_level,(double)
5638 mng_info->loop_count[loop_level]);
5640 if (mng_info->loop_count[loop_level] != 0)
5642 offset=SeekBlob(image,mng_info->loop_jump[loop_level],
5646 ThrowReaderException(CorruptImageError,
5647 "ImproperImageHeader");
5658 mng_info->loop_active[loop_level]=0;
5660 for (i=0; i < loop_level; i++)
5661 if (mng_info->loop_active[i] == 1)
5662 last_level=(short) i;
5663 loop_level=last_level;
5668 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5672 if (memcmp(type,mng_CLON,4) == 0)
5674 if (mng_info->clon_warning == 0)
5675 (void) ThrowMagickException(exception,GetMagickModule(),
5676 CoderError,"CLON is not implemented yet","`%s'",
5679 mng_info->clon_warning++;
5682 if (memcmp(type,mng_MAGN,4) == 0)
5697 magn_first=(p[0] << 8) | p[1];
5703 magn_last=(p[2] << 8) | p[3];
5706 magn_last=magn_first;
5707 #ifndef MNG_OBJECT_BUFFERS
5708 if (magn_first || magn_last)
5709 if (mng_info->magn_warning == 0)
5711 (void) ThrowMagickException(exception,
5712 GetMagickModule(),CoderError,
5713 "MAGN is not implemented yet for nonzero objects",
5714 "`%s'",image->filename);
5716 mng_info->magn_warning++;
5726 magn_mx=(p[5] << 8) | p[6];
5735 magn_my=(p[7] << 8) | p[8];
5744 magn_ml=(p[9] << 8) | p[10];
5753 magn_mr=(p[11] << 8) | p[12];
5762 magn_mt=(p[13] << 8) | p[14];
5771 magn_mb=(p[15] << 8) | p[16];
5783 magn_methy=magn_methx;
5786 if (magn_methx > 5 || magn_methy > 5)
5787 if (mng_info->magn_warning == 0)
5789 (void) ThrowMagickException(exception,
5790 GetMagickModule(),CoderError,
5791 "Unknown MAGN method in MNG datastream","`%s'",
5794 mng_info->magn_warning++;
5796 #ifdef MNG_OBJECT_BUFFERS
5797 /* Magnify existing objects in the range magn_first to magn_last */
5799 if (magn_first == 0 || magn_last == 0)
5801 /* Save the magnification factors for object 0 */
5802 mng_info->magn_mb=magn_mb;
5803 mng_info->magn_ml=magn_ml;
5804 mng_info->magn_mr=magn_mr;
5805 mng_info->magn_mt=magn_mt;
5806 mng_info->magn_mx=magn_mx;
5807 mng_info->magn_my=magn_my;
5808 mng_info->magn_methx=magn_methx;
5809 mng_info->magn_methy=magn_methy;
5813 if (memcmp(type,mng_PAST,4) == 0)
5815 if (mng_info->past_warning == 0)
5816 (void) ThrowMagickException(exception,GetMagickModule(),
5817 CoderError,"PAST is not implemented yet","`%s'",
5820 mng_info->past_warning++;
5823 if (memcmp(type,mng_SHOW,4) == 0)
5825 if (mng_info->show_warning == 0)
5826 (void) ThrowMagickException(exception,GetMagickModule(),
5827 CoderError,"SHOW is not implemented yet","`%s'",
5830 mng_info->show_warning++;
5833 if (memcmp(type,mng_sBIT,4) == 0)
5836 mng_info->have_global_sbit=MagickFalse;
5840 mng_info->global_sbit.gray=p[0];
5841 mng_info->global_sbit.red=p[0];
5842 mng_info->global_sbit.green=p[1];
5843 mng_info->global_sbit.blue=p[2];
5844 mng_info->global_sbit.alpha=p[3];
5845 mng_info->have_global_sbit=MagickTrue;
5848 if (memcmp(type,mng_pHYs,4) == 0)
5852 mng_info->global_x_pixels_per_unit=
5853 (size_t) mng_get_long(p);
5854 mng_info->global_y_pixels_per_unit=
5855 (size_t) mng_get_long(&p[4]);
5856 mng_info->global_phys_unit_type=p[8];
5857 mng_info->have_global_phys=MagickTrue;
5861 mng_info->have_global_phys=MagickFalse;
5863 if (memcmp(type,mng_pHYg,4) == 0)
5865 if (mng_info->phyg_warning == 0)
5866 (void) ThrowMagickException(exception,GetMagickModule(),
5867 CoderError,"pHYg is not implemented.","`%s'",image->filename);
5869 mng_info->phyg_warning++;
5871 if (memcmp(type,mng_BASI,4) == 0)
5873 skip_to_iend=MagickTrue;
5875 if (mng_info->basi_warning == 0)
5876 (void) ThrowMagickException(exception,GetMagickModule(),
5877 CoderError,"BASI is not implemented yet","`%s'",
5880 mng_info->basi_warning++;
5881 #ifdef MNG_BASI_SUPPORTED
5882 basi_width=(size_t) ((p[0] << 24) | (p[1] << 16) |
5883 (p[2] << 8) | p[3]);
5884 basi_height=(size_t) ((p[4] << 24) | (p[5] << 16) |
5885 (p[6] << 8) | p[7]);
5886 basi_color_type=p[8];
5887 basi_compression_method=p[9];
5888 basi_filter_type=p[10];
5889 basi_interlace_method=p[11];
5891 basi_red=(p[12] << 8) & p[13];
5897 basi_green=(p[14] << 8) & p[15];
5903 basi_blue=(p[16] << 8) & p[17];
5909 basi_alpha=(p[18] << 8) & p[19];
5913 if (basi_sample_depth == 16)
5920 basi_viewable=p[20];
5926 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5930 if (memcmp(type,mng_IHDR,4)
5931 #if defined(JNG_SUPPORTED)
5932 && memcmp(type,mng_JHDR,4)
5936 /* Not an IHDR or JHDR chunk */
5938 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5943 if (logging != MagickFalse)
5944 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5945 " Processing %c%c%c%c chunk",type[0],type[1],type[2],type[3]);
5947 mng_info->exists[object_id]=MagickTrue;
5948 mng_info->viewable[object_id]=MagickTrue;
5950 if (mng_info->invisible[object_id])
5952 if (logging != MagickFalse)
5953 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5954 " Skipping invisible object");
5956 skip_to_iend=MagickTrue;
5957 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5960 #if defined(MNG_INSERT_LAYERS)
5962 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
5964 image_width=(size_t) mng_get_long(p);
5965 image_height=(size_t) mng_get_long(&p[4]);
5967 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5970 Insert a transparent background layer behind the entire animation
5971 if it is not full screen.
5973 #if defined(MNG_INSERT_LAYERS)
5974 if (insert_layers && mng_type && first_mng_object)
5976 if ((mng_info->clip.left > 0) || (mng_info->clip.top > 0) ||
5977 (image_width < mng_info->mng_width) ||
5978 (mng_info->clip.right < (ssize_t) mng_info->mng_width) ||
5979 (image_height < mng_info->mng_height) ||
5980 (mng_info->clip.bottom < (ssize_t) mng_info->mng_height))
5982 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
5985 Allocate next image structure.
5987 AcquireNextImage(image_info,image,exception);
5989 if (GetNextImageInList(image) == (Image *) NULL)
5991 image=DestroyImageList(image);
5992 MngInfoFreeStruct(mng_info,&have_mng_structure);
5993 return((Image *) NULL);
5996 image=SyncNextImageInList(image);
5998 mng_info->image=image;
6000 if (term_chunk_found)
6002 image->start_loop=MagickTrue;
6003 image->iterations=mng_iterations;
6004 term_chunk_found=MagickFalse;
6008 image->start_loop=MagickFalse;
6010 /* Make a background rectangle. */
6013 image->columns=mng_info->mng_width;
6014 image->rows=mng_info->mng_height;
6015 image->page.width=mng_info->mng_width;
6016 image->page.height=mng_info->mng_height;
6019 image->background_color=mng_background_color;
6020 (void) SetImageBackgroundColor(image,exception);
6021 if (logging != MagickFalse)
6022 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6023 " Inserted transparent background layer, W=%.20g, H=%.20g",
6024 (double) mng_info->mng_width,(double) mng_info->mng_height);
6028 Insert a background layer behind the upcoming image if
6029 framing_mode is 3, and we haven't already inserted one.
6031 if (insert_layers && (mng_info->framing_mode == 3) &&
6032 (subframe_width) && (subframe_height) && (simplicity == 0 ||
6033 (simplicity & 0x08)))
6035 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
6038 Allocate next image structure.
6040 AcquireNextImage(image_info,image,exception);
6042 if (GetNextImageInList(image) == (Image *) NULL)
6044 image=DestroyImageList(image);
6045 MngInfoFreeStruct(mng_info,&have_mng_structure);
6046 return((Image *) NULL);
6049 image=SyncNextImageInList(image);
6052 mng_info->image=image;
6054 if (term_chunk_found)
6056 image->start_loop=MagickTrue;
6057 image->iterations=mng_iterations;
6058 term_chunk_found=MagickFalse;
6062 image->start_loop=MagickFalse;
6065 image->columns=subframe_width;
6066 image->rows=subframe_height;
6067 image->page.width=subframe_width;
6068 image->page.height=subframe_height;
6069 image->page.x=mng_info->clip.left;
6070 image->page.y=mng_info->clip.top;
6071 image->background_color=mng_background_color;
6072 image->alpha_trait=UndefinedPixelTrait;
6073 (void) SetImageBackgroundColor(image,exception);
6075 if (logging != MagickFalse)
6076 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6077 " Insert background layer, L=%.20g, R=%.20g T=%.20g, B=%.20g",
6078 (double) mng_info->clip.left,(double) mng_info->clip.right,
6079 (double) mng_info->clip.top,(double) mng_info->clip.bottom);
6081 #endif /* MNG_INSERT_LAYERS */
6082 first_mng_object=MagickFalse;
6084 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
6087 Allocate next image structure.
6089 AcquireNextImage(image_info,image,exception);
6091 if (GetNextImageInList(image) == (Image *) NULL)
6093 image=DestroyImageList(image);
6094 MngInfoFreeStruct(mng_info,&have_mng_structure);
6095 return((Image *) NULL);
6098 image=SyncNextImageInList(image);
6100 mng_info->image=image;
6101 status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
6102 GetBlobSize(image));
6104 if (status == MagickFalse)
6107 if (term_chunk_found)
6109 image->start_loop=MagickTrue;
6110 term_chunk_found=MagickFalse;
6114 image->start_loop=MagickFalse;
6116 if (mng_info->framing_mode == 1 || mng_info->framing_mode == 3)
6118 image->delay=frame_delay;
6119 frame_delay=default_frame_delay;
6125 image->page.width=mng_info->mng_width;
6126 image->page.height=mng_info->mng_height;
6127 image->page.x=mng_info->x_off[object_id];
6128 image->page.y=mng_info->y_off[object_id];
6129 image->iterations=mng_iterations;
6132 Seek back to the beginning of the IHDR or JHDR chunk's length field.
6135 if (logging != MagickFalse)
6136 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6137 " Seeking back to beginning of %c%c%c%c chunk",type[0],type[1],
6140 offset=SeekBlob(image,-((ssize_t) length+12),SEEK_CUR);
6143 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
6147 mng_info->image=image;
6148 mng_info->mng_type=mng_type;
6149 mng_info->object_id=object_id;
6151 if (memcmp(type,mng_IHDR,4) == 0)
6152 image=ReadOnePNGImage(mng_info,image_info,exception);
6154 #if defined(JNG_SUPPORTED)
6156 image=ReadOneJNGImage(mng_info,image_info,exception);
6159 if (image == (Image *) NULL)
6161 if (IsImageObject(previous) != MagickFalse)
6163 (void) DestroyImageList(previous);
6164 (void) CloseBlob(previous);
6167 MngInfoFreeStruct(mng_info,&have_mng_structure);
6168 return((Image *) NULL);
6171 if (image->columns == 0 || image->rows == 0)
6173 (void) CloseBlob(image);
6174 image=DestroyImageList(image);
6175 MngInfoFreeStruct(mng_info,&have_mng_structure);
6176 return((Image *) NULL);
6179 mng_info->image=image;
6186 if (mng_info->magn_methx || mng_info->magn_methy)
6192 if (logging != MagickFalse)
6193 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6194 " Processing MNG MAGN chunk");
6196 if (mng_info->magn_methx == 1)
6198 magnified_width=mng_info->magn_ml;
6200 if (image->columns > 1)
6201 magnified_width += mng_info->magn_mr;
6203 if (image->columns > 2)
6204 magnified_width += (png_uint_32)
6205 ((image->columns-2)*(mng_info->magn_mx));
6210 magnified_width=(png_uint_32) image->columns;
6212 if (image->columns > 1)
6213 magnified_width += mng_info->magn_ml-1;
6215 if (image->columns > 2)
6216 magnified_width += mng_info->magn_mr-1;
6218 if (image->columns > 3)
6219 magnified_width += (png_uint_32)
6220 ((image->columns-3)*(mng_info->magn_mx-1));
6223 if (mng_info->magn_methy == 1)
6225 magnified_height=mng_info->magn_mt;
6227 if (image->rows > 1)
6228 magnified_height += mng_info->magn_mb;
6230 if (image->rows > 2)
6231 magnified_height += (png_uint_32)
6232 ((image->rows-2)*(mng_info->magn_my));
6237 magnified_height=(png_uint_32) image->rows;
6239 if (image->rows > 1)
6240 magnified_height += mng_info->magn_mt-1;
6242 if (image->rows > 2)
6243 magnified_height += mng_info->magn_mb-1;
6245 if (image->rows > 3)
6246 magnified_height += (png_uint_32)
6247 ((image->rows-3)*(mng_info->magn_my-1));
6250 if (magnified_height > image->rows ||
6251 magnified_width > image->columns)
6278 /* Allocate next image structure. */
6280 if (logging != MagickFalse)
6281 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6282 " Allocate magnified image");
6284 AcquireNextImage(image_info,image,exception);
6286 if (GetNextImageInList(image) == (Image *) NULL)
6288 image=DestroyImageList(image);
6289 MngInfoFreeStruct(mng_info,&have_mng_structure);
6290 return((Image *) NULL);
6293 large_image=SyncNextImageInList(image);
6295 large_image->columns=magnified_width;
6296 large_image->rows=magnified_height;
6298 magn_methx=mng_info->magn_methx;
6299 magn_methy=mng_info->magn_methy;
6301 #if (MAGICKCORE_QUANTUM_DEPTH > 16)
6302 #define QM unsigned short
6303 if (magn_methx != 1 || magn_methy != 1)
6306 Scale pixels to unsigned shorts to prevent
6307 overflow of intermediate values of interpolations
6309 for (y=0; y < (ssize_t) image->rows; y++)
6311 q=GetAuthenticPixels(image,0,y,image->columns,1,
6314 for (x=(ssize_t) image->columns-1; x >= 0; x--)
6316 SetPixelRed(image,ScaleQuantumToShort(
6317 GetPixelRed(image,q)),q);
6318 SetPixelGreen(image,ScaleQuantumToShort(
6319 GetPixelGreen(image,q)),q);
6320 SetPixelBlue(image,ScaleQuantumToShort(
6321 GetPixelBlue(image,q)),q);
6322 SetPixelAlpha(image,ScaleQuantumToShort(
6323 GetPixelAlpha(image,q)),q);
6324 q+=GetPixelChannels(image);
6327 if (SyncAuthenticPixels(image,exception) == MagickFalse)
6335 if (image->alpha_trait == BlendPixelTrait)
6336 (void) SetImageBackgroundColor(large_image,exception);
6340 large_image->background_color.alpha=OpaqueAlpha;
6341 (void) SetImageBackgroundColor(large_image,exception);
6343 if (magn_methx == 4)
6346 if (magn_methx == 5)
6349 if (magn_methy == 4)
6352 if (magn_methy == 5)
6356 /* magnify the rows into the right side of the large image */
6358 if (logging != MagickFalse)
6359 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6360 " Magnify the rows to %.20g",(double) large_image->rows);
6361 m=(ssize_t) mng_info->magn_mt;
6363 length=(size_t) image->columns*GetPixelChannels(image);
6364 next=(Quantum *) AcquireQuantumMemory(length,sizeof(*next));
6365 prev=(Quantum *) AcquireQuantumMemory(length,sizeof(*prev));
6367 if ((prev == (Quantum *) NULL) ||
6368 (next == (Quantum *) NULL))
6370 image=DestroyImageList(image);
6371 MngInfoFreeStruct(mng_info,&have_mng_structure);
6372 ThrowReaderException(ResourceLimitError,
6373 "MemoryAllocationFailed");
6376 n=GetAuthenticPixels(image,0,0,image->columns,1,exception);
6377 (void) CopyMagickMemory(next,n,length);
6379 for (y=0; y < (ssize_t) image->rows; y++)
6382 m=(ssize_t) mng_info->magn_mt;
6384 else if (magn_methy > 1 && y == (ssize_t) image->rows-2)
6385 m=(ssize_t) mng_info->magn_mb;
6387 else if (magn_methy <= 1 && y == (ssize_t) image->rows-1)
6388 m=(ssize_t) mng_info->magn_mb;
6390 else if (magn_methy > 1 && y == (ssize_t) image->rows-1)
6394 m=(ssize_t) mng_info->magn_my;
6400 if (y < (ssize_t) image->rows-1)
6402 n=GetAuthenticPixels(image,0,y+1,image->columns,1,
6404 (void) CopyMagickMemory(next,n,length);
6407 for (i=0; i < m; i++, yy++)
6412 assert(yy < (ssize_t) large_image->rows);
6415 q=GetAuthenticPixels(large_image,0,yy,large_image->columns,
6417 q+=(large_image->columns-image->columns)*
6418 GetPixelChannels(large_image);
6420 for (x=(ssize_t) image->columns-1; x >= 0; x--)
6422 /* To do: get color as function of indexes[x] */
6424 if (image->storage_class == PseudoClass)
6429 if (magn_methy <= 1)
6431 /* replicate previous */
6432 SetPixelRed(large_image,GetPixelRed(image,pixels),q);
6433 SetPixelGreen(large_image,GetPixelGreen(image,
6435 SetPixelBlue(large_image,GetPixelBlue(image,
6437 SetPixelAlpha(large_image,GetPixelAlpha(image,
6441 else if (magn_methy == 2 || magn_methy == 4)
6445 SetPixelRed(large_image,GetPixelRed(image,
6447 SetPixelGreen(large_image,GetPixelGreen(image,
6449 SetPixelBlue(large_image,GetPixelBlue(image,
6451 SetPixelAlpha(large_image,GetPixelAlpha(image,
6458 SetPixelRed(large_image,((QM) (((ssize_t)
6459 (2*i*(GetPixelRed(image,n)
6460 -GetPixelRed(image,pixels)+m))/
6462 +GetPixelRed(image,pixels)))),q);
6463 SetPixelGreen(large_image,((QM) (((ssize_t)
6464 (2*i*(GetPixelGreen(image,n)
6465 -GetPixelGreen(image,pixels)+m))/
6467 +GetPixelGreen(image,pixels)))),q);
6468 SetPixelBlue(large_image,((QM) (((ssize_t)
6469 (2*i*(GetPixelBlue(image,n)
6470 -GetPixelBlue(image,pixels)+m))/
6472 +GetPixelBlue(image,pixels)))),q);
6474 if (image->alpha_trait == BlendPixelTrait)
6475 SetPixelAlpha(large_image, ((QM) (((ssize_t)
6476 (2*i*(GetPixelAlpha(image,n)
6477 -GetPixelAlpha(image,pixels)+m))
6479 GetPixelAlpha(image,pixels)))),q);
6482 if (magn_methy == 4)
6484 /* Replicate nearest */
6485 if (i <= ((m+1) << 1))
6486 SetPixelAlpha(large_image,GetPixelAlpha(image,
6489 SetPixelAlpha(large_image,GetPixelAlpha(image,
6494 else /* if (magn_methy == 3 || magn_methy == 5) */
6496 /* Replicate nearest */
6497 if (i <= ((m+1) << 1))
6499 SetPixelRed(large_image,GetPixelRed(image,
6501 SetPixelGreen(large_image,GetPixelGreen(image,
6503 SetPixelBlue(large_image,GetPixelBlue(image,
6505 SetPixelAlpha(large_image,GetPixelAlpha(image,
6511 SetPixelRed(large_image,GetPixelRed(image,n),q);
6512 SetPixelGreen(large_image,GetPixelGreen(image,n),
6514 SetPixelBlue(large_image,GetPixelBlue(image,n),
6516 SetPixelAlpha(large_image,GetPixelAlpha(image,n),
6520 if (magn_methy == 5)
6522 SetPixelAlpha(large_image,(QM) (((ssize_t) (2*i*
6523 (GetPixelAlpha(image,n)
6524 -GetPixelAlpha(image,pixels))
6525 +m))/((ssize_t) (m*2))
6526 +GetPixelAlpha(image,pixels)),q);
6529 n+=GetPixelChannels(image);
6530 q+=GetPixelChannels(large_image);
6531 pixels+=GetPixelChannels(image);
6534 if (SyncAuthenticPixels(large_image,exception) == 0)
6540 prev=(Quantum *) RelinquishMagickMemory(prev);
6541 next=(Quantum *) RelinquishMagickMemory(next);
6543 length=image->columns;
6545 if (logging != MagickFalse)
6546 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6547 " Delete original image");
6549 DeleteImageFromList(&image);
6553 mng_info->image=image;
6555 /* magnify the columns */
6556 if (logging != MagickFalse)
6557 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6558 " Magnify the columns to %.20g",(double) image->columns);
6560 for (y=0; y < (ssize_t) image->rows; y++)
6565 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
6566 pixels=q+(image->columns-length)*GetPixelChannels(image);
6567 n=pixels+GetPixelChannels(image);
6569 for (x=(ssize_t) (image->columns-length);
6570 x < (ssize_t) image->columns; x++)
6572 /* To do: Rewrite using Get/Set***PixelChannel() */
6574 if (x == (ssize_t) (image->columns-length))
6575 m=(ssize_t) mng_info->magn_ml;
6577 else if (magn_methx > 1 && x == (ssize_t) image->columns-2)
6578 m=(ssize_t) mng_info->magn_mr;
6580 else if (magn_methx <= 1 && x == (ssize_t) image->columns-1)
6581 m=(ssize_t) mng_info->magn_mr;
6583 else if (magn_methx > 1 && x == (ssize_t) image->columns-1)
6587 m=(ssize_t) mng_info->magn_mx;
6589 for (i=0; i < m; i++)
6591 if (magn_methx <= 1)
6593 /* replicate previous */
6594 SetPixelRed(image,GetPixelRed(image,pixels),q);
6595 SetPixelGreen(image,GetPixelGreen(image,pixels),q);
6596 SetPixelBlue(image,GetPixelBlue(image,pixels),q);
6597 SetPixelAlpha(image,GetPixelAlpha(image,pixels),q);
6600 else if (magn_methx == 2 || magn_methx == 4)
6604 SetPixelRed(image,GetPixelRed(image,pixels),q);
6605 SetPixelGreen(image,GetPixelGreen(image,pixels),q);
6606 SetPixelBlue(image,GetPixelBlue(image,pixels),q);
6607 SetPixelAlpha(image,GetPixelAlpha(image,pixels),q);
6610 /* To do: Rewrite using Get/Set***PixelChannel() */
6614 SetPixelRed(image,(QM) ((2*i*(
6615 GetPixelRed(image,n)
6616 -GetPixelRed(image,pixels))+m)
6618 GetPixelRed(image,pixels)),q);
6620 SetPixelGreen(image,(QM) ((2*i*(
6621 GetPixelGreen(image,n)
6622 -GetPixelGreen(image,pixels))+m)
6624 GetPixelGreen(image,pixels)),q);
6626 SetPixelBlue(image,(QM) ((2*i*(
6627 GetPixelBlue(image,n)
6628 -GetPixelBlue(image,pixels))+m)
6630 GetPixelBlue(image,pixels)),q);
6631 if (image->alpha_trait == BlendPixelTrait)
6632 SetPixelAlpha(image,(QM) ((2*i*(
6633 GetPixelAlpha(image,n)
6634 -GetPixelAlpha(image,pixels))+m)
6636 GetPixelAlpha(image,pixels)),q);
6639 if (magn_methx == 4)
6641 /* Replicate nearest */
6642 if (i <= ((m+1) << 1))
6644 SetPixelAlpha(image,
6645 GetPixelAlpha(image,pixels)+0,q);
6649 SetPixelAlpha(image,
6650 GetPixelAlpha(image,n)+0,q);
6655 else /* if (magn_methx == 3 || magn_methx == 5) */
6657 /* Replicate nearest */
6658 if (i <= ((m+1) << 1))
6660 SetPixelRed(image,GetPixelRed(image,pixels),q);
6661 SetPixelGreen(image,GetPixelGreen(image,pixels),q);
6662 SetPixelBlue(image,GetPixelBlue(image,pixels),q);
6663 SetPixelAlpha(image,GetPixelAlpha(image,pixels),q);
6668 SetPixelRed(image,GetPixelRed(image,n),q);
6669 SetPixelGreen(image,GetPixelGreen(image,n),q);
6670 SetPixelBlue(image,GetPixelBlue(image,n),q);
6671 SetPixelAlpha(image,GetPixelAlpha(image,n),q);
6674 if (magn_methx == 5)
6677 SetPixelAlpha(image,
6678 (QM) ((2*i*( GetPixelAlpha(image,n)
6679 -GetPixelAlpha(image,pixels))+m)/
6681 +GetPixelAlpha(image,pixels)),q);
6684 q+=GetPixelChannels(image);
6686 n+=GetPixelChannels(image);
6687 p+=GetPixelChannels(image);
6690 if (SyncAuthenticPixels(image,exception) == MagickFalse)
6693 #if (MAGICKCORE_QUANTUM_DEPTH > 16)
6694 if (magn_methx != 1 || magn_methy != 1)
6697 Rescale pixels to Quantum
6699 for (y=0; y < (ssize_t) image->rows; y++)
6701 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
6703 for (x=(ssize_t) image->columns-1; x >= 0; x--)
6705 SetPixelRed(image,ScaleShortToQuantum(
6706 GetPixelRed(image,q)),q);
6707 SetPixelGreen(image,ScaleShortToQuantum(
6708 GetPixelGreen(image,q)),q);
6709 SetPixelBlue(image,ScaleShortToQuantum(
6710 GetPixelBlue(image,q)),q);
6711 SetPixelAlpha(image,ScaleShortToQuantum(
6712 GetPixelAlpha(image,q)),q);
6713 q+=GetPixelChannels(image);
6716 if (SyncAuthenticPixels(image,exception) == MagickFalse)
6721 if (logging != MagickFalse)
6722 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6723 " Finished MAGN processing");
6728 Crop_box is with respect to the upper left corner of the MNG.
6730 crop_box.left=mng_info->image_box.left+mng_info->x_off[object_id];
6731 crop_box.right=mng_info->image_box.right+mng_info->x_off[object_id];
6732 crop_box.top=mng_info->image_box.top+mng_info->y_off[object_id];
6733 crop_box.bottom=mng_info->image_box.bottom+mng_info->y_off[object_id];
6734 crop_box=mng_minimum_box(crop_box,mng_info->clip);
6735 crop_box=mng_minimum_box(crop_box,mng_info->frame);
6736 crop_box=mng_minimum_box(crop_box,mng_info->object_clip[object_id]);
6737 if ((crop_box.left != (mng_info->image_box.left
6738 +mng_info->x_off[object_id])) ||
6739 (crop_box.right != (mng_info->image_box.right
6740 +mng_info->x_off[object_id])) ||
6741 (crop_box.top != (mng_info->image_box.top
6742 +mng_info->y_off[object_id])) ||
6743 (crop_box.bottom != (mng_info->image_box.bottom
6744 +mng_info->y_off[object_id])))
6746 if (logging != MagickFalse)
6747 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6748 " Crop the PNG image");
6750 if ((crop_box.left < crop_box.right) &&
6751 (crop_box.top < crop_box.bottom))
6760 Crop_info is with respect to the upper left corner of
6763 crop_info.x=(crop_box.left-mng_info->x_off[object_id]);
6764 crop_info.y=(crop_box.top-mng_info->y_off[object_id]);
6765 crop_info.width=(size_t) (crop_box.right-crop_box.left);
6766 crop_info.height=(size_t) (crop_box.bottom-crop_box.top);
6767 image->page.width=image->columns;
6768 image->page.height=image->rows;
6771 im=CropImage(image,&crop_info,exception);
6773 if (im != (Image *) NULL)
6775 image->columns=im->columns;
6776 image->rows=im->rows;
6777 im=DestroyImage(im);
6778 image->page.width=image->columns;
6779 image->page.height=image->rows;
6780 image->page.x=crop_box.left;
6781 image->page.y=crop_box.top;
6788 No pixels in crop area. The MNG spec still requires
6789 a layer, though, so make a single transparent pixel in
6790 the top left corner.
6795 (void) SetImageBackgroundColor(image,exception);
6796 image->page.width=1;
6797 image->page.height=1;
6802 #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
6803 image=mng_info->image;
6807 #if (MAGICKCORE_QUANTUM_DEPTH > 16)
6808 /* PNG does not handle depths greater than 16 so reduce it even
6811 if (image->depth > 16)
6815 #if (MAGICKCORE_QUANTUM_DEPTH > 8)
6816 if (image->depth > 8)
6818 /* To do: fill low byte properly */
6822 if (LosslessReduceDepthOK(image,exception) != MagickFalse)
6826 if (image_info->number_scenes != 0)
6828 if (mng_info->scenes_found >
6829 (ssize_t) (image_info->first_scene+image_info->number_scenes))
6833 if (logging != MagickFalse)
6834 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6835 " Finished reading image datastream.");
6837 } while (LocaleCompare(image_info->magick,"MNG") == 0);
6839 (void) CloseBlob(image);
6841 if (logging != MagickFalse)
6842 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6843 " Finished reading all image datastreams.");
6845 #if defined(MNG_INSERT_LAYERS)
6846 if (insert_layers && !mng_info->image_found && (mng_info->mng_width) &&
6847 (mng_info->mng_height))
6850 Insert a background layer if nothing else was found.
6852 if (logging != MagickFalse)
6853 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6854 " No images found. Inserting a background layer.");
6856 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
6859 Allocate next image structure.
6861 AcquireNextImage(image_info,image,exception);
6862 if (GetNextImageInList(image) == (Image *) NULL)
6864 image=DestroyImageList(image);
6865 MngInfoFreeStruct(mng_info,&have_mng_structure);
6867 if (logging != MagickFalse)
6868 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6869 " Allocation failed, returning NULL.");
6871 return((Image *) NULL);
6873 image=SyncNextImageInList(image);
6875 image->columns=mng_info->mng_width;
6876 image->rows=mng_info->mng_height;
6877 image->page.width=mng_info->mng_width;
6878 image->page.height=mng_info->mng_height;
6881 image->background_color=mng_background_color;
6882 image->alpha_trait=UndefinedPixelTrait;
6884 if (image_info->ping == MagickFalse)
6885 (void) SetImageBackgroundColor(image,exception);
6887 mng_info->image_found++;
6890 image->iterations=mng_iterations;
6892 if (mng_iterations == 1)
6893 image->start_loop=MagickTrue;
6895 while (GetPreviousImageInList(image) != (Image *) NULL)
6898 if (image_count > 10*mng_info->image_found)
6900 if (logging != MagickFalse)
6901 (void) LogMagickEvent(CoderEvent,GetMagickModule()," No beginning");
6903 (void) ThrowMagickException(exception,GetMagickModule(),
6904 CoderError,"Linked list is corrupted, beginning of list not found",
6905 "`%s'",image_info->filename);
6907 return((Image *) NULL);
6910 image=GetPreviousImageInList(image);
6912 if (GetNextImageInList(image) == (Image *) NULL)
6914 if (logging != MagickFalse)
6915 (void) LogMagickEvent(CoderEvent,GetMagickModule()," Corrupt list");
6917 (void) ThrowMagickException(exception,GetMagickModule(),
6918 CoderError,"Linked list is corrupted; next_image is NULL","`%s'",
6919 image_info->filename);
6923 if (mng_info->ticks_per_second && mng_info->image_found > 1 &&
6924 GetNextImageInList(image) ==
6927 if (logging != MagickFalse)
6928 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6929 " First image null");
6931 (void) ThrowMagickException(exception,GetMagickModule(),
6932 CoderError,"image->next for first image is NULL but shouldn't be.",
6933 "`%s'",image_info->filename);
6936 if (mng_info->image_found == 0)
6938 if (logging != MagickFalse)
6939 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6940 " No visible images found.");
6942 (void) ThrowMagickException(exception,GetMagickModule(),
6943 CoderError,"No visible images in file","`%s'",image_info->filename);
6945 if (image != (Image *) NULL)
6946 image=DestroyImageList(image);
6948 MngInfoFreeStruct(mng_info,&have_mng_structure);
6949 return((Image *) NULL);
6952 if (mng_info->ticks_per_second)
6953 final_delay=1UL*MagickMax(image->ticks_per_second,1L)*
6954 final_delay/mng_info->ticks_per_second;
6957 image->start_loop=MagickTrue;
6959 /* Find final nonzero image delay */
6960 final_image_delay=0;
6962 while (GetNextImageInList(image) != (Image *) NULL)
6965 final_image_delay=image->delay;
6967 image=GetNextImageInList(image);
6970 if (final_delay < final_image_delay)
6971 final_delay=final_image_delay;
6973 image->delay=final_delay;
6975 if (logging != MagickFalse)
6976 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6977 " image->delay=%.20g, final_delay=%.20g",(double) image->delay,
6978 (double) final_delay);
6980 if (logging != MagickFalse)
6986 image=GetFirstImageInList(image);
6988 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6989 " Before coalesce:");
6991 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6992 " scene 0 delay=%.20g",(double) image->delay);
6994 while (GetNextImageInList(image) != (Image *) NULL)
6996 image=GetNextImageInList(image);
6997 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6998 " scene %.20g delay=%.20g",(double) scene++,(double) image->delay);
7002 image=GetFirstImageInList(image);
7003 #ifdef MNG_COALESCE_LAYERS
7013 if (logging != MagickFalse)
7014 (void) LogMagickEvent(CoderEvent,GetMagickModule()," Coalesce Images");
7017 next_image=CoalesceImages(image,exception);
7019 if (next_image == (Image *) NULL)
7020 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
7022 image=DestroyImageList(image);
7025 for (next=image; next != (Image *) NULL; next=next_image)
7027 next->page.width=mng_info->mng_width;
7028 next->page.height=mng_info->mng_height;
7031 next->scene=scene++;
7032 next_image=GetNextImageInList(next);
7034 if (next_image == (Image *) NULL)
7037 if (next->delay == 0)
7040 next_image->previous=GetPreviousImageInList(next);
7041 if (GetPreviousImageInList(next) == (Image *) NULL)
7044 next->previous->next=next_image;
7045 next=DestroyImage(next);
7051 while (GetNextImageInList(image) != (Image *) NULL)
7052 image=GetNextImageInList(image);
7054 image->dispose=BackgroundDispose;
7056 if (logging != MagickFalse)
7062 image=GetFirstImageInList(image);
7064 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7065 " After coalesce:");
7067 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7068 " scene 0 delay=%.20g dispose=%.20g",(double) image->delay,
7069 (double) image->dispose);
7071 while (GetNextImageInList(image) != (Image *) NULL)
7073 image=GetNextImageInList(image);
7075 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7076 " scene %.20g delay=%.20g dispose=%.20g",(double) scene++,
7077 (double) image->delay,(double) image->dispose);
7081 image=GetFirstImageInList(image);
7082 MngInfoFreeStruct(mng_info,&have_mng_structure);
7083 have_mng_structure=MagickFalse;
7085 if (logging != MagickFalse)
7086 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit ReadMNGImage()");
7088 return(GetFirstImageInList(image));
7090 #else /* PNG_LIBPNG_VER > 10011 */
7091 static Image *ReadPNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
7093 printf("Your PNG library is too old: You have libpng-%s\n",
7094 PNG_LIBPNG_VER_STRING);
7096 (void) ThrowMagickException(exception,GetMagickModule(),CoderError,
7097 "PNG library is too old","`%s'",image_info->filename);
7099 return(Image *) NULL;
7102 static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
7104 return(ReadPNGImage(image_info,exception));
7106 #endif /* PNG_LIBPNG_VER > 10011 */
7110 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7114 % R e g i s t e r P N G I m a g e %
7118 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7120 % RegisterPNGImage() adds properties for the PNG image format to
7121 % the list of supported formats. The properties include the image format
7122 % tag, a method to read and/or write the format, whether the format
7123 % supports the saving of more than one frame to the same file or blob,
7124 % whether the format supports native in-memory I/O, and a brief
7125 % description of the format.
7127 % The format of the RegisterPNGImage method is:
7129 % size_t RegisterPNGImage(void)
7132 ModuleExport size_t RegisterPNGImage(void)
7135 version[MaxTextExtent];
7143 "See http://www.libpng.org/ for details about the PNG format."
7148 "See http://www.libpng.org/pub/mng/ for details about the JNG\n"
7154 "See http://www.libpng.org/pub/mng/ for details about the MNG\n"
7160 #if defined(PNG_LIBPNG_VER_STRING)
7161 (void) ConcatenateMagickString(version,"libpng ",MaxTextExtent);
7162 (void) ConcatenateMagickString(version,PNG_LIBPNG_VER_STRING,MaxTextExtent);
7164 if (LocaleCompare(PNG_LIBPNG_VER_STRING,png_get_header_ver(NULL)) != 0)
7166 (void) ConcatenateMagickString(version,",",MaxTextExtent);
7167 (void) ConcatenateMagickString(version,png_get_libpng_ver(NULL),
7172 entry=SetMagickInfo("MNG");
7173 entry->seekable_stream=MagickTrue; /* To do: eliminate this. */
7175 #if defined(MAGICKCORE_PNG_DELEGATE)
7176 entry->decoder=(DecodeImageHandler *) ReadMNGImage;
7177 entry->encoder=(EncodeImageHandler *) WriteMNGImage;
7180 entry->magick=(IsImageFormatHandler *) IsMNG;
7181 entry->description=ConstantString("Multiple-image Network Graphics");
7183 if (*version != '\0')
7184 entry->version=ConstantString(version);
7186 entry->module=ConstantString("PNG");
7187 entry->note=ConstantString(MNGNote);
7188 (void) RegisterMagickInfo(entry);
7190 entry=SetMagickInfo("PNG");
7192 #if defined(MAGICKCORE_PNG_DELEGATE)
7193 entry->decoder=(DecodeImageHandler *) ReadPNGImage;
7194 entry->encoder=(EncodeImageHandler *) WritePNGImage;
7197 entry->magick=(IsImageFormatHandler *) IsPNG;
7198 entry->adjoin=MagickFalse;
7199 entry->description=ConstantString("Portable Network Graphics");
7200 entry->module=ConstantString("PNG");
7202 if (*version != '\0')
7203 entry->version=ConstantString(version);
7205 entry->note=ConstantString(PNGNote);
7206 (void) RegisterMagickInfo(entry);
7208 entry=SetMagickInfo("PNG8");
7210 #if defined(MAGICKCORE_PNG_DELEGATE)
7211 entry->decoder=(DecodeImageHandler *) ReadPNGImage;
7212 entry->encoder=(EncodeImageHandler *) WritePNGImage;
7215 entry->magick=(IsImageFormatHandler *) IsPNG;
7216 entry->adjoin=MagickFalse;
7217 entry->description=ConstantString(
7218 "8-bit indexed with optional binary transparency");
7219 entry->module=ConstantString("PNG");
7220 (void) RegisterMagickInfo(entry);
7222 entry=SetMagickInfo("PNG24");
7225 #if defined(ZLIB_VERSION)
7226 (void) ConcatenateMagickString(version,"zlib ",MaxTextExtent);
7227 (void) ConcatenateMagickString(version,ZLIB_VERSION,MaxTextExtent);
7229 if (LocaleCompare(ZLIB_VERSION,zlib_version) != 0)
7231 (void) ConcatenateMagickString(version,",",MaxTextExtent);
7232 (void) ConcatenateMagickString(version,zlib_version,MaxTextExtent);
7236 if (*version != '\0')
7237 entry->version=ConstantString(version);
7239 #if defined(MAGICKCORE_PNG_DELEGATE)
7240 entry->decoder=(DecodeImageHandler *) ReadPNGImage;
7241 entry->encoder=(EncodeImageHandler *) WritePNGImage;
7244 entry->magick=(IsImageFormatHandler *) IsPNG;
7245 entry->adjoin=MagickFalse;
7246 entry->description=ConstantString("opaque 24-bit RGB");
7247 entry->module=ConstantString("PNG");
7248 (void) RegisterMagickInfo(entry);
7250 entry=SetMagickInfo("PNG32");
7252 #if defined(MAGICKCORE_PNG_DELEGATE)
7253 entry->decoder=(DecodeImageHandler *) ReadPNGImage;
7254 entry->encoder=(EncodeImageHandler *) WritePNGImage;
7257 entry->magick=(IsImageFormatHandler *) IsPNG;
7258 entry->adjoin=MagickFalse;
7259 entry->description=ConstantString("opaque or transparent 32-bit RGBA");
7260 entry->module=ConstantString("PNG");
7261 (void) RegisterMagickInfo(entry);
7263 entry=SetMagickInfo("JNG");
7265 #if defined(JNG_SUPPORTED)
7266 #if defined(MAGICKCORE_PNG_DELEGATE)
7267 entry->decoder=(DecodeImageHandler *) ReadJNGImage;
7268 entry->encoder=(EncodeImageHandler *) WriteJNGImage;
7272 entry->magick=(IsImageFormatHandler *) IsJNG;
7273 entry->adjoin=MagickFalse;
7274 entry->description=ConstantString("JPEG Network Graphics");
7275 entry->module=ConstantString("PNG");
7276 entry->note=ConstantString(JNGNote);
7277 (void) RegisterMagickInfo(entry);
7279 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
7280 ping_semaphore=AllocateSemaphoreInfo();
7283 return(MagickImageCoderSignature);
7287 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7291 % U n r e g i s t e r P N G I m a g e %
7295 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7297 % UnregisterPNGImage() removes format registrations made by the
7298 % PNG module from the list of supported formats.
7300 % The format of the UnregisterPNGImage method is:
7302 % UnregisterPNGImage(void)
7305 ModuleExport void UnregisterPNGImage(void)
7307 (void) UnregisterMagickInfo("MNG");
7308 (void) UnregisterMagickInfo("PNG");
7309 (void) UnregisterMagickInfo("PNG8");
7310 (void) UnregisterMagickInfo("PNG24");
7311 (void) UnregisterMagickInfo("PNG32");
7312 (void) UnregisterMagickInfo("JNG");
7314 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
7315 if (ping_semaphore != (SemaphoreInfo *) NULL)
7316 DestroySemaphoreInfo(&ping_semaphore);
7320 #if defined(MAGICKCORE_PNG_DELEGATE)
7321 #if PNG_LIBPNG_VER > 10011
7323 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7327 % W r i t e M N G I m a g e %
7331 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7333 % WriteMNGImage() writes an image in the Portable Network Graphics
7334 % Group's "Multiple-image Network Graphics" encoded image format.
7336 % MNG support written by Glenn Randers-Pehrson, glennrp@image...
7338 % The format of the WriteMNGImage method is:
7340 % MagickBooleanType WriteMNGImage(const ImageInfo *image_info,
7341 % Image *image,ExceptionInfo *exception)
7343 % A description of each parameter follows.
7345 % o image_info: the image info.
7347 % o image: The image.
7349 % o exception: return any errors or warnings in this structure.
7351 % To do (as of version 5.5.2, November 26, 2002 -- glennrp -- see also
7352 % "To do" under ReadPNGImage):
7354 % Preserve all unknown and not-yet-handled known chunks found in input
7355 % PNG file and copy them into output PNG files according to the PNG
7358 % Write the iCCP chunk at MNG level when (icc profile length > 0)
7360 % Improve selection of color type (use indexed-colour or indexed-colour
7361 % with tRNS when 256 or fewer unique RGBA values are present).
7363 % Figure out what to do with "dispose=<restore-to-previous>" (dispose == 3)
7364 % This will be complicated if we limit ourselves to generating MNG-LC
7365 % files. For now we ignore disposal method 3 and simply overlay the next
7368 % Check for identical PLTE's or PLTE/tRNS combinations and use a
7369 % global MNG PLTE or PLTE/tRNS combination when appropriate.
7370 % [mostly done 15 June 1999 but still need to take care of tRNS]
7372 % Check for identical sRGB and replace with a global sRGB (and remove
7373 % gAMA/cHRM if sRGB is found; check for identical gAMA/cHRM and
7374 % replace with global gAMA/cHRM (or with sRGB if appropriate; replace
7375 % local gAMA/cHRM with local sRGB if appropriate).
7377 % Check for identical sBIT chunks and write global ones.
7379 % Provide option to skip writing the signature tEXt chunks.
7381 % Use signatures to detect identical objects and reuse the first
7382 % instance of such objects instead of writing duplicate objects.
7384 % Use a smaller-than-32k value of compression window size when
7387 % Encode JNG datastreams. Mostly done as of 5.5.2; need to write
7388 % ancillary text chunks and save profiles.
7390 % Provide an option to force LC files (to ensure exact framing rate)
7393 % Provide an option to force VLC files instead of LC, even when offsets
7394 % are present. This will involve expanding the embedded images with a
7395 % transparent region at the top and/or left.
7399 Magick_png_write_raw_profile(const ImageInfo *image_info,png_struct *ping,
7400 png_info *ping_info, unsigned char *profile_type, unsigned char
7401 *profile_description, unsigned char *profile_data, png_uint_32 length)
7420 hex[16]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
7422 if (LocaleNCompare((char *) profile_type+1, "ng-chunk-",9) == 0)
7425 if (image_info->verbose)
7427 (void) printf("writing raw profile: type=%s, length=%.20g\n",
7428 (char *) profile_type, (double) length);
7431 #if PNG_LIBPNG_VER >= 14000
7432 text=(png_textp) png_malloc(ping,(png_alloc_size_t) sizeof(png_text));
7434 text=(png_textp) png_malloc(ping,(png_size_t) sizeof(png_text));
7436 description_length=(png_uint_32) strlen((const char *) profile_description);
7437 allocated_length=(png_uint_32) (length*2 + (length >> 5) + 20
7438 + description_length);
7439 #if PNG_LIBPNG_VER >= 14000
7440 text[0].text=(png_charp) png_malloc(ping,
7441 (png_alloc_size_t) allocated_length);
7442 text[0].key=(png_charp) png_malloc(ping, (png_alloc_size_t) 80);
7444 text[0].text=(png_charp) png_malloc(ping, (png_size_t) allocated_length);
7445 text[0].key=(png_charp) png_malloc(ping, (png_size_t) 80);
7447 text[0].key[0]='\0';
7448 (void) ConcatenateMagickString(text[0].key,
7449 "Raw profile type ",MaxTextExtent);
7450 (void) ConcatenateMagickString(text[0].key,(const char *) profile_type,62);
7454 (void) CopyMagickString(dp,(const char *) profile_description,
7456 dp+=description_length;
7458 (void) FormatLocaleString(dp,allocated_length-
7459 (png_size_t) (dp-text[0].text),"%8lu ",(unsigned long) length);
7462 for (i=0; i < (ssize_t) length; i++)
7466 *(dp++)=(char) hex[((*sp >> 4) & 0x0f)];
7467 *(dp++)=(char) hex[((*sp++ ) & 0x0f)];
7472 text[0].text_length=(png_size_t) (dp-text[0].text);
7473 text[0].compression=image_info->compression == NoCompression ||
7474 (image_info->compression == UndefinedCompression &&
7475 text[0].text_length < 128) ? -1 : 0;
7477 if (text[0].text_length <= allocated_length)
7478 png_set_text(ping,ping_info,text,1);
7480 png_free(ping,text[0].text);
7481 png_free(ping,text[0].key);
7482 png_free(ping,text);
7485 static MagickBooleanType Magick_png_write_chunk_from_profile(Image *image,
7486 const char *string, MagickBooleanType logging)
7499 ResetImageProfileIterator(image);
7501 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
7503 profile=GetImageProfile(image,name);
7505 if (profile != (const StringInfo *) NULL)
7510 if (LocaleNCompare(name,string,11) == 0)
7512 if (logging != MagickFalse)
7513 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7514 " Found %s profile",name);
7516 ping_profile=CloneStringInfo(profile);
7517 data=GetStringInfoDatum(ping_profile),
7518 length=(png_uint_32) GetStringInfoLength(ping_profile);
7523 (void) WriteBlobMSBULong(image,length-5); /* data length */
7524 (void) WriteBlob(image,length-1,data+1);
7525 (void) WriteBlobMSBULong(image,crc32(0,data+1,(uInt) length-1));
7526 ping_profile=DestroyStringInfo(ping_profile);
7530 name=GetNextImageProfile(image);
7537 /* Write one PNG image */
7538 static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
7539 const ImageInfo *IMimage_info,Image *IMimage,ExceptionInfo *exception)
7563 ping_trans_alpha[256];
7591 ping_have_cheap_transparency,
7602 /* ping_exclude_EXIF, */
7605 /* ping_exclude_iTXt, */
7610 /* ping_exclude_tRNS, */
7612 ping_exclude_zCCP, /* hex-encoded iCCP */
7615 ping_preserve_colormap,
7616 ping_need_colortype_warning,
7634 *volatile ping_pixels;
7640 ping_interlace_method,
7641 ping_compression_method,
7658 number_semitransparent,
7660 ping_pHYs_unit_type;
7663 ping_pHYs_x_resolution,
7664 ping_pHYs_y_resolution;
7666 logging=LogMagickEvent(CoderEvent,GetMagickModule(),
7667 " Enter WriteOnePNGImage()");
7669 image = CloneImage(IMimage,0,0,MagickFalse,exception);
7670 image_info=(ImageInfo *) CloneImageInfo(IMimage_info);
7671 if (image_info == (ImageInfo *) NULL)
7672 ThrowWriterException(ResourceLimitError, "MemoryAllocationFailed");
7674 /* Initialize some stuff */
7677 ping_interlace_method=0,
7678 ping_compression_method=0,
7679 ping_filter_method=0,
7682 ping_background.red = 0;
7683 ping_background.green = 0;
7684 ping_background.blue = 0;
7685 ping_background.gray = 0;
7686 ping_background.index = 0;
7688 ping_trans_color.red=0;
7689 ping_trans_color.green=0;
7690 ping_trans_color.blue=0;
7691 ping_trans_color.gray=0;
7693 ping_pHYs_unit_type = 0;
7694 ping_pHYs_x_resolution = 0;
7695 ping_pHYs_y_resolution = 0;
7697 ping_have_blob=MagickFalse;
7698 ping_have_color=MagickTrue;
7699 ping_have_non_bw=MagickTrue;
7700 ping_have_PLTE=MagickFalse;
7701 ping_have_bKGD=MagickFalse;
7702 ping_have_pHYs=MagickFalse;
7703 ping_have_tRNS=MagickFalse;
7705 ping_exclude_bKGD=mng_info->ping_exclude_bKGD;
7706 ping_exclude_cHRM=mng_info->ping_exclude_cHRM;
7707 ping_exclude_date=mng_info->ping_exclude_date;
7708 /* ping_exclude_EXIF=mng_info->ping_exclude_EXIF; */
7709 ping_exclude_gAMA=mng_info->ping_exclude_gAMA;
7710 ping_exclude_iCCP=mng_info->ping_exclude_iCCP;
7711 /* ping_exclude_iTXt=mng_info->ping_exclude_iTXt; */
7712 ping_exclude_oFFs=mng_info->ping_exclude_oFFs;
7713 ping_exclude_pHYs=mng_info->ping_exclude_pHYs;
7714 ping_exclude_sRGB=mng_info->ping_exclude_sRGB;
7715 ping_exclude_tEXt=mng_info->ping_exclude_tEXt;
7716 /* ping_exclude_tRNS=mng_info->ping_exclude_tRNS; */
7717 ping_exclude_vpAg=mng_info->ping_exclude_vpAg;
7718 ping_exclude_zCCP=mng_info->ping_exclude_zCCP; /* hex-encoded iCCP in zTXt */
7719 ping_exclude_zTXt=mng_info->ping_exclude_zTXt;
7721 ping_preserve_colormap = mng_info->ping_preserve_colormap;
7722 ping_need_colortype_warning = MagickFalse;
7724 /* Recognize the ICC sRGB profile and convert it to the sRGB chunk,
7725 * i.e., eliminate the ICC profile and set image->rendering_intent.
7726 * Note that this will not involve any changes to the actual pixels
7727 * but merely passes information to applications that read the resulting
7730 if (ping_exclude_sRGB == MagickFalse)
7738 ResetImageProfileIterator(image);
7739 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
7741 profile=GetImageProfile(image,name);
7743 if (profile != (StringInfo *) NULL)
7745 if ((LocaleCompare(name,"ICC") == 0) ||
7746 (LocaleCompare(name,"ICM") == 0))
7751 /* 0: not a known sRGB profile
7752 * 1: HP-Microsoft sRGB v2
7753 * 2: ICC sRGB v4 perceptual
7754 * 3: ICC sRGB v2 perceptual no black-compensation
7757 check_crc[4] = {0, 0xf29e526dUL, 0xbbef7812UL, 0x427ebb21UL},
7758 check_len[4] = {0, 3144, 60960, 3052};
7767 length=(png_uint_32) GetStringInfoLength(profile);
7769 for (icheck=3; icheck > 0; icheck--)
7771 if (length == check_len[icheck])
7773 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7774 " Got a %lu-byte ICC profile (potentially sRGB)",
7775 (unsigned long) length);
7777 data=GetStringInfoDatum(profile);
7778 profile_crc=crc32(0,data,length);
7780 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7781 " with crc=%8x",(unsigned int) profile_crc);
7783 if (profile_crc == check_crc[icheck])
7785 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7787 if (image->rendering_intent==UndefinedIntent)
7788 image->rendering_intent=PerceptualIntent;
7794 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7795 " Got a %lu-byte ICC profile",
7796 (unsigned long) length);
7799 name=GetNextImageProfile(image);
7804 number_semitransparent = 0;
7805 number_transparent = 0;
7807 if (logging != MagickFalse)
7809 if (image->storage_class == UndefinedClass)
7810 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7811 " storage_class=UndefinedClass");
7812 if (image->storage_class == DirectClass)
7813 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7814 " storage_class=DirectClass");
7815 if (image->storage_class == PseudoClass)
7816 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7817 " storage_class=PseudoClass");
7820 if (image->storage_class == PseudoClass &&
7821 (mng_info->write_png8 || mng_info->write_png24 || mng_info->write_png32 ||
7822 (mng_info->write_png_colortype != 0 &&
7823 mng_info->write_png_colortype != 4)))
7825 (void) SyncImage(image,exception);
7826 image->storage_class = DirectClass;
7829 if (ping_preserve_colormap == MagickFalse)
7831 if (image->storage_class != PseudoClass && image->colormap != NULL)
7833 /* Free the bogus colormap; it can cause trouble later */
7834 if (logging != MagickFalse)
7835 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7836 " Freeing bogus colormap");
7837 (void) RelinquishMagickMemory(image->colormap);
7838 image->colormap=NULL;
7842 if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
7843 (void) TransformImageColorspace(image,sRGBColorspace,exception);
7846 Sometimes we get PseudoClass images whose RGB values don't match
7847 the colors in the colormap. This code syncs the RGB values.
7849 if (image->depth <= 8 && image->taint && image->storage_class == PseudoClass)
7850 (void) SyncImage(image,exception);
7852 #if (MAGICKCORE_QUANTUM_DEPTH == 8)
7853 if (image->depth > 8)
7855 if (logging != MagickFalse)
7856 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7857 " Reducing PNG bit depth to 8 since this is a Q8 build.");
7863 /* Respect the -depth option */
7864 if (image->depth < MAGICKCORE_QUANTUM_DEPTH)
7869 if (image->depth > 8)
7871 #if MAGICKCORE_QUANTUM_DEPTH > 16
7872 /* Scale to 16-bit */
7873 LBR16PacketRGBO(image->background_color);
7875 for (y=0; y < (ssize_t) image->rows; y++)
7877 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
7879 if (r == (Quantum *) NULL)
7882 for (x=0; x < (ssize_t) image->columns; x++)
7885 r+=GetPixelChannels(image);
7888 if (SyncAuthenticPixels(image,exception) == MagickFalse)
7892 if (image->storage_class == PseudoClass && image->colormap != NULL)
7894 for (i=0; i < (ssize_t) image->colors; i++)
7896 LBR16PacketRGBO(image->colormap[i]);
7899 #endif /* MAGICKCORE_QUANTUM_DEPTH > 16 */
7902 else if (image->depth > 4)
7904 #if MAGICKCORE_QUANTUM_DEPTH > 8
7905 /* Scale to 8-bit */
7906 LBR08PacketRGBO(image->background_color);
7908 for (y=0; y < (ssize_t) image->rows; y++)
7910 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
7912 if (r == (Quantum *) NULL)
7915 for (x=0; x < (ssize_t) image->columns; x++)
7918 r+=GetPixelChannels(image);
7921 if (SyncAuthenticPixels(image,exception) == MagickFalse)
7925 if (image->storage_class == PseudoClass && image->colormap != NULL)
7927 for (i=0; i < (ssize_t) image->colors; i++)
7929 LBR08PacketRGBO(image->colormap[i]);
7932 #endif /* MAGICKCORE_QUANTUM_DEPTH > 8 */
7935 if (image->depth > 2)
7937 /* Scale to 4-bit */
7938 LBR04PacketRGBO(image->background_color);
7940 for (y=0; y < (ssize_t) image->rows; y++)
7942 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
7944 if (r == (Quantum *) NULL)
7947 for (x=0; x < (ssize_t) image->columns; x++)
7950 r+=GetPixelChannels(image);
7953 if (SyncAuthenticPixels(image,exception) == MagickFalse)
7957 if (image->storage_class == PseudoClass && image->colormap != NULL)
7959 for (i=0; i < (ssize_t) image->colors; i++)
7961 LBR04PacketRGBO(image->colormap[i]);
7966 else if (image->depth > 1)
7968 /* Scale to 2-bit */
7969 LBR02PacketRGBO(image->background_color);
7971 for (y=0; y < (ssize_t) image->rows; y++)
7973 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
7975 if (r == (Quantum *) NULL)
7978 for (x=0; x < (ssize_t) image->columns; x++)
7981 r+=GetPixelChannels(image);
7984 if (SyncAuthenticPixels(image,exception) == MagickFalse)
7988 if (image->storage_class == PseudoClass && image->colormap != NULL)
7990 for (i=0; i < (ssize_t) image->colors; i++)
7992 LBR02PacketRGBO(image->colormap[i]);
7998 /* Scale to 1-bit */
7999 LBR01PacketRGBO(image->background_color);
8001 for (y=0; y < (ssize_t) image->rows; y++)
8003 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8005 if (r == (Quantum *) NULL)
8008 for (x=0; x < (ssize_t) image->columns; x++)
8011 r+=GetPixelChannels(image);
8014 if (SyncAuthenticPixels(image,exception) == MagickFalse)
8018 if (image->storage_class == PseudoClass && image->colormap != NULL)
8020 for (i=0; i < (ssize_t) image->colors; i++)
8022 LBR01PacketRGBO(image->colormap[i]);
8028 /* To do: set to next higher multiple of 8 */
8029 if (image->depth < 8)
8032 #if (MAGICKCORE_QUANTUM_DEPTH > 16)
8033 /* PNG does not handle depths greater than 16 so reduce it even
8036 if (image->depth > 8)
8040 #if (MAGICKCORE_QUANTUM_DEPTH > 8)
8041 if (image->depth > 8)
8043 /* To do: fill low byte properly */
8047 if (image->depth == 16 && mng_info->write_png_depth != 16)
8048 if (mng_info->write_png8 || LosslessReduceDepthOK(image,exception) != MagickFalse)
8052 if (image->storage_class != PseudoClass && mng_info->write_png_colortype &&
8053 (mng_info->write_png_colortype > 4 || (mng_info->write_png_depth >= 8 &&
8054 mng_info->write_png_colortype < 4 &&
8055 image->alpha_trait != BlendPixelTrait)))
8057 /* Avoid the expensive BUILD_PALETTE operation if we're sure that we
8058 * are not going to need the result.
8060 image_colors=image->colors;
8061 number_opaque = image->colors;
8062 if (mng_info->write_png_colortype == 1 ||
8063 mng_info->write_png_colortype == 5)
8064 ping_have_color=MagickFalse;
8066 ping_have_color=MagickTrue;
8067 ping_have_non_bw=MagickFalse;
8069 if (image->alpha_trait == BlendPixelTrait)
8071 number_transparent = 2;
8072 number_semitransparent = 1;
8077 number_transparent = 0;
8078 number_semitransparent = 0;
8086 * Normally we run this just once, but in the case of writing PNG8
8087 * we reduce the transparency to binary and run again, then if there
8088 * are still too many colors we reduce to a simple 4-4-4-1, then 3-3-3-1
8089 * RGBA palette and run again, and then to a simple 3-3-2-1 RGBA
8090 * palette. Then (To do) we take care of a final reduction that is only
8091 * needed if there are still 256 colors present and one of them has both
8092 * transparent and opaque instances.
8095 tried_332 = MagickFalse;
8096 tried_333 = MagickFalse;
8097 tried_444 = MagickFalse;
8102 * Sometimes we get DirectClass images that have 256 colors or fewer.
8103 * This code will build a colormap.
8105 * Also, sometimes we get PseudoClass images with an out-of-date
8106 * colormap. This code will replace the colormap with a new one.
8107 * Sometimes we get PseudoClass images that have more than 256 colors.
8108 * This code will delete the colormap and change the image to
8111 * If image->alpha_trait is MagickFalse, we ignore the alpha channel
8112 * even though it sometimes contains left-over non-opaque values.
8114 * Also we gather some information (number of opaque, transparent,
8115 * and semitransparent pixels, and whether the image has any non-gray
8116 * pixels or only black-and-white pixels) that we might need later.
8118 * Even if the user wants to force GrayAlpha or RGBA (colortype 4 or 6)
8119 * we need to check for bogus non-opaque values, at least.
8127 semitransparent[260],
8130 register const Quantum
8137 if (logging != MagickFalse)
8138 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8139 " Enter BUILD_PALETTE:");
8141 if (logging != MagickFalse)
8143 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8144 " image->columns=%.20g",(double) image->columns);
8145 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8146 " image->rows=%.20g",(double) image->rows);
8147 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8148 " image->alpha_trait=%.20g",(double) image->alpha_trait);
8149 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8150 " image->depth=%.20g",(double) image->depth);
8152 if (image->storage_class == PseudoClass && image->colormap != NULL)
8154 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8155 " Original colormap:");
8156 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8157 " i (red,green,blue,alpha)");
8159 for (i=0; i < 256; i++)
8161 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8162 " %d (%d,%d,%d,%d)",
8164 (int) image->colormap[i].red,
8165 (int) image->colormap[i].green,
8166 (int) image->colormap[i].blue,
8167 (int) image->colormap[i].alpha);
8170 for (i=image->colors - 10; i < (ssize_t) image->colors; i++)
8174 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8175 " %d (%d,%d,%d,%d)",
8177 (int) image->colormap[i].red,
8178 (int) image->colormap[i].green,
8179 (int) image->colormap[i].blue,
8180 (int) image->colormap[i].alpha);
8185 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8186 " image->colors=%d",(int) image->colors);
8188 if (image->colors == 0)
8189 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8190 " (zero means unknown)");
8192 if (ping_preserve_colormap == MagickFalse)
8193 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8194 " Regenerate the colormap");
8199 number_semitransparent = 0;
8200 number_transparent = 0;
8202 for (y=0; y < (ssize_t) image->rows; y++)
8204 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8206 if (q == (Quantum *) NULL)
8209 for (x=0; x < (ssize_t) image->columns; x++)
8211 if (image->alpha_trait != BlendPixelTrait ||
8212 GetPixelAlpha(image,q) == OpaqueAlpha)
8214 if (number_opaque < 259)
8216 if (number_opaque == 0)
8218 GetPixelInfoPixel(image, q, opaque);
8219 opaque[0].alpha=OpaqueAlpha;
8223 for (i=0; i< (ssize_t) number_opaque; i++)
8225 if (IsPixelEquivalent(image,q, opaque+i))
8229 if (i == (ssize_t) number_opaque && number_opaque < 259)
8232 GetPixelInfoPixel(image, q, opaque+i);
8233 opaque[i].alpha=OpaqueAlpha;
8237 else if (GetPixelAlpha(image,q) == TransparentAlpha)
8239 if (number_transparent < 259)
8241 if (number_transparent == 0)
8243 GetPixelInfoPixel(image, q, transparent);
8244 ping_trans_color.red=(unsigned short)
8245 GetPixelRed(image,q);
8246 ping_trans_color.green=(unsigned short)
8247 GetPixelGreen(image,q);
8248 ping_trans_color.blue=(unsigned short)
8249 GetPixelBlue(image,q);
8250 ping_trans_color.gray=(unsigned short)
8251 GetPixelGray(image,q);
8252 number_transparent = 1;
8255 for (i=0; i< (ssize_t) number_transparent; i++)
8257 if (IsPixelEquivalent(image,q, transparent+i))
8261 if (i == (ssize_t) number_transparent &&
8262 number_transparent < 259)
8264 number_transparent++;
8265 GetPixelInfoPixel(image,q,transparent+i);
8271 if (number_semitransparent < 259)
8273 if (number_semitransparent == 0)
8275 GetPixelInfoPixel(image,q,semitransparent);
8276 number_semitransparent = 1;
8279 for (i=0; i< (ssize_t) number_semitransparent; i++)
8281 if (IsPixelEquivalent(image,q, semitransparent+i)
8282 && GetPixelAlpha(image,q) ==
8283 semitransparent[i].alpha)
8287 if (i == (ssize_t) number_semitransparent &&
8288 number_semitransparent < 259)
8290 number_semitransparent++;
8291 GetPixelInfoPixel(image, q, semitransparent+i);
8295 q+=GetPixelChannels(image);
8299 if (mng_info->write_png8 == MagickFalse &&
8300 ping_exclude_bKGD == MagickFalse)
8302 /* Add the background color to the palette, if it
8303 * isn't already there.
8305 if (logging != MagickFalse)
8307 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8308 " Check colormap for background (%d,%d,%d)",
8309 (int) image->background_color.red,
8310 (int) image->background_color.green,
8311 (int) image->background_color.blue);
8313 for (i=0; i<number_opaque; i++)
8315 if (opaque[i].red == image->background_color.red &&
8316 opaque[i].green == image->background_color.green &&
8317 opaque[i].blue == image->background_color.blue)
8320 if (number_opaque < 259 && i == number_opaque)
8322 opaque[i] = image->background_color;
8323 ping_background.index = i;
8325 if (logging != MagickFalse)
8327 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8328 " background_color index is %d",(int) i);
8332 else if (logging != MagickFalse)
8333 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8334 " No room in the colormap to add background color");
8337 image_colors=number_opaque+number_transparent+number_semitransparent;
8339 if (mng_info->write_png8 != MagickFalse && image_colors > 256)
8341 /* No room for the background color; remove it. */
8346 if (logging != MagickFalse)
8348 if (image_colors > 256)
8349 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8350 " image has more than 256 colors");
8353 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8354 " image has %d colors",image_colors);
8357 if (ping_preserve_colormap != MagickFalse)
8360 if (mng_info->write_png_colortype != 7) /* We won't need this info */
8362 ping_have_color=MagickFalse;
8363 ping_have_non_bw=MagickFalse;
8365 if ((IssRGBCompatibleColorspace(image->colorspace) == MagickFalse) ||
8366 (IssRGBColorspace(image->colorspace) != MagickFalse))
8368 ping_have_color=MagickTrue;
8369 ping_have_non_bw=MagickTrue;
8372 if(image_colors > 256)
8374 for (y=0; y < (ssize_t) image->rows; y++)
8376 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8378 if (q == (Quantum *) NULL)
8382 for (x=0; x < (ssize_t) image->columns; x++)
8384 if (GetPixelRed(image,s) != GetPixelGreen(image,s) ||
8385 GetPixelRed(image,s) != GetPixelBlue(image,s))
8387 ping_have_color=MagickTrue;
8388 ping_have_non_bw=MagickTrue;
8391 s+=GetPixelChannels(image);
8394 if (ping_have_color != MagickFalse)
8397 /* Worst case is black-and-white; we are looking at every
8401 if (ping_have_non_bw == MagickFalse)
8404 for (x=0; x < (ssize_t) image->columns; x++)
8406 if (GetPixelRed(image,s) != 0 &&
8407 GetPixelRed(image,s) != QuantumRange)
8409 ping_have_non_bw=MagickTrue;
8412 s+=GetPixelChannels(image);
8419 if (image_colors < 257)
8425 * Initialize image colormap.
8428 if (logging != MagickFalse)
8429 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8430 " Sort the new colormap");
8432 /* Sort palette, transparent first */;
8436 for (i=0; i<number_transparent; i++)
8437 colormap[n++] = transparent[i];
8439 for (i=0; i<number_semitransparent; i++)
8440 colormap[n++] = semitransparent[i];
8442 for (i=0; i<number_opaque; i++)
8443 colormap[n++] = opaque[i];
8445 ping_background.index +=
8446 (number_transparent + number_semitransparent);
8448 /* image_colors < 257; search the colormap instead of the pixels
8449 * to get ping_have_color and ping_have_non_bw
8453 if (ping_have_color == MagickFalse)
8455 if (colormap[i].red != colormap[i].green ||
8456 colormap[i].red != colormap[i].blue)
8458 ping_have_color=MagickTrue;
8459 ping_have_non_bw=MagickTrue;
8464 if (ping_have_non_bw == MagickFalse)
8466 if (colormap[i].red != 0 && colormap[i].red != QuantumRange)
8467 ping_have_non_bw=MagickTrue;
8471 if ((mng_info->ping_exclude_tRNS == MagickFalse ||
8472 (number_transparent == 0 && number_semitransparent == 0)) &&
8473 (((mng_info->write_png_colortype-1) ==
8474 PNG_COLOR_TYPE_PALETTE) ||
8475 (mng_info->write_png_colortype == 0)))
8477 if (logging != MagickFalse)
8479 if (n != (ssize_t) image_colors)
8480 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8481 " image_colors (%d) and n (%d) don't match",
8484 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8485 " AcquireImageColormap");
8488 image->colors = image_colors;
8490 if (AcquireImageColormap(image,image_colors,exception) ==
8492 ThrowWriterException(ResourceLimitError,
8493 "MemoryAllocationFailed");
8495 for (i=0; i< (ssize_t) image_colors; i++)
8496 image->colormap[i] = colormap[i];
8498 if (logging != MagickFalse)
8500 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8501 " image->colors=%d (%d)",
8502 (int) image->colors, image_colors);
8504 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8505 " Update the pixel indexes");
8508 /* Sync the pixel indices with the new colormap */
8510 for (y=0; y < (ssize_t) image->rows; y++)
8512 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8514 if (q == (Quantum *) NULL)
8517 for (x=0; x < (ssize_t) image->columns; x++)
8519 for (i=0; i< (ssize_t) image_colors; i++)
8521 if ((image->alpha_trait != BlendPixelTrait ||
8522 image->colormap[i].alpha == GetPixelAlpha(image,q)) &&
8523 image->colormap[i].red == GetPixelRed(image,q) &&
8524 image->colormap[i].green == GetPixelGreen(image,q) &&
8525 image->colormap[i].blue == GetPixelBlue(image,q))
8527 SetPixelIndex(image,i,q);
8531 q+=GetPixelChannels(image);
8534 if (SyncAuthenticPixels(image,exception) == MagickFalse)
8540 if (logging != MagickFalse)
8542 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8543 " image->colors=%d", (int) image->colors);
8545 if (image->colormap != NULL)
8547 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8548 " i (red,green,blue,alpha)");
8550 for (i=0; i < (ssize_t) image->colors; i++)
8552 if (i < 300 || i >= (ssize_t) image->colors - 10)
8554 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8555 " %d (%d,%d,%d,%d)",
8557 (int) image->colormap[i].red,
8558 (int) image->colormap[i].green,
8559 (int) image->colormap[i].blue,
8560 (int) image->colormap[i].alpha);
8565 if (number_transparent < 257)
8566 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8567 " number_transparent = %d",
8568 number_transparent);
8571 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8572 " number_transparent > 256");
8574 if (number_opaque < 257)
8575 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8576 " number_opaque = %d",
8580 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8581 " number_opaque > 256");
8583 if (number_semitransparent < 257)
8584 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8585 " number_semitransparent = %d",
8586 number_semitransparent);
8589 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8590 " number_semitransparent > 256");
8592 if (ping_have_non_bw == MagickFalse)
8593 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8594 " All pixels and the background are black or white");
8596 else if (ping_have_color == MagickFalse)
8597 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8598 " All pixels and the background are gray");
8601 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8602 " At least one pixel or the background is non-gray");
8604 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8605 " Exit BUILD_PALETTE:");
8608 if (mng_info->write_png8 == MagickFalse)
8611 /* Make any reductions necessary for the PNG8 format */
8612 if (image_colors <= 256 &&
8613 image_colors != 0 && image->colormap != NULL &&
8614 number_semitransparent == 0 &&
8615 number_transparent <= 1)
8618 /* PNG8 can't have semitransparent colors so we threshold the
8619 * opacity to 0 or OpaqueOpacity, and PNG8 can only have one
8620 * transparent color so if more than one is transparent we merge
8621 * them into image->background_color.
8623 if (number_semitransparent != 0 || number_transparent > 1)
8625 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8626 " Thresholding the alpha channel to binary");
8628 for (y=0; y < (ssize_t) image->rows; y++)
8630 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8632 if (r == (Quantum *) NULL)
8635 for (x=0; x < (ssize_t) image->columns; x++)
8637 if (GetPixelAlpha(image,r) < OpaqueAlpha/2)
8639 SetPixelInfoPixel(image,&image->background_color,r);
8640 SetPixelAlpha(image,TransparentAlpha,r);
8643 SetPixelAlpha(image,OpaqueAlpha,r);
8644 r+=GetPixelChannels(image);
8647 if (SyncAuthenticPixels(image,exception) == MagickFalse)
8650 if (image_colors != 0 && image_colors <= 256 &&
8651 image->colormap != NULL)
8652 for (i=0; i<image_colors; i++)
8653 image->colormap[i].alpha =
8654 (image->colormap[i].alpha > TransparentAlpha/2 ?
8655 TransparentAlpha : OpaqueAlpha);
8660 /* PNG8 can't have more than 256 colors so we quantize the pixels and
8661 * background color to the 4-4-4-1, 3-3-3-1 or 3-3-2-1 palette. If the
8662 * image is mostly gray, the 4-4-4-1 palette is likely to end up with 256
8665 if (tried_444 == MagickFalse && (image_colors == 0 || image_colors > 256))
8667 if (logging != MagickFalse)
8668 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8669 " Quantizing the background color to 4-4-4");
8671 tried_444 = MagickTrue;
8673 LBR04PacketRGB(image->background_color);
8675 if (logging != MagickFalse)
8676 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8677 " Quantizing the pixel colors to 4-4-4");
8679 if (image->colormap == NULL)
8681 for (y=0; y < (ssize_t) image->rows; y++)
8683 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8685 if (r == (Quantum *) NULL)
8688 for (x=0; x < (ssize_t) image->columns; x++)
8690 if (GetPixelAlpha(image,r) == OpaqueAlpha)
8692 r+=GetPixelChannels(image);
8695 if (SyncAuthenticPixels(image,exception) == MagickFalse)
8700 else /* Should not reach this; colormap already exists and
8703 if (logging != MagickFalse)
8704 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8705 " Quantizing the colormap to 4-4-4");
8707 for (i=0; i<image_colors; i++)
8709 LBR04PacketRGB(image->colormap[i]);
8715 if (tried_333 == MagickFalse && (image_colors == 0 || image_colors > 256))
8717 if (logging != MagickFalse)
8718 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8719 " Quantizing the background color to 3-3-3");
8721 tried_333 = MagickTrue;
8723 LBR03PacketRGB(image->background_color);
8725 if (logging != MagickFalse)
8726 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8727 " Quantizing the pixel colors to 3-3-3-1");
8729 if (image->colormap == NULL)
8731 for (y=0; y < (ssize_t) image->rows; y++)
8733 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8735 if (r == (Quantum *) NULL)
8738 for (x=0; x < (ssize_t) image->columns; x++)
8740 if (GetPixelAlpha(image,r) == OpaqueAlpha)
8742 r+=GetPixelChannels(image);
8745 if (SyncAuthenticPixels(image,exception) == MagickFalse)
8750 else /* Should not reach this; colormap already exists and
8753 if (logging != MagickFalse)
8754 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8755 " Quantizing the colormap to 3-3-3-1");
8756 for (i=0; i<image_colors; i++)
8758 LBR03PacketRGB(image->colormap[i]);
8764 if (tried_332 == MagickFalse && (image_colors == 0 || image_colors > 256))
8766 if (logging != MagickFalse)
8767 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8768 " Quantizing the background color to 3-3-2");
8770 tried_332 = MagickTrue;
8772 /* Red and green were already done so we only quantize the blue
8776 LBR02PacketBlue(image->background_color);
8778 if (logging != MagickFalse)
8779 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8780 " Quantizing the pixel colors to 3-3-2-1");
8782 if (image->colormap == NULL)
8784 for (y=0; y < (ssize_t) image->rows; y++)
8786 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8788 if (r == (Quantum *) NULL)
8791 for (x=0; x < (ssize_t) image->columns; x++)
8793 if (GetPixelAlpha(image,r) == OpaqueAlpha)
8795 r+=GetPixelChannels(image);
8798 if (SyncAuthenticPixels(image,exception) == MagickFalse)
8803 else /* Should not reach this; colormap already exists and
8806 if (logging != MagickFalse)
8807 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8808 " Quantizing the colormap to 3-3-2-1");
8809 for (i=0; i<image_colors; i++)
8811 LBR02PacketBlue(image->colormap[i]);
8818 if (image_colors == 0 || image_colors > 256)
8820 /* Take care of special case with 256 colors + 1 transparent
8821 * color. We don't need to quantize to 2-3-2-1; we only need to
8822 * eliminate one color, so we'll merge the two darkest red
8823 * colors (0x49, 0, 0) -> (0x24, 0, 0).
8825 if (ScaleQuantumToChar(image->background_color.red) == 0x49 &&
8826 ScaleQuantumToChar(image->background_color.green) == 0x00 &&
8827 ScaleQuantumToChar(image->background_color.blue) == 0x00)
8829 image->background_color.red=ScaleCharToQuantum(0x24);
8832 if (image->colormap == NULL)
8834 for (y=0; y < (ssize_t) image->rows; y++)
8836 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8838 if (r == (Quantum *) NULL)
8841 for (x=0; x < (ssize_t) image->columns; x++)
8843 if (ScaleQuantumToChar(GetPixelRed(image,r)) == 0x49 &&
8844 ScaleQuantumToChar(GetPixelGreen(image,r)) == 0x00 &&
8845 ScaleQuantumToChar(GetPixelBlue(image,r)) == 0x00 &&
8846 GetPixelAlpha(image,r) == OpaqueAlpha)
8848 SetPixelRed(image,ScaleCharToQuantum(0x24),r);
8850 r+=GetPixelChannels(image);
8853 if (SyncAuthenticPixels(image,exception) == MagickFalse)
8861 for (i=0; i<image_colors; i++)
8863 if (ScaleQuantumToChar(image->colormap[i].red) == 0x49 &&
8864 ScaleQuantumToChar(image->colormap[i].green) == 0x00 &&
8865 ScaleQuantumToChar(image->colormap[i].blue) == 0x00)
8867 image->colormap[i].red=ScaleCharToQuantum(0x24);
8874 /* END OF BUILD_PALETTE */
8876 /* If we are excluding the tRNS chunk and there is transparency,
8877 * then we must write a Gray-Alpha (color-type 4) or RGBA (color-type 6)
8880 if (mng_info->ping_exclude_tRNS != MagickFalse &&
8881 (number_transparent != 0 || number_semitransparent != 0))
8883 unsigned int colortype=mng_info->write_png_colortype;
8885 if (ping_have_color == MagickFalse)
8886 mng_info->write_png_colortype = 5;
8889 mng_info->write_png_colortype = 7;
8891 if (colortype != 0 &&
8892 mng_info->write_png_colortype != colortype)
8893 ping_need_colortype_warning=MagickTrue;
8897 /* See if cheap transparency is possible. It is only possible
8898 * when there is a single transparent color, no semitransparent
8899 * color, and no opaque color that has the same RGB components
8900 * as the transparent color. We only need this information if
8901 * we are writing a PNG with colortype 0 or 2, and we have not
8902 * excluded the tRNS chunk.
8904 if (number_transparent == 1 &&
8905 mng_info->write_png_colortype < 4)
8907 ping_have_cheap_transparency = MagickTrue;
8909 if (number_semitransparent != 0)
8910 ping_have_cheap_transparency = MagickFalse;
8912 else if (image_colors == 0 || image_colors > 256 ||
8913 image->colormap == NULL)
8915 register const Quantum
8918 for (y=0; y < (ssize_t) image->rows; y++)
8920 q=GetVirtualPixels(image,0,y,image->columns,1, exception);
8922 if (q == (Quantum *) NULL)
8925 for (x=0; x < (ssize_t) image->columns; x++)
8927 if (GetPixelAlpha(image,q) != TransparentAlpha &&
8928 (unsigned short) GetPixelRed(image,q) ==
8929 ping_trans_color.red &&
8930 (unsigned short) GetPixelGreen(image,q) ==
8931 ping_trans_color.green &&
8932 (unsigned short) GetPixelBlue(image,q) ==
8933 ping_trans_color.blue)
8935 ping_have_cheap_transparency = MagickFalse;
8939 q+=GetPixelChannels(image);
8942 if (ping_have_cheap_transparency == MagickFalse)
8948 /* Assuming that image->colormap[0] is the one transparent color
8949 * and that all others are opaque.
8951 if (image_colors > 1)
8952 for (i=1; i<image_colors; i++)
8953 if (image->colormap[i].red == image->colormap[0].red &&
8954 image->colormap[i].green == image->colormap[0].green &&
8955 image->colormap[i].blue == image->colormap[0].blue)
8957 ping_have_cheap_transparency = MagickFalse;
8962 if (logging != MagickFalse)
8964 if (ping_have_cheap_transparency == MagickFalse)
8965 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8966 " Cheap transparency is not possible.");
8969 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8970 " Cheap transparency is possible.");
8974 ping_have_cheap_transparency = MagickFalse;
8976 image_depth=image->depth;
8978 quantum_info = (QuantumInfo *) NULL;
8980 image_colors=(int) image->colors;
8981 image_matte=image->alpha_trait == BlendPixelTrait ? MagickTrue : MagickFalse;
8983 mng_info->IsPalette=image->storage_class == PseudoClass &&
8984 image_colors <= 256 && image->colormap != NULL;
8986 if ((mng_info->write_png_colortype == 4 || mng_info->write_png8) &&
8987 (image->colors == 0 || image->colormap == NULL))
8989 image_info=DestroyImageInfo(image_info);
8990 image=DestroyImage(image);
8991 (void) ThrowMagickException(exception,GetMagickModule(),CoderError,
8992 "Cannot write PNG8 or color-type 3; colormap is NULL",
8993 "`%s'",IMimage->filename);
8994 return(MagickFalse);
8998 Allocate the PNG structures
9000 #ifdef PNG_USER_MEM_SUPPORTED
9001 error_info.image=image;
9002 error_info.exception=exception;
9003 ping=png_create_write_struct_2(PNG_LIBPNG_VER_STRING,&error_info,
9004 MagickPNGErrorHandler,MagickPNGWarningHandler,(void *) NULL,
9005 (png_malloc_ptr) Magick_png_malloc,(png_free_ptr) Magick_png_free);
9008 ping=png_create_write_struct(PNG_LIBPNG_VER_STRING,&error_info,
9009 MagickPNGErrorHandler,MagickPNGWarningHandler);
9012 if (ping == (png_struct *) NULL)
9013 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
9015 ping_info=png_create_info_struct(ping);
9017 if (ping_info == (png_info *) NULL)
9019 png_destroy_write_struct(&ping,(png_info **) NULL);
9020 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
9023 png_set_write_fn(ping,image,png_put_data,png_flush_data);
9024 ping_pixels=(unsigned char *) NULL;
9026 if (setjmp(png_jmpbuf(ping)))
9032 if (image_info->verbose)
9033 (void) printf("PNG write has failed.\n");
9035 png_destroy_write_struct(&ping,&ping_info);
9036 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
9037 UnlockSemaphoreInfo(ping_semaphore);
9040 if (ping_pixels != (unsigned char *) NULL)
9041 ping_pixels=(unsigned char *) RelinquishMagickMemory(ping_pixels);
9043 if (quantum_info != (QuantumInfo *) NULL)
9044 quantum_info=DestroyQuantumInfo(quantum_info);
9046 if (ping_have_blob != MagickFalse)
9047 (void) CloseBlob(image);
9048 image_info=DestroyImageInfo(image_info);
9049 image=DestroyImage(image);
9050 return(MagickFalse);
9053 /* { For navigation to end of SETJMP-protected block. Within this
9054 * block, use png_error() instead of Throwing an Exception, to ensure
9055 * that libpng is able to clean up, and that the semaphore is unlocked.
9058 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
9059 LockSemaphoreInfo(ping_semaphore);
9063 Prepare PNG for writing.
9066 #if defined(PNG_MNG_FEATURES_SUPPORTED)
9067 if (mng_info->write_mng)
9069 (void) png_permit_mng_features(ping,PNG_ALL_MNG_FEATURES);
9070 # ifdef PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED
9071 /* Disable new libpng-1.5.10 feature when writing a MNG because
9072 * zero-length PLTE is OK
9074 png_set_check_for_invalid_index (ping, 0);
9079 # ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
9080 if (mng_info->write_mng)
9081 png_permit_empty_plte(ping,MagickTrue);
9088 ping_width=(png_uint_32) image->columns;
9089 ping_height=(png_uint_32) image->rows;
9091 if (mng_info->write_png8 || mng_info->write_png24 || mng_info->write_png32)
9094 if (mng_info->write_png_depth != 0)
9095 image_depth=mng_info->write_png_depth;
9097 /* Adjust requested depth to next higher valid depth if necessary */
9098 if (image_depth > 8)
9101 if ((image_depth > 4) && (image_depth < 8))
9104 if (image_depth == 3)
9107 if (logging != MagickFalse)
9109 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9110 " width=%.20g",(double) ping_width);
9111 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9112 " height=%.20g",(double) ping_height);
9113 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9114 " image_matte=%.20g",(double) image->alpha_trait);
9115 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9116 " image->depth=%.20g",(double) image->depth);
9117 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9118 " Tentative ping_bit_depth=%.20g",(double) image_depth);
9121 save_image_depth=image_depth;
9122 ping_bit_depth=(png_byte) save_image_depth;
9125 #if defined(PNG_pHYs_SUPPORTED)
9126 if (ping_exclude_pHYs == MagickFalse)
9128 if ((image->resolution.x != 0) && (image->resolution.y != 0) &&
9129 (!mng_info->write_mng || !mng_info->equal_physs))
9131 if (logging != MagickFalse)
9132 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9133 " Setting up pHYs chunk");
9135 if (image->units == PixelsPerInchResolution)
9137 ping_pHYs_unit_type=PNG_RESOLUTION_METER;
9138 ping_pHYs_x_resolution=
9139 (png_uint_32) ((100.0*image->resolution.x+0.5)/2.54);
9140 ping_pHYs_y_resolution=
9141 (png_uint_32) ((100.0*image->resolution.y+0.5)/2.54);
9144 else if (image->units == PixelsPerCentimeterResolution)
9146 ping_pHYs_unit_type=PNG_RESOLUTION_METER;
9147 ping_pHYs_x_resolution=(png_uint_32) (100.0*image->resolution.x+0.5);
9148 ping_pHYs_y_resolution=(png_uint_32) (100.0*image->resolution.y+0.5);
9153 ping_pHYs_unit_type=PNG_RESOLUTION_UNKNOWN;
9154 ping_pHYs_x_resolution=(png_uint_32) image->resolution.x;
9155 ping_pHYs_y_resolution=(png_uint_32) image->resolution.y;
9158 if (logging != MagickFalse)
9159 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9160 " Set up PNG pHYs chunk: xres: %.20g, yres: %.20g, units: %d.",
9161 (double) ping_pHYs_x_resolution,(double) ping_pHYs_y_resolution,
9162 (int) ping_pHYs_unit_type);
9163 ping_have_pHYs = MagickTrue;
9168 if (ping_exclude_bKGD == MagickFalse)
9170 if ((!mng_info->adjoin || !mng_info->equal_backgrounds))
9176 if (ping_bit_depth == 8)
9179 if (ping_bit_depth == 4)
9182 if (ping_bit_depth == 2)
9185 if (ping_bit_depth == 1)
9188 ping_background.red=(png_uint_16)
9189 (ScaleQuantumToShort(image->background_color.red) & mask);
9191 ping_background.green=(png_uint_16)
9192 (ScaleQuantumToShort(image->background_color.green) & mask);
9194 ping_background.blue=(png_uint_16)
9195 (ScaleQuantumToShort(image->background_color.blue) & mask);
9197 ping_background.gray=(png_uint_16) ping_background.green;
9200 if (logging != MagickFalse)
9202 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9203 " Setting up bKGD chunk (1)");
9204 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9205 " background_color index is %d",
9206 (int) ping_background.index);
9208 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9209 " ping_bit_depth=%d",ping_bit_depth);
9212 ping_have_bKGD = MagickTrue;
9216 Select the color type.
9221 if (mng_info->IsPalette && mng_info->write_png8)
9224 /* To do: make this a function cause it's used twice, except
9225 for reducing the sample depth from 8. */
9227 number_colors=image_colors;
9229 ping_have_tRNS=MagickFalse;
9234 ping_color_type=(png_byte) PNG_COLOR_TYPE_PALETTE;
9236 if (logging != MagickFalse)
9237 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9238 " Setting up PLTE chunk with %d colors (%d)",
9239 number_colors, image_colors);
9241 for (i=0; i < (ssize_t) number_colors; i++)
9243 palette[i].red=ScaleQuantumToChar(image->colormap[i].red);
9244 palette[i].green=ScaleQuantumToChar(image->colormap[i].green);
9245 palette[i].blue=ScaleQuantumToChar(image->colormap[i].blue);
9246 if (logging != MagickFalse)
9247 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9248 #if MAGICKCORE_QUANTUM_DEPTH == 8
9249 " %3ld (%3d,%3d,%3d)",
9251 " %5ld (%5d,%5d,%5d)",
9253 (long) i,palette[i].red,palette[i].green,palette[i].blue);
9257 ping_have_PLTE=MagickTrue;
9258 image_depth=ping_bit_depth;
9261 if (matte != MagickFalse)
9264 Identify which colormap entry is transparent.
9266 assert(number_colors <= 256);
9267 assert(image->colormap != NULL);
9269 for (i=0; i < (ssize_t) number_transparent; i++)
9270 ping_trans_alpha[i]=0;
9273 ping_num_trans=(unsigned short) (number_transparent +
9274 number_semitransparent);
9276 if (ping_num_trans == 0)
9277 ping_have_tRNS=MagickFalse;
9280 ping_have_tRNS=MagickTrue;
9283 if (ping_exclude_bKGD == MagickFalse)
9286 * Identify which colormap entry is the background color.
9289 for (i=0; i < (ssize_t) MagickMax(1L*number_colors-1L,1L); i++)
9290 if (IsPNGColorEqual(ping_background,image->colormap[i]))
9293 ping_background.index=(png_byte) i;
9295 if (logging != MagickFalse)
9297 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9298 " background_color index is %d",
9299 (int) ping_background.index);
9302 } /* end of write_png8 */
9304 else if (mng_info->write_png24 || mng_info->write_png_colortype == 3)
9306 image_matte=MagickFalse;
9307 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB;
9310 else if (mng_info->write_png32 || mng_info->write_png_colortype == 7)
9312 image_matte=MagickTrue;
9313 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB_ALPHA;
9316 else /* mng_info->write_pngNN not specified */
9318 image_depth=ping_bit_depth;
9320 if (mng_info->write_png_colortype != 0)
9322 ping_color_type=(png_byte) mng_info->write_png_colortype-1;
9324 if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA ||
9325 ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA)
9326 image_matte=MagickTrue;
9329 image_matte=MagickFalse;
9331 if (logging != MagickFalse)
9332 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9333 " PNG colortype %d was specified:",(int) ping_color_type);
9336 else /* write_png_colortype not specified */
9338 if (logging != MagickFalse)
9339 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9340 " Selecting PNG colortype:");
9342 ping_color_type=(png_byte) ((matte != MagickFalse)?
9343 PNG_COLOR_TYPE_RGB_ALPHA:PNG_COLOR_TYPE_RGB);
9345 if (image_info->type == TrueColorType)
9347 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB;
9348 image_matte=MagickFalse;
9351 if (image_info->type == TrueColorMatteType)
9353 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB_ALPHA;
9354 image_matte=MagickTrue;
9357 if (image_info->type == PaletteType ||
9358 image_info->type == PaletteMatteType)
9359 ping_color_type=(png_byte) PNG_COLOR_TYPE_PALETTE;
9361 if (mng_info->write_png_colortype == 0 &&
9362 (image_info->type == UndefinedType ||
9363 image_info->type == OptimizeType))
9365 if (ping_have_color == MagickFalse)
9367 if (image_matte == MagickFalse)
9369 ping_color_type=(png_byte) PNG_COLOR_TYPE_GRAY;
9370 image_matte=MagickFalse;
9375 ping_color_type=(png_byte) PNG_COLOR_TYPE_GRAY_ALPHA;
9376 image_matte=MagickTrue;
9381 if (image_matte == MagickFalse)
9383 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB;
9384 image_matte=MagickFalse;
9389 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGBA;
9390 image_matte=MagickTrue;
9397 if (logging != MagickFalse)
9398 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9399 " Selected PNG colortype=%d",ping_color_type);
9401 if (ping_bit_depth < 8)
9403 if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA ||
9404 ping_color_type == PNG_COLOR_TYPE_RGB ||
9405 ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA)
9409 old_bit_depth=ping_bit_depth;
9411 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
9413 if (image->alpha_trait != BlendPixelTrait && ping_have_non_bw == MagickFalse)
9417 if (ping_color_type == PNG_COLOR_TYPE_PALETTE)
9422 if (image->colors == 0)
9425 png_error(ping,"image has 0 colors");
9428 while ((int) (one << ping_bit_depth) < (ssize_t) image_colors)
9429 ping_bit_depth <<= 1;
9432 if (logging != MagickFalse)
9434 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9435 " Number of colors: %.20g",(double) image_colors);
9437 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9438 " Tentative PNG bit depth: %d",ping_bit_depth);
9441 if (ping_bit_depth < (int) mng_info->write_png_depth)
9442 ping_bit_depth = mng_info->write_png_depth;
9445 image_depth=ping_bit_depth;
9447 if (logging != MagickFalse)
9449 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9450 " Tentative PNG color type: %s (%.20g)",
9451 PngColorTypeToString(ping_color_type),
9452 (double) ping_color_type);
9454 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9455 " image_info->type: %.20g",(double) image_info->type);
9457 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9458 " image_depth: %.20g",(double) image_depth);
9460 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9462 " image->depth: %.20g",(double) image->depth);
9464 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9465 " ping_bit_depth: %.20g",(double) ping_bit_depth);
9468 if (matte != MagickFalse)
9470 if (mng_info->IsPalette)
9472 if (mng_info->write_png_colortype == 0)
9474 ping_color_type=PNG_COLOR_TYPE_GRAY_ALPHA;
9476 if (ping_have_color != MagickFalse)
9477 ping_color_type=PNG_COLOR_TYPE_RGBA;
9481 * Determine if there is any transparent color.
9483 if (number_transparent + number_semitransparent == 0)
9486 No transparent pixels are present. Change 4 or 6 to 0 or 2.
9489 image_matte=MagickFalse;
9491 if (mng_info->write_png_colortype == 0)
9492 ping_color_type&=0x03;
9502 if (ping_bit_depth == 8)
9505 if (ping_bit_depth == 4)
9508 if (ping_bit_depth == 2)
9511 if (ping_bit_depth == 1)
9514 ping_trans_color.red=(png_uint_16)
9515 (ScaleQuantumToShort(image->colormap[0].red) & mask);
9517 ping_trans_color.green=(png_uint_16)
9518 (ScaleQuantumToShort(image->colormap[0].green) & mask);
9520 ping_trans_color.blue=(png_uint_16)
9521 (ScaleQuantumToShort(image->colormap[0].blue) & mask);
9523 ping_trans_color.gray=(png_uint_16)
9524 (ScaleQuantumToShort(GetPixelInfoIntensity(
9525 image->colormap)) & mask);
9527 ping_trans_color.index=(png_byte) 0;
9529 ping_have_tRNS=MagickTrue;
9532 if (ping_have_tRNS != MagickFalse)
9535 * Determine if there is one and only one transparent color
9536 * and if so if it is fully transparent.
9538 if (ping_have_cheap_transparency == MagickFalse)
9539 ping_have_tRNS=MagickFalse;
9542 if (ping_have_tRNS != MagickFalse)
9544 if (mng_info->write_png_colortype == 0)
9545 ping_color_type &= 0x03; /* changes 4 or 6 to 0 or 2 */
9547 if (image_depth == 8)
9549 ping_trans_color.red&=0xff;
9550 ping_trans_color.green&=0xff;
9551 ping_trans_color.blue&=0xff;
9552 ping_trans_color.gray&=0xff;
9558 if (image_depth == 8)
9560 ping_trans_color.red&=0xff;
9561 ping_trans_color.green&=0xff;
9562 ping_trans_color.blue&=0xff;
9563 ping_trans_color.gray&=0xff;
9570 if (ping_have_tRNS != MagickFalse)
9571 image_matte=MagickFalse;
9573 if ((mng_info->IsPalette) &&
9574 mng_info->write_png_colortype-1 != PNG_COLOR_TYPE_PALETTE &&
9575 ping_have_color == MagickFalse &&
9576 (image_matte == MagickFalse || image_depth >= 8))
9580 if (image_matte != MagickFalse)
9581 ping_color_type=PNG_COLOR_TYPE_GRAY_ALPHA;
9583 else if (mng_info->write_png_colortype-1 != PNG_COLOR_TYPE_GRAY_ALPHA)
9585 ping_color_type=PNG_COLOR_TYPE_GRAY;
9587 if (save_image_depth == 16 && image_depth == 8)
9589 if (logging != MagickFalse)
9591 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9592 " Scaling ping_trans_color (0)");
9594 ping_trans_color.gray*=0x0101;
9598 if (image_depth > MAGICKCORE_QUANTUM_DEPTH)
9599 image_depth=MAGICKCORE_QUANTUM_DEPTH;
9601 if ((image_colors == 0) ||
9602 ((ssize_t) (image_colors-1) > (ssize_t) MaxColormapSize))
9603 image_colors=(int) (one << image_depth);
9605 if (image_depth > 8)
9611 if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
9613 if(!mng_info->write_png_depth)
9617 while ((int) (one << ping_bit_depth)
9618 < (ssize_t) image_colors)
9619 ping_bit_depth <<= 1;
9623 else if (ping_color_type ==
9624 PNG_COLOR_TYPE_GRAY && image_colors < 17 &&
9625 mng_info->IsPalette)
9627 /* Check if grayscale is reducible */
9630 depth_4_ok=MagickTrue,
9631 depth_2_ok=MagickTrue,
9632 depth_1_ok=MagickTrue;
9634 for (i=0; i < (ssize_t) image_colors; i++)
9639 intensity=ScaleQuantumToChar(image->colormap[i].red);
9641 if ((intensity & 0x0f) != ((intensity & 0xf0) >> 4))
9642 depth_4_ok=depth_2_ok=depth_1_ok=MagickFalse;
9643 else if ((intensity & 0x03) != ((intensity & 0x0c) >> 2))
9644 depth_2_ok=depth_1_ok=MagickFalse;
9645 else if ((intensity & 0x01) != ((intensity & 0x02) >> 1))
9646 depth_1_ok=MagickFalse;
9649 if (depth_1_ok && mng_info->write_png_depth <= 1)
9652 else if (depth_2_ok && mng_info->write_png_depth <= 2)
9655 else if (depth_4_ok && mng_info->write_png_depth <= 4)
9660 image_depth=ping_bit_depth;
9665 if (mng_info->IsPalette)
9667 number_colors=image_colors;
9669 if (image_depth <= 8)
9674 ping_color_type=(png_byte) PNG_COLOR_TYPE_PALETTE;
9676 if (mng_info->have_write_global_plte && matte == MagickFalse)
9678 png_set_PLTE(ping,ping_info,NULL,0);
9680 if (logging != MagickFalse)
9681 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9682 " Setting up empty PLTE chunk");
9687 for (i=0; i < (ssize_t) number_colors; i++)
9689 palette[i].red=ScaleQuantumToChar(image->colormap[i].red);
9690 palette[i].green=ScaleQuantumToChar(image->colormap[i].green);
9691 palette[i].blue=ScaleQuantumToChar(image->colormap[i].blue);
9694 if (logging != MagickFalse)
9695 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9696 " Setting up PLTE chunk with %d colors",
9699 ping_have_PLTE=MagickTrue;
9702 /* color_type is PNG_COLOR_TYPE_PALETTE */
9703 if (mng_info->write_png_depth == 0)
9711 while ((one << ping_bit_depth) < (size_t) number_colors)
9712 ping_bit_depth <<= 1;
9717 if (matte != MagickFalse)
9720 * Set up trans_colors array.
9722 assert(number_colors <= 256);
9724 ping_num_trans=(unsigned short) (number_transparent +
9725 number_semitransparent);
9727 if (ping_num_trans == 0)
9728 ping_have_tRNS=MagickFalse;
9732 if (logging != MagickFalse)
9734 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9735 " Scaling ping_trans_color (1)");
9737 ping_have_tRNS=MagickTrue;
9739 for (i=0; i < ping_num_trans; i++)
9741 ping_trans_alpha[i]= (png_byte)
9742 ScaleQuantumToChar(image->colormap[i].alpha);
9752 if (image_depth < 8)
9755 if ((save_image_depth == 16) && (image_depth == 8))
9757 if (logging != MagickFalse)
9759 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9760 " Scaling ping_trans_color from (%d,%d,%d)",
9761 (int) ping_trans_color.red,
9762 (int) ping_trans_color.green,
9763 (int) ping_trans_color.blue);
9766 ping_trans_color.red*=0x0101;
9767 ping_trans_color.green*=0x0101;
9768 ping_trans_color.blue*=0x0101;
9769 ping_trans_color.gray*=0x0101;
9771 if (logging != MagickFalse)
9773 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9775 (int) ping_trans_color.red,
9776 (int) ping_trans_color.green,
9777 (int) ping_trans_color.blue);
9782 if (ping_bit_depth < (ssize_t) mng_info->write_png_depth)
9783 ping_bit_depth = (ssize_t) mng_info->write_png_depth;
9786 Adjust background and transparency samples in sub-8-bit grayscale files.
9788 if (ping_bit_depth < 8 && ping_color_type ==
9789 PNG_COLOR_TYPE_GRAY)
9797 maxval=(png_uint_16) ((one << ping_bit_depth)-1);
9799 if (ping_exclude_bKGD == MagickFalse)
9802 ping_background.gray=(png_uint_16) ((maxval/65535.)*
9803 (ScaleQuantumToShort(((GetPixelInfoIntensity(
9804 &image->background_color))) +.5)));
9806 if (logging != MagickFalse)
9807 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9808 " Setting up bKGD chunk (2)");
9809 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9810 " background_color index is %d",
9811 (int) ping_background.index);
9813 ping_have_bKGD = MagickTrue;
9816 if (logging != MagickFalse)
9817 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9818 " Scaling ping_trans_color.gray from %d",
9819 (int)ping_trans_color.gray);
9821 ping_trans_color.gray=(png_uint_16) ((maxval/255.)*(
9822 ping_trans_color.gray)+.5);
9824 if (logging != MagickFalse)
9825 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9826 " to %d", (int)ping_trans_color.gray);
9829 if (ping_exclude_bKGD == MagickFalse)
9831 if (mng_info->IsPalette && (int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
9834 Identify which colormap entry is the background color.
9837 number_colors=image_colors;
9839 for (i=0; i < (ssize_t) MagickMax(1L*number_colors,1L); i++)
9840 if (IsPNGColorEqual(image->background_color,image->colormap[i]))
9843 ping_background.index=(png_byte) i;
9845 if (logging != MagickFalse)
9847 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9848 " Setting up bKGD chunk with index=%d",(int) i);
9851 if (i < (ssize_t) number_colors)
9853 ping_have_bKGD = MagickTrue;
9855 if (logging != MagickFalse)
9857 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9858 " background =(%d,%d,%d)",
9859 (int) ping_background.red,
9860 (int) ping_background.green,
9861 (int) ping_background.blue);
9865 else /* Can't happen */
9867 if (logging != MagickFalse)
9868 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9869 " No room in PLTE to add bKGD color");
9870 ping_have_bKGD = MagickFalse;
9875 if (logging != MagickFalse)
9876 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9877 " PNG color type: %s (%d)", PngColorTypeToString(ping_color_type),
9880 Initialize compression level and filtering.
9882 if (logging != MagickFalse)
9884 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9885 " Setting up deflate compression");
9887 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9888 " Compression buffer size: 32768");
9891 png_set_compression_buffer_size(ping,32768L);
9893 if (logging != MagickFalse)
9894 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9895 " Compression mem level: 9");
9897 png_set_compression_mem_level(ping, 9);
9899 /* Untangle the "-quality" setting:
9901 Undefined is 0; the default is used.
9906 0: Use Z_HUFFMAN_ONLY strategy with the
9907 zlib default compression level
9909 1-9: the zlib compression level
9913 0-4: the PNG filter method
9915 5: libpng adaptive filtering if compression level > 5
9916 libpng filter type "none" if compression level <= 5
9917 or if image is grayscale or palette
9919 6: libpng adaptive filtering
9921 7: "LOCO" filtering (intrapixel differing) if writing
9922 a MNG, othewise "none". Did not work in IM-6.7.0-9
9923 and earlier because of a missing "else".
9925 8: Z_RLE strategy, all filters
9926 Unused prior to IM-6.7.0-10, was same as 6
9928 9: Z_RLE strategy, no PNG filters
9929 Unused prior to IM-6.7.0-10, was same as 6
9931 Note that using the -quality option, not all combinations of
9932 PNG filter type, zlib compression level, and zlib compression
9933 strategy are possible. This will be addressed soon in a
9934 release that accomodates "-define png:compression-strategy", etc.
9938 quality=image->quality == UndefinedCompressionQuality ? 75UL :
9943 if (mng_info->write_png_compression_strategy == 0)
9944 mng_info->write_png_compression_strategy = Z_HUFFMAN_ONLY+1;
9947 else if (mng_info->write_png_compression_level == 0)
9952 level=(int) MagickMin((ssize_t) quality/10,9);
9954 mng_info->write_png_compression_level = level+1;
9957 if (mng_info->write_png_compression_strategy == 0)
9959 if ((quality %10) == 8 || (quality %10) == 9)
9960 #ifdef Z_RLE /* Z_RLE was added to zlib-1.2.0 */
9961 mng_info->write_png_compression_strategy=Z_RLE+1;
9963 mng_info->write_png_compression_strategy = Z_DEFAULT_STRATEGY+1;
9967 if (mng_info->write_png_compression_filter == 0)
9968 mng_info->write_png_compression_filter=((int) quality % 10) + 1;
9970 if (logging != MagickFalse)
9972 if (mng_info->write_png_compression_level)
9973 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9974 " Compression level: %d",
9975 (int) mng_info->write_png_compression_level-1);
9977 if (mng_info->write_png_compression_strategy)
9978 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9979 " Compression strategy: %d",
9980 (int) mng_info->write_png_compression_strategy-1);
9982 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9983 " Setting up filtering");
9985 if (mng_info->write_png_compression_filter == 6)
9986 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9987 " Base filter method: ADAPTIVE");
9988 else if (mng_info->write_png_compression_filter == 0 ||
9989 mng_info->write_png_compression_filter == 1)
9990 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9991 " Base filter method: NONE");
9993 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9994 " Base filter method: %d",
9995 (int) mng_info->write_png_compression_filter-1);
9998 if (mng_info->write_png_compression_level != 0)
9999 png_set_compression_level(ping,mng_info->write_png_compression_level-1);
10001 if (mng_info->write_png_compression_filter == 6)
10003 if (((int) ping_color_type == PNG_COLOR_TYPE_GRAY) ||
10004 ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE) ||
10006 png_set_filter(ping,PNG_FILTER_TYPE_BASE,PNG_NO_FILTERS);
10008 png_set_filter(ping,PNG_FILTER_TYPE_BASE,PNG_ALL_FILTERS);
10010 else if (mng_info->write_png_compression_filter == 7 ||
10011 mng_info->write_png_compression_filter == 10)
10012 png_set_filter(ping,PNG_FILTER_TYPE_BASE,PNG_ALL_FILTERS);
10014 else if (mng_info->write_png_compression_filter == 8)
10016 #if defined(PNG_MNG_FEATURES_SUPPORTED) && defined(PNG_INTRAPIXEL_DIFFERENCING)
10017 if (mng_info->write_mng)
10019 if (((int) ping_color_type == PNG_COLOR_TYPE_RGB) ||
10020 ((int) ping_color_type == PNG_COLOR_TYPE_RGBA))
10021 ping_filter_method=PNG_INTRAPIXEL_DIFFERENCING;
10024 png_set_filter(ping,PNG_FILTER_TYPE_BASE,PNG_NO_FILTERS);
10027 else if (mng_info->write_png_compression_filter == 9)
10028 png_set_filter(ping,PNG_FILTER_TYPE_BASE,PNG_NO_FILTERS);
10030 else if (mng_info->write_png_compression_filter != 0)
10031 png_set_filter(ping,PNG_FILTER_TYPE_BASE,
10032 mng_info->write_png_compression_filter-1);
10034 if (mng_info->write_png_compression_strategy != 0)
10035 png_set_compression_strategy(ping,
10036 mng_info->write_png_compression_strategy-1);
10038 /* Only write the iCCP chunk if we are not writing the sRGB chunk. */
10039 if (ping_exclude_sRGB != MagickFalse ||
10040 (image->rendering_intent == UndefinedIntent))
10042 if ((ping_exclude_tEXt == MagickFalse ||
10043 ping_exclude_zTXt == MagickFalse) &&
10044 (ping_exclude_iCCP == MagickFalse || ping_exclude_zCCP == MagickFalse))
10046 ResetImageProfileIterator(image);
10047 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
10049 profile=GetImageProfile(image,name);
10051 if (profile != (StringInfo *) NULL)
10053 #ifdef PNG_WRITE_iCCP_SUPPORTED
10054 if ((LocaleCompare(name,"ICC") == 0) ||
10055 (LocaleCompare(name,"ICM") == 0))
10058 if (ping_exclude_iCCP == MagickFalse)
10060 png_set_iCCP(ping,ping_info,(png_charp) name,0,
10061 #if (PNG_LIBPNG_VER < 10500)
10062 (png_charp) GetStringInfoDatum(profile),
10064 (png_const_bytep) GetStringInfoDatum(profile),
10066 (png_uint_32) GetStringInfoLength(profile));
10072 if (ping_exclude_zCCP == MagickFalse)
10074 Magick_png_write_raw_profile(image_info,ping,ping_info,
10075 (unsigned char *) name,(unsigned char *) name,
10076 GetStringInfoDatum(profile),
10077 (png_uint_32) GetStringInfoLength(profile));
10081 if (logging != MagickFalse)
10082 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10083 " Setting up text chunk with %s profile",name);
10085 name=GetNextImageProfile(image);
10090 #if defined(PNG_WRITE_sRGB_SUPPORTED)
10091 if ((mng_info->have_write_global_srgb == 0) &&
10092 (image->rendering_intent != UndefinedIntent))
10094 if (ping_exclude_sRGB == MagickFalse)
10097 Note image rendering intent.
10099 if (logging != MagickFalse)
10100 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10101 " Setting up sRGB chunk");
10103 (void) png_set_sRGB(ping,ping_info,(
10104 Magick_RenderingIntent_to_PNG_RenderingIntent(
10105 image->rendering_intent)));
10109 if ((!mng_info->write_mng) || (!png_get_valid(ping,ping_info,PNG_INFO_sRGB)))
10112 if (ping_exclude_gAMA == MagickFalse &&
10113 (ping_exclude_sRGB == MagickFalse ||
10114 (image->gamma < .45 || image->gamma > .46)))
10116 if ((mng_info->have_write_global_gama == 0) && (image->gamma != 0.0))
10120 To do: check for cHRM+gAMA == sRGB, and write sRGB instead.
10122 if (logging != MagickFalse)
10123 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10124 " Setting up gAMA chunk");
10126 png_set_gAMA(ping,ping_info,image->gamma);
10130 if (ping_exclude_cHRM == MagickFalse)
10132 if ((mng_info->have_write_global_chrm == 0) &&
10133 (image->chromaticity.red_primary.x != 0.0))
10136 Note image chromaticity.
10137 To do: check for cHRM+gAMA == sRGB, and write sRGB instead.
10145 wp=image->chromaticity.white_point;
10146 rp=image->chromaticity.red_primary;
10147 gp=image->chromaticity.green_primary;
10148 bp=image->chromaticity.blue_primary;
10150 if (logging != MagickFalse)
10151 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10152 " Setting up cHRM chunk");
10154 png_set_cHRM(ping,ping_info,wp.x,wp.y,rp.x,rp.y,gp.x,gp.y,
10160 ping_interlace_method=image_info->interlace != NoInterlace;
10162 if (mng_info->write_mng)
10163 png_set_sig_bytes(ping,8);
10165 /* Bail out if cannot meet defined png:bit-depth or png:color-type */
10167 if (mng_info->write_png_colortype != 0)
10169 if (mng_info->write_png_colortype-1 == PNG_COLOR_TYPE_GRAY)
10170 if (ping_have_color != MagickFalse)
10172 ping_color_type = PNG_COLOR_TYPE_RGB;
10174 if (ping_bit_depth < 8)
10178 if (mng_info->write_png_colortype-1 == PNG_COLOR_TYPE_GRAY_ALPHA)
10179 if (ping_have_color != MagickFalse)
10180 ping_color_type = PNG_COLOR_TYPE_RGB_ALPHA;
10183 if (ping_need_colortype_warning != MagickFalse ||
10184 ((mng_info->write_png_depth &&
10185 (int) mng_info->write_png_depth != ping_bit_depth) ||
10186 (mng_info->write_png_colortype &&
10187 ((int) mng_info->write_png_colortype-1 != ping_color_type &&
10188 mng_info->write_png_colortype != 7 &&
10189 !(mng_info->write_png_colortype == 5 && ping_color_type == 0)))))
10191 if (logging != MagickFalse)
10193 if (ping_need_colortype_warning != MagickFalse)
10195 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10196 " Image has transparency but tRNS chunk was excluded");
10199 if (mng_info->write_png_depth)
10201 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10202 " Defined png:bit-depth=%u, Computed depth=%u",
10203 mng_info->write_png_depth,
10207 if (mng_info->write_png_colortype)
10209 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10210 " Defined png:color-type=%u, Computed color type=%u",
10211 mng_info->write_png_colortype-1,
10217 "Cannot write image with defined png:bit-depth or png:color-type.");
10220 if (image_matte != MagickFalse && image->alpha_trait != BlendPixelTrait)
10222 /* Add an opaque matte channel */
10223 image->alpha_trait = BlendPixelTrait;
10224 (void) SetImageAlpha(image,OpaqueAlpha,exception);
10226 if (logging != MagickFalse)
10227 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10228 " Added an opaque matte channel");
10231 if (number_transparent != 0 || number_semitransparent != 0)
10233 if (ping_color_type < 4)
10235 ping_have_tRNS=MagickTrue;
10236 if (logging != MagickFalse)
10237 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10238 " Setting ping_have_tRNS=MagickTrue.");
10242 if (logging != MagickFalse)
10243 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10244 " Writing PNG header chunks");
10246 png_set_IHDR(ping,ping_info,ping_width,ping_height,
10247 ping_bit_depth,ping_color_type,
10248 ping_interlace_method,ping_compression_method,
10249 ping_filter_method);
10251 if (ping_color_type == 3 && ping_have_PLTE != MagickFalse)
10253 png_set_PLTE(ping,ping_info,palette,number_colors);
10255 if (logging != MagickFalse)
10257 for (i=0; i< (ssize_t) number_colors; i++)
10259 if (i < ping_num_trans)
10260 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10261 " PLTE[%d] = (%d,%d,%d), tRNS[%d] = (%d)",
10263 (int) palette[i].red,
10264 (int) palette[i].green,
10265 (int) palette[i].blue,
10267 (int) ping_trans_alpha[i]);
10269 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10270 " PLTE[%d] = (%d,%d,%d)",
10272 (int) palette[i].red,
10273 (int) palette[i].green,
10274 (int) palette[i].blue);
10279 if (ping_exclude_bKGD == MagickFalse)
10281 if (ping_have_bKGD != MagickFalse)
10283 png_set_bKGD(ping,ping_info,&ping_background);
10286 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10287 " Setting up bKGD chunk");
10288 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10289 " background color = (%d,%d,%d)",
10290 (int) ping_background.red,
10291 (int) ping_background.green,
10292 (int) ping_background.blue);
10293 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10294 " index = %d, gray=%d",
10295 (int) ping_background.index,
10296 (int) ping_background.gray);
10301 if (ping_exclude_pHYs == MagickFalse)
10303 if (ping_have_pHYs != MagickFalse)
10305 png_set_pHYs(ping,ping_info,
10306 ping_pHYs_x_resolution,
10307 ping_pHYs_y_resolution,
10308 ping_pHYs_unit_type);
10312 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10313 " Setting up pHYs chunk");
10314 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10315 " x_resolution=%lu",
10316 (unsigned long) ping_pHYs_x_resolution);
10317 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10318 " y_resolution=%lu",
10319 (unsigned long) ping_pHYs_y_resolution);
10320 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10322 (unsigned long) ping_pHYs_unit_type);
10327 #if defined(PNG_oFFs_SUPPORTED)
10328 if (ping_exclude_oFFs == MagickFalse)
10330 if (image->page.x || image->page.y)
10332 png_set_oFFs(ping,ping_info,(png_int_32) image->page.x,
10333 (png_int_32) image->page.y, 0);
10335 if (logging != MagickFalse)
10336 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10337 " Setting up oFFs chunk with x=%d, y=%d, units=0",
10338 (int) image->page.x, (int) image->page.y);
10343 if (mng_info->need_blob != MagickFalse)
10345 if (OpenBlob(image_info,image,WriteBinaryBlobMode,exception) ==
10347 png_error(ping,"WriteBlob Failed");
10349 ping_have_blob=MagickTrue;
10352 png_write_info_before_PLTE(ping, ping_info);
10354 if (ping_have_tRNS != MagickFalse && ping_color_type < 4)
10356 if (logging != MagickFalse)
10358 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10359 " Calling png_set_tRNS with num_trans=%d",ping_num_trans);
10362 if (ping_color_type == 3)
10363 (void) png_set_tRNS(ping, ping_info,
10370 (void) png_set_tRNS(ping, ping_info,
10373 &ping_trans_color);
10375 if (logging != MagickFalse)
10377 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10378 " tRNS color =(%d,%d,%d)",
10379 (int) ping_trans_color.red,
10380 (int) ping_trans_color.green,
10381 (int) ping_trans_color.blue);
10386 /* write any png-chunk-b profiles */
10387 (void) Magick_png_write_chunk_from_profile(image,"PNG-chunk-b",logging);
10389 png_write_info(ping,ping_info);
10391 /* write any PNG-chunk-m profiles */
10392 (void) Magick_png_write_chunk_from_profile(image,"PNG-chunk-m",logging);
10394 if (ping_exclude_vpAg == MagickFalse)
10396 if ((image->page.width != 0 && image->page.width != image->columns) ||
10397 (image->page.height != 0 && image->page.height != image->rows))
10402 (void) WriteBlobMSBULong(image,9L); /* data length=8 */
10403 PNGType(chunk,mng_vpAg);
10404 LogPNGChunk(logging,mng_vpAg,9L);
10405 PNGLong(chunk+4,(png_uint_32) image->page.width);
10406 PNGLong(chunk+8,(png_uint_32) image->page.height);
10407 chunk[12]=0; /* unit = pixels */
10408 (void) WriteBlob(image,13,chunk);
10409 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
10413 #if (PNG_LIBPNG_VER == 10206)
10414 /* avoid libpng-1.2.6 bug by setting PNG_HAVE_IDAT flag */
10415 #define PNG_HAVE_IDAT 0x04
10416 ping->mode |= PNG_HAVE_IDAT;
10417 #undef PNG_HAVE_IDAT
10420 png_set_packing(ping);
10424 rowbytes=image->columns;
10425 if (image_depth > 8)
10427 switch (ping_color_type)
10429 case PNG_COLOR_TYPE_RGB:
10433 case PNG_COLOR_TYPE_GRAY_ALPHA:
10437 case PNG_COLOR_TYPE_RGBA:
10445 if (logging != MagickFalse)
10447 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10448 " Writing PNG image data");
10450 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10451 " Allocating %.20g bytes of memory for pixels",(double) rowbytes);
10453 ping_pixels=(unsigned char *) AcquireQuantumMemory(rowbytes,
10454 sizeof(*ping_pixels));
10456 if (ping_pixels == (unsigned char *) NULL)
10457 png_error(ping,"Allocation of memory for pixels failed");
10460 Initialize image scanlines.
10462 quantum_info=AcquireQuantumInfo(image_info,image);
10463 if (quantum_info == (QuantumInfo *) NULL)
10464 png_error(ping,"Memory allocation for quantum_info failed");
10465 quantum_info->format=UndefinedQuantumFormat;
10466 quantum_info->depth=image_depth;
10467 (void) SetQuantumEndian(image,quantum_info,MSBEndian);
10468 num_passes=png_set_interlace_handling(ping);
10470 if ((!mng_info->write_png8 && !mng_info->write_png24 &&
10471 !mng_info->write_png32) &&
10472 (mng_info->IsPalette ||
10473 (image_info->type == BilevelType)) &&
10474 image_matte == MagickFalse &&
10475 ping_have_non_bw == MagickFalse)
10477 /* Palette, Bilevel, or Opaque Monochrome */
10478 register const Quantum
10481 quantum_info->depth=8;
10482 for (pass=0; pass < num_passes; pass++)
10485 Convert PseudoClass image to a PNG monochrome image.
10487 for (y=0; y < (ssize_t) image->rows; y++)
10489 if (logging != MagickFalse && y == 0)
10490 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10491 " Writing row of pixels (0)");
10493 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
10495 if (p == (const Quantum *) NULL)
10498 if (mng_info->IsPalette)
10500 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10501 quantum_info,GrayQuantum,ping_pixels,exception);
10502 if (mng_info->write_png_colortype-1 == PNG_COLOR_TYPE_PALETTE &&
10503 mng_info->write_png_depth &&
10504 mng_info->write_png_depth != old_bit_depth)
10506 /* Undo pixel scaling */
10507 for (i=0; i < (ssize_t) image->columns; i++)
10508 *(ping_pixels+i)=(unsigned char) (*(ping_pixels+i)
10509 >> (8-old_bit_depth));
10515 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10516 quantum_info,RedQuantum,ping_pixels,exception);
10519 if (mng_info->write_png_colortype-1 != PNG_COLOR_TYPE_PALETTE)
10520 for (i=0; i < (ssize_t) image->columns; i++)
10521 *(ping_pixels+i)=(unsigned char) ((*(ping_pixels+i) > 127) ?
10524 if (logging != MagickFalse && y == 0)
10525 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10526 " Writing row of pixels (1)");
10528 png_write_row(ping,ping_pixels);
10530 if (image->previous == (Image *) NULL)
10532 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
10533 if (status == MagickFalse)
10539 else /* Not Palette, Bilevel, or Opaque Monochrome */
10541 if ((!mng_info->write_png8 && !mng_info->write_png24 &&
10542 !mng_info->write_png32) &&
10543 (image_matte != MagickFalse ||
10544 (ping_bit_depth >= MAGICKCORE_QUANTUM_DEPTH)) &&
10545 (mng_info->IsPalette) && ping_have_color == MagickFalse)
10547 register const Quantum
10550 for (pass=0; pass < num_passes; pass++)
10553 for (y=0; y < (ssize_t) image->rows; y++)
10555 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
10557 if (p == (const Quantum *) NULL)
10560 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
10562 if (mng_info->IsPalette)
10563 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10564 quantum_info,GrayQuantum,ping_pixels,exception);
10567 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10568 quantum_info,RedQuantum,ping_pixels,exception);
10570 if (logging != MagickFalse && y == 0)
10571 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10572 " Writing GRAY PNG pixels (2)");
10575 else /* PNG_COLOR_TYPE_GRAY_ALPHA */
10577 if (logging != MagickFalse && y == 0)
10578 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10579 " Writing GRAY_ALPHA PNG pixels (2)");
10581 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10582 quantum_info,GrayAlphaQuantum,ping_pixels,exception);
10585 if (logging != MagickFalse && y == 0)
10586 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10587 " Writing row of pixels (2)");
10589 png_write_row(ping,ping_pixels);
10592 if (image->previous == (Image *) NULL)
10594 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
10595 if (status == MagickFalse)
10603 register const Quantum
10606 for (pass=0; pass < num_passes; pass++)
10608 if ((image_depth > 8) || (mng_info->write_png24 ||
10609 mng_info->write_png32 ||
10610 (!mng_info->write_png8 && !mng_info->IsPalette)))
10612 for (y=0; y < (ssize_t) image->rows; y++)
10614 p=GetVirtualPixels(image,0,y,image->columns,1, exception);
10616 if (p == (const Quantum *) NULL)
10619 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
10621 if (image->storage_class == DirectClass)
10622 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10623 quantum_info,RedQuantum,ping_pixels,exception);
10626 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10627 quantum_info,GrayQuantum,ping_pixels,exception);
10630 else if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
10632 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10633 quantum_info,GrayAlphaQuantum,ping_pixels,
10636 if (logging != MagickFalse && y == 0)
10637 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10638 " Writing GRAY_ALPHA PNG pixels (3)");
10641 else if (image_matte != MagickFalse)
10642 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10643 quantum_info,RGBAQuantum,ping_pixels,exception);
10646 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10647 quantum_info,RGBQuantum,ping_pixels,exception);
10649 if (logging != MagickFalse && y == 0)
10650 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10651 " Writing row of pixels (3)");
10653 png_write_row(ping,ping_pixels);
10658 /* not ((image_depth > 8) || (mng_info->write_png24 ||
10659 mng_info->write_png32 ||
10660 (!mng_info->write_png8 && !mng_info->IsPalette))) */
10662 if ((ping_color_type != PNG_COLOR_TYPE_GRAY) &&
10663 (ping_color_type != PNG_COLOR_TYPE_GRAY_ALPHA))
10665 if (logging != MagickFalse)
10666 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10667 " pass %d, Image Is not GRAY or GRAY_ALPHA",pass);
10669 quantum_info->depth=8;
10673 for (y=0; y < (ssize_t) image->rows; y++)
10675 if (logging != MagickFalse && y == 0)
10676 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10677 " pass %d, Image Is RGB, 16-bit GRAY, or GRAY_ALPHA",pass);
10679 p=GetVirtualPixels(image,0,y,image->columns,1, exception);
10681 if (p == (const Quantum *) NULL)
10684 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
10686 quantum_info->depth=image->depth;
10688 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10689 quantum_info,GrayQuantum,ping_pixels,exception);
10692 else if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
10694 if (logging != MagickFalse && y == 0)
10695 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10696 " Writing GRAY_ALPHA PNG pixels (4)");
10698 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10699 quantum_info,GrayAlphaQuantum,ping_pixels,
10705 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10706 quantum_info,IndexQuantum,ping_pixels,exception);
10708 if (logging != MagickFalse && y <= 2)
10710 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10711 " Writing row of non-gray pixels (4)");
10713 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10714 " ping_pixels[0]=%d,ping_pixels[1]=%d",
10715 (int)ping_pixels[0],(int)ping_pixels[1]);
10718 png_write_row(ping,ping_pixels);
10722 if (image->previous == (Image *) NULL)
10724 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
10725 if (status == MagickFalse)
10732 if (quantum_info != (QuantumInfo *) NULL)
10733 quantum_info=DestroyQuantumInfo(quantum_info);
10735 if (logging != MagickFalse)
10737 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10738 " Wrote PNG image data");
10740 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10741 " Width: %.20g",(double) ping_width);
10743 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10744 " Height: %.20g",(double) ping_height);
10746 if (mng_info->write_png_depth)
10748 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10749 " Defined png:bit-depth: %d",mng_info->write_png_depth);
10752 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10753 " PNG bit-depth written: %d",ping_bit_depth);
10755 if (mng_info->write_png_colortype)
10757 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10758 " Defined png:color-type: %d",mng_info->write_png_colortype-1);
10761 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10762 " PNG color-type written: %d",ping_color_type);
10764 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10765 " PNG Interlace method: %d",ping_interlace_method);
10768 Generate text chunks after IDAT.
10770 if (ping_exclude_tEXt == MagickFalse || ping_exclude_zTXt == MagickFalse)
10772 ResetImagePropertyIterator(image);
10773 property=GetNextImageProperty(image);
10774 while (property != (const char *) NULL)
10779 value=GetImageProperty(image,property,exception);
10781 /* Don't write any "png:" properties; those are just for "identify" */
10782 if (LocaleNCompare(property,"png:",4) != 0 &&
10784 /* Suppress density and units if we wrote a pHYs chunk */
10785 (ping_exclude_pHYs != MagickFalse ||
10786 LocaleCompare(property,"density") != 0 ||
10787 LocaleCompare(property,"units") != 0) &&
10789 /* Suppress the IM-generated Date:create and Date:modify */
10790 (ping_exclude_date == MagickFalse ||
10791 LocaleNCompare(property, "Date:",5) != 0))
10793 if (value != (const char *) NULL)
10796 #if PNG_LIBPNG_VER >= 14000
10797 text=(png_textp) png_malloc(ping,
10798 (png_alloc_size_t) sizeof(png_text));
10800 text=(png_textp) png_malloc(ping,(png_size_t) sizeof(png_text));
10802 text[0].key=(char *) property;
10803 text[0].text=(char *) value;
10804 text[0].text_length=strlen(value);
10806 if (ping_exclude_tEXt != MagickFalse)
10807 text[0].compression=PNG_TEXT_COMPRESSION_zTXt;
10809 else if (ping_exclude_zTXt != MagickFalse)
10810 text[0].compression=PNG_TEXT_COMPRESSION_NONE;
10814 text[0].compression=image_info->compression == NoCompression ||
10815 (image_info->compression == UndefinedCompression &&
10816 text[0].text_length < 128) ? PNG_TEXT_COMPRESSION_NONE :
10817 PNG_TEXT_COMPRESSION_zTXt ;
10820 if (logging != MagickFalse)
10822 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10823 " Setting up text chunk");
10825 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10826 " keyword: %s",text[0].key);
10829 png_set_text(ping,ping_info,text,1);
10830 png_free(ping,text);
10833 property=GetNextImageProperty(image);
10837 /* write any PNG-chunk-e profiles */
10838 (void) Magick_png_write_chunk_from_profile(image,"PNG-chunk-e",logging);
10840 if (logging != MagickFalse)
10841 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10842 " Writing PNG end info");
10844 png_write_end(ping,ping_info);
10846 if (mng_info->need_fram && (int) image->dispose == BackgroundDispose)
10848 if (mng_info->page.x || mng_info->page.y ||
10849 (ping_width != mng_info->page.width) ||
10850 (ping_height != mng_info->page.height))
10856 Write FRAM 4 with clipping boundaries followed by FRAM 1.
10858 (void) WriteBlobMSBULong(image,27L); /* data length=27 */
10859 PNGType(chunk,mng_FRAM);
10860 LogPNGChunk(logging,mng_FRAM,27L);
10862 chunk[5]=0; /* frame name separator (no name) */
10863 chunk[6]=1; /* flag for changing delay, for next frame only */
10864 chunk[7]=0; /* flag for changing frame timeout */
10865 chunk[8]=1; /* flag for changing frame clipping for next frame */
10866 chunk[9]=0; /* flag for changing frame sync_id */
10867 PNGLong(chunk+10,(png_uint_32) (0L)); /* temporary 0 delay */
10868 chunk[14]=0; /* clipping boundaries delta type */
10869 PNGLong(chunk+15,(png_uint_32) (mng_info->page.x)); /* left cb */
10871 (png_uint_32) (mng_info->page.x + ping_width));
10872 PNGLong(chunk+23,(png_uint_32) (mng_info->page.y)); /* top cb */
10874 (png_uint_32) (mng_info->page.y + ping_height));
10875 (void) WriteBlob(image,31,chunk);
10876 (void) WriteBlobMSBULong(image,crc32(0,chunk,31));
10877 mng_info->old_framing_mode=4;
10878 mng_info->framing_mode=1;
10882 mng_info->framing_mode=3;
10884 if (mng_info->write_mng && !mng_info->need_fram &&
10885 ((int) image->dispose == 3))
10886 png_error(ping, "Cannot convert GIF with disposal method 3 to MNG-LC");
10889 Free PNG resources.
10892 png_destroy_write_struct(&ping,&ping_info);
10894 ping_pixels=(unsigned char *) RelinquishMagickMemory(ping_pixels);
10896 if (ping_have_blob != MagickFalse)
10897 (void) CloseBlob(image);
10899 image_info=DestroyImageInfo(image_info);
10900 image=DestroyImage(image);
10902 /* Store bit depth actually written */
10903 s[0]=(char) ping_bit_depth;
10906 (void) SetImageProperty(IMimage,"png:bit-depth-written",s,exception);
10908 if (logging != MagickFalse)
10909 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10910 " exit WriteOnePNGImage()");
10912 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
10913 UnlockSemaphoreInfo(ping_semaphore);
10916 /* } for navigation to beginning of SETJMP-protected block. Revert to
10917 * Throwing an Exception when an error occurs.
10920 return(MagickTrue);
10921 /* End write one PNG image */
10926 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10930 % W r i t e P N G I m a g e %
10934 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10936 % WritePNGImage() writes a Portable Network Graphics (PNG) or
10937 % Multiple-image Network Graphics (MNG) image file.
10939 % MNG support written by Glenn Randers-Pehrson, glennrp@image...
10941 % The format of the WritePNGImage method is:
10943 % MagickBooleanType WritePNGImage(const ImageInfo *image_info,
10944 % Image *image,ExceptionInfo *exception)
10946 % A description of each parameter follows:
10948 % o image_info: the image info.
10950 % o image: The image.
10952 % o exception: return any errors or warnings in this structure.
10954 % Returns MagickTrue on success, MagickFalse on failure.
10956 % Communicating with the PNG encoder:
10958 % While the datastream written is always in PNG format and normally would
10959 % be given the "png" file extension, this method also writes the following
10960 % pseudo-formats which are subsets of png:
10962 % o PNG8: An 8-bit indexed PNG datastream is written. If the image has
10963 % a depth greater than 8, the depth is reduced. If transparency
10964 % is present, the tRNS chunk must only have values 0 and 255
10965 % (i.e., transparency is binary: fully opaque or fully
10966 % transparent). If other values are present they will be
10967 % 50%-thresholded to binary transparency. If more than 256
10968 % colors are present, they will be quantized to the 4-4-4-1,
10969 % 3-3-3-1, or 3-3-2-1 palette. The underlying RGB color
10970 % of any resulting fully-transparent pixels is changed to
10971 % the image's background color.
10973 % If you want better quantization or dithering of the colors
10974 % or alpha than that, you need to do it before calling the
10975 % PNG encoder. The pixels contain 8-bit indices even if
10976 % they could be represented with 1, 2, or 4 bits. Grayscale
10977 % images will be written as indexed PNG files even though the
10978 % PNG grayscale type might be slightly more efficient. Please
10979 % note that writing to the PNG8 format may result in loss
10980 % of color and alpha data.
10982 % o PNG24: An 8-bit per sample RGB PNG datastream is written. The tRNS
10983 % chunk can be present to convey binary transparency by naming
10984 % one of the colors as transparent. The only loss incurred
10985 % is reduction of sample depth to 8. If the image has more
10986 % than one transparent color, has semitransparent pixels, or
10987 % has an opaque pixel with the same RGB components as the
10988 % transparent color, an image is not written.
10990 % o PNG32: An 8-bit per sample RGBA PNG is written. Partial
10991 % transparency is permitted, i.e., the alpha sample for
10992 % each pixel can have any value from 0 to 255. The alpha
10993 % channel is present even if the image is fully opaque.
10994 % The only loss in data is the reduction of the sample depth
10997 % o -define: For more precise control of the PNG output, you can use the
10998 % Image options "png:bit-depth" and "png:color-type". These
10999 % can be set from the commandline with "-define" and also
11000 % from the application programming interfaces. The options
11001 % are case-independent and are converted to lowercase before
11002 % being passed to this encoder.
11004 % png:color-type can be 0, 2, 3, 4, or 6.
11006 % When png:color-type is 0 (Grayscale), png:bit-depth can
11007 % be 1, 2, 4, 8, or 16.
11009 % When png:color-type is 2 (RGB), png:bit-depth can
11012 % When png:color-type is 3 (Indexed), png:bit-depth can
11013 % be 1, 2, 4, or 8. This refers to the number of bits
11014 % used to store the index. The color samples always have
11015 % bit-depth 8 in indexed PNG files.
11017 % When png:color-type is 4 (Gray-Matte) or 6 (RGB-Matte),
11018 % png:bit-depth can be 8 or 16.
11020 % If the image cannot be written without loss with the requested bit-depth
11021 % and color-type, a PNG file will not be written, and the encoder will
11022 % return MagickFalse.
11024 % Since image encoders should not be responsible for the "heavy lifting",
11025 % the user should make sure that ImageMagick has already reduced the
11026 % image depth and number of colors and limit transparency to binary
11027 % transparency prior to attempting to write the image with depth, color,
11028 % or transparency limitations.
11030 % Note that another definition, "png:bit-depth-written" exists, but it
11031 % is not intended for external use. It is only used internally by the
11032 % PNG encoder to inform the JNG encoder of the depth of the alpha channel.
11034 % It is possible to request that the PNG encoder write previously-formatted
11035 % ancillary chunks in the output PNG file, using the "-profile" commandline
11036 % option as shown below or by setting the profile via a programming
11039 % -profile PNG-chunk-x:<file>
11041 % where x is a location flag and <file> is a file containing the chunk
11042 % name in the first 4 bytes, then a colon (":"), followed by the chunk data.
11043 % This encoder will compute the chunk length and CRC, so those must not
11044 % be included in the file.
11046 % "x" can be "b" (before PLTE), "m" (middle, i.e., between PLTE and IDAT),
11047 % or "e" (end, i.e., after IDAT). If you want to write multiple chunks
11048 % of the same type, then add a short unique string after the "x" to prevent
11049 % subsequent profiles from overwriting the preceding ones, e.g.,
11051 % -profile PNG-chunk-b01:file01 -profile PNG-chunk-b02:file02
11053 % As of version 6.6.6 the following optimizations are always done:
11055 % o 32-bit depth is reduced to 16.
11056 % o 16-bit depth is reduced to 8 if all pixels contain samples whose
11057 % high byte and low byte are identical.
11058 % o Palette is sorted to remove unused entries and to put a
11059 % transparent color first, if BUILD_PNG_PALETTE is defined.
11060 % o Opaque matte channel is removed when writing an indexed PNG.
11061 % o Grayscale images are reduced to 1, 2, or 4 bit depth if
11062 % this can be done without loss and a larger bit depth N was not
11063 % requested via the "-define png:bit-depth=N" option.
11064 % o If matte channel is present but only one transparent color is
11065 % present, RGB+tRNS is written instead of RGBA
11066 % o Opaque matte channel is removed (or added, if color-type 4 or 6
11067 % was requested when converting an opaque image).
11069 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11071 static MagickBooleanType WritePNGImage(const ImageInfo *image_info,
11072 Image *image,ExceptionInfo *exception)
11077 have_mng_structure,
11093 assert(image_info != (const ImageInfo *) NULL);
11094 assert(image_info->signature == MagickSignature);
11095 assert(image != (Image *) NULL);
11096 assert(image->signature == MagickSignature);
11097 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
11098 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter WritePNGImage()");
11100 Allocate a MngInfo structure.
11102 have_mng_structure=MagickFalse;
11103 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
11105 if (mng_info == (MngInfo *) NULL)
11106 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
11109 Initialize members of the MngInfo structure.
11111 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
11112 mng_info->image=image;
11113 mng_info->equal_backgrounds=MagickTrue;
11114 have_mng_structure=MagickTrue;
11116 /* See if user has requested a specific PNG subformat */
11118 mng_info->write_png8=LocaleCompare(image_info->magick,"PNG8") == 0;
11119 mng_info->write_png24=LocaleCompare(image_info->magick,"PNG24") == 0;
11120 mng_info->write_png32=LocaleCompare(image_info->magick,"PNG32") == 0;
11122 value=GetImageOption(image_info,"png:format");
11124 if (value != (char *) NULL)
11126 if (LocaleCompare(value,"png8") == 0)
11128 mng_info->write_png8 = MagickTrue;
11129 mng_info->write_png24 = MagickFalse;
11130 mng_info->write_png32 = MagickFalse;
11133 else if (LocaleCompare(value,"png24") == 0)
11135 mng_info->write_png8 = MagickFalse;
11136 mng_info->write_png24 = MagickTrue;
11137 mng_info->write_png32 = MagickFalse;
11140 else if (LocaleCompare(value,"png32") == 0)
11142 mng_info->write_png8 = MagickFalse;
11143 mng_info->write_png24 = MagickFalse;
11144 mng_info->write_png32 = MagickTrue;
11147 if (mng_info->write_png8)
11149 mng_info->write_png_colortype = /* 3 */ 4;
11150 mng_info->write_png_depth = 8;
11154 if (mng_info->write_png24)
11156 mng_info->write_png_colortype = /* 2 */ 3;
11157 mng_info->write_png_depth = 8;
11160 if (image->alpha_trait == BlendPixelTrait)
11161 (void) SetImageType(image,TrueColorMatteType,exception);
11164 (void) SetImageType(image,TrueColorType,exception);
11166 (void) SyncImage(image,exception);
11169 if (mng_info->write_png32)
11171 mng_info->write_png_colortype = /* 6 */ 7;
11172 mng_info->write_png_depth = 8;
11175 if (image->alpha_trait == BlendPixelTrait)
11176 (void) SetImageType(image,TrueColorMatteType,exception);
11179 (void) SetImageType(image,TrueColorType,exception);
11181 (void) SyncImage(image,exception);
11184 value=GetImageOption(image_info,"png:bit-depth");
11186 if (value != (char *) NULL)
11188 if (LocaleCompare(value,"1") == 0)
11189 mng_info->write_png_depth = 1;
11191 else if (LocaleCompare(value,"2") == 0)
11192 mng_info->write_png_depth = 2;
11194 else if (LocaleCompare(value,"4") == 0)
11195 mng_info->write_png_depth = 4;
11197 else if (LocaleCompare(value,"8") == 0)
11198 mng_info->write_png_depth = 8;
11200 else if (LocaleCompare(value,"16") == 0)
11201 mng_info->write_png_depth = 16;
11204 (void) ThrowMagickException(exception,
11205 GetMagickModule(),CoderWarning,
11206 "ignoring invalid defined png:bit-depth",
11209 if (logging != MagickFalse)
11210 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11211 " png:bit-depth=%d was defined.\n",mng_info->write_png_depth);
11214 value=GetImageOption(image_info,"png:color-type");
11216 if (value != (char *) NULL)
11218 /* We must store colortype+1 because 0 is a valid colortype */
11219 if (LocaleCompare(value,"0") == 0)
11220 mng_info->write_png_colortype = 1;
11222 else if (LocaleCompare(value,"1") == 0)
11223 mng_info->write_png_colortype = 2;
11225 else if (LocaleCompare(value,"2") == 0)
11226 mng_info->write_png_colortype = 3;
11228 else if (LocaleCompare(value,"3") == 0)
11229 mng_info->write_png_colortype = 4;
11231 else if (LocaleCompare(value,"4") == 0)
11232 mng_info->write_png_colortype = 5;
11234 else if (LocaleCompare(value,"6") == 0)
11235 mng_info->write_png_colortype = 7;
11238 (void) ThrowMagickException(exception,
11239 GetMagickModule(),CoderWarning,
11240 "ignoring invalid defined png:color-type",
11243 if (logging != MagickFalse)
11244 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11245 " png:color-type=%d was defined.\n",mng_info->write_png_colortype-1);
11248 /* Check for chunks to be excluded:
11250 * The default is to not exclude any known chunks except for any
11251 * listed in the "unused_chunks" array, above.
11253 * Chunks can be listed for exclusion via a "png:exclude-chunk"
11254 * define (in the image properties or in the image artifacts)
11255 * or via a mng_info member. For convenience, in addition
11256 * to or instead of a comma-separated list of chunks, the
11257 * "exclude-chunk" string can be simply "all" or "none".
11259 * The exclude-chunk define takes priority over the mng_info.
11261 * A "png:include-chunk" define takes priority over both the
11262 * mng_info and the "png:exclude-chunk" define. Like the
11263 * "exclude-chunk" string, it can define "all" or "none" as
11264 * well as a comma-separated list. Chunks that are unknown to
11265 * ImageMagick are always excluded, regardless of their "copy-safe"
11266 * status according to the PNG specification, and even if they
11267 * appear in the "include-chunk" list. Such defines appearing among
11268 * the image options take priority over those found among the image
11271 * Finally, all chunks listed in the "unused_chunks" array are
11272 * automatically excluded, regardless of the other instructions
11275 * if you exclude sRGB but not gAMA (recommended), then sRGB chunk
11276 * will not be written and the gAMA chunk will only be written if it
11277 * is not between .45 and .46, or approximately (1.0/2.2).
11279 * If you exclude tRNS and the image has transparency, the colortype
11280 * is forced to be 4 or 6 (GRAY_ALPHA or RGB_ALPHA).
11282 * The -strip option causes StripImage() to set the png:include-chunk
11283 * artifact to "none,trns,gama".
11286 mng_info->ping_exclude_bKGD=MagickFalse;
11287 mng_info->ping_exclude_cHRM=MagickFalse;
11288 mng_info->ping_exclude_date=MagickFalse;
11289 mng_info->ping_exclude_EXIF=MagickFalse; /* hex-encoded EXIF in zTXt */
11290 mng_info->ping_exclude_gAMA=MagickFalse;
11291 mng_info->ping_exclude_iCCP=MagickFalse;
11292 /* mng_info->ping_exclude_iTXt=MagickFalse; */
11293 mng_info->ping_exclude_oFFs=MagickFalse;
11294 mng_info->ping_exclude_pHYs=MagickFalse;
11295 mng_info->ping_exclude_sRGB=MagickFalse;
11296 mng_info->ping_exclude_tEXt=MagickFalse;
11297 mng_info->ping_exclude_tRNS=MagickFalse;
11298 mng_info->ping_exclude_vpAg=MagickFalse;
11299 mng_info->ping_exclude_zCCP=MagickFalse; /* hex-encoded iCCP in zTXt */
11300 mng_info->ping_exclude_zTXt=MagickFalse;
11302 mng_info->ping_preserve_colormap=MagickFalse;
11304 value=GetImageArtifact(image,"png:preserve-colormap");
11306 value=GetImageOption(image_info,"png:preserve-colormap");
11308 mng_info->ping_preserve_colormap=MagickTrue;
11310 /* Thes compression-level, compression-strategy, and compression-filter
11311 * defines take precedence over values from the -quality option.
11313 value=GetImageArtifact(image,"png:compression-level");
11315 value=GetImageOption(image_info,"png:compression-level");
11318 /* We have to add 1 to everything because 0 is a valid input,
11319 * and we want to use 0 (the default) to mean undefined.
11321 if (LocaleCompare(value,"0") == 0)
11322 mng_info->write_png_compression_level = 1;
11324 else if (LocaleCompare(value,"1") == 0)
11325 mng_info->write_png_compression_level = 2;
11327 else if (LocaleCompare(value,"2") == 0)
11328 mng_info->write_png_compression_level = 3;
11330 else if (LocaleCompare(value,"3") == 0)
11331 mng_info->write_png_compression_level = 4;
11333 else if (LocaleCompare(value,"4") == 0)
11334 mng_info->write_png_compression_level = 5;
11336 else if (LocaleCompare(value,"5") == 0)
11337 mng_info->write_png_compression_level = 6;
11339 else if (LocaleCompare(value,"6") == 0)
11340 mng_info->write_png_compression_level = 7;
11342 else if (LocaleCompare(value,"7") == 0)
11343 mng_info->write_png_compression_level = 8;
11345 else if (LocaleCompare(value,"8") == 0)
11346 mng_info->write_png_compression_level = 9;
11348 else if (LocaleCompare(value,"9") == 0)
11349 mng_info->write_png_compression_level = 10;
11352 (void) ThrowMagickException(exception,
11353 GetMagickModule(),CoderWarning,
11354 "ignoring invalid defined png:compression-level",
11358 value=GetImageArtifact(image,"png:compression-strategy");
11360 value=GetImageOption(image_info,"png:compression-strategy");
11364 if (LocaleCompare(value,"0") == 0)
11365 mng_info->write_png_compression_strategy = Z_DEFAULT_STRATEGY+1;
11367 else if (LocaleCompare(value,"1") == 0)
11368 mng_info->write_png_compression_strategy = Z_FILTERED+1;
11370 else if (LocaleCompare(value,"2") == 0)
11371 mng_info->write_png_compression_strategy = Z_HUFFMAN_ONLY+1;
11373 else if (LocaleCompare(value,"3") == 0)
11374 #ifdef Z_RLE /* Z_RLE was added to zlib-1.2.0 */
11375 mng_info->write_png_compression_strategy = Z_RLE+1;
11377 mng_info->write_png_compression_strategy = Z_DEFAULT_STRATEGY+1;
11380 else if (LocaleCompare(value,"4") == 0)
11381 #ifdef Z_FIXED /* Z_FIXED was added to zlib-1.2.2.2 */
11382 mng_info->write_png_compression_strategy = Z_FIXED+1;
11384 mng_info->write_png_compression_strategy = Z_DEFAULT_STRATEGY+1;
11388 (void) ThrowMagickException(exception,
11389 GetMagickModule(),CoderWarning,
11390 "ignoring invalid defined png:compression-strategy",
11394 value=GetImageArtifact(image,"png:compression-filter");
11396 value=GetImageOption(image_info,"png:compression-filter");
11400 /* To do: combinations of filters allowed by libpng
11401 * masks 0x08 through 0xf8
11403 * Implement this as a comma-separated list of 0,1,2,3,4,5
11404 * where 5 is a special case meaning PNG_ALL_FILTERS.
11407 if (LocaleCompare(value,"0") == 0)
11408 mng_info->write_png_compression_filter = 1;
11410 else if (LocaleCompare(value,"1") == 0)
11411 mng_info->write_png_compression_filter = 2;
11413 else if (LocaleCompare(value,"2") == 0)
11414 mng_info->write_png_compression_filter = 3;
11416 else if (LocaleCompare(value,"3") == 0)
11417 mng_info->write_png_compression_filter = 4;
11419 else if (LocaleCompare(value,"4") == 0)
11420 mng_info->write_png_compression_filter = 5;
11422 else if (LocaleCompare(value,"5") == 0)
11423 mng_info->write_png_compression_filter = 6;
11426 (void) ThrowMagickException(exception,
11427 GetMagickModule(),CoderWarning,
11428 "ignoring invalid defined png:compression-filter",
11432 excluding=MagickFalse;
11434 for (source=0; source<1; source++)
11438 value=GetImageArtifact(image,"png:exclude-chunk");
11441 value=GetImageArtifact(image,"png:exclude-chunks");
11445 value=GetImageOption(image_info,"png:exclude-chunk");
11448 value=GetImageOption(image_info,"png:exclude-chunks");
11457 excluding=MagickTrue;
11459 if (logging != MagickFalse)
11462 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11463 " png:exclude-chunk=%s found in image artifacts.\n", value);
11465 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11466 " png:exclude-chunk=%s found in image properties.\n", value);
11469 last=strlen(value);
11471 for (i=0; i<(int) last; i+=5)
11474 if (LocaleNCompare(value+i,"all",3) == 0)
11476 mng_info->ping_exclude_bKGD=MagickTrue;
11477 mng_info->ping_exclude_cHRM=MagickTrue;
11478 mng_info->ping_exclude_date=MagickTrue;
11479 mng_info->ping_exclude_EXIF=MagickTrue;
11480 mng_info->ping_exclude_gAMA=MagickTrue;
11481 mng_info->ping_exclude_iCCP=MagickTrue;
11482 /* mng_info->ping_exclude_iTXt=MagickTrue; */
11483 mng_info->ping_exclude_oFFs=MagickTrue;
11484 mng_info->ping_exclude_pHYs=MagickTrue;
11485 mng_info->ping_exclude_sRGB=MagickTrue;
11486 mng_info->ping_exclude_tEXt=MagickTrue;
11487 mng_info->ping_exclude_tRNS=MagickTrue;
11488 mng_info->ping_exclude_vpAg=MagickTrue;
11489 mng_info->ping_exclude_zCCP=MagickTrue;
11490 mng_info->ping_exclude_zTXt=MagickTrue;
11494 if (LocaleNCompare(value+i,"none",4) == 0)
11496 mng_info->ping_exclude_bKGD=MagickFalse;
11497 mng_info->ping_exclude_cHRM=MagickFalse;
11498 mng_info->ping_exclude_date=MagickFalse;
11499 mng_info->ping_exclude_EXIF=MagickFalse;
11500 mng_info->ping_exclude_gAMA=MagickFalse;
11501 mng_info->ping_exclude_iCCP=MagickFalse;
11502 /* mng_info->ping_exclude_iTXt=MagickFalse; */
11503 mng_info->ping_exclude_oFFs=MagickFalse;
11504 mng_info->ping_exclude_pHYs=MagickFalse;
11505 mng_info->ping_exclude_sRGB=MagickFalse;
11506 mng_info->ping_exclude_tEXt=MagickFalse;
11507 mng_info->ping_exclude_tRNS=MagickFalse;
11508 mng_info->ping_exclude_vpAg=MagickFalse;
11509 mng_info->ping_exclude_zCCP=MagickFalse;
11510 mng_info->ping_exclude_zTXt=MagickFalse;
11513 if (LocaleNCompare(value+i,"bkgd",4) == 0)
11514 mng_info->ping_exclude_bKGD=MagickTrue;
11516 if (LocaleNCompare(value+i,"chrm",4) == 0)
11517 mng_info->ping_exclude_cHRM=MagickTrue;
11519 if (LocaleNCompare(value+i,"date",4) == 0)
11520 mng_info->ping_exclude_date=MagickTrue;
11522 if (LocaleNCompare(value+i,"exif",4) == 0)
11523 mng_info->ping_exclude_EXIF=MagickTrue;
11525 if (LocaleNCompare(value+i,"gama",4) == 0)
11526 mng_info->ping_exclude_gAMA=MagickTrue;
11528 if (LocaleNCompare(value+i,"iccp",4) == 0)
11529 mng_info->ping_exclude_iCCP=MagickTrue;
11532 if (LocaleNCompare(value+i,"itxt",4) == 0)
11533 mng_info->ping_exclude_iTXt=MagickTrue;
11536 if (LocaleNCompare(value+i,"gama",4) == 0)
11537 mng_info->ping_exclude_gAMA=MagickTrue;
11539 if (LocaleNCompare(value+i,"offs",4) == 0)
11540 mng_info->ping_exclude_oFFs=MagickTrue;
11542 if (LocaleNCompare(value+i,"phys",4) == 0)
11543 mng_info->ping_exclude_pHYs=MagickTrue;
11545 if (LocaleNCompare(value+i,"srgb",4) == 0)
11546 mng_info->ping_exclude_sRGB=MagickTrue;
11548 if (LocaleNCompare(value+i,"text",4) == 0)
11549 mng_info->ping_exclude_tEXt=MagickTrue;
11551 if (LocaleNCompare(value+i,"trns",4) == 0)
11552 mng_info->ping_exclude_tRNS=MagickTrue;
11554 if (LocaleNCompare(value+i,"vpag",4) == 0)
11555 mng_info->ping_exclude_vpAg=MagickTrue;
11557 if (LocaleNCompare(value+i,"zccp",4) == 0)
11558 mng_info->ping_exclude_zCCP=MagickTrue;
11560 if (LocaleNCompare(value+i,"ztxt",4) == 0)
11561 mng_info->ping_exclude_zTXt=MagickTrue;
11567 for (source=0; source<1; source++)
11571 value=GetImageArtifact(image,"png:include-chunk");
11574 value=GetImageArtifact(image,"png:include-chunks");
11578 value=GetImageOption(image_info,"png:include-chunk");
11581 value=GetImageOption(image_info,"png:include-chunks");
11589 excluding=MagickTrue;
11591 if (logging != MagickFalse)
11594 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11595 " png:include-chunk=%s found in image artifacts.\n", value);
11597 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11598 " png:include-chunk=%s found in image properties.\n", value);
11601 last=strlen(value);
11603 for (i=0; i<(int) last; i+=5)
11605 if (LocaleNCompare(value+i,"all",3) == 0)
11607 mng_info->ping_exclude_bKGD=MagickFalse;
11608 mng_info->ping_exclude_cHRM=MagickFalse;
11609 mng_info->ping_exclude_date=MagickFalse;
11610 mng_info->ping_exclude_EXIF=MagickFalse;
11611 mng_info->ping_exclude_gAMA=MagickFalse;
11612 mng_info->ping_exclude_iCCP=MagickFalse;
11613 /* mng_info->ping_exclude_iTXt=MagickFalse; */
11614 mng_info->ping_exclude_oFFs=MagickFalse;
11615 mng_info->ping_exclude_pHYs=MagickFalse;
11616 mng_info->ping_exclude_sRGB=MagickFalse;
11617 mng_info->ping_exclude_tEXt=MagickFalse;
11618 mng_info->ping_exclude_tRNS=MagickFalse;
11619 mng_info->ping_exclude_vpAg=MagickFalse;
11620 mng_info->ping_exclude_zCCP=MagickFalse;
11621 mng_info->ping_exclude_zTXt=MagickFalse;
11625 if (LocaleNCompare(value+i,"none",4) == 0)
11627 mng_info->ping_exclude_bKGD=MagickTrue;
11628 mng_info->ping_exclude_cHRM=MagickTrue;
11629 mng_info->ping_exclude_date=MagickTrue;
11630 mng_info->ping_exclude_EXIF=MagickTrue;
11631 mng_info->ping_exclude_gAMA=MagickTrue;
11632 mng_info->ping_exclude_iCCP=MagickTrue;
11633 /* mng_info->ping_exclude_iTXt=MagickTrue; */
11634 mng_info->ping_exclude_oFFs=MagickTrue;
11635 mng_info->ping_exclude_pHYs=MagickTrue;
11636 mng_info->ping_exclude_sRGB=MagickTrue;
11637 mng_info->ping_exclude_tEXt=MagickTrue;
11638 mng_info->ping_exclude_tRNS=MagickTrue;
11639 mng_info->ping_exclude_vpAg=MagickTrue;
11640 mng_info->ping_exclude_zCCP=MagickTrue;
11641 mng_info->ping_exclude_zTXt=MagickTrue;
11644 if (LocaleNCompare(value+i,"bkgd",4) == 0)
11645 mng_info->ping_exclude_bKGD=MagickFalse;
11647 if (LocaleNCompare(value+i,"chrm",4) == 0)
11648 mng_info->ping_exclude_cHRM=MagickFalse;
11650 if (LocaleNCompare(value+i,"date",4) == 0)
11651 mng_info->ping_exclude_date=MagickFalse;
11653 if (LocaleNCompare(value+i,"exif",4) == 0)
11654 mng_info->ping_exclude_EXIF=MagickFalse;
11656 if (LocaleNCompare(value+i,"gama",4) == 0)
11657 mng_info->ping_exclude_gAMA=MagickFalse;
11659 if (LocaleNCompare(value+i,"iccp",4) == 0)
11660 mng_info->ping_exclude_iCCP=MagickFalse;
11663 if (LocaleNCompare(value+i,"itxt",4) == 0)
11664 mng_info->ping_exclude_iTXt=MagickFalse;
11667 if (LocaleNCompare(value+i,"gama",4) == 0)
11668 mng_info->ping_exclude_gAMA=MagickFalse;
11670 if (LocaleNCompare(value+i,"offs",4) == 0)
11671 mng_info->ping_exclude_oFFs=MagickFalse;
11673 if (LocaleNCompare(value+i,"phys",4) == 0)
11674 mng_info->ping_exclude_pHYs=MagickFalse;
11676 if (LocaleNCompare(value+i,"srgb",4) == 0)
11677 mng_info->ping_exclude_sRGB=MagickFalse;
11679 if (LocaleNCompare(value+i,"text",4) == 0)
11680 mng_info->ping_exclude_tEXt=MagickFalse;
11682 if (LocaleNCompare(value+i,"trns",4) == 0)
11683 mng_info->ping_exclude_tRNS=MagickFalse;
11685 if (LocaleNCompare(value+i,"vpag",4) == 0)
11686 mng_info->ping_exclude_vpAg=MagickFalse;
11688 if (LocaleNCompare(value+i,"zccp",4) == 0)
11689 mng_info->ping_exclude_zCCP=MagickFalse;
11691 if (LocaleNCompare(value+i,"ztxt",4) == 0)
11692 mng_info->ping_exclude_zTXt=MagickFalse;
11698 if (excluding != MagickFalse && logging != MagickFalse)
11700 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11701 " Chunks to be excluded from the output png:");
11702 if (mng_info->ping_exclude_bKGD != MagickFalse)
11703 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11705 if (mng_info->ping_exclude_cHRM != MagickFalse)
11706 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11708 if (mng_info->ping_exclude_date != MagickFalse)
11709 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11711 if (mng_info->ping_exclude_EXIF != MagickFalse)
11712 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11714 if (mng_info->ping_exclude_gAMA != MagickFalse)
11715 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11717 if (mng_info->ping_exclude_iCCP != MagickFalse)
11718 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11721 if (mng_info->ping_exclude_iTXt != MagickFalse)
11722 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11725 if (mng_info->ping_exclude_oFFs != MagickFalse)
11726 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11728 if (mng_info->ping_exclude_pHYs != MagickFalse)
11729 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11731 if (mng_info->ping_exclude_sRGB != MagickFalse)
11732 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11734 if (mng_info->ping_exclude_tEXt != MagickFalse)
11735 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11737 if (mng_info->ping_exclude_tRNS != MagickFalse)
11738 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11740 if (mng_info->ping_exclude_vpAg != MagickFalse)
11741 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11743 if (mng_info->ping_exclude_zCCP != MagickFalse)
11744 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11746 if (mng_info->ping_exclude_zTXt != MagickFalse)
11747 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11751 mng_info->need_blob = MagickTrue;
11753 status=WriteOnePNGImage(mng_info,image_info,image,exception);
11755 MngInfoFreeStruct(mng_info,&have_mng_structure);
11757 if (logging != MagickFalse)
11758 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit WritePNGImage()");
11763 #if defined(JNG_SUPPORTED)
11765 /* Write one JNG image */
11766 static MagickBooleanType WriteOneJNGImage(MngInfo *mng_info,
11767 const ImageInfo *image_info,Image *image,ExceptionInfo *exception)
11788 jng_alpha_compression_method,
11789 jng_alpha_sample_depth,
11797 logging=LogMagickEvent(CoderEvent,GetMagickModule(),
11798 " Enter WriteOneJNGImage()");
11800 blob=(unsigned char *) NULL;
11801 jpeg_image=(Image *) NULL;
11802 jpeg_image_info=(ImageInfo *) NULL;
11805 transparent=image_info->type==GrayscaleMatteType ||
11806 image_info->type==TrueColorMatteType || image->alpha_trait == BlendPixelTrait;
11808 jng_quality=image_info->quality == 0UL ? 75UL : image_info->quality%1000;
11810 jng_alpha_compression_method=image->compression==JPEGCompression? 8 : 0;
11812 jng_alpha_quality=image_info->quality == 0UL ? 75UL :
11813 image_info->quality;
11815 if (jng_alpha_quality >= 1000)
11816 jng_alpha_quality /= 1000;
11822 /* Create JPEG blob, image, and image_info */
11823 if (logging != MagickFalse)
11824 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11825 " Creating jpeg_image_info for alpha.");
11827 jpeg_image_info=(ImageInfo *) CloneImageInfo(image_info);
11829 if (jpeg_image_info == (ImageInfo *) NULL)
11830 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
11832 if (logging != MagickFalse)
11833 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11834 " Creating jpeg_image.");
11836 jpeg_image=SeparateImage(image,AlphaChannel,exception);
11837 if (jpeg_image == (Image *) NULL)
11838 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
11839 (void) CopyMagickString(jpeg_image->magick,"JPEG",MaxTextExtent);
11840 jpeg_image->alpha_trait=UndefinedPixelTrait;
11841 jpeg_image->quality=jng_alpha_quality;
11842 jpeg_image_info->type=GrayscaleType;
11843 (void) SetImageType(jpeg_image,GrayscaleType,exception);
11844 (void) AcquireUniqueFilename(jpeg_image->filename);
11845 (void) FormatLocaleString(jpeg_image_info->filename,MaxTextExtent,
11846 "%s",jpeg_image->filename);
11850 jng_alpha_compression_method=0;
11852 jng_alpha_sample_depth=0;
11855 /* To do: check bit depth of PNG alpha channel */
11857 /* Check if image is grayscale. */
11858 if (image_info->type != TrueColorMatteType && image_info->type !=
11859 TrueColorType && IsImageGray(image,exception))
11862 if (logging != MagickFalse)
11864 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11865 " JNG Quality = %d",(int) jng_quality);
11866 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11867 " JNG Color Type = %d",jng_color_type);
11870 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11871 " JNG Alpha Compression = %d",jng_alpha_compression_method);
11872 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11873 " JNG Alpha Depth = %d",jng_alpha_sample_depth);
11874 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11875 " JNG Alpha Quality = %d",(int) jng_alpha_quality);
11881 if (jng_alpha_compression_method==0)
11886 /* Encode alpha as a grayscale PNG blob */
11887 status=OpenBlob(jpeg_image_info,jpeg_image,WriteBinaryBlobMode,
11889 if (logging != MagickFalse)
11890 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11891 " Creating PNG blob.");
11894 (void) CopyMagickString(jpeg_image_info->magick,"PNG",MaxTextExtent);
11895 (void) CopyMagickString(jpeg_image->magick,"PNG",MaxTextExtent);
11896 jpeg_image_info->interlace=NoInterlace;
11898 /* Exclude all ancillary chunks */
11899 (void) SetImageArtifact(jpeg_image,"png:exclude-chunks","all");
11901 blob=ImageToBlob(jpeg_image_info,jpeg_image,&length,
11904 /* Retrieve sample depth used */
11905 value=GetImageProperty(jpeg_image,"png:bit-depth-written",exception);
11906 if (value != (char *) NULL)
11907 jng_alpha_sample_depth= (unsigned int) value[0];
11911 /* Encode alpha as a grayscale JPEG blob */
11913 status=OpenBlob(jpeg_image_info,jpeg_image,WriteBinaryBlobMode,
11916 (void) CopyMagickString(jpeg_image_info->magick,"JPEG",MaxTextExtent);
11917 (void) CopyMagickString(jpeg_image->magick,"JPEG",MaxTextExtent);
11918 jpeg_image_info->interlace=NoInterlace;
11919 if (logging != MagickFalse)
11920 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11921 " Creating blob.");
11922 blob=ImageToBlob(jpeg_image_info,jpeg_image,&length,
11924 jng_alpha_sample_depth=8;
11926 if (logging != MagickFalse)
11927 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11928 " Successfully read jpeg_image into a blob, length=%.20g.",
11932 /* Destroy JPEG image and image_info */
11933 jpeg_image=DestroyImage(jpeg_image);
11934 (void) RelinquishUniqueFileResource(jpeg_image_info->filename);
11935 jpeg_image_info=DestroyImageInfo(jpeg_image_info);
11938 /* Write JHDR chunk */
11939 (void) WriteBlobMSBULong(image,16L); /* chunk data length=16 */
11940 PNGType(chunk,mng_JHDR);
11941 LogPNGChunk(logging,mng_JHDR,16L);
11942 PNGLong(chunk+4,(png_uint_32) image->columns);
11943 PNGLong(chunk+8,(png_uint_32) image->rows);
11944 chunk[12]=jng_color_type;
11945 chunk[13]=8; /* sample depth */
11946 chunk[14]=8; /*jng_image_compression_method */
11947 chunk[15]=(unsigned char) (image_info->interlace == NoInterlace ? 0 : 8);
11948 chunk[16]=jng_alpha_sample_depth;
11949 chunk[17]=jng_alpha_compression_method;
11950 chunk[18]=0; /*jng_alpha_filter_method */
11951 chunk[19]=0; /*jng_alpha_interlace_method */
11952 (void) WriteBlob(image,20,chunk);
11953 (void) WriteBlobMSBULong(image,crc32(0,chunk,20));
11954 if (logging != MagickFalse)
11956 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11957 " JNG width:%15lu",(unsigned long) image->columns);
11959 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11960 " JNG height:%14lu",(unsigned long) image->rows);
11962 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11963 " JNG color type:%10d",jng_color_type);
11965 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11966 " JNG sample depth:%8d",8);
11968 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11969 " JNG compression:%9d",8);
11971 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11972 " JNG interlace:%11d",0);
11974 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11975 " JNG alpha depth:%9d",jng_alpha_sample_depth);
11977 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11978 " JNG alpha compression:%3d",jng_alpha_compression_method);
11980 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11981 " JNG alpha filter:%8d",0);
11983 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11984 " JNG alpha interlace:%5d",0);
11987 /* Write any JNG-chunk-b profiles */
11988 (void) Magick_png_write_chunk_from_profile(image,"JNG-chunk-b",logging);
11991 Write leading ancillary chunks
11997 Write JNG bKGD chunk
12008 if (jng_color_type == 8 || jng_color_type == 12)
12012 (void) WriteBlobMSBULong(image,(size_t) (num_bytes-4L));
12013 PNGType(chunk,mng_bKGD);
12014 LogPNGChunk(logging,mng_bKGD,(size_t) (num_bytes-4L));
12015 red=ScaleQuantumToChar(image->background_color.red);
12016 green=ScaleQuantumToChar(image->background_color.green);
12017 blue=ScaleQuantumToChar(image->background_color.blue);
12024 (void) WriteBlob(image,(size_t) num_bytes,chunk);
12025 (void) WriteBlobMSBULong(image,crc32(0,chunk,(uInt) num_bytes));
12028 if ((image->colorspace == sRGBColorspace || image->rendering_intent))
12031 Write JNG sRGB chunk
12033 (void) WriteBlobMSBULong(image,1L);
12034 PNGType(chunk,mng_sRGB);
12035 LogPNGChunk(logging,mng_sRGB,1L);
12037 if (image->rendering_intent != UndefinedIntent)
12038 chunk[4]=(unsigned char)
12039 Magick_RenderingIntent_to_PNG_RenderingIntent(
12040 (image->rendering_intent));
12043 chunk[4]=(unsigned char)
12044 Magick_RenderingIntent_to_PNG_RenderingIntent(
12045 (PerceptualIntent));
12047 (void) WriteBlob(image,5,chunk);
12048 (void) WriteBlobMSBULong(image,crc32(0,chunk,5));
12052 if (image->gamma != 0.0)
12055 Write JNG gAMA chunk
12057 (void) WriteBlobMSBULong(image,4L);
12058 PNGType(chunk,mng_gAMA);
12059 LogPNGChunk(logging,mng_gAMA,4L);
12060 PNGLong(chunk+4,(png_uint_32) (100000*image->gamma+0.5));
12061 (void) WriteBlob(image,8,chunk);
12062 (void) WriteBlobMSBULong(image,crc32(0,chunk,8));
12065 if ((mng_info->equal_chrms == MagickFalse) &&
12066 (image->chromaticity.red_primary.x != 0.0))
12072 Write JNG cHRM chunk
12074 (void) WriteBlobMSBULong(image,32L);
12075 PNGType(chunk,mng_cHRM);
12076 LogPNGChunk(logging,mng_cHRM,32L);
12077 primary=image->chromaticity.white_point;
12078 PNGLong(chunk+4,(png_uint_32) (100000*primary.x+0.5));
12079 PNGLong(chunk+8,(png_uint_32) (100000*primary.y+0.5));
12080 primary=image->chromaticity.red_primary;
12081 PNGLong(chunk+12,(png_uint_32) (100000*primary.x+0.5));
12082 PNGLong(chunk+16,(png_uint_32) (100000*primary.y+0.5));
12083 primary=image->chromaticity.green_primary;
12084 PNGLong(chunk+20,(png_uint_32) (100000*primary.x+0.5));
12085 PNGLong(chunk+24,(png_uint_32) (100000*primary.y+0.5));
12086 primary=image->chromaticity.blue_primary;
12087 PNGLong(chunk+28,(png_uint_32) (100000*primary.x+0.5));
12088 PNGLong(chunk+32,(png_uint_32) (100000*primary.y+0.5));
12089 (void) WriteBlob(image,36,chunk);
12090 (void) WriteBlobMSBULong(image,crc32(0,chunk,36));
12094 if (image->resolution.x && image->resolution.y && !mng_info->equal_physs)
12097 Write JNG pHYs chunk
12099 (void) WriteBlobMSBULong(image,9L);
12100 PNGType(chunk,mng_pHYs);
12101 LogPNGChunk(logging,mng_pHYs,9L);
12102 if (image->units == PixelsPerInchResolution)
12104 PNGLong(chunk+4,(png_uint_32)
12105 (image->resolution.x*100.0/2.54+0.5));
12107 PNGLong(chunk+8,(png_uint_32)
12108 (image->resolution.y*100.0/2.54+0.5));
12115 if (image->units == PixelsPerCentimeterResolution)
12117 PNGLong(chunk+4,(png_uint_32)
12118 (image->resolution.x*100.0+0.5));
12120 PNGLong(chunk+8,(png_uint_32)
12121 (image->resolution.y*100.0+0.5));
12128 PNGLong(chunk+4,(png_uint_32) (image->resolution.x+0.5));
12129 PNGLong(chunk+8,(png_uint_32) (image->resolution.y+0.5));
12133 (void) WriteBlob(image,13,chunk);
12134 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
12137 if (mng_info->write_mng == 0 && (image->page.x || image->page.y))
12140 Write JNG oFFs chunk
12142 (void) WriteBlobMSBULong(image,9L);
12143 PNGType(chunk,mng_oFFs);
12144 LogPNGChunk(logging,mng_oFFs,9L);
12145 PNGsLong(chunk+4,(ssize_t) (image->page.x));
12146 PNGsLong(chunk+8,(ssize_t) (image->page.y));
12148 (void) WriteBlob(image,13,chunk);
12149 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
12151 if (mng_info->write_mng == 0 && (image->page.width || image->page.height))
12153 (void) WriteBlobMSBULong(image,9L); /* data length=8 */
12154 PNGType(chunk,mng_vpAg);
12155 LogPNGChunk(logging,mng_vpAg,9L);
12156 PNGLong(chunk+4,(png_uint_32) image->page.width);
12157 PNGLong(chunk+8,(png_uint_32) image->page.height);
12158 chunk[12]=0; /* unit = pixels */
12159 (void) WriteBlob(image,13,chunk);
12160 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
12166 if (jng_alpha_compression_method==0)
12174 /* Write IDAT chunk header */
12175 if (logging != MagickFalse)
12176 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12177 " Write IDAT chunks from blob, length=%.20g.",(double)
12180 /* Copy IDAT chunks */
12183 for (i=8; i<(ssize_t) length; i+=len+12)
12185 len=(*p<<24)|((*(p+1))<<16)|((*(p+2))<<8)|(*(p+3));
12188 if (*(p)==73 && *(p+1)==68 && *(p+2)==65 && *(p+3)==84) /* IDAT */
12190 /* Found an IDAT chunk. */
12191 (void) WriteBlobMSBULong(image,(size_t) len);
12192 LogPNGChunk(logging,mng_IDAT,(size_t) len);
12193 (void) WriteBlob(image,(size_t) len+4,p);
12194 (void) WriteBlobMSBULong(image,
12195 crc32(0,p,(uInt) len+4));
12200 if (logging != MagickFalse)
12201 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12202 " Skipping %c%c%c%c chunk, length=%.20g.",
12203 *(p),*(p+1),*(p+2),*(p+3),(double) len);
12210 /* Write JDAA chunk header */
12211 if (logging != MagickFalse)
12212 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12213 " Write JDAA chunk, length=%.20g.",(double) length);
12214 (void) WriteBlobMSBULong(image,(size_t) length);
12215 PNGType(chunk,mng_JDAA);
12216 LogPNGChunk(logging,mng_JDAA,length);
12217 /* Write JDAT chunk(s) data */
12218 (void) WriteBlob(image,4,chunk);
12219 (void) WriteBlob(image,length,blob);
12220 (void) WriteBlobMSBULong(image,crc32(crc32(0,chunk,4),blob,
12223 blob=(unsigned char *) RelinquishMagickMemory(blob);
12226 /* Encode image as a JPEG blob */
12227 if (logging != MagickFalse)
12228 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12229 " Creating jpeg_image_info.");
12230 jpeg_image_info=(ImageInfo *) CloneImageInfo(image_info);
12231 if (jpeg_image_info == (ImageInfo *) NULL)
12232 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
12234 if (logging != MagickFalse)
12235 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12236 " Creating jpeg_image.");
12238 jpeg_image=CloneImage(image,0,0,MagickTrue,exception);
12239 if (jpeg_image == (Image *) NULL)
12240 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
12241 (void) CopyMagickString(jpeg_image->magick,"JPEG",MaxTextExtent);
12243 (void) AcquireUniqueFilename(jpeg_image->filename);
12244 (void) FormatLocaleString(jpeg_image_info->filename,MaxTextExtent,"%s",
12245 jpeg_image->filename);
12247 status=OpenBlob(jpeg_image_info,jpeg_image,WriteBinaryBlobMode,
12250 if (logging != MagickFalse)
12251 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12252 " Created jpeg_image, %.20g x %.20g.",(double) jpeg_image->columns,
12253 (double) jpeg_image->rows);
12255 if (jng_color_type == 8 || jng_color_type == 12)
12256 jpeg_image_info->type=GrayscaleType;
12258 jpeg_image_info->quality=jng_quality;
12259 jpeg_image->quality=jng_quality;
12260 (void) CopyMagickString(jpeg_image_info->magick,"JPEG",MaxTextExtent);
12261 (void) CopyMagickString(jpeg_image->magick,"JPEG",MaxTextExtent);
12263 if (logging != MagickFalse)
12264 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12265 " Creating blob.");
12267 blob=ImageToBlob(jpeg_image_info,jpeg_image,&length,exception);
12269 if (logging != MagickFalse)
12271 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12272 " Successfully read jpeg_image into a blob, length=%.20g.",
12275 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12276 " Write JDAT chunk, length=%.20g.",(double) length);
12279 /* Write JDAT chunk(s) */
12280 (void) WriteBlobMSBULong(image,(size_t) length);
12281 PNGType(chunk,mng_JDAT);
12282 LogPNGChunk(logging,mng_JDAT,length);
12283 (void) WriteBlob(image,4,chunk);
12284 (void) WriteBlob(image,length,blob);
12285 (void) WriteBlobMSBULong(image,crc32(crc32(0,chunk,4),blob,(uInt) length));
12287 jpeg_image=DestroyImage(jpeg_image);
12288 (void) RelinquishUniqueFileResource(jpeg_image_info->filename);
12289 jpeg_image_info=DestroyImageInfo(jpeg_image_info);
12290 blob=(unsigned char *) RelinquishMagickMemory(blob);
12292 /* Write any JNG-chunk-e profiles */
12293 (void) Magick_png_write_chunk_from_profile(image,"JNG-chunk-e",logging);
12295 /* Write IEND chunk */
12296 (void) WriteBlobMSBULong(image,0L);
12297 PNGType(chunk,mng_IEND);
12298 LogPNGChunk(logging,mng_IEND,0);
12299 (void) WriteBlob(image,4,chunk);
12300 (void) WriteBlobMSBULong(image,crc32(0,chunk,4));
12302 if (logging != MagickFalse)
12303 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12304 " exit WriteOneJNGImage()");
12311 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12315 % W r i t e J N G I m a g e %
12319 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12321 % WriteJNGImage() writes a JPEG Network Graphics (JNG) image file.
12323 % JNG support written by Glenn Randers-Pehrson, glennrp@image...
12325 % The format of the WriteJNGImage method is:
12327 % MagickBooleanType WriteJNGImage(const ImageInfo *image_info,
12328 % Image *image,ExceptionInfo *exception)
12330 % A description of each parameter follows:
12332 % o image_info: the image info.
12334 % o image: The image.
12336 % o exception: return any errors or warnings in this structure.
12338 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12340 static MagickBooleanType WriteJNGImage(const ImageInfo *image_info,Image *image,
12341 ExceptionInfo *exception)
12344 have_mng_structure,
12354 assert(image_info != (const ImageInfo *) NULL);
12355 assert(image_info->signature == MagickSignature);
12356 assert(image != (Image *) NULL);
12357 assert(image->signature == MagickSignature);
12358 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
12359 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter WriteJNGImage()");
12360 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
12361 if (status == MagickFalse)
12365 Allocate a MngInfo structure.
12367 have_mng_structure=MagickFalse;
12368 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
12369 if (mng_info == (MngInfo *) NULL)
12370 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
12372 Initialize members of the MngInfo structure.
12374 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
12375 mng_info->image=image;
12376 have_mng_structure=MagickTrue;
12378 (void) WriteBlob(image,8,(const unsigned char *) "\213JNG\r\n\032\n");
12380 status=WriteOneJNGImage(mng_info,image_info,image,exception);
12381 (void) CloseBlob(image);
12383 (void) CatchImageException(image);
12384 MngInfoFreeStruct(mng_info,&have_mng_structure);
12385 if (logging != MagickFalse)
12386 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit WriteJNGImage()");
12391 static MagickBooleanType WriteMNGImage(const ImageInfo *image_info,Image *image,
12392 ExceptionInfo *exception)
12401 have_mng_structure,
12404 volatile MagickBooleanType
12416 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
12417 defined(PNG_MNG_FEATURES_SUPPORTED)
12420 all_images_are_gray,
12430 volatile unsigned int
12441 #if (PNG_LIBPNG_VER < 10200)
12442 if (image_info->verbose)
12443 printf("Your PNG library (libpng-%s) is rather old.\n",
12444 PNG_LIBPNG_VER_STRING);
12450 assert(image_info != (const ImageInfo *) NULL);
12451 assert(image_info->signature == MagickSignature);
12452 assert(image != (Image *) NULL);
12453 assert(image->signature == MagickSignature);
12454 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
12455 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter WriteMNGImage()");
12456 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
12457 if (status == MagickFalse)
12461 Allocate a MngInfo structure.
12463 have_mng_structure=MagickFalse;
12464 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
12465 if (mng_info == (MngInfo *) NULL)
12466 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
12468 Initialize members of the MngInfo structure.
12470 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
12471 mng_info->image=image;
12472 have_mng_structure=MagickTrue;
12473 write_mng=LocaleCompare(image_info->magick,"MNG") == 0;
12476 * See if user has requested a specific PNG subformat to be used
12477 * for all of the PNGs in the MNG being written, e.g.,
12479 * convert *.png png8:animation.mng
12481 * To do: check -define png:bit_depth and png:color_type as well,
12482 * or perhaps use mng:bit_depth and mng:color_type instead for
12486 mng_info->write_png8=LocaleCompare(image_info->magick,"PNG8") == 0;
12487 mng_info->write_png24=LocaleCompare(image_info->magick,"PNG24") == 0;
12488 mng_info->write_png32=LocaleCompare(image_info->magick,"PNG32") == 0;
12490 write_jng=MagickFalse;
12491 if (image_info->compression == JPEGCompression)
12492 write_jng=MagickTrue;
12494 mng_info->adjoin=image_info->adjoin &&
12495 (GetNextImageInList(image) != (Image *) NULL) && write_mng;
12497 if (logging != MagickFalse)
12499 /* Log some info about the input */
12503 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12504 " Checking input image(s)");
12506 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12507 " Image_info depth: %.20g",(double) image_info->depth);
12509 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12510 " Type: %d",image_info->type);
12513 for (p=image; p != (Image *) NULL; p=GetNextImageInList(p))
12515 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12516 " Scene: %.20g",(double) scene++);
12518 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12519 " Image depth: %.20g",(double) p->depth);
12521 if (p->alpha_trait)
12522 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12526 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12529 if (p->storage_class == PseudoClass)
12530 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12531 " Storage class: PseudoClass");
12534 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12535 " Storage class: DirectClass");
12538 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12539 " Number of colors: %.20g",(double) p->colors);
12542 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12543 " Number of colors: unspecified");
12545 if (mng_info->adjoin == MagickFalse)
12550 use_global_plte=MagickFalse;
12551 all_images_are_gray=MagickFalse;
12552 #ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
12553 need_local_plte=MagickTrue;
12555 need_defi=MagickFalse;
12556 need_matte=MagickFalse;
12557 mng_info->framing_mode=1;
12558 mng_info->old_framing_mode=1;
12561 if (image_info->page != (char *) NULL)
12564 Determine image bounding box.
12566 SetGeometry(image,&mng_info->page);
12567 (void) ParseMetaGeometry(image_info->page,&mng_info->page.x,
12568 &mng_info->page.y,&mng_info->page.width,&mng_info->page.height);
12580 mng_info->page=image->page;
12581 need_geom=MagickTrue;
12582 if (mng_info->page.width || mng_info->page.height)
12583 need_geom=MagickFalse;
12585 Check all the scenes.
12587 initial_delay=image->delay;
12588 need_iterations=MagickFalse;
12589 mng_info->equal_chrms=image->chromaticity.red_primary.x != 0.0;
12590 mng_info->equal_physs=MagickTrue,
12591 mng_info->equal_gammas=MagickTrue;
12592 mng_info->equal_srgbs=MagickTrue;
12593 mng_info->equal_backgrounds=MagickTrue;
12595 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
12596 defined(PNG_MNG_FEATURES_SUPPORTED)
12597 all_images_are_gray=MagickTrue;
12598 mng_info->equal_palettes=MagickFalse;
12599 need_local_plte=MagickFalse;
12601 for (next_image=image; next_image != (Image *) NULL; )
12605 if ((next_image->columns+next_image->page.x) > mng_info->page.width)
12606 mng_info->page.width=next_image->columns+next_image->page.x;
12608 if ((next_image->rows+next_image->page.y) > mng_info->page.height)
12609 mng_info->page.height=next_image->rows+next_image->page.y;
12612 if (next_image->page.x || next_image->page.y)
12613 need_defi=MagickTrue;
12615 if (next_image->alpha_trait)
12616 need_matte=MagickTrue;
12618 if ((int) next_image->dispose >= BackgroundDispose)
12619 if (next_image->alpha_trait || next_image->page.x || next_image->page.y ||
12620 ((next_image->columns < mng_info->page.width) &&
12621 (next_image->rows < mng_info->page.height)))
12622 mng_info->need_fram=MagickTrue;
12624 if (next_image->iterations)
12625 need_iterations=MagickTrue;
12627 final_delay=next_image->delay;
12629 if (final_delay != initial_delay || final_delay > 1UL*
12630 next_image->ticks_per_second)
12631 mng_info->need_fram=1;
12633 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
12634 defined(PNG_MNG_FEATURES_SUPPORTED)
12636 check for global palette possibility.
12638 if (image->alpha_trait == BlendPixelTrait)
12639 need_local_plte=MagickTrue;
12641 if (need_local_plte == 0)
12643 if (IsImageGray(image,exception) == MagickFalse)
12644 all_images_are_gray=MagickFalse;
12645 mng_info->equal_palettes=PalettesAreEqual(image,next_image);
12646 if (use_global_plte == 0)
12647 use_global_plte=mng_info->equal_palettes;
12648 need_local_plte=!mng_info->equal_palettes;
12651 if (GetNextImageInList(next_image) != (Image *) NULL)
12653 if (next_image->background_color.red !=
12654 next_image->next->background_color.red ||
12655 next_image->background_color.green !=
12656 next_image->next->background_color.green ||
12657 next_image->background_color.blue !=
12658 next_image->next->background_color.blue)
12659 mng_info->equal_backgrounds=MagickFalse;
12661 if (next_image->gamma != next_image->next->gamma)
12662 mng_info->equal_gammas=MagickFalse;
12664 if (next_image->rendering_intent !=
12665 next_image->next->rendering_intent)
12666 mng_info->equal_srgbs=MagickFalse;
12668 if ((next_image->units != next_image->next->units) ||
12669 (next_image->resolution.x != next_image->next->resolution.x) ||
12670 (next_image->resolution.y != next_image->next->resolution.y))
12671 mng_info->equal_physs=MagickFalse;
12673 if (mng_info->equal_chrms)
12675 if (next_image->chromaticity.red_primary.x !=
12676 next_image->next->chromaticity.red_primary.x ||
12677 next_image->chromaticity.red_primary.y !=
12678 next_image->next->chromaticity.red_primary.y ||
12679 next_image->chromaticity.green_primary.x !=
12680 next_image->next->chromaticity.green_primary.x ||
12681 next_image->chromaticity.green_primary.y !=
12682 next_image->next->chromaticity.green_primary.y ||
12683 next_image->chromaticity.blue_primary.x !=
12684 next_image->next->chromaticity.blue_primary.x ||
12685 next_image->chromaticity.blue_primary.y !=
12686 next_image->next->chromaticity.blue_primary.y ||
12687 next_image->chromaticity.white_point.x !=
12688 next_image->next->chromaticity.white_point.x ||
12689 next_image->chromaticity.white_point.y !=
12690 next_image->next->chromaticity.white_point.y)
12691 mng_info->equal_chrms=MagickFalse;
12695 next_image=GetNextImageInList(next_image);
12697 if (image_count < 2)
12699 mng_info->equal_backgrounds=MagickFalse;
12700 mng_info->equal_chrms=MagickFalse;
12701 mng_info->equal_gammas=MagickFalse;
12702 mng_info->equal_srgbs=MagickFalse;
12703 mng_info->equal_physs=MagickFalse;
12704 use_global_plte=MagickFalse;
12705 #ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
12706 need_local_plte=MagickTrue;
12708 need_iterations=MagickFalse;
12711 if (mng_info->need_fram == MagickFalse)
12714 Only certain framing rates 100/n are exactly representable without
12715 the FRAM chunk but we'll allow some slop in VLC files
12717 if (final_delay == 0)
12719 if (need_iterations != MagickFalse)
12722 It's probably a GIF with loop; don't run it *too* fast.
12724 if (mng_info->adjoin)
12727 (void) ThrowMagickException(exception,GetMagickModule(),
12729 "input has zero delay between all frames; assuming",
12734 mng_info->ticks_per_second=0;
12736 if (final_delay != 0)
12737 mng_info->ticks_per_second=(png_uint_32)
12738 (image->ticks_per_second/final_delay);
12739 if (final_delay > 50)
12740 mng_info->ticks_per_second=2;
12742 if (final_delay > 75)
12743 mng_info->ticks_per_second=1;
12745 if (final_delay > 125)
12746 mng_info->need_fram=MagickTrue;
12748 if (need_defi && final_delay > 2 && (final_delay != 4) &&
12749 (final_delay != 5) && (final_delay != 10) && (final_delay != 20) &&
12750 (final_delay != 25) && (final_delay != 50) && (final_delay !=
12751 1UL*image->ticks_per_second))
12752 mng_info->need_fram=MagickTrue; /* make it exact; cannot be VLC */
12755 if (mng_info->need_fram != MagickFalse)
12756 mng_info->ticks_per_second=1UL*image->ticks_per_second;
12758 If pseudocolor, we should also check to see if all the
12759 palettes are identical and write a global PLTE if they are.
12763 Write the MNG version 1.0 signature and MHDR chunk.
12765 (void) WriteBlob(image,8,(const unsigned char *) "\212MNG\r\n\032\n");
12766 (void) WriteBlobMSBULong(image,28L); /* chunk data length=28 */
12767 PNGType(chunk,mng_MHDR);
12768 LogPNGChunk(logging,mng_MHDR,28L);
12769 PNGLong(chunk+4,(png_uint_32) mng_info->page.width);
12770 PNGLong(chunk+8,(png_uint_32) mng_info->page.height);
12771 PNGLong(chunk+12,mng_info->ticks_per_second);
12772 PNGLong(chunk+16,0L); /* layer count=unknown */
12773 PNGLong(chunk+20,0L); /* frame count=unknown */
12774 PNGLong(chunk+24,0L); /* play time=unknown */
12779 if (need_defi || mng_info->need_fram || use_global_plte)
12780 PNGLong(chunk+28,27L); /* simplicity=LC+JNG */
12783 PNGLong(chunk+28,25L); /* simplicity=VLC+JNG */
12788 if (need_defi || mng_info->need_fram || use_global_plte)
12789 PNGLong(chunk+28,19L); /* simplicity=LC+JNG, no transparency */
12792 PNGLong(chunk+28,17L); /* simplicity=VLC+JNG, no transparency */
12800 if (need_defi || mng_info->need_fram || use_global_plte)
12801 PNGLong(chunk+28,11L); /* simplicity=LC */
12804 PNGLong(chunk+28,9L); /* simplicity=VLC */
12809 if (need_defi || mng_info->need_fram || use_global_plte)
12810 PNGLong(chunk+28,3L); /* simplicity=LC, no transparency */
12813 PNGLong(chunk+28,1L); /* simplicity=VLC, no transparency */
12816 (void) WriteBlob(image,32,chunk);
12817 (void) WriteBlobMSBULong(image,crc32(0,chunk,32));
12818 option=GetImageOption(image_info,"mng:need-cacheoff");
12819 if (option != (const char *) NULL)
12825 Write "nEED CACHEOFF" to turn playback caching off for streaming MNG.
12827 PNGType(chunk,mng_nEED);
12828 length=CopyMagickString((char *) chunk+4,"CACHEOFF",20);
12829 (void) WriteBlobMSBULong(image,(size_t) length);
12830 LogPNGChunk(logging,mng_nEED,(size_t) length);
12832 (void) WriteBlob(image,length,chunk);
12833 (void) WriteBlobMSBULong(image,crc32(0,chunk,(uInt) length));
12835 if ((GetPreviousImageInList(image) == (Image *) NULL) &&
12836 (GetNextImageInList(image) != (Image *) NULL) &&
12837 (image->iterations != 1))
12840 Write MNG TERM chunk
12842 (void) WriteBlobMSBULong(image,10L); /* data length=10 */
12843 PNGType(chunk,mng_TERM);
12844 LogPNGChunk(logging,mng_TERM,10L);
12845 chunk[4]=3; /* repeat animation */
12846 chunk[5]=0; /* show last frame when done */
12847 PNGLong(chunk+6,(png_uint_32) (mng_info->ticks_per_second*
12848 final_delay/MagickMax(image->ticks_per_second,1)));
12850 if (image->iterations == 0)
12851 PNGLong(chunk+10,PNG_UINT_31_MAX);
12854 PNGLong(chunk+10,(png_uint_32) image->iterations);
12856 if (logging != MagickFalse)
12858 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12859 " TERM delay: %.20g",(double) (mng_info->ticks_per_second*
12860 final_delay/MagickMax(image->ticks_per_second,1)));
12862 if (image->iterations == 0)
12863 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12864 " TERM iterations: %.20g",(double) PNG_UINT_31_MAX);
12867 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12868 " Image iterations: %.20g",(double) image->iterations);
12870 (void) WriteBlob(image,14,chunk);
12871 (void) WriteBlobMSBULong(image,crc32(0,chunk,14));
12874 To do: check for cHRM+gAMA == sRGB, and write sRGB instead.
12876 if ((image->colorspace == sRGBColorspace || image->rendering_intent) &&
12877 mng_info->equal_srgbs)
12880 Write MNG sRGB chunk
12882 (void) WriteBlobMSBULong(image,1L);
12883 PNGType(chunk,mng_sRGB);
12884 LogPNGChunk(logging,mng_sRGB,1L);
12886 if (image->rendering_intent != UndefinedIntent)
12887 chunk[4]=(unsigned char)
12888 Magick_RenderingIntent_to_PNG_RenderingIntent(
12889 (image->rendering_intent));
12892 chunk[4]=(unsigned char)
12893 Magick_RenderingIntent_to_PNG_RenderingIntent(
12894 (PerceptualIntent));
12896 (void) WriteBlob(image,5,chunk);
12897 (void) WriteBlobMSBULong(image,crc32(0,chunk,5));
12898 mng_info->have_write_global_srgb=MagickTrue;
12903 if (image->gamma && mng_info->equal_gammas)
12906 Write MNG gAMA chunk
12908 (void) WriteBlobMSBULong(image,4L);
12909 PNGType(chunk,mng_gAMA);
12910 LogPNGChunk(logging,mng_gAMA,4L);
12911 PNGLong(chunk+4,(png_uint_32) (100000*image->gamma+0.5));
12912 (void) WriteBlob(image,8,chunk);
12913 (void) WriteBlobMSBULong(image,crc32(0,chunk,8));
12914 mng_info->have_write_global_gama=MagickTrue;
12916 if (mng_info->equal_chrms)
12922 Write MNG cHRM chunk
12924 (void) WriteBlobMSBULong(image,32L);
12925 PNGType(chunk,mng_cHRM);
12926 LogPNGChunk(logging,mng_cHRM,32L);
12927 primary=image->chromaticity.white_point;
12928 PNGLong(chunk+4,(png_uint_32) (100000*primary.x+0.5));
12929 PNGLong(chunk+8,(png_uint_32) (100000*primary.y+0.5));
12930 primary=image->chromaticity.red_primary;
12931 PNGLong(chunk+12,(png_uint_32) (100000*primary.x+0.5));
12932 PNGLong(chunk+16,(png_uint_32) (100000*primary.y+0.5));
12933 primary=image->chromaticity.green_primary;
12934 PNGLong(chunk+20,(png_uint_32) (100000*primary.x+0.5));
12935 PNGLong(chunk+24,(png_uint_32) (100000*primary.y+0.5));
12936 primary=image->chromaticity.blue_primary;
12937 PNGLong(chunk+28,(png_uint_32) (100000*primary.x+0.5));
12938 PNGLong(chunk+32,(png_uint_32) (100000*primary.y+0.5));
12939 (void) WriteBlob(image,36,chunk);
12940 (void) WriteBlobMSBULong(image,crc32(0,chunk,36));
12941 mng_info->have_write_global_chrm=MagickTrue;
12944 if (image->resolution.x && image->resolution.y && mng_info->equal_physs)
12947 Write MNG pHYs chunk
12949 (void) WriteBlobMSBULong(image,9L);
12950 PNGType(chunk,mng_pHYs);
12951 LogPNGChunk(logging,mng_pHYs,9L);
12953 if (image->units == PixelsPerInchResolution)
12955 PNGLong(chunk+4,(png_uint_32)
12956 (image->resolution.x*100.0/2.54+0.5));
12958 PNGLong(chunk+8,(png_uint_32)
12959 (image->resolution.y*100.0/2.54+0.5));
12966 if (image->units == PixelsPerCentimeterResolution)
12968 PNGLong(chunk+4,(png_uint_32)
12969 (image->resolution.x*100.0+0.5));
12971 PNGLong(chunk+8,(png_uint_32)
12972 (image->resolution.y*100.0+0.5));
12979 PNGLong(chunk+4,(png_uint_32) (image->resolution.x+0.5));
12980 PNGLong(chunk+8,(png_uint_32) (image->resolution.y+0.5));
12984 (void) WriteBlob(image,13,chunk);
12985 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
12988 Write MNG BACK chunk and global bKGD chunk, if the image is transparent
12989 or does not cover the entire frame.
12991 if (write_mng && (image->alpha_trait || image->page.x > 0 ||
12992 image->page.y > 0 || (image->page.width &&
12993 (image->page.width+image->page.x < mng_info->page.width))
12994 || (image->page.height && (image->page.height+image->page.y
12995 < mng_info->page.height))))
12997 (void) WriteBlobMSBULong(image,6L);
12998 PNGType(chunk,mng_BACK);
12999 LogPNGChunk(logging,mng_BACK,6L);
13000 red=ScaleQuantumToShort(image->background_color.red);
13001 green=ScaleQuantumToShort(image->background_color.green);
13002 blue=ScaleQuantumToShort(image->background_color.blue);
13003 PNGShort(chunk+4,red);
13004 PNGShort(chunk+6,green);
13005 PNGShort(chunk+8,blue);
13006 (void) WriteBlob(image,10,chunk);
13007 (void) WriteBlobMSBULong(image,crc32(0,chunk,10));
13008 if (mng_info->equal_backgrounds)
13010 (void) WriteBlobMSBULong(image,6L);
13011 PNGType(chunk,mng_bKGD);
13012 LogPNGChunk(logging,mng_bKGD,6L);
13013 (void) WriteBlob(image,10,chunk);
13014 (void) WriteBlobMSBULong(image,crc32(0,chunk,10));
13018 #ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
13019 if ((need_local_plte == MagickFalse) &&
13020 (image->storage_class == PseudoClass) &&
13021 (all_images_are_gray == MagickFalse))
13027 Write MNG PLTE chunk
13029 data_length=3*image->colors;
13030 (void) WriteBlobMSBULong(image,data_length);
13031 PNGType(chunk,mng_PLTE);
13032 LogPNGChunk(logging,mng_PLTE,data_length);
13034 for (i=0; i < (ssize_t) image->colors; i++)
13036 chunk[4+i*3]=(unsigned char) (ScaleQuantumToChar(
13037 image->colormap[i].red) & 0xff);
13038 chunk[5+i*3]=(unsigned char) (ScaleQuantumToChar(
13039 image->colormap[i].green) & 0xff);
13040 chunk[6+i*3]=(unsigned char) (ScaleQuantumToChar(
13041 image->colormap[i].blue) & 0xff);
13044 (void) WriteBlob(image,data_length+4,chunk);
13045 (void) WriteBlobMSBULong(image,crc32(0,chunk,(uInt) (data_length+4)));
13046 mng_info->have_write_global_plte=MagickTrue;
13052 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
13053 defined(PNG_MNG_FEATURES_SUPPORTED)
13054 mng_info->equal_palettes=MagickFalse;
13058 if (mng_info->adjoin)
13060 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
13061 defined(PNG_MNG_FEATURES_SUPPORTED)
13063 If we aren't using a global palette for the entire MNG, check to
13064 see if we can use one for two or more consecutive images.
13066 if (need_local_plte && use_global_plte && !all_images_are_gray)
13068 if (mng_info->IsPalette)
13071 When equal_palettes is true, this image has the same palette
13072 as the previous PseudoClass image
13074 mng_info->have_write_global_plte=mng_info->equal_palettes;
13075 mng_info->equal_palettes=PalettesAreEqual(image,image->next);
13076 if (mng_info->equal_palettes && !mng_info->have_write_global_plte)
13079 Write MNG PLTE chunk
13084 data_length=3*image->colors;
13085 (void) WriteBlobMSBULong(image,data_length);
13086 PNGType(chunk,mng_PLTE);
13087 LogPNGChunk(logging,mng_PLTE,data_length);
13089 for (i=0; i < (ssize_t) image->colors; i++)
13091 chunk[4+i*3]=ScaleQuantumToChar(image->colormap[i].red);
13092 chunk[5+i*3]=ScaleQuantumToChar(image->colormap[i].green);
13093 chunk[6+i*3]=ScaleQuantumToChar(image->colormap[i].blue);
13096 (void) WriteBlob(image,data_length+4,chunk);
13097 (void) WriteBlobMSBULong(image,crc32(0,chunk,
13098 (uInt) (data_length+4)));
13099 mng_info->have_write_global_plte=MagickTrue;
13103 mng_info->have_write_global_plte=MagickFalse;
13114 previous_x=mng_info->page.x;
13115 previous_y=mng_info->page.y;
13122 mng_info->page=image->page;
13123 if ((mng_info->page.x != previous_x) ||
13124 (mng_info->page.y != previous_y))
13126 (void) WriteBlobMSBULong(image,12L); /* data length=12 */
13127 PNGType(chunk,mng_DEFI);
13128 LogPNGChunk(logging,mng_DEFI,12L);
13129 chunk[4]=0; /* object 0 MSB */
13130 chunk[5]=0; /* object 0 LSB */
13131 chunk[6]=0; /* visible */
13132 chunk[7]=0; /* abstract */
13133 PNGLong(chunk+8,(png_uint_32) mng_info->page.x);
13134 PNGLong(chunk+12,(png_uint_32) mng_info->page.y);
13135 (void) WriteBlob(image,16,chunk);
13136 (void) WriteBlobMSBULong(image,crc32(0,chunk,16));
13141 mng_info->write_mng=write_mng;
13143 if ((int) image->dispose >= 3)
13144 mng_info->framing_mode=3;
13146 if (mng_info->need_fram && mng_info->adjoin &&
13147 ((image->delay != mng_info->delay) ||
13148 (mng_info->framing_mode != mng_info->old_framing_mode)))
13150 if (image->delay == mng_info->delay)
13153 Write a MNG FRAM chunk with the new framing mode.
13155 (void) WriteBlobMSBULong(image,1L); /* data length=1 */
13156 PNGType(chunk,mng_FRAM);
13157 LogPNGChunk(logging,mng_FRAM,1L);
13158 chunk[4]=(unsigned char) mng_info->framing_mode;
13159 (void) WriteBlob(image,5,chunk);
13160 (void) WriteBlobMSBULong(image,crc32(0,chunk,5));
13165 Write a MNG FRAM chunk with the delay.
13167 (void) WriteBlobMSBULong(image,10L); /* data length=10 */
13168 PNGType(chunk,mng_FRAM);
13169 LogPNGChunk(logging,mng_FRAM,10L);
13170 chunk[4]=(unsigned char) mng_info->framing_mode;
13171 chunk[5]=0; /* frame name separator (no name) */
13172 chunk[6]=2; /* flag for changing default delay */
13173 chunk[7]=0; /* flag for changing frame timeout */
13174 chunk[8]=0; /* flag for changing frame clipping */
13175 chunk[9]=0; /* flag for changing frame sync_id */
13176 PNGLong(chunk+10,(png_uint_32)
13177 ((mng_info->ticks_per_second*
13178 image->delay)/MagickMax(image->ticks_per_second,1)));
13179 (void) WriteBlob(image,14,chunk);
13180 (void) WriteBlobMSBULong(image,crc32(0,chunk,14));
13181 mng_info->delay=(png_uint_32) image->delay;
13183 mng_info->old_framing_mode=mng_info->framing_mode;
13186 #if defined(JNG_SUPPORTED)
13187 if (image_info->compression == JPEGCompression)
13192 if (logging != MagickFalse)
13193 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
13194 " Writing JNG object.");
13195 /* To do: specify the desired alpha compression method. */
13196 write_info=CloneImageInfo(image_info);
13197 write_info->compression=UndefinedCompression;
13198 status=WriteOneJNGImage(mng_info,write_info,image,exception);
13199 write_info=DestroyImageInfo(write_info);
13204 if (logging != MagickFalse)
13205 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
13206 " Writing PNG object.");
13208 mng_info->need_blob = MagickFalse;
13209 mng_info->ping_preserve_colormap = MagickFalse;
13211 /* We don't want any ancillary chunks written */
13212 mng_info->ping_exclude_bKGD=MagickTrue;
13213 mng_info->ping_exclude_cHRM=MagickTrue;
13214 mng_info->ping_exclude_date=MagickTrue;
13215 mng_info->ping_exclude_EXIF=MagickTrue;
13216 mng_info->ping_exclude_gAMA=MagickTrue;
13217 mng_info->ping_exclude_iCCP=MagickTrue;
13218 /* mng_info->ping_exclude_iTXt=MagickTrue; */
13219 mng_info->ping_exclude_oFFs=MagickTrue;
13220 mng_info->ping_exclude_pHYs=MagickTrue;
13221 mng_info->ping_exclude_sRGB=MagickTrue;
13222 mng_info->ping_exclude_tEXt=MagickTrue;
13223 mng_info->ping_exclude_tRNS=MagickTrue;
13224 mng_info->ping_exclude_vpAg=MagickTrue;
13225 mng_info->ping_exclude_zCCP=MagickTrue;
13226 mng_info->ping_exclude_zTXt=MagickTrue;
13228 status=WriteOnePNGImage(mng_info,image_info,image,exception);
13231 if (status == MagickFalse)
13233 MngInfoFreeStruct(mng_info,&have_mng_structure);
13234 (void) CloseBlob(image);
13235 return(MagickFalse);
13237 (void) CatchImageException(image);
13238 if (GetNextImageInList(image) == (Image *) NULL)
13240 image=SyncNextImageInList(image);
13241 status=SetImageProgress(image,SaveImagesTag,scene++,
13242 GetImageListLength(image));
13244 if (status == MagickFalse)
13247 } while (mng_info->adjoin);
13251 while (GetPreviousImageInList(image) != (Image *) NULL)
13252 image=GetPreviousImageInList(image);
13254 Write the MEND chunk.
13256 (void) WriteBlobMSBULong(image,0x00000000L);
13257 PNGType(chunk,mng_MEND);
13258 LogPNGChunk(logging,mng_MEND,0L);
13259 (void) WriteBlob(image,4,chunk);
13260 (void) WriteBlobMSBULong(image,crc32(0,chunk,4));
13263 Relinquish resources.
13265 (void) CloseBlob(image);
13266 MngInfoFreeStruct(mng_info,&have_mng_structure);
13268 if (logging != MagickFalse)
13269 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit WriteMNGImage()");
13271 return(MagickTrue);
13273 #else /* PNG_LIBPNG_VER > 10011 */
13275 static MagickBooleanType WritePNGImage(const ImageInfo *image_info,Image *image)
13278 printf("Your PNG library is too old: You have libpng-%s\n",
13279 PNG_LIBPNG_VER_STRING);
13281 ThrowBinaryException(CoderError,"PNG library is too old",
13282 image_info->filename);
13285 static MagickBooleanType WriteMNGImage(const ImageInfo *image_info,Image *image)
13287 return(WritePNGImage(image_info,image));
13289 #endif /* PNG_LIBPNG_VER > 10011 */