2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13 % Read/Write Portable Network Graphics Image Format %
17 % Glenn Randers-Pehrson %
21 % Copyright 1999-2012 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 (ScaleQuantumToChar(GetPixelRed(image,(pixel))) < 0x10 ? \
173 #define LBR01PixelGreen(pixel) \
174 (ScaleQuantumToChar(GetPixelGreen(image,(pixel))) < 0x10 ? \
177 #define LBR01PixelBlue(pixel) \
178 (ScaleQuantumToChar(GetPixelBlue(image,(pixel))) < 0x10 ? \
181 #define LBR01PixelAlpha(pixel) \
182 (ScaleQuantumToChar(GetPixelAlpha(image,(pixel))) < 0x10 ? \
185 #define LBR01PixelRGB(pixel) \
187 LBR01PixelRed((pixel)); \
188 LBR01PixelGreen((pixel)); \
189 LBR01PixelBlue((pixel)); \
192 #define LBR01PixelRGBA(pixel) \
194 LBR01PixelRGB((pixel)); \
195 LBR01PixelAlpha((pixel)); \
198 /* LBR02: Replicate top 2 bits */
200 #define LBR02PacketRed(pixelpacket) \
202 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).red) & 0xc0; \
203 (pixelpacket).red=ScaleCharToQuantum( \
204 (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))); \
206 #define LBR02PacketGreen(pixelpacket) \
208 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).green) & 0xc0; \
209 (pixelpacket).green=ScaleCharToQuantum( \
210 (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))); \
212 #define LBR02PacketBlue(pixelpacket) \
214 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).blue) & 0xc0; \
215 (pixelpacket).blue=ScaleCharToQuantum( \
216 (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))); \
218 #define LBR02PacketAlpha(pixelpacket) \
220 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).alpha) & 0xc0; \
221 (pixelpacket).alpha=ScaleCharToQuantum( \
222 (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))); \
225 #define LBR02PacketRGB(pixelpacket) \
227 LBR02PacketRed((pixelpacket)); \
228 LBR02PacketGreen((pixelpacket)); \
229 LBR02PacketBlue((pixelpacket)); \
232 #define LBR02PacketRGBO(pixelpacket) \
234 LBR02PacketRGB((pixelpacket)); \
235 LBR02PacketAlpha((pixelpacket)); \
238 #define LBR02PixelRed(pixel) \
240 unsigned char lbr_bits=ScaleQuantumToChar(GetPixelRed(image,(pixel))) \
242 SetPixelRed(image, ScaleCharToQuantum( \
243 (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))), \
246 #define LBR02PixelGreen(pixel) \
248 unsigned char lbr_bits=ScaleQuantumToChar(GetPixelGreen(image,(pixel)))\
250 SetPixelGreen(image, ScaleCharToQuantum( \
251 (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))), \
254 #define LBR02PixelBlue(pixel) \
256 unsigned char lbr_bits= \
257 ScaleQuantumToChar(GetPixelBlue(image,(pixel))) & 0xc0; \
258 SetPixelBlue(image, ScaleCharToQuantum( \
259 (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))), \
262 #define LBR02PixelAlpha(pixel) \
264 unsigned char lbr_bits= \
265 ScaleQuantumToChar(GetPixelAlpha(image,(pixel))) & 0xc0; \
266 SetPixelAlpha(image, ScaleCharToQuantum( \
267 (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))), \
271 #define LBR02PixelRGB(pixel) \
273 LBR02PixelRed((pixel)); \
274 LBR02PixelGreen((pixel)); \
275 LBR02PixelBlue((pixel)); \
278 #define LBR02PixelRGBA(pixel) \
280 LBR02PixelRGB((pixel)); \
281 LBR02PixelAlpha((pixel)); \
284 /* LBR03: Replicate top 3 bits (only used with opaque pixels during
285 PNG8 quantization) */
287 #define LBR03PacketRed(pixelpacket) \
289 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).red) & 0xe0; \
290 (pixelpacket).red=ScaleCharToQuantum( \
291 (lbr_bits | (lbr_bits >> 3) | (lbr_bits >> 6))); \
293 #define LBR03PacketGreen(pixelpacket) \
295 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).green) & 0xe0; \
296 (pixelpacket).green=ScaleCharToQuantum( \
297 (lbr_bits | (lbr_bits >> 3) | (lbr_bits >> 6))); \
299 #define LBR03PacketBlue(pixelpacket) \
301 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).blue) & 0xe0; \
302 (pixelpacket).blue=ScaleCharToQuantum( \
303 (lbr_bits | (lbr_bits >> 3) | (lbr_bits >> 6))); \
306 #define LBR03PacketRGB(pixelpacket) \
308 LBR03PacketRed((pixelpacket)); \
309 LBR03PacketGreen((pixelpacket)); \
310 LBR03PacketBlue((pixelpacket)); \
313 #define LBR03PixelRed(pixel) \
315 unsigned char lbr_bits=ScaleQuantumToChar(GetPixelRed(image,(pixel))) \
317 SetPixelRed(image, ScaleCharToQuantum( \
318 (lbr_bits | (lbr_bits >> 3) | (lbr_bits >> 6))), (pixel)); \
320 #define LBR03Green(pixel) \
322 unsigned char lbr_bits=ScaleQuantumToChar(GetPixelGreen(image,(pixel)))\
324 SetPixelGreen(image, ScaleCharToQuantum( \
325 (lbr_bits | (lbr_bits >> 3) | (lbr_bits >> 6))), (pixel)); \
327 #define LBR03Blue(pixel) \
329 unsigned char lbr_bits=ScaleQuantumToChar(GetPixelBlue(image,(pixel))) \
331 SetPixelBlue(image, ScaleCharToQuantum( \
332 (lbr_bits | (lbr_bits >> 3) | (lbr_bits >> 6))), (pixel)); \
335 #define LBR03RGB(pixel) \
337 LBR03PixelRed((pixel)); \
338 LBR03Green((pixel)); \
339 LBR03Blue((pixel)); \
342 /* LBR04: Replicate top 4 bits */
344 #define LBR04PacketRed(pixelpacket) \
346 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).red) & 0xf0; \
347 (pixelpacket).red=ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))); \
349 #define LBR04PacketGreen(pixelpacket) \
351 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).green) & 0xf0; \
352 (pixelpacket).green=ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))); \
354 #define LBR04PacketBlue(pixelpacket) \
356 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).blue) & 0xf0; \
357 (pixelpacket).blue=ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))); \
359 #define LBR04PacketAlpha(pixelpacket) \
361 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).alpha) & 0xf0; \
362 (pixelpacket).alpha=ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))); \
365 #define LBR04PacketRGB(pixelpacket) \
367 LBR04PacketRed((pixelpacket)); \
368 LBR04PacketGreen((pixelpacket)); \
369 LBR04PacketBlue((pixelpacket)); \
372 #define LBR04PacketRGBO(pixelpacket) \
374 LBR04PacketRGB((pixelpacket)); \
375 LBR04PacketAlpha((pixelpacket)); \
378 #define LBR04PixelRed(pixel) \
380 unsigned char lbr_bits=ScaleQuantumToChar(GetPixelRed(image,(pixel))) \
383 ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))), (pixel)); \
385 #define LBR04PixelGreen(pixel) \
387 unsigned char lbr_bits=ScaleQuantumToChar(GetPixelGreen(image,(pixel)))\
389 SetPixelGreen(image,\
390 ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))), (pixel)); \
392 #define LBR04PixelBlue(pixel) \
394 unsigned char lbr_bits= \
395 ScaleQuantumToChar(GetPixelBlue(image,(pixel))) & 0xf0; \
397 ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))), (pixel)); \
399 #define LBR04PixelAlpha(pixel) \
401 unsigned char lbr_bits= \
402 ScaleQuantumToChar(GetPixelAlpha(image,(pixel))) & 0xf0; \
403 SetPixelAlpha(image,\
404 ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))), (pixel)); \
407 #define LBR04PixelRGB(pixel) \
409 LBR04PixelRed((pixel)); \
410 LBR04PixelGreen((pixel)); \
411 LBR04PixelBlue((pixel)); \
414 #define LBR04PixelRGBA(pixel) \
416 LBR04PixelRGB((pixel)); \
417 LBR04PixelAlpha((pixel)); \
421 /* LBR08: Replicate top 8 bits */
423 #define LBR08PacketRed(pixelpacket) \
425 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).red); \
426 (pixelpacket).red=ScaleCharToQuantum((lbr_bits)); \
428 #define LBR08PacketGreen(pixelpacket) \
430 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).green); \
431 (pixelpacket).green=ScaleCharToQuantum((lbr_bits)); \
433 #define LBR08PacketBlue(pixelpacket) \
435 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).blue); \
436 (pixelpacket).blue=ScaleCharToQuantum((lbr_bits)); \
438 #define LBR08PacketAlpha(pixelpacket) \
440 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).alpha); \
441 (pixelpacket).alpha=ScaleCharToQuantum((lbr_bits)); \
444 #define LBR08PacketRGB(pixelpacket) \
446 LBR08PacketRed((pixelpacket)); \
447 LBR08PacketGreen((pixelpacket)); \
448 LBR08PacketBlue((pixelpacket)); \
451 #define LBR08PacketRGBO(pixelpacket) \
453 LBR08PacketRGB((pixelpacket)); \
454 LBR08PacketAlpha((pixelpacket)); \
457 #define LBR08PixelRed(pixel) \
459 unsigned char lbr_bits= \
460 ScaleQuantumToChar(GetPixelRed(image,(pixel))); \
462 ScaleCharToQuantum((lbr_bits)), (pixel)); \
464 #define LBR08PixelGreen(pixel) \
466 unsigned char lbr_bits= \
467 ScaleQuantumToChar(GetPixelGreen(image,(pixel))); \
468 SetPixelGreen(image,\
469 ScaleCharToQuantum((lbr_bits)), (pixel)); \
471 #define LBR08PixelBlue(pixel) \
473 unsigned char lbr_bits= \
474 ScaleQuantumToChar(GetPixelBlue(image,(pixel))); \
476 ScaleCharToQuantum((lbr_bits)), (pixel)); \
478 #define LBR08PixelAlpha(pixel) \
480 unsigned char lbr_bits= \
481 ScaleQuantumToChar(GetPixelAlpha(image,(pixel))); \
482 SetPixelAlpha(image,\
483 ScaleCharToQuantum((lbr_bits)), (pixel)); \
486 #define LBR08PixelRGB(pixel) \
488 LBR08PixelRed((pixel)); \
489 LBR08PixelGreen((pixel)); \
490 LBR08PixelBlue((pixel)); \
493 #define LBR08PixelRGBA(pixel) \
495 LBR08PixelRGB((pixel)); \
496 LBR08PixelAlpha((pixel)); \
500 /* LBR16: Replicate top 16 bits */
502 #define LBR16PacketRed(pixelpacket) \
504 unsigned short lbr_bits=ScaleQuantumToShort((pixelpacket).red); \
505 (pixelpacket).red=ScaleShortToQuantum((lbr_bits)); \
507 #define LBR16PacketGreen(pixelpacket) \
509 unsigned short lbr_bits=ScaleQuantumToShort((pixelpacket).green); \
510 (pixelpacket).green=ScaleShortToQuantum((lbr_bits)); \
512 #define LBR16PacketBlue(pixelpacket) \
514 unsigned short lbr_bits=ScaleQuantumToShort((pixelpacket).blue); \
515 (pixelpacket).blue=ScaleShortToQuantum((lbr_bits)); \
517 #define LBR16PacketAlpha(pixelpacket) \
519 unsigned short lbr_bits=ScaleQuantumToShort((pixelpacket).alpha); \
520 (pixelpacket).alpha=ScaleShortToQuantum((lbr_bits)); \
523 #define LBR16PacketRGB(pixelpacket) \
525 LBR16PacketRed((pixelpacket)); \
526 LBR16PacketGreen((pixelpacket)); \
527 LBR16PacketBlue((pixelpacket)); \
530 #define LBR16PacketRGBO(pixelpacket) \
532 LBR16PacketRGB((pixelpacket)); \
533 LBR16PacketAlpha((pixelpacket)); \
536 #define LBR16PixelRed(pixel) \
538 unsigned short lbr_bits= \
539 ScaleQuantumToShort(GetPixelRed(image,(pixel))); \
541 ScaleShortToQuantum((lbr_bits)),(pixel)); \
543 #define LBR16PixelGreen(pixel) \
545 unsigned short lbr_bits= \
546 ScaleQuantumToShort(GetPixelGreen(image,(pixel))); \
547 SetPixelGreen(image,\
548 ScaleShortToQuantum((lbr_bits)),(pixel)); \
550 #define LBR16PixelBlue(pixel) \
552 unsigned short lbr_bits= \
553 ScaleQuantumToShort(GetPixelBlue(image,(pixel))); \
555 ScaleShortToQuantum((lbr_bits)),(pixel)); \
557 #define LBR16PixelAlpha(pixel) \
559 unsigned short lbr_bits= \
560 ScaleQuantumToShort(GetPixelAlpha(image,(pixel))); \
561 SetPixelAlpha(image,\
562 ScaleShortToQuantum((lbr_bits)),(pixel)); \
565 #define LBR16PixelRGB(pixel) \
567 LBR16PixelRed((pixel)); \
568 LBR16PixelGreen((pixel)); \
569 LBR16PixelBlue((pixel)); \
572 #define LBR16PixelRGBA(pixel) \
574 LBR16PixelRGB((pixel)); \
575 LBR16PixelAlpha((pixel)); \
579 Establish thread safety.
580 setjmp/longjmp is claimed to be safe on these platforms:
581 setjmp/longjmp is alleged to be unsafe on these platforms:
583 #ifndef SETJMP_IS_THREAD_SAFE
584 #define PNG_SETJMP_NOT_THREAD_SAFE
587 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
589 *ping_semaphore = (SemaphoreInfo *) NULL;
593 This temporary until I set up malloc'ed object attributes array.
594 Recompile with MNG_MAX_OBJECTS=65536L to avoid this limit but
597 #define MNG_MAX_OBJECTS 256
600 If this not defined, spec is interpreted strictly. If it is
601 defined, an attempt will be made to recover from some errors,
603 o global PLTE too short
608 Don't try to define PNG_MNG_FEATURES_SUPPORTED here. Make sure
609 it's defined in libpng/pngconf.h, version 1.0.9 or later. It won't work
610 with earlier versions of libpng. From libpng-1.0.3a to libpng-1.0.8,
611 PNG_READ|WRITE_EMPTY_PLTE were used but those have been deprecated in
612 libpng in favor of PNG_MNG_FEATURES_SUPPORTED, so we set them here.
613 PNG_MNG_FEATURES_SUPPORTED is disabled by default in libpng-1.0.9 and
614 will be enabled by default in libpng-1.2.0.
616 #ifdef PNG_MNG_FEATURES_SUPPORTED
617 # ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
618 # define PNG_READ_EMPTY_PLTE_SUPPORTED
620 # ifndef PNG_WRITE_EMPTY_PLTE_SUPPORTED
621 # define PNG_WRITE_EMPTY_PLTE_SUPPORTED
626 Maximum valid size_t in PNG/MNG chunks is (2^31)-1
627 This macro is only defined in libpng-1.0.3 and later.
628 Previously it was PNG_MAX_UINT but that was deprecated in libpng-1.2.6
630 #ifndef PNG_UINT_31_MAX
631 #define PNG_UINT_31_MAX (png_uint_32) 0x7fffffffL
635 Constant strings for known chunk types. If you need to add a chunk,
636 add a string holding the name here. To make the code more
637 portable, we use ASCII numbers like this, not characters.
640 static png_byte mng_MHDR[5]={ 77, 72, 68, 82, (png_byte) '\0'};
641 static png_byte mng_BACK[5]={ 66, 65, 67, 75, (png_byte) '\0'};
642 static png_byte mng_BASI[5]={ 66, 65, 83, 73, (png_byte) '\0'};
643 static png_byte mng_CLIP[5]={ 67, 76, 73, 80, (png_byte) '\0'};
644 static png_byte mng_CLON[5]={ 67, 76, 79, 78, (png_byte) '\0'};
645 static png_byte mng_DEFI[5]={ 68, 69, 70, 73, (png_byte) '\0'};
646 static png_byte mng_DHDR[5]={ 68, 72, 68, 82, (png_byte) '\0'};
647 static png_byte mng_DISC[5]={ 68, 73, 83, 67, (png_byte) '\0'};
648 static png_byte mng_ENDL[5]={ 69, 78, 68, 76, (png_byte) '\0'};
649 static png_byte mng_FRAM[5]={ 70, 82, 65, 77, (png_byte) '\0'};
650 static png_byte mng_IEND[5]={ 73, 69, 78, 68, (png_byte) '\0'};
651 static png_byte mng_IHDR[5]={ 73, 72, 68, 82, (png_byte) '\0'};
652 static png_byte mng_JHDR[5]={ 74, 72, 68, 82, (png_byte) '\0'};
653 static png_byte mng_LOOP[5]={ 76, 79, 79, 80, (png_byte) '\0'};
654 static png_byte mng_MAGN[5]={ 77, 65, 71, 78, (png_byte) '\0'};
655 static png_byte mng_MEND[5]={ 77, 69, 78, 68, (png_byte) '\0'};
656 static png_byte mng_MOVE[5]={ 77, 79, 86, 69, (png_byte) '\0'};
657 static png_byte mng_PAST[5]={ 80, 65, 83, 84, (png_byte) '\0'};
658 static png_byte mng_PLTE[5]={ 80, 76, 84, 69, (png_byte) '\0'};
659 static png_byte mng_SAVE[5]={ 83, 65, 86, 69, (png_byte) '\0'};
660 static png_byte mng_SEEK[5]={ 83, 69, 69, 75, (png_byte) '\0'};
661 static png_byte mng_SHOW[5]={ 83, 72, 79, 87, (png_byte) '\0'};
662 static png_byte mng_TERM[5]={ 84, 69, 82, 77, (png_byte) '\0'};
663 static png_byte mng_bKGD[5]={ 98, 75, 71, 68, (png_byte) '\0'};
664 static png_byte mng_cHRM[5]={ 99, 72, 82, 77, (png_byte) '\0'};
665 static png_byte mng_gAMA[5]={103, 65, 77, 65, (png_byte) '\0'};
666 static png_byte mng_iCCP[5]={105, 67, 67, 80, (png_byte) '\0'};
667 static png_byte mng_nEED[5]={110, 69, 69, 68, (png_byte) '\0'};
668 static png_byte mng_pHYg[5]={112, 72, 89, 103, (png_byte) '\0'};
669 static png_byte mng_vpAg[5]={118, 112, 65, 103, (png_byte) '\0'};
670 static png_byte mng_pHYs[5]={112, 72, 89, 115, (png_byte) '\0'};
671 static png_byte mng_sBIT[5]={115, 66, 73, 84, (png_byte) '\0'};
672 static png_byte mng_sRGB[5]={115, 82, 71, 66, (png_byte) '\0'};
673 static png_byte mng_tRNS[5]={116, 82, 78, 83, (png_byte) '\0'};
675 #if defined(JNG_SUPPORTED)
676 static png_byte mng_IDAT[5]={ 73, 68, 65, 84, (png_byte) '\0'};
677 static png_byte mng_JDAT[5]={ 74, 68, 65, 84, (png_byte) '\0'};
678 static png_byte mng_JDAA[5]={ 74, 68, 65, 65, (png_byte) '\0'};
679 static png_byte mng_JdAA[5]={ 74, 100, 65, 65, (png_byte) '\0'};
680 static png_byte mng_JSEP[5]={ 74, 83, 69, 80, (png_byte) '\0'};
681 static png_byte mng_oFFs[5]={111, 70, 70, 115, (png_byte) '\0'};
685 Other known chunks that are not yet supported by ImageMagick:
686 static png_byte mng_hIST[5]={104, 73, 83, 84, (png_byte) '\0'};
687 static png_byte mng_iCCP[5]={105, 67, 67, 80, (png_byte) '\0'};
688 static png_byte mng_iTXt[5]={105, 84, 88, 116, (png_byte) '\0'};
689 static png_byte mng_sPLT[5]={115, 80, 76, 84, (png_byte) '\0'};
690 static png_byte mng_sTER[5]={115, 84, 69, 82, (png_byte) '\0'};
691 static png_byte mng_tEXt[5]={116, 69, 88, 116, (png_byte) '\0'};
692 static png_byte mng_tIME[5]={116, 73, 77, 69, (png_byte) '\0'};
693 static png_byte mng_zTXt[5]={122, 84, 88, 116, (png_byte) '\0'};
696 typedef struct _MngBox
705 typedef struct _MngPair
712 #ifdef MNG_OBJECT_BUFFERS
713 typedef struct _MngBuffer
745 typedef struct _MngInfo
748 #ifdef MNG_OBJECT_BUFFERS
750 *ob[MNG_MAX_OBJECTS];
761 #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
762 bytes_in_read_buffer,
768 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
769 defined(PNG_MNG_FEATURES_SUPPORTED)
781 have_saved_bkgd_index,
782 have_write_global_chrm,
783 have_write_global_gama,
784 have_write_global_plte,
785 have_write_global_srgb,
799 x_off[MNG_MAX_OBJECTS],
800 y_off[MNG_MAX_OBJECTS];
806 object_clip[MNG_MAX_OBJECTS];
809 /* These flags could be combined into one byte */
810 exists[MNG_MAX_OBJECTS],
811 frozen[MNG_MAX_OBJECTS],
813 invisible[MNG_MAX_OBJECTS],
814 viewable[MNG_MAX_OBJECTS];
826 #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
844 global_x_pixels_per_unit,
845 global_y_pixels_per_unit,
855 global_phys_unit_type,
870 write_png_compression_level,
871 write_png_compression_strategy,
872 write_png_compression_filter,
877 #ifdef MNG_BASI_SUPPORTED
885 basi_compression_method,
887 basi_interlace_method,
910 /* Added at version 6.6.6-7 */
918 /* ping_exclude_iTXt, */
925 ping_exclude_zCCP, /* hex-encoded iCCP */
927 ping_preserve_colormap;
933 Forward declarations.
935 static MagickBooleanType
936 WritePNGImage(const ImageInfo *,Image *,ExceptionInfo *);
938 static MagickBooleanType
939 WriteMNGImage(const ImageInfo *,Image *,ExceptionInfo *);
941 #if defined(JNG_SUPPORTED)
942 static MagickBooleanType
943 WriteJNGImage(const ImageInfo *,Image *,ExceptionInfo *);
946 #if PNG_LIBPNG_VER > 10011
949 #if (MAGICKCORE_QUANTUM_DEPTH >= 16)
950 static MagickBooleanType
951 LosslessReduceDepthOK(Image *image,ExceptionInfo *exception)
953 /* Reduce bit depth if it can be reduced losslessly from 16+ to 8.
955 * This is true if the high byte and the next highest byte of
956 * each sample of the image, the colormap, and the background color
957 * are equal to each other. We check this by seeing if the samples
958 * are unchanged when we scale them down to 8 and back up to Quantum.
960 * We don't use the method GetImageDepth() because it doesn't check
961 * background and doesn't handle PseudoClass specially.
964 #define QuantumToCharToQuantumEqQuantum(quantum) \
965 ((ScaleCharToQuantum((unsigned char) ScaleQuantumToChar(quantum))) == quantum)
968 ok_to_reduce=MagickFalse;
970 if (image->depth >= 16)
977 QuantumToCharToQuantumEqQuantum(image->background_color.red) &&
978 QuantumToCharToQuantumEqQuantum(image->background_color.green) &&
979 QuantumToCharToQuantumEqQuantum(image->background_color.blue) ?
980 MagickTrue : MagickFalse;
982 if (ok_to_reduce != MagickFalse && image->storage_class == PseudoClass)
986 for (indx=0; indx < (ssize_t) image->colors; indx++)
989 QuantumToCharToQuantumEqQuantum(
990 image->colormap[indx].red) &&
991 QuantumToCharToQuantumEqQuantum(
992 image->colormap[indx].green) &&
993 QuantumToCharToQuantumEqQuantum(
994 image->colormap[indx].blue)) ?
995 MagickTrue : MagickFalse;
997 if (ok_to_reduce == MagickFalse)
1002 if ((ok_to_reduce != MagickFalse) &&
1003 (image->storage_class != PseudoClass))
1011 for (y=0; y < (ssize_t) image->rows; y++)
1013 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1015 if (p == (const Quantum *) NULL)
1017 ok_to_reduce = MagickFalse;
1021 for (x=(ssize_t) image->columns-1; x >= 0; x--)
1024 QuantumToCharToQuantumEqQuantum(GetPixelRed(image,p)) &&
1025 QuantumToCharToQuantumEqQuantum(GetPixelGreen(image,p)) &&
1026 QuantumToCharToQuantumEqQuantum(GetPixelBlue(image,p)) ?
1027 MagickTrue : MagickFalse;
1029 if (ok_to_reduce == MagickFalse)
1032 p+=GetPixelChannels(image);
1039 if (ok_to_reduce != MagickFalse)
1041 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1042 " OK to reduce PNG bit depth to 8 without loss of info");
1046 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1047 " Not OK to reduce PNG bit depth to 8 without loss of info");
1051 return ok_to_reduce;
1053 #endif /* MAGICKCORE_QUANTUM_DEPTH >= 16 */
1055 static const char* PngColorTypeToString(const unsigned int color_type)
1058 *result = "Unknown";
1062 case PNG_COLOR_TYPE_GRAY:
1065 case PNG_COLOR_TYPE_GRAY_ALPHA:
1066 result = "Gray+Alpha";
1068 case PNG_COLOR_TYPE_PALETTE:
1071 case PNG_COLOR_TYPE_RGB:
1074 case PNG_COLOR_TYPE_RGB_ALPHA:
1075 result = "RGB+Alpha";
1083 Magick_RenderingIntent_to_PNG_RenderingIntent(const RenderingIntent intent)
1087 case PerceptualIntent:
1090 case RelativeIntent:
1093 case SaturationIntent:
1096 case AbsoluteIntent:
1104 static RenderingIntent
1105 Magick_RenderingIntent_from_PNG_RenderingIntent(const int ping_intent)
1107 switch (ping_intent)
1110 return PerceptualIntent;
1113 return RelativeIntent;
1116 return SaturationIntent;
1119 return AbsoluteIntent;
1122 return UndefinedIntent;
1126 static inline ssize_t MagickMax(const ssize_t x,const ssize_t y)
1134 static inline ssize_t MagickMin(const ssize_t x,const ssize_t y)
1144 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1148 % I m a g e I s G r a y %
1152 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1154 % Like IsImageGray except does not change DirectClass to PseudoClass %
1156 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1158 static MagickBooleanType ImageIsGray(Image *image,ExceptionInfo *exception)
1160 register const Quantum
1168 assert(image != (Image *) NULL);
1169 assert(image->signature == MagickSignature);
1170 if (image->debug != MagickFalse)
1171 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1173 if (image->storage_class == PseudoClass)
1175 for (i=0; i < (ssize_t) image->colors; i++)
1176 if (IsPixelInfoGray(image->colormap+i) == MagickFalse)
1177 return(MagickFalse);
1180 for (y=0; y < (ssize_t) image->rows; y++)
1182 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1183 if (p == (const Quantum *) NULL)
1184 return(MagickFalse);
1185 for (x=(ssize_t) image->columns-1; x >= 0; x--)
1187 if (IsPixelGray(image,p) == MagickFalse)
1188 return(MagickFalse);
1189 p+=GetPixelChannels(image);
1194 #endif /* PNG_LIBPNG_VER > 10011 */
1195 #endif /* MAGICKCORE_PNG_DELEGATE */
1198 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1206 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1208 % IsMNG() returns MagickTrue if the image format type, identified by the
1209 % magick string, is MNG.
1211 % The format of the IsMNG method is:
1213 % MagickBooleanType IsMNG(const unsigned char *magick,const size_t length)
1215 % A description of each parameter follows:
1217 % o magick: compare image format pattern against these bytes.
1219 % o length: Specifies the length of the magick string.
1223 static MagickBooleanType IsMNG(const unsigned char *magick,const size_t length)
1226 return(MagickFalse);
1228 if (memcmp(magick,"\212MNG\r\n\032\n",8) == 0)
1231 return(MagickFalse);
1235 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1243 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1245 % IsJNG() returns MagickTrue if the image format type, identified by the
1246 % magick string, is JNG.
1248 % The format of the IsJNG method is:
1250 % MagickBooleanType IsJNG(const unsigned char *magick,const size_t length)
1252 % A description of each parameter follows:
1254 % o magick: compare image format pattern against these bytes.
1256 % o length: Specifies the length of the magick string.
1260 static MagickBooleanType IsJNG(const unsigned char *magick,const size_t length)
1263 return(MagickFalse);
1265 if (memcmp(magick,"\213JNG\r\n\032\n",8) == 0)
1268 return(MagickFalse);
1272 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1280 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1282 % IsPNG() returns MagickTrue if the image format type, identified by the
1283 % magick string, is PNG.
1285 % The format of the IsPNG method is:
1287 % MagickBooleanType IsPNG(const unsigned char *magick,const size_t length)
1289 % A description of each parameter follows:
1291 % o magick: compare image format pattern against these bytes.
1293 % o length: Specifies the length of the magick string.
1296 static MagickBooleanType IsPNG(const unsigned char *magick,const size_t length)
1299 return(MagickFalse);
1301 if (memcmp(magick,"\211PNG\r\n\032\n",8) == 0)
1304 return(MagickFalse);
1307 #if defined(MAGICKCORE_PNG_DELEGATE)
1308 #if defined(__cplusplus) || defined(c_plusplus)
1312 #if (PNG_LIBPNG_VER > 10011)
1313 static size_t WriteBlobMSBULong(Image *image,const size_t value)
1318 assert(image != (Image *) NULL);
1319 assert(image->signature == MagickSignature);
1320 buffer[0]=(unsigned char) (value >> 24);
1321 buffer[1]=(unsigned char) (value >> 16);
1322 buffer[2]=(unsigned char) (value >> 8);
1323 buffer[3]=(unsigned char) value;
1324 return((size_t) WriteBlob(image,4,buffer));
1327 static void PNGLong(png_bytep p,png_uint_32 value)
1329 *p++=(png_byte) ((value >> 24) & 0xff);
1330 *p++=(png_byte) ((value >> 16) & 0xff);
1331 *p++=(png_byte) ((value >> 8) & 0xff);
1332 *p++=(png_byte) (value & 0xff);
1335 #if defined(JNG_SUPPORTED)
1336 static void PNGsLong(png_bytep p,png_int_32 value)
1338 *p++=(png_byte) ((value >> 24) & 0xff);
1339 *p++=(png_byte) ((value >> 16) & 0xff);
1340 *p++=(png_byte) ((value >> 8) & 0xff);
1341 *p++=(png_byte) (value & 0xff);
1345 static void PNGShort(png_bytep p,png_uint_16 value)
1347 *p++=(png_byte) ((value >> 8) & 0xff);
1348 *p++=(png_byte) (value & 0xff);
1351 static void PNGType(png_bytep p,png_bytep type)
1353 (void) CopyMagickMemory(p,type,4*sizeof(png_byte));
1356 static void LogPNGChunk(MagickBooleanType logging, png_bytep type,
1359 if (logging != MagickFalse)
1360 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1361 " Writing %c%c%c%c chunk, length: %.20g",
1362 type[0],type[1],type[2],type[3],(double) length);
1364 #endif /* PNG_LIBPNG_VER > 10011 */
1366 #if defined(__cplusplus) || defined(c_plusplus)
1370 #if PNG_LIBPNG_VER > 10011
1372 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1376 % R e a d P N G I m a g e %
1380 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1382 % ReadPNGImage() reads a Portable Network Graphics (PNG) or
1383 % Multiple-image Network Graphics (MNG) image file and returns it. It
1384 % allocates the memory necessary for the new Image structure and returns a
1385 % pointer to the new image or set of images.
1387 % MNG support written by Glenn Randers-Pehrson, glennrp@image...
1389 % The format of the ReadPNGImage method is:
1391 % Image *ReadPNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
1393 % A description of each parameter follows:
1395 % o image_info: the image info.
1397 % o exception: return any errors or warnings in this structure.
1399 % To do, more or less in chronological order (as of version 5.5.2,
1400 % November 26, 2002 -- glennrp -- see also "To do" under WriteMNGImage):
1402 % Get 16-bit cheap transparency working.
1404 % (At this point, PNG decoding is supposed to be in full MNG-LC compliance)
1406 % Preserve all unknown and not-yet-handled known chunks found in input
1407 % PNG file and copy them into output PNG files according to the PNG
1410 % (At this point, PNG encoding should be in full MNG compliance)
1412 % Provide options for choice of background to use when the MNG BACK
1413 % chunk is not present or is not mandatory (i.e., leave transparent,
1414 % user specified, MNG BACK, PNG bKGD)
1416 % Implement LOOP/ENDL [done, but could do discretionary loops more
1417 % efficiently by linking in the duplicate frames.].
1419 % Decode and act on the MHDR simplicity profile (offer option to reject
1420 % files or attempt to process them anyway when the profile isn't LC or VLC).
1422 % Upgrade to full MNG without Delta-PNG.
1424 % o BACK [done a while ago except for background image ID]
1425 % o MOVE [done 15 May 1999]
1426 % o CLIP [done 15 May 1999]
1427 % o DISC [done 19 May 1999]
1428 % o SAVE [partially done 19 May 1999 (marks objects frozen)]
1429 % o SEEK [partially done 19 May 1999 (discard function only)]
1433 % o MNG-level tEXt/iTXt/zTXt
1438 % o iTXt (wait for libpng implementation).
1440 % Use the scene signature to discover when an identical scene is
1441 % being reused, and just point to the original image->exception instead
1442 % of storing another set of pixels. This not specific to MNG
1443 % but could be applied generally.
1445 % Upgrade to full MNG with Delta-PNG.
1447 % JNG tEXt/iTXt/zTXt
1449 % We will not attempt to read files containing the CgBI chunk.
1450 % They are really Xcode files meant for display on the iPhone.
1451 % These are not valid PNG files and it is impossible to recover
1452 % the original PNG from files that have been converted to Xcode-PNG,
1453 % since irretrievable loss of color data has occurred due to the
1454 % use of premultiplied alpha.
1457 #if defined(__cplusplus) || defined(c_plusplus)
1462 This the function that does the actual reading of data. It is
1463 the same as the one supplied in libpng, except that it receives the
1464 datastream from the ReadBlob() function instead of standard input.
1466 static void png_get_data(png_structp png_ptr,png_bytep data,png_size_t length)
1471 image=(Image *) png_get_io_ptr(png_ptr);
1477 check=(png_size_t) ReadBlob(image,(size_t) length,data);
1478 if (check != length)
1483 (void) FormatLocaleString(msg,MaxTextExtent,
1484 "Expected %.20g bytes; found %.20g bytes",(double) length,
1486 png_warning(png_ptr,msg);
1487 png_error(png_ptr,"Read Exception");
1492 #if !defined(PNG_READ_EMPTY_PLTE_SUPPORTED) && \
1493 !defined(PNG_MNG_FEATURES_SUPPORTED)
1494 /* We use mng_get_data() instead of png_get_data() if we have a libpng
1495 * older than libpng-1.0.3a, which was the first to allow the empty
1496 * PLTE, or a newer libpng in which PNG_MNG_FEATURES_SUPPORTED was
1497 * ifdef'ed out. Earlier versions would crash if the bKGD chunk was
1498 * encountered after an empty PLTE, so we have to look ahead for bKGD
1499 * chunks and remove them from the datastream that is passed to libpng,
1500 * and store their contents for later use.
1502 static void mng_get_data(png_structp png_ptr,png_bytep data,png_size_t length)
1517 mng_info=(MngInfo *) png_get_io_ptr(png_ptr);
1518 image=(Image *) mng_info->image;
1519 while (mng_info->bytes_in_read_buffer && length)
1521 data[i]=mng_info->read_buffer[i];
1522 mng_info->bytes_in_read_buffer--;
1528 check=(png_size_t) ReadBlob(image,(size_t) length,(char *) data);
1530 if (check != length)
1531 png_error(png_ptr,"Read Exception");
1535 if ((data[0] == 0) && (data[1] == 0) && (data[2] == 0) &&
1538 check=(png_size_t) ReadBlob(image,(size_t) length,
1539 (char *) mng_info->read_buffer);
1540 mng_info->read_buffer[4]=0;
1541 mng_info->bytes_in_read_buffer=4;
1542 if (memcmp(mng_info->read_buffer,mng_PLTE,4) == 0)
1543 mng_info->found_empty_plte=MagickTrue;
1544 if (memcmp(mng_info->read_buffer,mng_IEND,4) == 0)
1546 mng_info->found_empty_plte=MagickFalse;
1547 mng_info->have_saved_bkgd_index=MagickFalse;
1551 if ((data[0] == 0) && (data[1] == 0) && (data[2] == 0) &&
1554 check=(png_size_t) ReadBlob(image,(size_t) length,
1555 (char *) mng_info->read_buffer);
1556 mng_info->read_buffer[4]=0;
1557 mng_info->bytes_in_read_buffer=4;
1558 if (memcmp(mng_info->read_buffer,mng_bKGD,4) == 0)
1559 if (mng_info->found_empty_plte)
1562 Skip the bKGD data byte and CRC.
1565 ReadBlob(image,5,(char *) mng_info->read_buffer);
1566 check=(png_size_t) ReadBlob(image,(size_t) length,
1567 (char *) mng_info->read_buffer);
1568 mng_info->saved_bkgd_index=mng_info->read_buffer[0];
1569 mng_info->have_saved_bkgd_index=MagickTrue;
1570 mng_info->bytes_in_read_buffer=0;
1578 static void png_put_data(png_structp png_ptr,png_bytep data,png_size_t length)
1583 image=(Image *) png_get_io_ptr(png_ptr);
1589 check=(png_size_t) WriteBlob(image,(size_t) length,data);
1591 if (check != length)
1592 png_error(png_ptr,"WriteBlob Failed");
1596 static void png_flush_data(png_structp png_ptr)
1601 #ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
1602 static int PalettesAreEqual(Image *a,Image *b)
1607 if ((a == (Image *) NULL) || (b == (Image *) NULL))
1608 return((int) MagickFalse);
1610 if (a->storage_class != PseudoClass || b->storage_class != PseudoClass)
1611 return((int) MagickFalse);
1613 if (a->colors != b->colors)
1614 return((int) MagickFalse);
1616 for (i=0; i < (ssize_t) a->colors; i++)
1618 if ((a->colormap[i].red != b->colormap[i].red) ||
1619 (a->colormap[i].green != b->colormap[i].green) ||
1620 (a->colormap[i].blue != b->colormap[i].blue))
1621 return((int) MagickFalse);
1624 return((int) MagickTrue);
1628 static void MngInfoDiscardObject(MngInfo *mng_info,int i)
1630 if (i && (i < MNG_MAX_OBJECTS) && (mng_info != (MngInfo *) NULL) &&
1631 mng_info->exists[i] && !mng_info->frozen[i])
1633 #ifdef MNG_OBJECT_BUFFERS
1634 if (mng_info->ob[i] != (MngBuffer *) NULL)
1636 if (mng_info->ob[i]->reference_count > 0)
1637 mng_info->ob[i]->reference_count--;
1639 if (mng_info->ob[i]->reference_count == 0)
1641 if (mng_info->ob[i]->image != (Image *) NULL)
1642 mng_info->ob[i]->image=DestroyImage(mng_info->ob[i]->image);
1644 mng_info->ob[i]=DestroyString(mng_info->ob[i]);
1647 mng_info->ob[i]=(MngBuffer *) NULL;
1649 mng_info->exists[i]=MagickFalse;
1650 mng_info->invisible[i]=MagickFalse;
1651 mng_info->viewable[i]=MagickFalse;
1652 mng_info->frozen[i]=MagickFalse;
1653 mng_info->x_off[i]=0;
1654 mng_info->y_off[i]=0;
1655 mng_info->object_clip[i].left=0;
1656 mng_info->object_clip[i].right=(ssize_t) PNG_UINT_31_MAX;
1657 mng_info->object_clip[i].top=0;
1658 mng_info->object_clip[i].bottom=(ssize_t) PNG_UINT_31_MAX;
1662 static void MngInfoFreeStruct(MngInfo *mng_info,
1663 MagickBooleanType *have_mng_structure)
1665 if (*have_mng_structure != MagickFalse && (mng_info != (MngInfo *) NULL))
1670 for (i=1; i < MNG_MAX_OBJECTS; i++)
1671 MngInfoDiscardObject(mng_info,i);
1673 if (mng_info->global_plte != (png_colorp) NULL)
1674 mng_info->global_plte=(png_colorp)
1675 RelinquishMagickMemory(mng_info->global_plte);
1677 mng_info=(MngInfo *) RelinquishMagickMemory(mng_info);
1678 *have_mng_structure=MagickFalse;
1682 static MngBox mng_minimum_box(MngBox box1,MngBox box2)
1688 if (box.left < box2.left)
1691 if (box.top < box2.top)
1694 if (box.right > box2.right)
1695 box.right=box2.right;
1697 if (box.bottom > box2.bottom)
1698 box.bottom=box2.bottom;
1703 static MngBox mng_read_box(MngBox previous_box,char delta_type,unsigned char *p)
1709 Read clipping boundaries from DEFI, CLIP, FRAM, or PAST chunk.
1711 box.left=(ssize_t) ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]);
1712 box.right=(ssize_t) ((p[4] << 24) | (p[5] << 16) | (p[6] << 8) | p[7]);
1713 box.top=(ssize_t) ((p[8] << 24) | (p[9] << 16) | (p[10] << 8) | p[11]);
1714 box.bottom=(ssize_t) ((p[12] << 24) | (p[13] << 16) | (p[14] << 8) | p[15]);
1715 if (delta_type != 0)
1717 box.left+=previous_box.left;
1718 box.right+=previous_box.right;
1719 box.top+=previous_box.top;
1720 box.bottom+=previous_box.bottom;
1726 static MngPair mng_read_pair(MngPair previous_pair,int delta_type,
1732 Read two ssize_ts from CLON, MOVE or PAST chunk
1734 pair.a=(long) ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]);
1735 pair.b=(long) ((p[4] << 24) | (p[5] << 16) | (p[6] << 8) | p[7]);
1737 if (delta_type != 0)
1739 pair.a+=previous_pair.a;
1740 pair.b+=previous_pair.b;
1746 static long mng_get_long(unsigned char *p)
1748 return((long) ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]));
1751 typedef struct _PNGErrorInfo
1760 static void MagickPNGErrorHandler(png_struct *ping,png_const_charp message)
1771 error_info=(PNGErrorInfo *) png_get_error_ptr(ping);
1772 image=error_info->image;
1773 exception=error_info->exception;
1775 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1776 " libpng-%s error: %s", PNG_LIBPNG_VER_STRING,message);
1778 (void) ThrowMagickException(exception,GetMagickModule(),CoderError,message,
1779 "`%s'",image->filename);
1781 #if (PNG_LIBPNG_VER < 10500)
1782 /* A warning about deprecated use of jmpbuf here is unavoidable if you
1783 * are building with libpng-1.4.x and can be ignored.
1785 longjmp(ping->jmpbuf,1);
1787 png_longjmp(ping,1);
1791 static void MagickPNGWarningHandler(png_struct *ping,png_const_charp message)
1802 if (LocaleCompare(message, "Missing PLTE before tRNS") == 0)
1803 png_error(ping, message);
1805 error_info=(PNGErrorInfo *) png_get_error_ptr(ping);
1806 image=error_info->image;
1807 exception=error_info->exception;
1808 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1809 " libpng-%s warning: %s", PNG_LIBPNG_VER_STRING,message);
1811 (void) ThrowMagickException(exception,GetMagickModule(),CoderWarning,
1812 message,"`%s'",image->filename);
1815 #ifdef PNG_USER_MEM_SUPPORTED
1816 static png_voidp Magick_png_malloc(png_structp png_ptr,png_uint_32 size)
1819 return((png_voidp) AcquireMagickMemory((size_t) size));
1823 Free a pointer. It is removed from the list at the same time.
1825 static png_free_ptr Magick_png_free(png_structp png_ptr,png_voidp ptr)
1828 ptr=RelinquishMagickMemory(ptr);
1829 return((png_free_ptr) NULL);
1833 #if defined(__cplusplus) || defined(c_plusplus)
1838 Magick_png_read_raw_profile(png_struct *ping,Image *image,
1839 const ImageInfo *image_info, png_textp text,int ii,ExceptionInfo *exception)
1844 register unsigned char
1858 unhex[103]={0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,
1859 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,
1860 0,0,0,0,0,0,0,0,0,1, 2,3,4,5,6,7,8,9,0,0,
1861 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,
1862 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,10,11,12,
1866 /* look for newline */
1870 /* look for length */
1871 while (*sp == '\0' || *sp == ' ' || *sp == '\n')
1874 length=(png_uint_32) StringToLong(sp);
1876 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1877 " length: %lu",(unsigned long) length);
1879 while (*sp != ' ' && *sp != '\n')
1882 /* allocate space */
1885 png_warning(ping,"invalid profile length");
1886 return(MagickFalse);
1889 profile=BlobToStringInfo((const void *) NULL,length);
1891 if (profile == (StringInfo *) NULL)
1893 png_warning(ping, "unable to copy profile");
1894 return(MagickFalse);
1897 /* copy profile, skipping white space and column 1 "=" signs */
1898 dp=GetStringInfoDatum(profile);
1901 for (i=0; i < (ssize_t) nibbles; i++)
1903 while (*sp < '0' || (*sp > '9' && *sp < 'a') || *sp > 'f')
1907 png_warning(ping, "ran out of profile data");
1908 profile=DestroyStringInfo(profile);
1909 return(MagickFalse);
1915 *dp=(unsigned char) (16*unhex[(int) *sp++]);
1918 (*dp++)+=unhex[(int) *sp++];
1921 We have already read "Raw profile type.
1923 (void) SetImageProfile(image,&text[ii].key[17],profile,exception);
1924 profile=DestroyStringInfo(profile);
1926 if (image_info->verbose)
1927 (void) printf(" Found a generic profile, type %s\n",&text[ii].key[17]);
1932 #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
1933 static int read_vpag_chunk_callback(png_struct *ping, png_unknown_chunkp chunk)
1939 /* The unknown chunk structure contains the chunk data:
1944 Note that libpng has already taken care of the CRC handling.
1948 if (chunk->name[0] != 118 || chunk->name[1] != 112 ||
1949 chunk->name[2] != 65 ||chunk-> name[3] != 103)
1950 return(0); /* Did not recognize */
1952 /* recognized vpAg */
1954 if (chunk->size != 9)
1955 return(-1); /* Error return */
1957 if (chunk->data[8] != 0)
1958 return(0); /* ImageMagick requires pixel units */
1960 image=(Image *) png_get_user_chunk_ptr(ping);
1962 image->page.width=(size_t) ((chunk->data[0] << 24) |
1963 (chunk->data[1] << 16) | (chunk->data[2] << 8) | chunk->data[3]);
1965 image->page.height=(size_t) ((chunk->data[4] << 24) |
1966 (chunk->data[5] << 16) | (chunk->data[6] << 8) | chunk->data[7]);
1968 /* Return one of the following: */
1969 /* return(-n); chunk had an error */
1970 /* return(0); did not recognize */
1971 /* return(n); success */
1979 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1983 % R e a d O n e P N G I m a g e %
1987 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1989 % ReadOnePNGImage() reads a Portable Network Graphics (PNG) image file
1990 % (minus the 8-byte signature) and returns it. It allocates the memory
1991 % necessary for the new Image structure and returns a pointer to the new
1994 % The format of the ReadOnePNGImage method is:
1996 % Image *ReadOnePNGImage(MngInfo *mng_info, const ImageInfo *image_info,
1997 % ExceptionInfo *exception)
1999 % A description of each parameter follows:
2001 % o mng_info: Specifies a pointer to a MngInfo structure.
2003 % o image_info: the image info.
2005 % o exception: return any errors or warnings in this structure.
2008 static Image *ReadOnePNGImage(MngInfo *mng_info,
2009 const ImageInfo *image_info, ExceptionInfo *exception)
2011 /* Read one PNG image */
2013 /* To do: Read the tIME chunk into the date:modify property */
2014 /* To do: Read the tEXt/Creation Time chunk into the date:create property */
2028 ping_interlace_method,
2029 ping_compression_method,
2080 register unsigned char
2097 #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
2098 png_byte unused_chunks[]=
2100 104, 73, 83, 84, (png_byte) '\0', /* hIST */
2101 105, 84, 88, 116, (png_byte) '\0', /* iTXt */
2102 112, 67, 65, 76, (png_byte) '\0', /* pCAL */
2103 115, 67, 65, 76, (png_byte) '\0', /* sCAL */
2104 115, 80, 76, 84, (png_byte) '\0', /* sPLT */
2105 116, 73, 77, 69, (png_byte) '\0', /* tIME */
2109 logging=LogMagickEvent(CoderEvent,GetMagickModule(),
2110 " Enter ReadOnePNGImage()");
2112 #if (PNG_LIBPNG_VER < 10200)
2113 if (image_info->verbose)
2114 printf("Your PNG library (libpng-%s) is rather old.\n",
2115 PNG_LIBPNG_VER_STRING);
2118 #if (PNG_LIBPNG_VER >= 10400)
2119 # ifndef PNG_TRANSFORM_GRAY_TO_RGB /* Added at libpng-1.4.0beta67 */
2120 if (image_info->verbose)
2122 printf("Your PNG library (libpng-%s) is an old beta version.\n",
2123 PNG_LIBPNG_VER_STRING);
2124 printf("Please update it.\n");
2130 quantum_info = (QuantumInfo *) NULL;
2131 image=mng_info->image;
2133 if (logging != MagickFalse)
2134 (void)LogMagickEvent(CoderEvent,GetMagickModule(),
2135 " image->matte=%d",(int) image->matte);
2137 /* Set to an out-of-range color unless tRNS chunk is present */
2138 transparent_color.red=65537;
2139 transparent_color.green=65537;
2140 transparent_color.blue=65537;
2141 transparent_color.alpha=65537;
2145 num_raw_profiles = 0;
2148 Allocate the PNG structures
2150 #ifdef PNG_USER_MEM_SUPPORTED
2151 error_info.image=image;
2152 error_info.exception=exception;
2153 ping=png_create_read_struct_2(PNG_LIBPNG_VER_STRING,&error_info,
2154 MagickPNGErrorHandler,MagickPNGWarningHandler, NULL,
2155 (png_malloc_ptr) Magick_png_malloc,(png_free_ptr) Magick_png_free);
2157 ping=png_create_read_struct(PNG_LIBPNG_VER_STRING,&error_info,
2158 MagickPNGErrorHandler,MagickPNGWarningHandler);
2160 if (ping == (png_struct *) NULL)
2161 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2163 ping_info=png_create_info_struct(ping);
2165 if (ping_info == (png_info *) NULL)
2167 png_destroy_read_struct(&ping,(png_info **) NULL,(png_info **) NULL);
2168 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2171 end_info=png_create_info_struct(ping);
2173 if (end_info == (png_info *) NULL)
2175 png_destroy_read_struct(&ping,&ping_info,(png_info **) NULL);
2176 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2179 ping_pixels=(unsigned char *) NULL;
2181 if (setjmp(png_jmpbuf(ping)))
2184 PNG image is corrupt.
2186 png_destroy_read_struct(&ping,&ping_info,&end_info);
2188 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
2189 UnlockSemaphoreInfo(ping_semaphore);
2192 if (ping_pixels != (unsigned char *) NULL)
2193 ping_pixels=(unsigned char *) RelinquishMagickMemory(ping_pixels);
2195 if (logging != MagickFalse)
2196 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2197 " exit ReadOnePNGImage() with error.");
2199 if (image != (Image *) NULL)
2201 InheritException(exception,exception);
2205 return(GetFirstImageInList(image));
2208 /* { For navigation to end of SETJMP-protected block. Within this
2209 * block, use png_error() instead of Throwing an Exception, to ensure
2210 * that libpng is able to clean up, and that the semaphore is unlocked.
2213 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
2214 LockSemaphoreInfo(ping_semaphore);
2218 Prepare PNG for reading.
2221 mng_info->image_found++;
2222 png_set_sig_bytes(ping,8);
2224 if (LocaleCompare(image_info->magick,"MNG") == 0)
2226 #if defined(PNG_MNG_FEATURES_SUPPORTED)
2227 (void) png_permit_mng_features(ping,PNG_ALL_MNG_FEATURES);
2228 png_set_read_fn(ping,image,png_get_data);
2230 #if defined(PNG_READ_EMPTY_PLTE_SUPPORTED)
2231 png_permit_empty_plte(ping,MagickTrue);
2232 png_set_read_fn(ping,image,png_get_data);
2234 mng_info->image=image;
2235 mng_info->bytes_in_read_buffer=0;
2236 mng_info->found_empty_plte=MagickFalse;
2237 mng_info->have_saved_bkgd_index=MagickFalse;
2238 png_set_read_fn(ping,mng_info,mng_get_data);
2244 png_set_read_fn(ping,image,png_get_data);
2246 #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
2247 /* Ignore unused chunks and all unknown chunks except for vpAg */
2248 png_set_keep_unknown_chunks(ping, 1, NULL, 0);
2249 png_set_keep_unknown_chunks(ping, 2, mng_vpAg, 1);
2250 png_set_keep_unknown_chunks(ping, 1, unused_chunks,
2251 (int)sizeof(unused_chunks)/5);
2252 /* Callback for other unknown chunks */
2253 png_set_read_user_chunk_fn(ping, image, read_vpag_chunk_callback);
2256 #if (PNG_LIBPNG_VER < 10400)
2257 # if defined(PNG_USE_PNGGCCRD) && defined(PNG_ASSEMBLER_CODE_SUPPORTED) && \
2258 (PNG_LIBPNG_VER >= 10200) && (PNG_LIBPNG_VER < 10220) && defined(__i386__)
2259 /* Disable thread-unsafe features of pnggccrd */
2260 if (png_access_version_number() >= 10200)
2262 png_uint_32 mmx_disable_mask=0;
2263 png_uint_32 asm_flags;
2265 mmx_disable_mask |= ( PNG_ASM_FLAG_MMX_READ_COMBINE_ROW \
2266 | PNG_ASM_FLAG_MMX_READ_FILTER_SUB \
2267 | PNG_ASM_FLAG_MMX_READ_FILTER_AVG \
2268 | PNG_ASM_FLAG_MMX_READ_FILTER_PAETH );
2269 asm_flags=png_get_asm_flags(ping);
2270 png_set_asm_flags(ping, asm_flags & ~mmx_disable_mask);
2275 png_read_info(ping,ping_info);
2277 png_get_IHDR(ping,ping_info,&ping_width,&ping_height,
2278 &ping_bit_depth,&ping_color_type,
2279 &ping_interlace_method,&ping_compression_method,
2280 &ping_filter_method);
2282 (void) png_get_tRNS(ping, ping_info, &ping_trans_alpha, &ping_num_trans,
2285 (void) png_get_bKGD(ping, ping_info, &ping_background);
2287 if (ping_bit_depth < 8)
2289 if (((int) ping_color_type == PNG_COLOR_TYPE_PALETTE))
2291 png_set_packing(ping);
2296 image->depth=ping_bit_depth;
2297 image->depth=GetImageQuantumDepth(image,MagickFalse);
2298 image->interlace=ping_interlace_method != 0 ? PNGInterlace : NoInterlace;
2299 if (logging != MagickFalse)
2301 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2302 " PNG width: %.20g, height: %.20g",
2303 (double) ping_width, (double) ping_height);
2305 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2306 " PNG color_type: %d, bit_depth: %d",
2307 ping_color_type, ping_bit_depth);
2309 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2310 " PNG compression_method: %d",
2311 ping_compression_method);
2313 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2314 " PNG interlace_method: %d, filter_method: %d",
2315 ping_interlace_method,ping_filter_method);
2318 #ifdef PNG_READ_iCCP_SUPPORTED
2319 if (png_get_valid(ping,ping_info,PNG_INFO_iCCP))
2324 #if (PNG_LIBPNG_VER < 10500)
2338 (void) png_get_iCCP(ping,ping_info,&name,(int *) &compression,&info,
2341 if (profile_length != 0)
2346 if (logging != MagickFalse)
2347 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2348 " Reading PNG iCCP chunk.");
2349 profile=BlobToStringInfo(info,profile_length);
2350 if (profile == (StringInfo *) NULL)
2352 png_warning(ping, "ICC profile is NULL");
2353 profile=DestroyStringInfo(profile);
2357 (void) SetImageProfile(image,"icc",profile,exception);
2358 profile=DestroyStringInfo(profile);
2363 #if defined(PNG_READ_sRGB_SUPPORTED)
2365 if (mng_info->have_global_srgb)
2367 image->rendering_intent=Magick_RenderingIntent_from_PNG_RenderingIntent
2368 (mng_info->global_srgb_intent);
2371 if (png_get_sRGB(ping,ping_info,&intent))
2373 image->rendering_intent=Magick_RenderingIntent_from_PNG_RenderingIntent
2376 if (logging != MagickFalse)
2377 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2378 " Reading PNG sRGB chunk: rendering_intent: %d",intent);
2383 if (!png_get_gAMA(ping,ping_info,&file_gamma))
2384 if (mng_info->have_global_gama)
2385 png_set_gAMA(ping,ping_info,mng_info->global_gamma);
2387 if (png_get_gAMA(ping,ping_info,&file_gamma))
2389 image->gamma=(float) file_gamma;
2390 if (logging != MagickFalse)
2391 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2392 " Reading PNG gAMA chunk: gamma: %f",file_gamma);
2395 if (!png_get_valid(ping,ping_info,PNG_INFO_cHRM))
2397 if (mng_info->have_global_chrm != MagickFalse)
2399 (void) png_set_cHRM(ping,ping_info,
2400 mng_info->global_chrm.white_point.x,
2401 mng_info->global_chrm.white_point.y,
2402 mng_info->global_chrm.red_primary.x,
2403 mng_info->global_chrm.red_primary.y,
2404 mng_info->global_chrm.green_primary.x,
2405 mng_info->global_chrm.green_primary.y,
2406 mng_info->global_chrm.blue_primary.x,
2407 mng_info->global_chrm.blue_primary.y);
2411 if (png_get_valid(ping,ping_info,PNG_INFO_cHRM))
2413 (void) png_get_cHRM(ping,ping_info,
2414 &image->chromaticity.white_point.x,
2415 &image->chromaticity.white_point.y,
2416 &image->chromaticity.red_primary.x,
2417 &image->chromaticity.red_primary.y,
2418 &image->chromaticity.green_primary.x,
2419 &image->chromaticity.green_primary.y,
2420 &image->chromaticity.blue_primary.x,
2421 &image->chromaticity.blue_primary.y);
2423 if (logging != MagickFalse)
2424 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2425 " Reading PNG cHRM chunk.");
2428 if (image->rendering_intent != UndefinedIntent)
2430 png_set_sRGB(ping,ping_info,
2431 Magick_RenderingIntent_to_PNG_RenderingIntent
2432 (image->rendering_intent));
2433 png_set_gAMA(ping,ping_info,1.000f/2.200f);
2434 png_set_cHRM(ping,ping_info,
2435 0.6400f, 0.3300f, 0.3000f, 0.6000f,
2436 0.1500f, 0.0600f, 0.3127f, 0.3290f);
2438 #if defined(PNG_oFFs_SUPPORTED)
2439 if (png_get_valid(ping,ping_info,PNG_INFO_oFFs))
2441 image->page.x=(ssize_t) png_get_x_offset_pixels(ping, ping_info);
2442 image->page.y=(ssize_t) png_get_y_offset_pixels(ping, ping_info);
2444 if (logging != MagickFalse)
2445 if (image->page.x || image->page.y)
2446 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2447 " Reading PNG oFFs chunk: x: %.20g, y: %.20g.",(double)
2448 image->page.x,(double) image->page.y);
2451 #if defined(PNG_pHYs_SUPPORTED)
2452 if (!png_get_valid(ping,ping_info,PNG_INFO_pHYs))
2454 if (mng_info->have_global_phys)
2456 png_set_pHYs(ping,ping_info,
2457 mng_info->global_x_pixels_per_unit,
2458 mng_info->global_y_pixels_per_unit,
2459 mng_info->global_phys_unit_type);
2463 if (png_get_valid(ping,ping_info,PNG_INFO_pHYs))
2466 Set image resolution.
2468 (void) png_get_pHYs(ping,ping_info,&x_resolution,&y_resolution,
2470 image->resolution.x=(double) x_resolution;
2471 image->resolution.y=(double) y_resolution;
2473 if (unit_type == PNG_RESOLUTION_METER)
2475 image->units=PixelsPerCentimeterResolution;
2476 image->resolution.x=(double) x_resolution/100.0;
2477 image->resolution.y=(double) y_resolution/100.0;
2480 if (logging != MagickFalse)
2481 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2482 " Reading PNG pHYs chunk: xres: %.20g, yres: %.20g, units: %d.",
2483 (double) x_resolution,(double) y_resolution,unit_type);
2487 if (png_get_valid(ping,ping_info,PNG_INFO_PLTE))
2495 (void) png_get_PLTE(ping,ping_info,&palette,&number_colors);
2497 if ((number_colors == 0) &&
2498 ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE))
2500 if (mng_info->global_plte_length)
2502 png_set_PLTE(ping,ping_info,mng_info->global_plte,
2503 (int) mng_info->global_plte_length);
2505 if (!png_get_valid(ping,ping_info,PNG_INFO_tRNS))
2507 if (mng_info->global_trns_length)
2510 "global tRNS has more entries than global PLTE");
2514 png_set_tRNS(ping,ping_info,mng_info->global_trns,
2515 (int) mng_info->global_trns_length,NULL);
2518 #ifdef PNG_READ_bKGD_SUPPORTED
2520 #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
2521 mng_info->have_saved_bkgd_index ||
2523 png_get_valid(ping,ping_info,PNG_INFO_bKGD))
2528 #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
2529 if (mng_info->have_saved_bkgd_index)
2530 background.index=mng_info->saved_bkgd_index;
2532 if (png_get_valid(ping, ping_info, PNG_INFO_bKGD))
2533 background.index=ping_background->index;
2535 background.red=(png_uint_16)
2536 mng_info->global_plte[background.index].red;
2538 background.green=(png_uint_16)
2539 mng_info->global_plte[background.index].green;
2541 background.blue=(png_uint_16)
2542 mng_info->global_plte[background.index].blue;
2544 background.gray=(png_uint_16)
2545 mng_info->global_plte[background.index].green;
2547 png_set_bKGD(ping,ping_info,&background);
2552 png_error(ping,"No global PLTE in file");
2556 #ifdef PNG_READ_bKGD_SUPPORTED
2557 if (mng_info->have_global_bkgd &&
2558 (!png_get_valid(ping,ping_info,PNG_INFO_bKGD)))
2559 image->background_color=mng_info->mng_global_bkgd;
2561 if (png_get_valid(ping,ping_info,PNG_INFO_bKGD))
2567 Set image background color.
2569 if (logging != MagickFalse)
2570 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2571 " Reading PNG bKGD chunk.");
2573 /* Scale background components to 16-bit, then scale
2576 if (logging != MagickFalse)
2577 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2578 " raw ping_background=(%d,%d,%d).",ping_background->red,
2579 ping_background->green,ping_background->blue);
2583 if (ping_bit_depth == 1)
2586 else if (ping_bit_depth == 2)
2589 else if (ping_bit_depth == 4)
2592 if (ping_bit_depth <= 8)
2595 ping_background->red *= bkgd_scale;
2596 ping_background->green *= bkgd_scale;
2597 ping_background->blue *= bkgd_scale;
2599 if (logging != MagickFalse)
2601 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2602 " bkgd_scale=%d.",bkgd_scale);
2604 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2605 " ping_background=(%d,%d,%d).",ping_background->red,
2606 ping_background->green,ping_background->blue);
2609 image->background_color.red=
2610 ScaleShortToQuantum(ping_background->red);
2612 image->background_color.green=
2613 ScaleShortToQuantum(ping_background->green);
2615 image->background_color.blue=
2616 ScaleShortToQuantum(ping_background->blue);
2618 image->background_color.alpha=OpaqueAlpha;
2620 if (logging != MagickFalse)
2621 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2622 " image->background_color=(%.20g,%.20g,%.20g).",
2623 (double) image->background_color.red,
2624 (double) image->background_color.green,
2625 (double) image->background_color.blue);
2627 #endif /* PNG_READ_bKGD_SUPPORTED */
2629 if (png_get_valid(ping,ping_info,PNG_INFO_tRNS))
2632 Image has a tRNS chunk.
2640 if (logging != MagickFalse)
2641 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2642 " Reading PNG tRNS chunk.");
2644 max_sample = (int) ((one << ping_bit_depth) - 1);
2646 if ((ping_color_type == PNG_COLOR_TYPE_GRAY &&
2647 (int)ping_trans_color->gray > max_sample) ||
2648 (ping_color_type == PNG_COLOR_TYPE_RGB &&
2649 ((int)ping_trans_color->red > max_sample ||
2650 (int)ping_trans_color->green > max_sample ||
2651 (int)ping_trans_color->blue > max_sample)))
2653 if (logging != MagickFalse)
2654 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2655 " Ignoring PNG tRNS chunk with out-of-range sample.");
2656 png_free_data(ping, ping_info, PNG_FREE_TRNS, 0);
2657 png_set_invalid(ping,ping_info,PNG_INFO_tRNS);
2658 image->matte=MagickFalse;
2665 scale_to_short = 65535L/((1UL << ping_bit_depth)-1);
2667 /* Scale transparent_color to short */
2668 transparent_color.red= scale_to_short*ping_trans_color->red;
2669 transparent_color.green= scale_to_short*ping_trans_color->green;
2670 transparent_color.blue= scale_to_short*ping_trans_color->blue;
2671 transparent_color.alpha= scale_to_short*ping_trans_color->gray;
2673 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
2675 if (logging != MagickFalse)
2677 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2678 " Raw tRNS graylevel is %d.",ping_trans_color->gray);
2680 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2681 " scaled graylevel is %.20g.",transparent_color.alpha);
2683 transparent_color.red=transparent_color.alpha;
2684 transparent_color.green=transparent_color.alpha;
2685 transparent_color.blue=transparent_color.alpha;
2689 #if defined(PNG_READ_sBIT_SUPPORTED)
2690 if (mng_info->have_global_sbit)
2692 if (!png_get_valid(ping,ping_info,PNG_INFO_sBIT))
2693 png_set_sBIT(ping,ping_info,&mng_info->global_sbit);
2696 num_passes=png_set_interlace_handling(ping);
2698 png_read_update_info(ping,ping_info);
2700 ping_rowbytes=png_get_rowbytes(ping,ping_info);
2703 Initialize image structure.
2705 mng_info->image_box.left=0;
2706 mng_info->image_box.right=(ssize_t) ping_width;
2707 mng_info->image_box.top=0;
2708 mng_info->image_box.bottom=(ssize_t) ping_height;
2709 if (mng_info->mng_type == 0)
2711 mng_info->mng_width=ping_width;
2712 mng_info->mng_height=ping_height;
2713 mng_info->frame=mng_info->image_box;
2714 mng_info->clip=mng_info->image_box;
2719 image->page.y=mng_info->y_off[mng_info->object_id];
2722 image->compression=ZipCompression;
2723 image->columns=ping_width;
2724 image->rows=ping_height;
2725 if (((int) ping_color_type == PNG_COLOR_TYPE_GRAY) ||
2726 ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA))
2727 image->colorspace=GRAYColorspace;
2728 if (((int) ping_color_type == PNG_COLOR_TYPE_PALETTE) ||
2729 ((int) ping_color_type == PNG_COLOR_TYPE_GRAY))
2734 image->storage_class=PseudoClass;
2736 image->colors=one << ping_bit_depth;
2737 #if (MAGICKCORE_QUANTUM_DEPTH == 8)
2738 if (image->colors > 256)
2741 if (image->colors > 65536L)
2742 image->colors=65536L;
2744 if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
2752 (void) png_get_PLTE(ping,ping_info,&palette,&number_colors);
2753 image->colors=(size_t) number_colors;
2755 if (logging != MagickFalse)
2756 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2757 " Reading PNG PLTE chunk: number_colors: %d.",number_colors);
2761 if (image->storage_class == PseudoClass)
2764 Initialize image colormap.
2766 if (AcquireImageColormap(image,image->colors,exception) == MagickFalse)
2767 png_error(ping,"Memory allocation failed");
2769 if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
2777 (void) png_get_PLTE(ping,ping_info,&palette,&number_colors);
2779 for (i=0; i < (ssize_t) number_colors; i++)
2781 image->colormap[i].red=ScaleCharToQuantum(palette[i].red);
2782 image->colormap[i].green=ScaleCharToQuantum(palette[i].green);
2783 image->colormap[i].blue=ScaleCharToQuantum(palette[i].blue);
2786 for ( ; i < (ssize_t) image->colors; i++)
2788 image->colormap[i].red=0;
2789 image->colormap[i].green=0;
2790 image->colormap[i].blue=0;
2799 scale=(QuantumRange/((1UL << ping_bit_depth)-1));
2804 for (i=0; i < (ssize_t) image->colors; i++)
2806 image->colormap[i].red=(Quantum) (i*scale);
2807 image->colormap[i].green=(Quantum) (i*scale);
2808 image->colormap[i].blue=(Quantum) (i*scale);
2813 /* Set some properties for reporting by "identify" */
2818 /* encode ping_width, ping_height, ping_bit_depth, ping_color_type,
2819 ping_interlace_method in value */
2821 (void) FormatLocaleString(msg,MaxTextExtent,
2822 "%d, %d",(int) ping_width, (int) ping_height);
2823 (void) SetImageProperty(image,"png:IHDR.width,height ",msg,exception);
2825 (void) FormatLocaleString(msg,MaxTextExtent,"%d",(int) ping_bit_depth);
2826 (void) SetImageProperty(image,"png:IHDR.bit_depth ",msg,exception);
2828 (void) FormatLocaleString(msg,MaxTextExtent,"%d",(int) ping_color_type);
2829 (void) SetImageProperty(image,"png:IHDR.color_type ",msg,exception);
2831 (void) FormatLocaleString(msg,MaxTextExtent,"%d",
2832 (int) ping_interlace_method);
2833 (void) SetImageProperty(image,"png:IHDR.interlace_method",msg,exception);
2837 Read image scanlines.
2839 if (image->delay != 0)
2840 mng_info->scenes_found++;
2842 if ((mng_info->mng_type == 0 && (image->ping != MagickFalse)) || (
2843 (image_info->number_scenes != 0) && (mng_info->scenes_found > (ssize_t)
2844 (image_info->first_scene+image_info->number_scenes))))
2846 /* This happens later in non-ping decodes */
2847 if (png_get_valid(ping,ping_info,PNG_INFO_tRNS))
2848 image->storage_class=DirectClass;
2850 if (logging != MagickFalse)
2851 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2852 " Skipping PNG image data for scene %.20g",(double)
2853 mng_info->scenes_found-1);
2854 png_destroy_read_struct(&ping,&ping_info,&end_info);
2856 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
2857 UnlockSemaphoreInfo(ping_semaphore);
2860 if (logging != MagickFalse)
2861 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2862 " exit ReadOnePNGImage().");
2867 if (logging != MagickFalse)
2868 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2869 " Reading PNG IDAT chunk(s)");
2872 ping_pixels=(unsigned char *) AcquireQuantumMemory(image->rows,
2873 ping_rowbytes*sizeof(*ping_pixels));
2876 ping_pixels=(unsigned char *) AcquireQuantumMemory(ping_rowbytes,
2877 sizeof(*ping_pixels));
2879 if (ping_pixels == (unsigned char *) NULL)
2880 png_error(ping,"Memory allocation failed");
2882 if (logging != MagickFalse)
2883 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2884 " Converting PNG pixels to pixel packets");
2886 Convert PNG pixels to pixel packets.
2888 quantum_info=AcquireQuantumInfo(image_info,image);
2890 if (quantum_info == (QuantumInfo *) NULL)
2891 png_error(ping,"Failed to allocate quantum_info");
2896 found_transparent_pixel;
2898 found_transparent_pixel=MagickFalse;
2900 if (image->storage_class == DirectClass)
2902 for (pass=0; pass < num_passes; pass++)
2905 Convert image to DirectClass pixel packets.
2907 #if (MAGICKCORE_QUANTUM_DEPTH == 8)
2911 depth=(ssize_t) ping_bit_depth;
2913 image->matte=(((int) ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA) ||
2914 ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) ||
2915 (png_get_valid(ping,ping_info,PNG_INFO_tRNS))) ?
2916 MagickTrue : MagickFalse;
2918 for (y=0; y < (ssize_t) image->rows; y++)
2921 row_offset=ping_rowbytes*y;
2926 png_read_row(ping,ping_pixels+row_offset,NULL);
2927 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
2929 if (q == (Quantum *) NULL)
2932 if ((int) ping_color_type == PNG_COLOR_TYPE_GRAY)
2933 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
2934 GrayQuantum,ping_pixels+row_offset,exception);
2936 else if ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
2937 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
2938 GrayAlphaQuantum,ping_pixels+row_offset,exception);
2940 else if ((int) ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA)
2941 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
2942 RGBAQuantum,ping_pixels+row_offset,exception);
2944 else if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
2945 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
2946 IndexQuantum,ping_pixels+row_offset,exception);
2948 else /* ping_color_type == PNG_COLOR_TYPE_RGB */
2949 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
2950 RGBQuantum,ping_pixels+row_offset,exception);
2952 if (found_transparent_pixel == MagickFalse)
2954 /* Is there a transparent pixel in the row? */
2955 if (y== 0 && logging != MagickFalse)
2956 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2957 " Looking for cheap transparent pixel");
2959 for (x=(ssize_t) image->columns-1; x >= 0; x--)
2961 if ((ping_color_type == PNG_COLOR_TYPE_RGBA ||
2962 ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) &&
2963 (GetPixelAlpha(image,q) != OpaqueAlpha))
2965 if (logging != MagickFalse)
2966 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2969 found_transparent_pixel = MagickTrue;
2972 if ((ping_color_type == PNG_COLOR_TYPE_RGB ||
2973 ping_color_type == PNG_COLOR_TYPE_GRAY) &&
2974 (ScaleQuantumToShort(GetPixelRed(image,q)) ==
2975 transparent_color.red &&
2976 ScaleQuantumToShort(GetPixelGreen(image,q)) ==
2977 transparent_color.green &&
2978 ScaleQuantumToShort(GetPixelBlue(image,q)) ==
2979 transparent_color.blue))
2981 if (logging != MagickFalse)
2982 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2984 found_transparent_pixel = MagickTrue;
2987 q+=GetPixelChannels(image);
2991 if ((image->previous == (Image *) NULL) && (num_passes == 1))
2993 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
2996 if (status == MagickFalse)
2999 if (SyncAuthenticPixels(image,exception) == MagickFalse)
3003 if ((image->previous == (Image *) NULL) && (num_passes != 1))
3005 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
3006 if (status == MagickFalse)
3012 else /* image->storage_class != DirectClass */
3014 for (pass=0; pass < num_passes; pass++)
3023 Convert grayscale image to PseudoClass pixel packets.
3025 if (logging != MagickFalse)
3026 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3027 " Converting grayscale pixels to pixel packets");
3029 image->matte=ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA ?
3030 MagickTrue : MagickFalse;
3032 quantum_scanline=(Quantum *) AcquireQuantumMemory(image->columns,
3033 (image->matte ? 2 : 1)*sizeof(*quantum_scanline));
3035 if (quantum_scanline == (Quantum *) NULL)
3036 png_error(ping,"Memory allocation failed");
3038 for (y=0; y < (ssize_t) image->rows; y++)
3041 row_offset=ping_rowbytes*y;
3046 png_read_row(ping,ping_pixels+row_offset,NULL);
3047 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
3049 if (q == (Quantum *) NULL)
3052 p=ping_pixels+row_offset;
3055 switch (ping_bit_depth)
3062 for (x=(ssize_t) image->columns-7; x > 0; x-=8)
3064 for (bit=7; bit >= 0; bit--)
3065 *r++=(Quantum) ((*p) & (0x01 << bit) ? 0x01 : 0x00);
3069 if ((image->columns % 8) != 0)
3071 for (bit=7; bit >= (ssize_t) (8-(image->columns % 8)); bit--)
3072 *r++=(Quantum) ((*p) & (0x01 << bit) ? 0x01 : 0x00);
3080 for (x=(ssize_t) image->columns-3; x > 0; x-=4)
3082 *r++=(*p >> 6) & 0x03;
3083 *r++=(*p >> 4) & 0x03;
3084 *r++=(*p >> 2) & 0x03;
3088 if ((image->columns % 4) != 0)
3090 for (i=3; i >= (ssize_t) (4-(image->columns % 4)); i--)
3091 *r++=(Quantum) ((*p >> (i*2)) & 0x03);
3099 for (x=(ssize_t) image->columns-1; x > 0; x-=2)
3101 *r++=(*p >> 4) & 0x0f;
3105 if ((image->columns % 2) != 0)
3106 *r++=(*p++ >> 4) & 0x0f;
3113 if (ping_color_type == 4)
3114 for (x=(ssize_t) image->columns-1; x >= 0; x--)
3117 SetPixelAlpha(image,ScaleCharToQuantum((unsigned char) *p++),q);
3118 if (GetPixelAlpha(image,q) != OpaqueAlpha)
3119 found_transparent_pixel = MagickTrue;
3120 q+=GetPixelChannels(image);
3124 for (x=(ssize_t) image->columns-1; x >= 0; x--)
3132 for (x=(ssize_t) image->columns-1; x >= 0; x--)
3134 #if (MAGICKCORE_QUANTUM_DEPTH == 16) || (MAGICKCORE_QUANTUM_DEPTH == 32)
3138 if (image->colors > 256)
3139 quantum=((*p++) << 8);
3145 *r=ScaleShortToQuantum(quantum);
3148 if (ping_color_type == 4)
3150 if (image->colors > 256)
3151 quantum=((*p++) << 8);
3156 SetPixelAlpha(image,ScaleShortToQuantum(quantum),q);
3157 if (GetPixelAlpha(image,q) != OpaqueAlpha)
3158 found_transparent_pixel = MagickTrue;
3159 q+=GetPixelChannels(image);
3162 #else /* MAGICKCORE_QUANTUM_DEPTH == 8 */
3164 p++; /* strip low byte */
3166 if (ping_color_type == 4)
3168 SetPixelAlpha(image,*p++,q);
3169 if (GetPixelAlpha(image,q) != OpaqueAlpha)
3170 found_transparent_pixel = MagickTrue;
3172 q+=GetPixelChannels(image);
3185 Transfer image scanline.
3189 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
3191 if (q == (Quantum *) NULL)
3193 for (x=0; x < (ssize_t) image->columns; x++)
3195 SetPixelIndex(image,*r++,q);
3196 q+=GetPixelChannels(image);
3199 if (SyncAuthenticPixels(image,exception) == MagickFalse)
3202 if ((image->previous == (Image *) NULL) && (num_passes == 1))
3204 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
3207 if (status == MagickFalse)
3212 if ((image->previous == (Image *) NULL) && (num_passes != 1))
3214 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
3216 if (status == MagickFalse)
3220 quantum_scanline=(Quantum *) RelinquishMagickMemory(quantum_scanline);
3223 image->matte=found_transparent_pixel;
3225 if (logging != MagickFalse)
3227 if (found_transparent_pixel != MagickFalse)
3228 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3229 " Found transparent pixel");
3232 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3233 " No transparent pixel was found");
3235 ping_color_type&=0x03;
3240 if (quantum_info != (QuantumInfo *) NULL)
3241 quantum_info=DestroyQuantumInfo(quantum_info);
3243 if (image->storage_class == PseudoClass)
3249 image->matte=MagickFalse;
3250 (void) SyncImage(image,exception);
3254 png_read_end(ping,end_info);
3256 if (image_info->number_scenes != 0 && mng_info->scenes_found-1 <
3257 (ssize_t) image_info->first_scene && image->delay != 0)
3259 png_destroy_read_struct(&ping,&ping_info,&end_info);
3260 ping_pixels=(unsigned char *) RelinquishMagickMemory(ping_pixels);
3262 (void) SetImageBackgroundColor(image,exception);
3263 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
3264 UnlockSemaphoreInfo(ping_semaphore);
3266 if (logging != MagickFalse)
3267 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3268 " exit ReadOnePNGImage() early.");
3272 if (png_get_valid(ping,ping_info,PNG_INFO_tRNS))
3278 Image has a transparent background.
3280 storage_class=image->storage_class;
3281 image->matte=MagickTrue;
3283 /* Balfour fix from imagemagick discourse server, 5 Feb 2010 */
3285 if (storage_class == PseudoClass)
3287 if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
3289 for (x=0; x < ping_num_trans; x++)
3291 image->colormap[x].matte=MagickTrue;
3292 image->colormap[x].alpha =
3293 ScaleCharToQuantum((unsigned char)ping_trans_alpha[x]);
3297 else if (ping_color_type == PNG_COLOR_TYPE_GRAY)
3299 for (x=0; x < (int) image->colors; x++)
3301 if (ScaleQuantumToShort(image->colormap[x].red) ==
3302 transparent_color.alpha)
3304 image->colormap[x].matte=MagickTrue;
3305 image->colormap[x].alpha = (Quantum) TransparentAlpha;
3309 (void) SyncImage(image,exception);
3312 #if 1 /* Should have already been done above, but glennrp problem P10
3317 for (y=0; y < (ssize_t) image->rows; y++)
3319 image->storage_class=storage_class;
3320 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
3322 if (q == (Quantum *) NULL)
3326 /* Caution: on a Q8 build, this does not distinguish between
3327 * 16-bit colors that differ only in the low byte
3329 for (x=(ssize_t) image->columns-1; x >= 0; x--)
3331 if (ScaleQuantumToShort(GetPixelRed(image,q)) ==
3332 transparent_color.red &&
3333 ScaleQuantumToShort(GetPixelGreen(image,q)) ==
3334 transparent_color.green &&
3335 ScaleQuantumToShort(GetPixelBlue(image,q)) ==
3336 transparent_color.blue)
3338 SetPixelAlpha(image,TransparentAlpha,q);
3341 #if 0 /* I have not found a case where this is needed. */
3344 SetPixelAlpha(image,q)=(Quantum) OpaqueAlpha;
3348 q+=GetPixelChannels(image);
3351 if (SyncAuthenticPixels(image,exception) == MagickFalse)
3357 image->storage_class=DirectClass;
3360 for (j = 0; j < 2; j++)
3363 status = png_get_text(ping,ping_info,&text,&num_text) != 0 ?
3364 MagickTrue : MagickFalse;
3366 status = png_get_text(ping,end_info,&text,&num_text) != 0 ?
3367 MagickTrue : MagickFalse;
3369 if (status != MagickFalse)
3370 for (i=0; i < (ssize_t) num_text; i++)
3372 /* Check for a profile */
3374 if (logging != MagickFalse)
3375 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3376 " Reading PNG text chunk");
3378 if (memcmp(text[i].key, "Raw profile type ",17) == 0)
3380 (void) Magick_png_read_raw_profile(ping,image,image_info,text,
3390 length=text[i].text_length;
3391 value=(char *) AcquireQuantumMemory(length+MaxTextExtent,
3393 if (value == (char *) NULL)
3395 png_error(ping,"Memory allocation failed");
3399 (void) ConcatenateMagickString(value,text[i].text,length+2);
3401 /* Don't save "density" or "units" property if we have a pHYs
3404 if (!png_get_valid(ping,ping_info,PNG_INFO_pHYs) ||
3405 (LocaleCompare(text[i].key,"density") != 0 &&
3406 LocaleCompare(text[i].key,"units") != 0))
3407 (void) SetImageProperty(image,text[i].key,value,exception);
3409 if (logging != MagickFalse)
3411 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3412 " length: %lu",(unsigned long) length);
3413 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3414 " Keyword: %s",text[i].key);
3417 value=DestroyString(value);
3420 num_text_total += num_text;
3423 #ifdef MNG_OBJECT_BUFFERS
3425 Store the object if necessary.
3427 if (object_id && !mng_info->frozen[object_id])
3429 if (mng_info->ob[object_id] == (MngBuffer *) NULL)
3432 create a new object buffer.
3434 mng_info->ob[object_id]=(MngBuffer *)
3435 AcquireMagickMemory(sizeof(MngBuffer));
3437 if (mng_info->ob[object_id] != (MngBuffer *) NULL)
3439 mng_info->ob[object_id]->image=(Image *) NULL;
3440 mng_info->ob[object_id]->reference_count=1;
3444 if ((mng_info->ob[object_id] == (MngBuffer *) NULL) ||
3445 mng_info->ob[object_id]->frozen)
3447 if (mng_info->ob[object_id] == (MngBuffer *) NULL)
3448 png_error(ping,"Memory allocation failed");
3450 if (mng_info->ob[object_id]->frozen)
3451 png_error(ping,"Cannot overwrite frozen MNG object buffer");
3457 if (mng_info->ob[object_id]->image != (Image *) NULL)
3458 mng_info->ob[object_id]->image=DestroyImage
3459 (mng_info->ob[object_id]->image);
3461 mng_info->ob[object_id]->image=CloneImage(image,0,0,MagickTrue,
3464 if (mng_info->ob[object_id]->image != (Image *) NULL)
3465 mng_info->ob[object_id]->image->file=(FILE *) NULL;
3468 png_error(ping, "Cloning image for object buffer failed");
3470 if (ping_width > 250000L || ping_height > 250000L)
3471 png_error(ping,"PNG Image dimensions are too large.");
3473 mng_info->ob[object_id]->width=ping_width;
3474 mng_info->ob[object_id]->height=ping_height;
3475 mng_info->ob[object_id]->color_type=ping_color_type;
3476 mng_info->ob[object_id]->sample_depth=ping_bit_depth;
3477 mng_info->ob[object_id]->interlace_method=ping_interlace_method;
3478 mng_info->ob[object_id]->compression_method=
3479 ping_compression_method;
3480 mng_info->ob[object_id]->filter_method=ping_filter_method;
3482 if (png_get_valid(ping,ping_info,PNG_INFO_PLTE))
3491 Copy the PLTE to the object buffer.
3493 png_get_PLTE(ping,ping_info,&plte,&number_colors);
3494 mng_info->ob[object_id]->plte_length=number_colors;
3496 for (i=0; i < number_colors; i++)
3498 mng_info->ob[object_id]->plte[i]=plte[i];
3503 mng_info->ob[object_id]->plte_length=0;
3508 /* Set image->matte to MagickTrue if the input colortype supports
3509 * alpha or if a valid tRNS chunk is present, no matter whether there
3510 * is actual transparency present.
3512 image->matte=(((int) ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA) ||
3513 ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) ||
3514 (png_get_valid(ping,ping_info,PNG_INFO_tRNS))) ?
3515 MagickTrue : MagickFalse;
3517 /* Set more properties for identify to retrieve */
3522 if (num_text_total != 0)
3524 /* libpng doesn't tell us whether they were tEXt, zTXt, or iTXt */
3525 (void) FormatLocaleString(msg,MaxTextExtent,
3526 "%d tEXt/zTXt/iTXt chunks were found", num_text_total);
3527 (void) SetImageProperty(image,"png:text ",msg,
3531 if (num_raw_profiles != 0)
3533 (void) FormatLocaleString(msg,MaxTextExtent,
3534 "%d were found", num_raw_profiles);
3535 (void) SetImageProperty(image,"png:text-encoded profiles",msg,
3539 if (png_get_valid(ping,ping_info,PNG_INFO_cHRM))
3541 (void) FormatLocaleString(msg,MaxTextExtent,"%s",
3542 "chunk was found (see Chromaticity, above)");
3543 (void) SetImageProperty(image,"png:cHRM ",msg,
3547 if (png_get_valid(ping,ping_info,PNG_INFO_bKGD))
3549 (void) FormatLocaleString(msg,MaxTextExtent,"%s",
3550 "chunk was found (see Background color, above)");
3551 (void) SetImageProperty(image,"png:bKGD ",msg,
3555 (void) FormatLocaleString(msg,MaxTextExtent,"%s",
3558 if (png_get_valid(ping,ping_info,PNG_INFO_iCCP))
3559 (void) SetImageProperty(image,"png:iCCP ",msg,
3562 if (png_get_valid(ping,ping_info,PNG_INFO_tRNS))
3563 (void) SetImageProperty(image,"png:tRNS ",msg,
3566 #if defined(PNG_sRGB_SUPPORTED)
3567 if (png_get_valid(ping,ping_info,PNG_INFO_sRGB))
3569 (void) FormatLocaleString(msg,MaxTextExtent,
3570 "intent=%d (See Rendering intent)", (int) intent);
3571 (void) SetImageProperty(image,"png:sRGB ",msg,
3576 if (png_get_valid(ping,ping_info,PNG_INFO_gAMA))
3578 (void) FormatLocaleString(msg,MaxTextExtent,
3579 "gamma=%.8g (See Gamma, above)",
3581 (void) SetImageProperty(image,"png:gAMA ",msg,
3585 #if defined(PNG_pHYs_SUPPORTED)
3586 if (png_get_valid(ping,ping_info,PNG_INFO_pHYs))
3588 (void) FormatLocaleString(msg,MaxTextExtent,
3589 "x_res=%.10g, y_res=%.10g, units=%d",
3590 (double) x_resolution,(double) y_resolution, unit_type);
3591 (void) SetImageProperty(image,"png:pHYs ",msg,
3596 #if defined(PNG_oFFs_SUPPORTED)
3597 if (png_get_valid(ping,ping_info,PNG_INFO_oFFs))
3599 (void) FormatLocaleString(msg,MaxTextExtent,"x_off=%.20g, y_off=%.20g",
3600 (double) image->page.x,(double) image->page.y);
3601 (void) SetImageProperty(image,"png:oFFs ",msg,
3606 if ((image->page.width != 0 && image->page.width != image->columns) ||
3607 (image->page.height != 0 && image->page.height != image->rows))
3609 (void) FormatLocaleString(msg,MaxTextExtent,
3610 "width=%.20g, height=%.20g",
3611 (double) image->page.width,(double) image->page.height);
3612 (void) SetImageProperty(image,"png:vpAg ",msg,
3618 Relinquish resources.
3620 png_destroy_read_struct(&ping,&ping_info,&end_info);
3622 ping_pixels=(unsigned char *) RelinquishMagickMemory(ping_pixels);
3624 if (logging != MagickFalse)
3625 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3626 " exit ReadOnePNGImage()");
3628 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
3629 UnlockSemaphoreInfo(ping_semaphore);
3632 /* } for navigation to beginning of SETJMP-protected block, revert to
3633 * Throwing an Exception when an error occurs.
3638 /* end of reading one PNG image */
3641 static Image *ReadPNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
3656 magic_number[MaxTextExtent];
3664 assert(image_info != (const ImageInfo *) NULL);
3665 assert(image_info->signature == MagickSignature);
3667 if (image_info->debug != MagickFalse)
3668 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
3669 image_info->filename);
3671 assert(exception != (ExceptionInfo *) NULL);
3672 assert(exception->signature == MagickSignature);
3673 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter ReadPNGImage()");
3674 image=AcquireImage(image_info,exception);
3675 mng_info=(MngInfo *) NULL;
3676 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
3678 if (status == MagickFalse)
3679 ThrowReaderException(FileOpenError,"UnableToOpenFile");
3682 Verify PNG signature.
3684 count=ReadBlob(image,8,(unsigned char *) magic_number);
3686 if (count < 8 || memcmp(magic_number,"\211PNG\r\n\032\n",8) != 0)
3687 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
3690 Allocate a MngInfo structure.
3692 have_mng_structure=MagickFalse;
3693 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
3695 if (mng_info == (MngInfo *) NULL)
3696 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
3699 Initialize members of the MngInfo structure.
3701 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
3702 mng_info->image=image;
3703 have_mng_structure=MagickTrue;
3706 image=ReadOnePNGImage(mng_info,image_info,exception);
3707 MngInfoFreeStruct(mng_info,&have_mng_structure);
3709 if (image == (Image *) NULL)
3711 if (previous != (Image *) NULL)
3713 if (previous->signature != MagickSignature)
3714 ThrowReaderException(CorruptImageError,"CorruptImage");
3716 (void) CloseBlob(previous);
3717 (void) DestroyImageList(previous);
3720 if (logging != MagickFalse)
3721 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3722 "exit ReadPNGImage() with error");
3724 return((Image *) NULL);
3727 (void) CloseBlob(image);
3729 if ((image->columns == 0) || (image->rows == 0))
3731 if (logging != MagickFalse)
3732 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3733 "exit ReadPNGImage() with error.");
3735 ThrowReaderException(CorruptImageError,"CorruptImage");
3738 if (LocaleCompare(image_info->magick,"PNG24") == 0)
3740 (void) SetImageType(image,TrueColorType,exception);
3741 image->matte=MagickFalse;
3744 if (LocaleCompare(image_info->magick,"PNG32") == 0)
3745 (void) SetImageType(image,TrueColorMatteType,exception);
3747 if (logging != MagickFalse)
3748 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3749 " page.w: %.20g, page.h: %.20g,page.x: %.20g, page.y: %.20g.",
3750 (double) image->page.width,(double) image->page.height,
3751 (double) image->page.x,(double) image->page.y);
3753 if (logging != MagickFalse)
3754 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit ReadPNGImage()");
3761 #if defined(JNG_SUPPORTED)
3763 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3767 % R e a d O n e J N G I m a g e %
3771 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3773 % ReadOneJNGImage() reads a JPEG Network Graphics (JNG) image file
3774 % (minus the 8-byte signature) and returns it. It allocates the memory
3775 % necessary for the new Image structure and returns a pointer to the new
3778 % JNG support written by Glenn Randers-Pehrson, glennrp@image...
3780 % The format of the ReadOneJNGImage method is:
3782 % Image *ReadOneJNGImage(MngInfo *mng_info, const ImageInfo *image_info,
3783 % ExceptionInfo *exception)
3785 % A description of each parameter follows:
3787 % o mng_info: Specifies a pointer to a MngInfo structure.
3789 % o image_info: the image info.
3791 % o exception: return any errors or warnings in this structure.
3794 static Image *ReadOneJNGImage(MngInfo *mng_info,
3795 const ImageInfo *image_info, ExceptionInfo *exception)
3822 jng_image_sample_depth,
3823 jng_image_compression_method,
3824 jng_image_interlace_method,
3825 jng_alpha_sample_depth,
3826 jng_alpha_compression_method,
3827 jng_alpha_filter_method,
3828 jng_alpha_interlace_method;
3830 register const Quantum
3840 register unsigned char
3851 jng_alpha_compression_method=0;
3852 jng_alpha_sample_depth=8;
3856 alpha_image=(Image *) NULL;
3857 color_image=(Image *) NULL;
3858 alpha_image_info=(ImageInfo *) NULL;
3859 color_image_info=(ImageInfo *) NULL;
3861 logging=LogMagickEvent(CoderEvent,GetMagickModule(),
3862 " Enter ReadOneJNGImage()");
3864 image=mng_info->image;
3866 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
3869 Allocate next image structure.
3871 if (logging != MagickFalse)
3872 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3873 " AcquireNextImage()");
3875 AcquireNextImage(image_info,image,exception);
3877 if (GetNextImageInList(image) == (Image *) NULL)
3878 return((Image *) NULL);
3880 image=SyncNextImageInList(image);
3882 mng_info->image=image;
3885 Signature bytes have already been read.
3888 read_JSEP=MagickFalse;
3889 reading_idat=MagickFalse;
3890 skip_to_iend=MagickFalse;
3894 type[MaxTextExtent];
3903 Read a new JNG chunk.
3905 status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
3906 2*GetBlobSize(image));
3908 if (status == MagickFalse)
3912 (void) ConcatenateMagickString(type,"errr",MaxTextExtent);
3913 length=ReadBlobMSBLong(image);
3914 count=(unsigned int) ReadBlob(image,4,(unsigned char *) type);
3916 if (logging != MagickFalse)
3917 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3918 " Reading JNG chunk type %c%c%c%c, length: %.20g",
3919 type[0],type[1],type[2],type[3],(double) length);
3921 if (length > PNG_UINT_31_MAX || count == 0)
3922 ThrowReaderException(CorruptImageError,"CorruptImage");
3925 chunk=(unsigned char *) NULL;
3929 chunk=(unsigned char *) AcquireQuantumMemory(length,sizeof(*chunk));
3931 if (chunk == (unsigned char *) NULL)
3932 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
3934 for (i=0; i < (ssize_t) length; i++)
3935 chunk[i]=(unsigned char) ReadBlobByte(image);
3940 (void) ReadBlobMSBLong(image); /* read crc word */
3945 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
3950 if (memcmp(type,mng_JHDR,4) == 0)
3954 jng_width=(size_t) ((p[0] << 24) | (p[1] << 16) |
3955 (p[2] << 8) | p[3]);
3956 jng_height=(size_t) ((p[4] << 24) | (p[5] << 16) |
3957 (p[6] << 8) | p[7]);
3958 jng_color_type=p[8];
3959 jng_image_sample_depth=p[9];
3960 jng_image_compression_method=p[10];
3961 jng_image_interlace_method=p[11];
3963 image->interlace=jng_image_interlace_method != 0 ? PNGInterlace :
3966 jng_alpha_sample_depth=p[12];
3967 jng_alpha_compression_method=p[13];
3968 jng_alpha_filter_method=p[14];
3969 jng_alpha_interlace_method=p[15];
3971 if (logging != MagickFalse)
3973 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3974 " jng_width: %16lu",(unsigned long) jng_width);
3976 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3977 " jng_width: %16lu",(unsigned long) jng_height);
3979 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3980 " jng_color_type: %16d",jng_color_type);
3982 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3983 " jng_image_sample_depth: %3d",
3984 jng_image_sample_depth);
3986 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3987 " jng_image_compression_method:%3d",
3988 jng_image_compression_method);
3990 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3991 " jng_image_interlace_method: %3d",
3992 jng_image_interlace_method);
3994 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3995 " jng_alpha_sample_depth: %3d",
3996 jng_alpha_sample_depth);
3998 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3999 " jng_alpha_compression_method:%3d",
4000 jng_alpha_compression_method);
4002 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4003 " jng_alpha_filter_method: %3d",
4004 jng_alpha_filter_method);
4006 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4007 " jng_alpha_interlace_method: %3d",
4008 jng_alpha_interlace_method);
4013 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4019 if ((reading_idat == MagickFalse) && (read_JSEP == MagickFalse) &&
4020 ((memcmp(type,mng_JDAT,4) == 0) || (memcmp(type,mng_JdAA,4) == 0) ||
4021 (memcmp(type,mng_IDAT,4) == 0) || (memcmp(type,mng_JDAA,4) == 0)))
4024 o create color_image
4025 o open color_blob, attached to color_image
4026 o if (color type has alpha)
4027 open alpha_blob, attached to alpha_image
4030 color_image_info=(ImageInfo *)AcquireMagickMemory(sizeof(ImageInfo));
4032 if (color_image_info == (ImageInfo *) NULL)
4033 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
4035 GetImageInfo(color_image_info);
4036 color_image=AcquireImage(color_image_info,exception);
4038 if (color_image == (Image *) NULL)
4039 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
4041 if (logging != MagickFalse)
4042 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4043 " Creating color_blob.");
4045 (void) AcquireUniqueFilename(color_image->filename);
4046 status=OpenBlob(color_image_info,color_image,WriteBinaryBlobMode,
4049 if (status == MagickFalse)
4050 return((Image *) NULL);
4052 if ((image_info->ping == MagickFalse) && (jng_color_type >= 12))
4054 alpha_image_info=(ImageInfo *)
4055 AcquireMagickMemory(sizeof(ImageInfo));
4057 if (alpha_image_info == (ImageInfo *) NULL)
4058 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
4060 GetImageInfo(alpha_image_info);
4061 alpha_image=AcquireImage(alpha_image_info,exception);
4063 if (alpha_image == (Image *) NULL)
4065 alpha_image=DestroyImage(alpha_image);
4066 ThrowReaderException(ResourceLimitError,
4067 "MemoryAllocationFailed");
4070 if (logging != MagickFalse)
4071 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4072 " Creating alpha_blob.");
4074 (void) AcquireUniqueFilename(alpha_image->filename);
4075 status=OpenBlob(alpha_image_info,alpha_image,WriteBinaryBlobMode,
4078 if (status == MagickFalse)
4079 return((Image *) NULL);
4081 if (jng_alpha_compression_method == 0)
4086 if (logging != MagickFalse)
4087 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4088 " Writing IHDR chunk to alpha_blob.");
4090 (void) WriteBlob(alpha_image,8,(const unsigned char *)
4091 "\211PNG\r\n\032\n");
4093 (void) WriteBlobMSBULong(alpha_image,13L);
4094 PNGType(data,mng_IHDR);
4095 LogPNGChunk(logging,mng_IHDR,13L);
4096 PNGLong(data+4,jng_width);
4097 PNGLong(data+8,jng_height);
4098 data[12]=jng_alpha_sample_depth;
4099 data[13]=0; /* color_type gray */
4100 data[14]=0; /* compression method 0 */
4101 data[15]=0; /* filter_method 0 */
4102 data[16]=0; /* interlace_method 0 */
4103 (void) WriteBlob(alpha_image,17,data);
4104 (void) WriteBlobMSBULong(alpha_image,crc32(0,data,17));
4107 reading_idat=MagickTrue;
4110 if (memcmp(type,mng_JDAT,4) == 0)
4112 /* Copy chunk to color_image->blob */
4114 if (logging != MagickFalse)
4115 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4116 " Copying JDAT chunk data to color_blob.");
4118 (void) WriteBlob(color_image,length,chunk);
4121 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4126 if (memcmp(type,mng_IDAT,4) == 0)
4131 /* Copy IDAT header and chunk data to alpha_image->blob */
4133 if (image_info->ping == MagickFalse)
4135 if (logging != MagickFalse)
4136 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4137 " Copying IDAT chunk data to alpha_blob.");
4139 (void) WriteBlobMSBULong(alpha_image,(size_t) length);
4140 PNGType(data,mng_IDAT);
4141 LogPNGChunk(logging,mng_IDAT,length);
4142 (void) WriteBlob(alpha_image,4,data);
4143 (void) WriteBlob(alpha_image,length,chunk);
4144 (void) WriteBlobMSBULong(alpha_image,
4145 crc32(crc32(0,data,4),chunk,(uInt) length));
4149 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4154 if ((memcmp(type,mng_JDAA,4) == 0) || (memcmp(type,mng_JdAA,4) == 0))
4156 /* Copy chunk data to alpha_image->blob */
4158 if (image_info->ping == MagickFalse)
4160 if (logging != MagickFalse)
4161 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4162 " Copying JDAA chunk data to alpha_blob.");
4164 (void) WriteBlob(alpha_image,length,chunk);
4168 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4173 if (memcmp(type,mng_JSEP,4) == 0)
4175 read_JSEP=MagickTrue;
4178 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4183 if (memcmp(type,mng_bKGD,4) == 0)
4187 image->background_color.red=ScaleCharToQuantum(p[1]);
4188 image->background_color.green=image->background_color.red;
4189 image->background_color.blue=image->background_color.red;
4194 image->background_color.red=ScaleCharToQuantum(p[1]);
4195 image->background_color.green=ScaleCharToQuantum(p[3]);
4196 image->background_color.blue=ScaleCharToQuantum(p[5]);
4199 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4203 if (memcmp(type,mng_gAMA,4) == 0)
4206 image->gamma=((float) mng_get_long(p))*0.00001;
4208 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4212 if (memcmp(type,mng_cHRM,4) == 0)
4216 image->chromaticity.white_point.x=0.00001*mng_get_long(p);
4217 image->chromaticity.white_point.y=0.00001*mng_get_long(&p[4]);
4218 image->chromaticity.red_primary.x=0.00001*mng_get_long(&p[8]);
4219 image->chromaticity.red_primary.y=0.00001*mng_get_long(&p[12]);
4220 image->chromaticity.green_primary.x=0.00001*mng_get_long(&p[16]);
4221 image->chromaticity.green_primary.y=0.00001*mng_get_long(&p[20]);
4222 image->chromaticity.blue_primary.x=0.00001*mng_get_long(&p[24]);
4223 image->chromaticity.blue_primary.y=0.00001*mng_get_long(&p[28]);
4226 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4230 if (memcmp(type,mng_sRGB,4) == 0)
4234 image->rendering_intent=
4235 Magick_RenderingIntent_from_PNG_RenderingIntent(p[0]);
4236 image->gamma=1.000f/2.200f;
4237 image->chromaticity.red_primary.x=0.6400f;
4238 image->chromaticity.red_primary.y=0.3300f;
4239 image->chromaticity.green_primary.x=0.3000f;
4240 image->chromaticity.green_primary.y=0.6000f;
4241 image->chromaticity.blue_primary.x=0.1500f;
4242 image->chromaticity.blue_primary.y=0.0600f;
4243 image->chromaticity.white_point.x=0.3127f;
4244 image->chromaticity.white_point.y=0.3290f;
4247 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4251 if (memcmp(type,mng_oFFs,4) == 0)
4255 image->page.x=(ssize_t) mng_get_long(p);
4256 image->page.y=(ssize_t) mng_get_long(&p[4]);
4258 if ((int) p[8] != 0)
4260 image->page.x/=10000;
4261 image->page.y/=10000;
4266 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4271 if (memcmp(type,mng_pHYs,4) == 0)
4275 image->resolution.x=(double) mng_get_long(p);
4276 image->resolution.y=(double) mng_get_long(&p[4]);
4277 if ((int) p[8] == PNG_RESOLUTION_METER)
4279 image->units=PixelsPerCentimeterResolution;
4280 image->resolution.x=image->resolution.x/100.0f;
4281 image->resolution.y=image->resolution.y/100.0f;
4285 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4290 if (memcmp(type,mng_iCCP,4) == 0)
4294 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4301 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4303 if (memcmp(type,mng_IEND,4))
4313 Finish up reading image data:
4315 o read main image from color_blob.
4319 o if (color_type has alpha)
4320 if alpha_encoding is PNG
4321 read secondary image from alpha_blob via ReadPNG
4322 if alpha_encoding is JPEG
4323 read secondary image from alpha_blob via ReadJPEG
4327 o copy intensity of secondary image into
4328 alpha samples of main image.
4330 o destroy the secondary image.
4333 (void) CloseBlob(color_image);
4335 if (logging != MagickFalse)
4336 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4337 " Reading jng_image from color_blob.");
4339 (void) FormatLocaleString(color_image_info->filename,MaxTextExtent,"%s",
4340 color_image->filename);
4342 color_image_info->ping=MagickFalse; /* To do: avoid this */
4343 jng_image=ReadImage(color_image_info,exception);
4345 if (jng_image == (Image *) NULL)
4346 return((Image *) NULL);
4348 (void) RelinquishUniqueFileResource(color_image->filename);
4349 color_image=DestroyImage(color_image);
4350 color_image_info=DestroyImageInfo(color_image_info);
4352 if (jng_image == (Image *) NULL)
4353 return((Image *) NULL);
4355 if (logging != MagickFalse)
4356 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4357 " Copying jng_image pixels to main image.");
4359 image->rows=jng_height;
4360 image->columns=jng_width;
4362 for (y=0; y < (ssize_t) image->rows; y++)
4364 s=GetVirtualPixels(jng_image,0,y,image->columns,1,exception);
4365 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
4366 for (x=(ssize_t) image->columns; x != 0; x--)
4368 SetPixelRed(image,GetPixelRed(jng_image,s),q);
4369 SetPixelGreen(image,GetPixelGreen(jng_image,s),q);
4370 SetPixelBlue(image,GetPixelBlue(jng_image,s),q);
4371 q+=GetPixelChannels(image);
4372 s+=GetPixelChannels(jng_image);
4375 if (SyncAuthenticPixels(image,exception) == MagickFalse)
4379 jng_image=DestroyImage(jng_image);
4381 if (image_info->ping == MagickFalse)
4383 if (jng_color_type >= 12)
4385 if (jng_alpha_compression_method == 0)
4389 (void) WriteBlobMSBULong(alpha_image,0x00000000L);
4390 PNGType(data,mng_IEND);
4391 LogPNGChunk(logging,mng_IEND,0L);
4392 (void) WriteBlob(alpha_image,4,data);
4393 (void) WriteBlobMSBULong(alpha_image,crc32(0,data,4));
4396 (void) CloseBlob(alpha_image);
4398 if (logging != MagickFalse)
4399 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4400 " Reading alpha from alpha_blob.");
4402 (void) FormatLocaleString(alpha_image_info->filename,MaxTextExtent,
4403 "%s",alpha_image->filename);
4405 jng_image=ReadImage(alpha_image_info,exception);
4407 if (jng_image != (Image *) NULL)
4408 for (y=0; y < (ssize_t) image->rows; y++)
4410 s=GetVirtualPixels(jng_image,0,y,image->columns,1,
4412 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
4414 if (image->matte != MagickFalse)
4415 for (x=(ssize_t) image->columns; x != 0; x--)
4417 SetPixelAlpha(image,GetPixelRed(jng_image,s),q);
4418 q+=GetPixelChannels(image);
4419 s+=GetPixelChannels(jng_image);
4423 for (x=(ssize_t) image->columns; x != 0; x--)
4425 SetPixelAlpha(image,GetPixelRed(jng_image,s),q);
4426 if (GetPixelAlpha(image,q) != OpaqueAlpha)
4427 image->matte=MagickTrue;
4428 q+=GetPixelChannels(image);
4429 s+=GetPixelChannels(jng_image);
4432 if (SyncAuthenticPixels(image,exception) == MagickFalse)
4435 (void) RelinquishUniqueFileResource(alpha_image->filename);
4436 alpha_image=DestroyImage(alpha_image);
4437 alpha_image_info=DestroyImageInfo(alpha_image_info);
4438 if (jng_image != (Image *) NULL)
4439 jng_image=DestroyImage(jng_image);
4443 /* Read the JNG image. */
4445 if (mng_info->mng_type == 0)
4447 mng_info->mng_width=jng_width;
4448 mng_info->mng_height=jng_height;
4451 if (image->page.width == 0 && image->page.height == 0)
4453 image->page.width=jng_width;
4454 image->page.height=jng_height;
4457 if (image->page.x == 0 && image->page.y == 0)
4459 image->page.x=mng_info->x_off[mng_info->object_id];
4460 image->page.y=mng_info->y_off[mng_info->object_id];
4465 image->page.y=mng_info->y_off[mng_info->object_id];
4468 mng_info->image_found++;
4469 status=SetImageProgress(image,LoadImagesTag,2*TellBlob(image),
4470 2*GetBlobSize(image));
4472 if (logging != MagickFalse)
4473 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4474 " exit ReadOneJNGImage()");
4480 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4484 % R e a d J N G I m a g e %
4488 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4490 % ReadJNGImage() reads a JPEG Network Graphics (JNG) image file
4491 % (including the 8-byte signature) and returns it. It allocates the memory
4492 % necessary for the new Image structure and returns a pointer to the new
4495 % JNG support written by Glenn Randers-Pehrson, glennrp@image...
4497 % The format of the ReadJNGImage method is:
4499 % Image *ReadJNGImage(const ImageInfo *image_info, ExceptionInfo
4502 % A description of each parameter follows:
4504 % o image_info: the image info.
4506 % o exception: return any errors or warnings in this structure.
4510 static Image *ReadJNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
4525 magic_number[MaxTextExtent];
4533 assert(image_info != (const ImageInfo *) NULL);
4534 assert(image_info->signature == MagickSignature);
4535 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image_info->filename);
4536 assert(exception != (ExceptionInfo *) NULL);
4537 assert(exception->signature == MagickSignature);
4538 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter ReadJNGImage()");
4539 image=AcquireImage(image_info,exception);
4540 mng_info=(MngInfo *) NULL;
4541 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
4543 if (status == MagickFalse)
4544 return((Image *) NULL);
4546 if (LocaleCompare(image_info->magick,"JNG") != 0)
4547 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
4549 /* Verify JNG signature. */
4551 count=(size_t) ReadBlob(image,8,(unsigned char *) magic_number);
4553 if (count < 8 || memcmp(magic_number,"\213JNG\r\n\032\n",8) != 0)
4554 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
4556 /* Allocate a MngInfo structure. */
4558 have_mng_structure=MagickFalse;
4559 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(*mng_info));
4561 if (mng_info == (MngInfo *) NULL)
4562 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
4564 /* Initialize members of the MngInfo structure. */
4566 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
4567 have_mng_structure=MagickTrue;
4569 mng_info->image=image;
4571 image=ReadOneJNGImage(mng_info,image_info,exception);
4572 MngInfoFreeStruct(mng_info,&have_mng_structure);
4574 if (image == (Image *) NULL)
4576 if (IsImageObject(previous) != MagickFalse)
4578 (void) CloseBlob(previous);
4579 (void) DestroyImageList(previous);
4582 if (logging != MagickFalse)
4583 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4584 "exit ReadJNGImage() with error");
4586 return((Image *) NULL);
4588 (void) CloseBlob(image);
4590 if (image->columns == 0 || image->rows == 0)
4592 if (logging != MagickFalse)
4593 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4594 "exit ReadJNGImage() with error");
4596 ThrowReaderException(CorruptImageError,"CorruptImage");
4599 if (logging != MagickFalse)
4600 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit ReadJNGImage()");
4606 static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
4609 page_geometry[MaxTextExtent];
4642 #if defined(MNG_INSERT_LAYERS)
4644 mng_background_color;
4647 register unsigned char
4662 #if defined(MNG_INSERT_LAYERS)
4667 volatile unsigned int
4668 #ifdef MNG_OBJECT_BUFFERS
4669 mng_background_object=0,
4671 mng_type=0; /* 0: PNG or JNG; 1: MNG; 2: MNG-LC; 3: MNG-VLC */
4674 default_frame_timeout,
4676 #if defined(MNG_INSERT_LAYERS)
4682 /* These delays are all measured in image ticks_per_second,
4683 * not in MNG ticks_per_second
4686 default_frame_delay,
4690 #if defined(MNG_INSERT_LAYERS)
4699 previous_fb.bottom=0;
4701 previous_fb.right=0;
4703 default_fb.bottom=0;
4707 /* Open image file. */
4709 assert(image_info != (const ImageInfo *) NULL);
4710 assert(image_info->signature == MagickSignature);
4711 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image_info->filename);
4712 assert(exception != (ExceptionInfo *) NULL);
4713 assert(exception->signature == MagickSignature);
4714 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter ReadMNGImage()");
4715 image=AcquireImage(image_info,exception);
4716 mng_info=(MngInfo *) NULL;
4717 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
4719 if (status == MagickFalse)
4720 return((Image *) NULL);
4722 first_mng_object=MagickFalse;
4724 have_mng_structure=MagickFalse;
4726 /* Allocate a MngInfo structure. */
4728 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
4730 if (mng_info == (MngInfo *) NULL)
4731 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
4733 /* Initialize members of the MngInfo structure. */
4735 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
4736 mng_info->image=image;
4737 have_mng_structure=MagickTrue;
4739 if (LocaleCompare(image_info->magick,"MNG") == 0)
4742 magic_number[MaxTextExtent];
4744 /* Verify MNG signature. */
4745 count=(size_t) ReadBlob(image,8,(unsigned char *) magic_number);
4746 if (memcmp(magic_number,"\212MNG\r\n\032\n",8) != 0)
4747 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
4749 /* Initialize some nonzero members of the MngInfo structure. */
4750 for (i=0; i < MNG_MAX_OBJECTS; i++)
4752 mng_info->object_clip[i].right=(ssize_t) PNG_UINT_31_MAX;
4753 mng_info->object_clip[i].bottom=(ssize_t) PNG_UINT_31_MAX;
4755 mng_info->exists[0]=MagickTrue;
4758 first_mng_object=MagickTrue;
4760 #if defined(MNG_INSERT_LAYERS)
4761 insert_layers=MagickFalse; /* should be False when converting or mogrifying */
4763 default_frame_delay=0;
4764 default_frame_timeout=0;
4767 mng_info->ticks_per_second=1UL*image->ticks_per_second;
4769 skip_to_iend=MagickFalse;
4770 term_chunk_found=MagickFalse;
4771 mng_info->framing_mode=1;
4772 #if defined(MNG_INSERT_LAYERS)
4773 mandatory_back=MagickFalse;
4775 #if defined(MNG_INSERT_LAYERS)
4776 mng_background_color=image->background_color;
4778 default_fb=mng_info->frame;
4779 previous_fb=mng_info->frame;
4783 type[MaxTextExtent];
4785 if (LocaleCompare(image_info->magick,"MNG") == 0)
4794 (void) ConcatenateMagickString(type,"errr",MaxTextExtent);
4795 length=ReadBlobMSBLong(image);
4796 count=(size_t) ReadBlob(image,4,(unsigned char *) type);
4798 if (logging != MagickFalse)
4799 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4800 " Reading MNG chunk type %c%c%c%c, length: %.20g",
4801 type[0],type[1],type[2],type[3],(double) length);
4803 if (length > PNG_UINT_31_MAX)
4807 ThrowReaderException(CorruptImageError,"CorruptImage");
4810 chunk=(unsigned char *) NULL;
4814 chunk=(unsigned char *) AcquireQuantumMemory(length,sizeof(*chunk));
4816 if (chunk == (unsigned char *) NULL)
4817 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
4819 for (i=0; i < (ssize_t) length; i++)
4820 chunk[i]=(unsigned char) ReadBlobByte(image);
4825 (void) ReadBlobMSBLong(image); /* read crc word */
4827 #if !defined(JNG_SUPPORTED)
4828 if (memcmp(type,mng_JHDR,4) == 0)
4830 skip_to_iend=MagickTrue;
4832 if (mng_info->jhdr_warning == 0)
4833 (void) ThrowMagickException(exception,GetMagickModule(),
4834 CoderError,"JNGCompressNotSupported","`%s'",image->filename);
4836 mng_info->jhdr_warning++;
4839 if (memcmp(type,mng_DHDR,4) == 0)
4841 skip_to_iend=MagickTrue;
4843 if (mng_info->dhdr_warning == 0)
4844 (void) ThrowMagickException(exception,GetMagickModule(),
4845 CoderError,"DeltaPNGNotSupported","`%s'",image->filename);
4847 mng_info->dhdr_warning++;
4849 if (memcmp(type,mng_MEND,4) == 0)
4854 if (memcmp(type,mng_IEND,4) == 0)
4855 skip_to_iend=MagickFalse;
4858 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4860 if (logging != MagickFalse)
4861 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4867 if (memcmp(type,mng_MHDR,4) == 0)
4869 mng_info->mng_width=(size_t) ((p[0] << 24) | (p[1] << 16) |
4870 (p[2] << 8) | p[3]);
4872 mng_info->mng_height=(size_t) ((p[4] << 24) | (p[5] << 16) |
4873 (p[6] << 8) | p[7]);
4875 if (logging != MagickFalse)
4877 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4878 " MNG width: %.20g",(double) mng_info->mng_width);
4879 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4880 " MNG height: %.20g",(double) mng_info->mng_height);
4884 mng_info->ticks_per_second=(size_t) mng_get_long(p);
4886 if (mng_info->ticks_per_second == 0)
4887 default_frame_delay=0;
4890 default_frame_delay=1UL*image->ticks_per_second/
4891 mng_info->ticks_per_second;
4893 frame_delay=default_frame_delay;
4899 simplicity=(size_t) mng_get_long(p);
4902 mng_type=1; /* Full MNG */
4904 if ((simplicity != 0) && ((simplicity | 11) == 11))
4905 mng_type=2; /* LC */
4907 if ((simplicity != 0) && ((simplicity | 9) == 9))
4908 mng_type=3; /* VLC */
4910 #if defined(MNG_INSERT_LAYERS)
4912 insert_layers=MagickTrue;
4914 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
4916 /* Allocate next image structure. */
4917 AcquireNextImage(image_info,image,exception);
4919 if (GetNextImageInList(image) == (Image *) NULL)
4920 return((Image *) NULL);
4922 image=SyncNextImageInList(image);
4923 mng_info->image=image;
4926 if ((mng_info->mng_width > 65535L) ||
4927 (mng_info->mng_height > 65535L))
4928 ThrowReaderException(ImageError,"WidthOrHeightExceedsLimit");
4930 (void) FormatLocaleString(page_geometry,MaxTextExtent,
4931 "%.20gx%.20g+0+0",(double) mng_info->mng_width,(double)
4932 mng_info->mng_height);
4934 mng_info->frame.left=0;
4935 mng_info->frame.right=(ssize_t) mng_info->mng_width;
4936 mng_info->frame.top=0;
4937 mng_info->frame.bottom=(ssize_t) mng_info->mng_height;
4938 mng_info->clip=default_fb=previous_fb=mng_info->frame;
4940 for (i=0; i < MNG_MAX_OBJECTS; i++)
4941 mng_info->object_clip[i]=mng_info->frame;
4943 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4947 if (memcmp(type,mng_TERM,4) == 0)
4958 final_delay=(png_uint_32) mng_get_long(&p[2]);
4959 mng_iterations=(png_uint_32) mng_get_long(&p[6]);
4961 if (mng_iterations == PNG_UINT_31_MAX)
4964 image->iterations=mng_iterations;
4965 term_chunk_found=MagickTrue;
4968 if (logging != MagickFalse)
4970 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4971 " repeat=%d",repeat);
4973 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4974 " final_delay=%.20g",(double) final_delay);
4976 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4977 " image->iterations=%.20g",(double) image->iterations);
4980 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4983 if (memcmp(type,mng_DEFI,4) == 0)
4986 (void) ThrowMagickException(exception,GetMagickModule(),
4987 CoderError,"DEFI chunk found in MNG-VLC datastream","`%s'",
4990 object_id=(p[0] << 8) | p[1];
4992 if (mng_type == 2 && object_id != 0)
4993 (void) ThrowMagickException(exception,GetMagickModule(),
4994 CoderError,"Nonzero object_id in MNG-LC datastream","`%s'",
4997 if (object_id > MNG_MAX_OBJECTS)
5000 Instead of using a warning we should allocate a larger
5001 MngInfo structure and continue.
5003 (void) ThrowMagickException(exception,GetMagickModule(),
5004 CoderError,"object id too large","`%s'",image->filename);
5005 object_id=MNG_MAX_OBJECTS;
5008 if (mng_info->exists[object_id])
5009 if (mng_info->frozen[object_id])
5011 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5012 (void) ThrowMagickException(exception,
5013 GetMagickModule(),CoderError,
5014 "DEFI cannot redefine a frozen MNG object","`%s'",
5019 mng_info->exists[object_id]=MagickTrue;
5022 mng_info->invisible[object_id]=p[2];
5025 Extract object offset info.
5029 mng_info->x_off[object_id]=(ssize_t) ((p[4] << 24) |
5030 (p[5] << 16) | (p[6] << 8) | p[7]);
5032 mng_info->y_off[object_id]=(ssize_t) ((p[8] << 24) |
5033 (p[9] << 16) | (p[10] << 8) | p[11]);
5035 if (logging != MagickFalse)
5037 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5038 " x_off[%d]: %.20g",object_id,(double)
5039 mng_info->x_off[object_id]);
5041 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5042 " y_off[%d]: %.20g",object_id,(double)
5043 mng_info->y_off[object_id]);
5048 Extract object clipping info.
5051 mng_info->object_clip[object_id]=mng_read_box(mng_info->frame,0,
5054 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5057 if (memcmp(type,mng_bKGD,4) == 0)
5059 mng_info->have_global_bkgd=MagickFalse;
5063 mng_info->mng_global_bkgd.red=
5064 ScaleShortToQuantum((unsigned short) ((p[0] << 8) | p[1]));
5066 mng_info->mng_global_bkgd.green=
5067 ScaleShortToQuantum((unsigned short) ((p[2] << 8) | p[3]));
5069 mng_info->mng_global_bkgd.blue=
5070 ScaleShortToQuantum((unsigned short) ((p[4] << 8) | p[5]));
5072 mng_info->have_global_bkgd=MagickTrue;
5075 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5078 if (memcmp(type,mng_BACK,4) == 0)
5080 #if defined(MNG_INSERT_LAYERS)
5082 mandatory_back=p[6];
5087 if (mandatory_back && length > 5)
5089 mng_background_color.red=
5090 ScaleShortToQuantum((unsigned short) ((p[0] << 8) | p[1]));
5092 mng_background_color.green=
5093 ScaleShortToQuantum((unsigned short) ((p[2] << 8) | p[3]));
5095 mng_background_color.blue=
5096 ScaleShortToQuantum((unsigned short) ((p[4] << 8) | p[5]));
5098 mng_background_color.alpha=OpaqueAlpha;
5101 #ifdef MNG_OBJECT_BUFFERS
5103 mng_background_object=(p[7] << 8) | p[8];
5106 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5110 if (memcmp(type,mng_PLTE,4) == 0)
5112 /* Read global PLTE. */
5114 if (length && (length < 769))
5116 if (mng_info->global_plte == (png_colorp) NULL)
5117 mng_info->global_plte=(png_colorp) AcquireQuantumMemory(256,
5118 sizeof(*mng_info->global_plte));
5120 for (i=0; i < (ssize_t) (length/3); i++)
5122 mng_info->global_plte[i].red=p[3*i];
5123 mng_info->global_plte[i].green=p[3*i+1];
5124 mng_info->global_plte[i].blue=p[3*i+2];
5127 mng_info->global_plte_length=(unsigned int) (length/3);
5130 for ( ; i < 256; i++)
5132 mng_info->global_plte[i].red=i;
5133 mng_info->global_plte[i].green=i;
5134 mng_info->global_plte[i].blue=i;
5138 mng_info->global_plte_length=256;
5141 mng_info->global_plte_length=0;
5143 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5147 if (memcmp(type,mng_tRNS,4) == 0)
5149 /* read global tRNS */
5152 for (i=0; i < (ssize_t) length; i++)
5153 mng_info->global_trns[i]=p[i];
5156 for ( ; i < 256; i++)
5157 mng_info->global_trns[i]=255;
5159 mng_info->global_trns_length=(unsigned int) length;
5160 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5163 if (memcmp(type,mng_gAMA,4) == 0)
5170 igamma=mng_get_long(p);
5171 mng_info->global_gamma=((float) igamma)*0.00001;
5172 mng_info->have_global_gama=MagickTrue;
5176 mng_info->have_global_gama=MagickFalse;
5178 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5182 if (memcmp(type,mng_cHRM,4) == 0)
5184 /* Read global cHRM */
5188 mng_info->global_chrm.white_point.x=0.00001*mng_get_long(p);
5189 mng_info->global_chrm.white_point.y=0.00001*mng_get_long(&p[4]);
5190 mng_info->global_chrm.red_primary.x=0.00001*mng_get_long(&p[8]);
5191 mng_info->global_chrm.red_primary.y=0.00001*
5192 mng_get_long(&p[12]);
5193 mng_info->global_chrm.green_primary.x=0.00001*
5194 mng_get_long(&p[16]);
5195 mng_info->global_chrm.green_primary.y=0.00001*
5196 mng_get_long(&p[20]);
5197 mng_info->global_chrm.blue_primary.x=0.00001*
5198 mng_get_long(&p[24]);
5199 mng_info->global_chrm.blue_primary.y=0.00001*
5200 mng_get_long(&p[28]);
5201 mng_info->have_global_chrm=MagickTrue;
5204 mng_info->have_global_chrm=MagickFalse;
5206 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5210 if (memcmp(type,mng_sRGB,4) == 0)
5217 mng_info->global_srgb_intent=
5218 Magick_RenderingIntent_from_PNG_RenderingIntent(p[0]);
5219 mng_info->have_global_srgb=MagickTrue;
5222 mng_info->have_global_srgb=MagickFalse;
5224 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5228 if (memcmp(type,mng_iCCP,4) == 0)
5236 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5241 if (memcmp(type,mng_FRAM,4) == 0)
5244 (void) ThrowMagickException(exception,GetMagickModule(),
5245 CoderError,"FRAM chunk found in MNG-VLC datastream","`%s'",
5248 if ((mng_info->framing_mode == 2) || (mng_info->framing_mode == 4))
5249 image->delay=frame_delay;
5251 frame_delay=default_frame_delay;
5252 frame_timeout=default_frame_timeout;
5257 mng_info->framing_mode=p[0];
5259 if (logging != MagickFalse)
5260 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5261 " Framing_mode=%d",mng_info->framing_mode);
5265 /* Note the delay and frame clipping boundaries. */
5267 p++; /* framing mode */
5269 while (*p && ((p-chunk) < (ssize_t) length))
5270 p++; /* frame name */
5272 p++; /* frame name terminator */
5274 if ((p-chunk) < (ssize_t) (length-4))
5281 change_delay=(*p++);
5282 change_timeout=(*p++);
5283 change_clipping=(*p++);
5284 p++; /* change_sync */
5288 frame_delay=1UL*image->ticks_per_second*
5291 if (mng_info->ticks_per_second != 0)
5292 frame_delay/=mng_info->ticks_per_second;
5295 frame_delay=PNG_UINT_31_MAX;
5297 if (change_delay == 2)
5298 default_frame_delay=frame_delay;
5302 if (logging != MagickFalse)
5303 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5304 " Framing_delay=%.20g",(double) frame_delay);
5309 frame_timeout=1UL*image->ticks_per_second*
5312 if (mng_info->ticks_per_second != 0)
5313 frame_timeout/=mng_info->ticks_per_second;
5316 frame_timeout=PNG_UINT_31_MAX;
5318 if (change_delay == 2)
5319 default_frame_timeout=frame_timeout;
5323 if (logging != MagickFalse)
5324 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5325 " Framing_timeout=%.20g",(double) frame_timeout);
5328 if (change_clipping)
5330 fb=mng_read_box(previous_fb,(char) p[0],&p[1]);
5334 if (logging != MagickFalse)
5335 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5336 " Frame_clip: L=%.20g R=%.20g T=%.20g B=%.20g",
5337 (double) fb.left,(double) fb.right,(double) fb.top,
5338 (double) fb.bottom);
5340 if (change_clipping == 2)
5346 mng_info->clip=mng_minimum_box(fb,mng_info->frame);
5348 subframe_width=(size_t) (mng_info->clip.right
5349 -mng_info->clip.left);
5351 subframe_height=(size_t) (mng_info->clip.bottom
5352 -mng_info->clip.top);
5354 Insert a background layer behind the frame if framing_mode is 4.
5356 #if defined(MNG_INSERT_LAYERS)
5357 if (logging != MagickFalse)
5358 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5359 " subframe_width=%.20g, subframe_height=%.20g",(double)
5360 subframe_width,(double) subframe_height);
5362 if (insert_layers && (mng_info->framing_mode == 4) &&
5363 (subframe_width) && (subframe_height))
5365 /* Allocate next image structure. */
5366 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
5368 AcquireNextImage(image_info,image,exception);
5370 if (GetNextImageInList(image) == (Image *) NULL)
5372 image=DestroyImageList(image);
5373 MngInfoFreeStruct(mng_info,&have_mng_structure);
5374 return((Image *) NULL);
5377 image=SyncNextImageInList(image);
5380 mng_info->image=image;
5382 if (term_chunk_found)
5384 image->start_loop=MagickTrue;
5385 image->iterations=mng_iterations;
5386 term_chunk_found=MagickFalse;
5390 image->start_loop=MagickFalse;
5392 image->columns=subframe_width;
5393 image->rows=subframe_height;
5394 image->page.width=subframe_width;
5395 image->page.height=subframe_height;
5396 image->page.x=mng_info->clip.left;
5397 image->page.y=mng_info->clip.top;
5398 image->background_color=mng_background_color;
5399 image->matte=MagickFalse;
5401 (void) SetImageBackgroundColor(image,exception);
5403 if (logging != MagickFalse)
5404 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5405 " Insert backgd layer, L=%.20g, R=%.20g T=%.20g, B=%.20g",
5406 (double) mng_info->clip.left,(double) mng_info->clip.right,
5407 (double) mng_info->clip.top,(double) mng_info->clip.bottom);
5410 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5413 if (memcmp(type,mng_CLIP,4) == 0)
5422 first_object=(p[0] << 8) | p[1];
5423 last_object=(p[2] << 8) | p[3];
5425 for (i=(int) first_object; i <= (int) last_object; i++)
5427 if (mng_info->exists[i] && !mng_info->frozen[i])
5432 box=mng_info->object_clip[i];
5433 mng_info->object_clip[i]=mng_read_box(box,(char) p[4],&p[5]);
5437 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5440 if (memcmp(type,mng_SAVE,4) == 0)
5442 for (i=1; i < MNG_MAX_OBJECTS; i++)
5443 if (mng_info->exists[i])
5445 mng_info->frozen[i]=MagickTrue;
5446 #ifdef MNG_OBJECT_BUFFERS
5447 if (mng_info->ob[i] != (MngBuffer *) NULL)
5448 mng_info->ob[i]->frozen=MagickTrue;
5453 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5458 if ((memcmp(type,mng_DISC,4) == 0) || (memcmp(type,mng_SEEK,4) == 0))
5460 /* Read DISC or SEEK. */
5462 if ((length == 0) || !memcmp(type,mng_SEEK,4))
5464 for (i=1; i < MNG_MAX_OBJECTS; i++)
5465 MngInfoDiscardObject(mng_info,i);
5473 for (j=0; j < (ssize_t) length; j+=2)
5475 i=p[j] << 8 | p[j+1];
5476 MngInfoDiscardObject(mng_info,i);
5481 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5486 if (memcmp(type,mng_MOVE,4) == 0)
5494 first_object=(p[0] << 8) | p[1];
5495 last_object=(p[2] << 8) | p[3];
5496 for (i=(ssize_t) first_object; i <= (ssize_t) last_object; i++)
5498 if (mng_info->exists[i] && !mng_info->frozen[i])
5506 old_pair.a=mng_info->x_off[i];
5507 old_pair.b=mng_info->y_off[i];
5508 new_pair=mng_read_pair(old_pair,(int) p[4],&p[5]);
5509 mng_info->x_off[i]=new_pair.a;
5510 mng_info->y_off[i]=new_pair.b;
5514 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5518 if (memcmp(type,mng_LOOP,4) == 0)
5520 ssize_t loop_iters=1;
5521 loop_level=chunk[0];
5522 mng_info->loop_active[loop_level]=1; /* mark loop active */
5524 /* Record starting point. */
5525 loop_iters=mng_get_long(&chunk[1]);
5527 if (logging != MagickFalse)
5528 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5529 " LOOP level %.20g has %.20g iterations ",(double) loop_level,
5530 (double) loop_iters);
5532 if (loop_iters == 0)
5533 skipping_loop=loop_level;
5537 mng_info->loop_jump[loop_level]=TellBlob(image);
5538 mng_info->loop_count[loop_level]=loop_iters;
5541 mng_info->loop_iteration[loop_level]=0;
5542 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5546 if (memcmp(type,mng_ENDL,4) == 0)
5548 loop_level=chunk[0];
5550 if (skipping_loop > 0)
5552 if (skipping_loop == loop_level)
5555 Found end of zero-iteration loop.
5558 mng_info->loop_active[loop_level]=0;
5564 if (mng_info->loop_active[loop_level] == 1)
5566 mng_info->loop_count[loop_level]--;
5567 mng_info->loop_iteration[loop_level]++;
5569 if (logging != MagickFalse)
5570 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5571 " ENDL: LOOP level %.20g has %.20g remaining iters ",
5572 (double) loop_level,(double)
5573 mng_info->loop_count[loop_level]);
5575 if (mng_info->loop_count[loop_level] != 0)
5577 offset=SeekBlob(image,mng_info->loop_jump[loop_level],
5581 ThrowReaderException(CorruptImageError,
5582 "ImproperImageHeader");
5593 mng_info->loop_active[loop_level]=0;
5595 for (i=0; i < loop_level; i++)
5596 if (mng_info->loop_active[i] == 1)
5597 last_level=(short) i;
5598 loop_level=last_level;
5603 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5607 if (memcmp(type,mng_CLON,4) == 0)
5609 if (mng_info->clon_warning == 0)
5610 (void) ThrowMagickException(exception,GetMagickModule(),
5611 CoderError,"CLON is not implemented yet","`%s'",
5614 mng_info->clon_warning++;
5617 if (memcmp(type,mng_MAGN,4) == 0)
5632 magn_first=(p[0] << 8) | p[1];
5638 magn_last=(p[2] << 8) | p[3];
5641 magn_last=magn_first;
5642 #ifndef MNG_OBJECT_BUFFERS
5643 if (magn_first || magn_last)
5644 if (mng_info->magn_warning == 0)
5646 (void) ThrowMagickException(exception,
5647 GetMagickModule(),CoderError,
5648 "MAGN is not implemented yet for nonzero objects",
5649 "`%s'",image->filename);
5651 mng_info->magn_warning++;
5661 magn_mx=(p[5] << 8) | p[6];
5670 magn_my=(p[7] << 8) | p[8];
5679 magn_ml=(p[9] << 8) | p[10];
5688 magn_mr=(p[11] << 8) | p[12];
5697 magn_mt=(p[13] << 8) | p[14];
5706 magn_mb=(p[15] << 8) | p[16];
5718 magn_methy=magn_methx;
5721 if (magn_methx > 5 || magn_methy > 5)
5722 if (mng_info->magn_warning == 0)
5724 (void) ThrowMagickException(exception,
5725 GetMagickModule(),CoderError,
5726 "Unknown MAGN method in MNG datastream","`%s'",
5729 mng_info->magn_warning++;
5731 #ifdef MNG_OBJECT_BUFFERS
5732 /* Magnify existing objects in the range magn_first to magn_last */
5734 if (magn_first == 0 || magn_last == 0)
5736 /* Save the magnification factors for object 0 */
5737 mng_info->magn_mb=magn_mb;
5738 mng_info->magn_ml=magn_ml;
5739 mng_info->magn_mr=magn_mr;
5740 mng_info->magn_mt=magn_mt;
5741 mng_info->magn_mx=magn_mx;
5742 mng_info->magn_my=magn_my;
5743 mng_info->magn_methx=magn_methx;
5744 mng_info->magn_methy=magn_methy;
5748 if (memcmp(type,mng_PAST,4) == 0)
5750 if (mng_info->past_warning == 0)
5751 (void) ThrowMagickException(exception,GetMagickModule(),
5752 CoderError,"PAST is not implemented yet","`%s'",
5755 mng_info->past_warning++;
5758 if (memcmp(type,mng_SHOW,4) == 0)
5760 if (mng_info->show_warning == 0)
5761 (void) ThrowMagickException(exception,GetMagickModule(),
5762 CoderError,"SHOW is not implemented yet","`%s'",
5765 mng_info->show_warning++;
5768 if (memcmp(type,mng_sBIT,4) == 0)
5771 mng_info->have_global_sbit=MagickFalse;
5775 mng_info->global_sbit.gray=p[0];
5776 mng_info->global_sbit.red=p[0];
5777 mng_info->global_sbit.green=p[1];
5778 mng_info->global_sbit.blue=p[2];
5779 mng_info->global_sbit.alpha=p[3];
5780 mng_info->have_global_sbit=MagickTrue;
5783 if (memcmp(type,mng_pHYs,4) == 0)
5787 mng_info->global_x_pixels_per_unit=
5788 (size_t) mng_get_long(p);
5789 mng_info->global_y_pixels_per_unit=
5790 (size_t) mng_get_long(&p[4]);
5791 mng_info->global_phys_unit_type=p[8];
5792 mng_info->have_global_phys=MagickTrue;
5796 mng_info->have_global_phys=MagickFalse;
5798 if (memcmp(type,mng_pHYg,4) == 0)
5800 if (mng_info->phyg_warning == 0)
5801 (void) ThrowMagickException(exception,GetMagickModule(),
5802 CoderError,"pHYg is not implemented.","`%s'",image->filename);
5804 mng_info->phyg_warning++;
5806 if (memcmp(type,mng_BASI,4) == 0)
5808 skip_to_iend=MagickTrue;
5810 if (mng_info->basi_warning == 0)
5811 (void) ThrowMagickException(exception,GetMagickModule(),
5812 CoderError,"BASI is not implemented yet","`%s'",
5815 mng_info->basi_warning++;
5816 #ifdef MNG_BASI_SUPPORTED
5817 basi_width=(size_t) ((p[0] << 24) | (p[1] << 16) |
5818 (p[2] << 8) | p[3]);
5819 basi_height=(size_t) ((p[4] << 24) | (p[5] << 16) |
5820 (p[6] << 8) | p[7]);
5821 basi_color_type=p[8];
5822 basi_compression_method=p[9];
5823 basi_filter_type=p[10];
5824 basi_interlace_method=p[11];
5826 basi_red=(p[12] << 8) & p[13];
5832 basi_green=(p[14] << 8) & p[15];
5838 basi_blue=(p[16] << 8) & p[17];
5844 basi_alpha=(p[18] << 8) & p[19];
5848 if (basi_sample_depth == 16)
5855 basi_viewable=p[20];
5861 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5865 if (memcmp(type,mng_IHDR,4)
5866 #if defined(JNG_SUPPORTED)
5867 && memcmp(type,mng_JHDR,4)
5871 /* Not an IHDR or JHDR chunk */
5873 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5878 if (logging != MagickFalse)
5879 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5880 " Processing %c%c%c%c chunk",type[0],type[1],type[2],type[3]);
5882 mng_info->exists[object_id]=MagickTrue;
5883 mng_info->viewable[object_id]=MagickTrue;
5885 if (mng_info->invisible[object_id])
5887 if (logging != MagickFalse)
5888 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5889 " Skipping invisible object");
5891 skip_to_iend=MagickTrue;
5892 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5895 #if defined(MNG_INSERT_LAYERS)
5897 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
5899 image_width=(size_t) mng_get_long(p);
5900 image_height=(size_t) mng_get_long(&p[4]);
5902 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5905 Insert a transparent background layer behind the entire animation
5906 if it is not full screen.
5908 #if defined(MNG_INSERT_LAYERS)
5909 if (insert_layers && mng_type && first_mng_object)
5911 if ((mng_info->clip.left > 0) || (mng_info->clip.top > 0) ||
5912 (image_width < mng_info->mng_width) ||
5913 (mng_info->clip.right < (ssize_t) mng_info->mng_width) ||
5914 (image_height < mng_info->mng_height) ||
5915 (mng_info->clip.bottom < (ssize_t) mng_info->mng_height))
5917 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
5920 Allocate next image structure.
5922 AcquireNextImage(image_info,image,exception);
5924 if (GetNextImageInList(image) == (Image *) NULL)
5926 image=DestroyImageList(image);
5927 MngInfoFreeStruct(mng_info,&have_mng_structure);
5928 return((Image *) NULL);
5931 image=SyncNextImageInList(image);
5933 mng_info->image=image;
5935 if (term_chunk_found)
5937 image->start_loop=MagickTrue;
5938 image->iterations=mng_iterations;
5939 term_chunk_found=MagickFalse;
5943 image->start_loop=MagickFalse;
5945 /* Make a background rectangle. */
5948 image->columns=mng_info->mng_width;
5949 image->rows=mng_info->mng_height;
5950 image->page.width=mng_info->mng_width;
5951 image->page.height=mng_info->mng_height;
5954 image->background_color=mng_background_color;
5955 (void) SetImageBackgroundColor(image,exception);
5956 if (logging != MagickFalse)
5957 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5958 " Inserted transparent background layer, W=%.20g, H=%.20g",
5959 (double) mng_info->mng_width,(double) mng_info->mng_height);
5963 Insert a background layer behind the upcoming image if
5964 framing_mode is 3, and we haven't already inserted one.
5966 if (insert_layers && (mng_info->framing_mode == 3) &&
5967 (subframe_width) && (subframe_height) && (simplicity == 0 ||
5968 (simplicity & 0x08)))
5970 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
5973 Allocate next image structure.
5975 AcquireNextImage(image_info,image,exception);
5977 if (GetNextImageInList(image) == (Image *) NULL)
5979 image=DestroyImageList(image);
5980 MngInfoFreeStruct(mng_info,&have_mng_structure);
5981 return((Image *) NULL);
5984 image=SyncNextImageInList(image);
5987 mng_info->image=image;
5989 if (term_chunk_found)
5991 image->start_loop=MagickTrue;
5992 image->iterations=mng_iterations;
5993 term_chunk_found=MagickFalse;
5997 image->start_loop=MagickFalse;
6000 image->columns=subframe_width;
6001 image->rows=subframe_height;
6002 image->page.width=subframe_width;
6003 image->page.height=subframe_height;
6004 image->page.x=mng_info->clip.left;
6005 image->page.y=mng_info->clip.top;
6006 image->background_color=mng_background_color;
6007 image->matte=MagickFalse;
6008 (void) SetImageBackgroundColor(image,exception);
6010 if (logging != MagickFalse)
6011 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6012 " Insert background layer, L=%.20g, R=%.20g T=%.20g, B=%.20g",
6013 (double) mng_info->clip.left,(double) mng_info->clip.right,
6014 (double) mng_info->clip.top,(double) mng_info->clip.bottom);
6016 #endif /* MNG_INSERT_LAYERS */
6017 first_mng_object=MagickFalse;
6019 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
6022 Allocate next image structure.
6024 AcquireNextImage(image_info,image,exception);
6026 if (GetNextImageInList(image) == (Image *) NULL)
6028 image=DestroyImageList(image);
6029 MngInfoFreeStruct(mng_info,&have_mng_structure);
6030 return((Image *) NULL);
6033 image=SyncNextImageInList(image);
6035 mng_info->image=image;
6036 status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
6037 GetBlobSize(image));
6039 if (status == MagickFalse)
6042 if (term_chunk_found)
6044 image->start_loop=MagickTrue;
6045 term_chunk_found=MagickFalse;
6049 image->start_loop=MagickFalse;
6051 if (mng_info->framing_mode == 1 || mng_info->framing_mode == 3)
6053 image->delay=frame_delay;
6054 frame_delay=default_frame_delay;
6060 image->page.width=mng_info->mng_width;
6061 image->page.height=mng_info->mng_height;
6062 image->page.x=mng_info->x_off[object_id];
6063 image->page.y=mng_info->y_off[object_id];
6064 image->iterations=mng_iterations;
6067 Seek back to the beginning of the IHDR or JHDR chunk's length field.
6070 if (logging != MagickFalse)
6071 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6072 " Seeking back to beginning of %c%c%c%c chunk",type[0],type[1],
6075 offset=SeekBlob(image,-((ssize_t) length+12),SEEK_CUR);
6078 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
6082 mng_info->image=image;
6083 mng_info->mng_type=mng_type;
6084 mng_info->object_id=object_id;
6086 if (memcmp(type,mng_IHDR,4) == 0)
6087 image=ReadOnePNGImage(mng_info,image_info,exception);
6089 #if defined(JNG_SUPPORTED)
6091 image=ReadOneJNGImage(mng_info,image_info,exception);
6094 if (image == (Image *) NULL)
6096 if (IsImageObject(previous) != MagickFalse)
6098 (void) DestroyImageList(previous);
6099 (void) CloseBlob(previous);
6102 MngInfoFreeStruct(mng_info,&have_mng_structure);
6103 return((Image *) NULL);
6106 if (image->columns == 0 || image->rows == 0)
6108 (void) CloseBlob(image);
6109 image=DestroyImageList(image);
6110 MngInfoFreeStruct(mng_info,&have_mng_structure);
6111 return((Image *) NULL);
6114 mng_info->image=image;
6121 if (mng_info->magn_methx || mng_info->magn_methy)
6127 if (logging != MagickFalse)
6128 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6129 " Processing MNG MAGN chunk");
6131 if (mng_info->magn_methx == 1)
6133 magnified_width=mng_info->magn_ml;
6135 if (image->columns > 1)
6136 magnified_width += mng_info->magn_mr;
6138 if (image->columns > 2)
6139 magnified_width += (png_uint_32)
6140 ((image->columns-2)*(mng_info->magn_mx));
6145 magnified_width=(png_uint_32) image->columns;
6147 if (image->columns > 1)
6148 magnified_width += mng_info->magn_ml-1;
6150 if (image->columns > 2)
6151 magnified_width += mng_info->magn_mr-1;
6153 if (image->columns > 3)
6154 magnified_width += (png_uint_32)
6155 ((image->columns-3)*(mng_info->magn_mx-1));
6158 if (mng_info->magn_methy == 1)
6160 magnified_height=mng_info->magn_mt;
6162 if (image->rows > 1)
6163 magnified_height += mng_info->magn_mb;
6165 if (image->rows > 2)
6166 magnified_height += (png_uint_32)
6167 ((image->rows-2)*(mng_info->magn_my));
6172 magnified_height=(png_uint_32) image->rows;
6174 if (image->rows > 1)
6175 magnified_height += mng_info->magn_mt-1;
6177 if (image->rows > 2)
6178 magnified_height += mng_info->magn_mb-1;
6180 if (image->rows > 3)
6181 magnified_height += (png_uint_32)
6182 ((image->rows-3)*(mng_info->magn_my-1));
6185 if (magnified_height > image->rows ||
6186 magnified_width > image->columns)
6213 /* Allocate next image structure. */
6215 if (logging != MagickFalse)
6216 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6217 " Allocate magnified image");
6219 AcquireNextImage(image_info,image,exception);
6221 if (GetNextImageInList(image) == (Image *) NULL)
6223 image=DestroyImageList(image);
6224 MngInfoFreeStruct(mng_info,&have_mng_structure);
6225 return((Image *) NULL);
6228 large_image=SyncNextImageInList(image);
6230 large_image->columns=magnified_width;
6231 large_image->rows=magnified_height;
6233 magn_methx=mng_info->magn_methx;
6234 magn_methy=mng_info->magn_methy;
6236 #if (MAGICKCORE_QUANTUM_DEPTH > 16)
6237 #define QM unsigned short
6238 if (magn_methx != 1 || magn_methy != 1)
6241 Scale pixels to unsigned shorts to prevent
6242 overflow of intermediate values of interpolations
6244 for (y=0; y < (ssize_t) image->rows; y++)
6246 q=GetAuthenticPixels(image,0,y,image->columns,1,
6249 for (x=(ssize_t) image->columns-1; x >= 0; x--)
6251 SetPixelRed(image,ScaleQuantumToShort(
6252 GetPixelRed(image,q)),q);
6253 SetPixelGreen(image,ScaleQuantumToShort(
6254 GetPixelGreen(image,q)),q);
6255 SetPixelBlue(image,ScaleQuantumToShort(
6256 GetPixelBlue(image,q)),q);
6257 SetPixelAlpha(image,ScaleQuantumToShort(
6258 GetPixelAlpha(image,q)),q);
6259 q+=GetPixelChannels(image);
6262 if (SyncAuthenticPixels(image,exception) == MagickFalse)
6270 if (image->matte != MagickFalse)
6271 (void) SetImageBackgroundColor(large_image,exception);
6275 large_image->background_color.alpha=OpaqueAlpha;
6276 (void) SetImageBackgroundColor(large_image,exception);
6278 if (magn_methx == 4)
6281 if (magn_methx == 5)
6284 if (magn_methy == 4)
6287 if (magn_methy == 5)
6291 /* magnify the rows into the right side of the large image */
6293 if (logging != MagickFalse)
6294 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6295 " Magnify the rows to %.20g",(double) large_image->rows);
6296 m=(ssize_t) mng_info->magn_mt;
6298 length=(size_t) image->columns*GetPixelChannels(image);
6299 next=(Quantum *) AcquireQuantumMemory(length,sizeof(*next));
6300 prev=(Quantum *) AcquireQuantumMemory(length,sizeof(*prev));
6302 if ((prev == (Quantum *) NULL) ||
6303 (next == (Quantum *) NULL))
6305 image=DestroyImageList(image);
6306 MngInfoFreeStruct(mng_info,&have_mng_structure);
6307 ThrowReaderException(ResourceLimitError,
6308 "MemoryAllocationFailed");
6311 n=GetAuthenticPixels(image,0,0,image->columns,1,exception);
6312 (void) CopyMagickMemory(next,n,length);
6314 for (y=0; y < (ssize_t) image->rows; y++)
6317 m=(ssize_t) mng_info->magn_mt;
6319 else if (magn_methy > 1 && y == (ssize_t) image->rows-2)
6320 m=(ssize_t) mng_info->magn_mb;
6322 else if (magn_methy <= 1 && y == (ssize_t) image->rows-1)
6323 m=(ssize_t) mng_info->magn_mb;
6325 else if (magn_methy > 1 && y == (ssize_t) image->rows-1)
6329 m=(ssize_t) mng_info->magn_my;
6335 if (y < (ssize_t) image->rows-1)
6337 n=GetAuthenticPixels(image,0,y+1,image->columns,1,
6339 (void) CopyMagickMemory(next,n,length);
6342 for (i=0; i < m; i++, yy++)
6347 assert(yy < (ssize_t) large_image->rows);
6350 q=GetAuthenticPixels(large_image,0,yy,large_image->columns,
6352 q+=(large_image->columns-image->columns)*
6353 GetPixelChannels(large_image);
6355 for (x=(ssize_t) image->columns-1; x >= 0; x--)
6357 /* To do: get color as function of indexes[x] */
6359 if (image->storage_class == PseudoClass)
6364 if (magn_methy <= 1)
6366 /* replicate previous */
6367 SetPixelRed(large_image,GetPixelRed(image,pixels),q);
6368 SetPixelGreen(large_image,GetPixelGreen(image,
6370 SetPixelBlue(large_image,GetPixelBlue(image,
6372 SetPixelAlpha(large_image,GetPixelAlpha(image,
6376 else if (magn_methy == 2 || magn_methy == 4)
6380 SetPixelRed(large_image,GetPixelRed(image,
6382 SetPixelGreen(large_image,GetPixelGreen(image,
6384 SetPixelBlue(large_image,GetPixelBlue(image,
6386 SetPixelAlpha(large_image,GetPixelAlpha(image,
6393 SetPixelRed(large_image,((QM) (((ssize_t)
6394 (2*i*(GetPixelRed(image,n)
6395 -GetPixelRed(image,pixels)+m))/
6397 +GetPixelRed(image,pixels)))),q);
6398 SetPixelGreen(large_image,((QM) (((ssize_t)
6399 (2*i*(GetPixelGreen(image,n)
6400 -GetPixelGreen(image,pixels)+m))/
6402 +GetPixelGreen(image,pixels)))),q);
6403 SetPixelBlue(large_image,((QM) (((ssize_t)
6404 (2*i*(GetPixelBlue(image,n)
6405 -GetPixelBlue(image,pixels)+m))/
6407 +GetPixelBlue(image,pixels)))),q);
6409 if (image->matte != MagickFalse)
6410 SetPixelAlpha(large_image, ((QM) (((ssize_t)
6411 (2*i*(GetPixelAlpha(image,n)
6412 -GetPixelAlpha(image,pixels)+m))
6414 GetPixelAlpha(image,pixels)))),q);
6417 if (magn_methy == 4)
6419 /* Replicate nearest */
6420 if (i <= ((m+1) << 1))
6421 SetPixelAlpha(large_image,GetPixelAlpha(image,
6424 SetPixelAlpha(large_image,GetPixelAlpha(image,
6429 else /* if (magn_methy == 3 || magn_methy == 5) */
6431 /* Replicate nearest */
6432 if (i <= ((m+1) << 1))
6434 SetPixelRed(large_image,GetPixelRed(image,
6436 SetPixelGreen(large_image,GetPixelGreen(image,
6438 SetPixelBlue(large_image,GetPixelBlue(image,
6440 SetPixelAlpha(large_image,GetPixelAlpha(image,
6446 SetPixelRed(large_image,GetPixelRed(image,n),q);
6447 SetPixelGreen(large_image,GetPixelGreen(image,n),
6449 SetPixelBlue(large_image,GetPixelBlue(image,n),
6451 SetPixelAlpha(large_image,GetPixelAlpha(image,n),
6455 if (magn_methy == 5)
6457 SetPixelAlpha(large_image,(QM) (((ssize_t) (2*i*
6458 (GetPixelAlpha(image,n)
6459 -GetPixelAlpha(image,pixels))
6460 +m))/((ssize_t) (m*2))
6461 +GetPixelAlpha(image,pixels)),q);
6464 n+=GetPixelChannels(image);
6465 q+=GetPixelChannels(large_image);
6466 pixels+=GetPixelChannels(image);
6469 if (SyncAuthenticPixels(large_image,exception) == 0)
6475 prev=(Quantum *) RelinquishMagickMemory(prev);
6476 next=(Quantum *) RelinquishMagickMemory(next);
6478 length=image->columns;
6480 if (logging != MagickFalse)
6481 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6482 " Delete original image");
6484 DeleteImageFromList(&image);
6488 mng_info->image=image;
6490 /* magnify the columns */
6491 if (logging != MagickFalse)
6492 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6493 " Magnify the columns to %.20g",(double) image->columns);
6495 for (y=0; y < (ssize_t) image->rows; y++)
6500 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
6501 pixels=q+(image->columns-length)*GetPixelChannels(image);
6502 n=pixels+GetPixelChannels(image);
6504 for (x=(ssize_t) (image->columns-length);
6505 x < (ssize_t) image->columns; x++)
6507 /* To do: Rewrite using Get/Set***PixelChannel() */
6509 if (x == (ssize_t) (image->columns-length))
6510 m=(ssize_t) mng_info->magn_ml;
6512 else if (magn_methx > 1 && x == (ssize_t) image->columns-2)
6513 m=(ssize_t) mng_info->magn_mr;
6515 else if (magn_methx <= 1 && x == (ssize_t) image->columns-1)
6516 m=(ssize_t) mng_info->magn_mr;
6518 else if (magn_methx > 1 && x == (ssize_t) image->columns-1)
6522 m=(ssize_t) mng_info->magn_mx;
6524 for (i=0; i < m; i++)
6526 if (magn_methx <= 1)
6528 /* replicate previous */
6529 SetPixelRed(image,GetPixelRed(image,pixels),q);
6530 SetPixelGreen(image,GetPixelGreen(image,pixels),q);
6531 SetPixelBlue(image,GetPixelBlue(image,pixels),q);
6532 SetPixelAlpha(image,GetPixelAlpha(image,pixels),q);
6535 else if (magn_methx == 2 || magn_methx == 4)
6539 SetPixelRed(image,GetPixelRed(image,pixels),q);
6540 SetPixelGreen(image,GetPixelGreen(image,pixels),q);
6541 SetPixelBlue(image,GetPixelBlue(image,pixels),q);
6542 SetPixelAlpha(image,GetPixelAlpha(image,pixels),q);
6545 /* To do: Rewrite using Get/Set***PixelChannel() */
6549 SetPixelRed(image,(QM) ((2*i*(
6550 GetPixelRed(image,n)
6551 -GetPixelRed(image,pixels))+m)
6553 GetPixelRed(image,pixels)),q);
6555 SetPixelGreen(image,(QM) ((2*i*(
6556 GetPixelGreen(image,n)
6557 -GetPixelGreen(image,pixels))+m)
6559 GetPixelGreen(image,pixels)),q);
6561 SetPixelBlue(image,(QM) ((2*i*(
6562 GetPixelBlue(image,n)
6563 -GetPixelBlue(image,pixels))+m)
6565 GetPixelBlue(image,pixels)),q);
6566 if (image->matte != MagickFalse)
6567 SetPixelAlpha(image,(QM) ((2*i*(
6568 GetPixelAlpha(image,n)
6569 -GetPixelAlpha(image,pixels))+m)
6571 GetPixelAlpha(image,pixels)),q);
6574 if (magn_methx == 4)
6576 /* Replicate nearest */
6577 if (i <= ((m+1) << 1))
6579 SetPixelAlpha(image,
6580 GetPixelAlpha(image,pixels)+0,q);
6584 SetPixelAlpha(image,
6585 GetPixelAlpha(image,n)+0,q);
6590 else /* if (magn_methx == 3 || magn_methx == 5) */
6592 /* Replicate nearest */
6593 if (i <= ((m+1) << 1))
6595 SetPixelRed(image,GetPixelRed(image,pixels),q);
6596 SetPixelGreen(image,GetPixelGreen(image,pixels),q);
6597 SetPixelBlue(image,GetPixelBlue(image,pixels),q);
6598 SetPixelAlpha(image,GetPixelAlpha(image,pixels),q);
6603 SetPixelRed(image,GetPixelRed(image,n),q);
6604 SetPixelGreen(image,GetPixelGreen(image,n),q);
6605 SetPixelBlue(image,GetPixelBlue(image,n),q);
6606 SetPixelAlpha(image,GetPixelAlpha(image,n),q);
6609 if (magn_methx == 5)
6612 SetPixelAlpha(image,
6613 (QM) ((2*i*( GetPixelAlpha(image,n)
6614 -GetPixelAlpha(image,pixels))+m)/
6616 +GetPixelAlpha(image,pixels)),q);
6619 q+=GetPixelChannels(image);
6621 n+=GetPixelChannels(image);
6622 p+=GetPixelChannels(image);
6625 if (SyncAuthenticPixels(image,exception) == MagickFalse)
6628 #if (MAGICKCORE_QUANTUM_DEPTH > 16)
6629 if (magn_methx != 1 || magn_methy != 1)
6632 Rescale pixels to Quantum
6634 for (y=0; y < (ssize_t) image->rows; y++)
6636 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
6638 for (x=(ssize_t) image->columns-1; x >= 0; x--)
6640 SetPixelRed(image,ScaleShortToQuantum(
6641 GetPixelRed(image,q)),q);
6642 SetPixelGreen(image,ScaleShortToQuantum(
6643 GetPixelGreen(image,q)),q);
6644 SetPixelBlue(image,ScaleShortToQuantum(
6645 GetPixelBlue(image,q)),q);
6646 SetPixelAlpha(image,ScaleShortToQuantum(
6647 GetPixelAlpha(image,q)),q);
6648 q+=GetPixelChannels(image);
6651 if (SyncAuthenticPixels(image,exception) == MagickFalse)
6656 if (logging != MagickFalse)
6657 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6658 " Finished MAGN processing");
6663 Crop_box is with respect to the upper left corner of the MNG.
6665 crop_box.left=mng_info->image_box.left+mng_info->x_off[object_id];
6666 crop_box.right=mng_info->image_box.right+mng_info->x_off[object_id];
6667 crop_box.top=mng_info->image_box.top+mng_info->y_off[object_id];
6668 crop_box.bottom=mng_info->image_box.bottom+mng_info->y_off[object_id];
6669 crop_box=mng_minimum_box(crop_box,mng_info->clip);
6670 crop_box=mng_minimum_box(crop_box,mng_info->frame);
6671 crop_box=mng_minimum_box(crop_box,mng_info->object_clip[object_id]);
6672 if ((crop_box.left != (mng_info->image_box.left
6673 +mng_info->x_off[object_id])) ||
6674 (crop_box.right != (mng_info->image_box.right
6675 +mng_info->x_off[object_id])) ||
6676 (crop_box.top != (mng_info->image_box.top
6677 +mng_info->y_off[object_id])) ||
6678 (crop_box.bottom != (mng_info->image_box.bottom
6679 +mng_info->y_off[object_id])))
6681 if (logging != MagickFalse)
6682 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6683 " Crop the PNG image");
6685 if ((crop_box.left < crop_box.right) &&
6686 (crop_box.top < crop_box.bottom))
6695 Crop_info is with respect to the upper left corner of
6698 crop_info.x=(crop_box.left-mng_info->x_off[object_id]);
6699 crop_info.y=(crop_box.top-mng_info->y_off[object_id]);
6700 crop_info.width=(size_t) (crop_box.right-crop_box.left);
6701 crop_info.height=(size_t) (crop_box.bottom-crop_box.top);
6702 image->page.width=image->columns;
6703 image->page.height=image->rows;
6706 im=CropImage(image,&crop_info,exception);
6708 if (im != (Image *) NULL)
6710 image->columns=im->columns;
6711 image->rows=im->rows;
6712 im=DestroyImage(im);
6713 image->page.width=image->columns;
6714 image->page.height=image->rows;
6715 image->page.x=crop_box.left;
6716 image->page.y=crop_box.top;
6723 No pixels in crop area. The MNG spec still requires
6724 a layer, though, so make a single transparent pixel in
6725 the top left corner.
6730 (void) SetImageBackgroundColor(image,exception);
6731 image->page.width=1;
6732 image->page.height=1;
6737 #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
6738 image=mng_info->image;
6742 #if (MAGICKCORE_QUANTUM_DEPTH > 16)
6743 /* PNG does not handle depths greater than 16 so reduce it even
6746 if (image->depth > 16)
6750 #if (MAGICKCORE_QUANTUM_DEPTH > 8)
6751 if (image->depth > 8)
6753 /* To do: fill low byte properly */
6757 if (LosslessReduceDepthOK(image,exception) != MagickFalse)
6761 if (image_info->number_scenes != 0)
6763 if (mng_info->scenes_found >
6764 (ssize_t) (image_info->first_scene+image_info->number_scenes))
6768 if (logging != MagickFalse)
6769 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6770 " Finished reading image datastream.");
6772 } while (LocaleCompare(image_info->magick,"MNG") == 0);
6774 (void) CloseBlob(image);
6776 if (logging != MagickFalse)
6777 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6778 " Finished reading all image datastreams.");
6780 #if defined(MNG_INSERT_LAYERS)
6781 if (insert_layers && !mng_info->image_found && (mng_info->mng_width) &&
6782 (mng_info->mng_height))
6785 Insert a background layer if nothing else was found.
6787 if (logging != MagickFalse)
6788 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6789 " No images found. Inserting a background layer.");
6791 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
6794 Allocate next image structure.
6796 AcquireNextImage(image_info,image,exception);
6797 if (GetNextImageInList(image) == (Image *) NULL)
6799 image=DestroyImageList(image);
6800 MngInfoFreeStruct(mng_info,&have_mng_structure);
6802 if (logging != MagickFalse)
6803 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6804 " Allocation failed, returning NULL.");
6806 return((Image *) NULL);
6808 image=SyncNextImageInList(image);
6810 image->columns=mng_info->mng_width;
6811 image->rows=mng_info->mng_height;
6812 image->page.width=mng_info->mng_width;
6813 image->page.height=mng_info->mng_height;
6816 image->background_color=mng_background_color;
6817 image->matte=MagickFalse;
6819 if (image_info->ping == MagickFalse)
6820 (void) SetImageBackgroundColor(image,exception);
6822 mng_info->image_found++;
6825 image->iterations=mng_iterations;
6827 if (mng_iterations == 1)
6828 image->start_loop=MagickTrue;
6830 while (GetPreviousImageInList(image) != (Image *) NULL)
6833 if (image_count > 10*mng_info->image_found)
6835 if (logging != MagickFalse)
6836 (void) LogMagickEvent(CoderEvent,GetMagickModule()," No beginning");
6838 (void) ThrowMagickException(exception,GetMagickModule(),
6839 CoderError,"Linked list is corrupted, beginning of list not found",
6840 "`%s'",image_info->filename);
6842 return((Image *) NULL);
6845 image=GetPreviousImageInList(image);
6847 if (GetNextImageInList(image) == (Image *) NULL)
6849 if (logging != MagickFalse)
6850 (void) LogMagickEvent(CoderEvent,GetMagickModule()," Corrupt list");
6852 (void) ThrowMagickException(exception,GetMagickModule(),
6853 CoderError,"Linked list is corrupted; next_image is NULL","`%s'",
6854 image_info->filename);
6858 if (mng_info->ticks_per_second && mng_info->image_found > 1 &&
6859 GetNextImageInList(image) ==
6862 if (logging != MagickFalse)
6863 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6864 " First image null");
6866 (void) ThrowMagickException(exception,GetMagickModule(),
6867 CoderError,"image->next for first image is NULL but shouldn't be.",
6868 "`%s'",image_info->filename);
6871 if (mng_info->image_found == 0)
6873 if (logging != MagickFalse)
6874 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6875 " No visible images found.");
6877 (void) ThrowMagickException(exception,GetMagickModule(),
6878 CoderError,"No visible images in file","`%s'",image_info->filename);
6880 if (image != (Image *) NULL)
6881 image=DestroyImageList(image);
6883 MngInfoFreeStruct(mng_info,&have_mng_structure);
6884 return((Image *) NULL);
6887 if (mng_info->ticks_per_second)
6888 final_delay=1UL*MagickMax(image->ticks_per_second,1L)*
6889 final_delay/mng_info->ticks_per_second;
6892 image->start_loop=MagickTrue;
6894 /* Find final nonzero image delay */
6895 final_image_delay=0;
6897 while (GetNextImageInList(image) != (Image *) NULL)
6900 final_image_delay=image->delay;
6902 image=GetNextImageInList(image);
6905 if (final_delay < final_image_delay)
6906 final_delay=final_image_delay;
6908 image->delay=final_delay;
6910 if (logging != MagickFalse)
6911 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6912 " image->delay=%.20g, final_delay=%.20g",(double) image->delay,
6913 (double) final_delay);
6915 if (logging != MagickFalse)
6921 image=GetFirstImageInList(image);
6923 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6924 " Before coalesce:");
6926 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6927 " scene 0 delay=%.20g",(double) image->delay);
6929 while (GetNextImageInList(image) != (Image *) NULL)
6931 image=GetNextImageInList(image);
6932 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6933 " scene %.20g delay=%.20g",(double) scene++,(double) image->delay);
6937 image=GetFirstImageInList(image);
6938 #ifdef MNG_COALESCE_LAYERS
6948 if (logging != MagickFalse)
6949 (void) LogMagickEvent(CoderEvent,GetMagickModule()," Coalesce Images");
6952 next_image=CoalesceImages(image,exception);
6954 if (next_image == (Image *) NULL)
6955 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
6957 image=DestroyImageList(image);
6960 for (next=image; next != (Image *) NULL; next=next_image)
6962 next->page.width=mng_info->mng_width;
6963 next->page.height=mng_info->mng_height;
6966 next->scene=scene++;
6967 next_image=GetNextImageInList(next);
6969 if (next_image == (Image *) NULL)
6972 if (next->delay == 0)
6975 next_image->previous=GetPreviousImageInList(next);
6976 if (GetPreviousImageInList(next) == (Image *) NULL)
6979 next->previous->next=next_image;
6980 next=DestroyImage(next);
6986 while (GetNextImageInList(image) != (Image *) NULL)
6987 image=GetNextImageInList(image);
6989 image->dispose=BackgroundDispose;
6991 if (logging != MagickFalse)
6997 image=GetFirstImageInList(image);
6999 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7000 " After coalesce:");
7002 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7003 " scene 0 delay=%.20g dispose=%.20g",(double) image->delay,
7004 (double) image->dispose);
7006 while (GetNextImageInList(image) != (Image *) NULL)
7008 image=GetNextImageInList(image);
7010 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7011 " scene %.20g delay=%.20g dispose=%.20g",(double) scene++,
7012 (double) image->delay,(double) image->dispose);
7016 image=GetFirstImageInList(image);
7017 MngInfoFreeStruct(mng_info,&have_mng_structure);
7018 have_mng_structure=MagickFalse;
7020 if (logging != MagickFalse)
7021 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit ReadMNGImage()");
7023 return(GetFirstImageInList(image));
7025 #else /* PNG_LIBPNG_VER > 10011 */
7026 static Image *ReadPNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
7028 printf("Your PNG library is too old: You have libpng-%s\n",
7029 PNG_LIBPNG_VER_STRING);
7031 (void) ThrowMagickException(exception,GetMagickModule(),CoderError,
7032 "PNG library is too old","`%s'",image_info->filename);
7034 return(Image *) NULL;
7037 static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
7039 return(ReadPNGImage(image_info,exception));
7041 #endif /* PNG_LIBPNG_VER > 10011 */
7045 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7049 % R e g i s t e r P N G I m a g e %
7053 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7055 % RegisterPNGImage() adds properties for the PNG image format to
7056 % the list of supported formats. The properties include the image format
7057 % tag, a method to read and/or write the format, whether the format
7058 % supports the saving of more than one frame to the same file or blob,
7059 % whether the format supports native in-memory I/O, and a brief
7060 % description of the format.
7062 % The format of the RegisterPNGImage method is:
7064 % size_t RegisterPNGImage(void)
7067 ModuleExport size_t RegisterPNGImage(void)
7070 version[MaxTextExtent];
7078 "See http://www.libpng.org/ for details about the PNG format."
7083 "See http://www.libpng.org/pub/mng/ for details about the JNG\n"
7089 "See http://www.libpng.org/pub/mng/ for details about the MNG\n"
7095 #if defined(PNG_LIBPNG_VER_STRING)
7096 (void) ConcatenateMagickString(version,"libpng ",MaxTextExtent);
7097 (void) ConcatenateMagickString(version,PNG_LIBPNG_VER_STRING,MaxTextExtent);
7099 if (LocaleCompare(PNG_LIBPNG_VER_STRING,png_get_header_ver(NULL)) != 0)
7101 (void) ConcatenateMagickString(version,",",MaxTextExtent);
7102 (void) ConcatenateMagickString(version,png_get_libpng_ver(NULL),
7107 entry=SetMagickInfo("MNG");
7108 entry->seekable_stream=MagickTrue; /* To do: eliminate this. */
7110 #if defined(MAGICKCORE_PNG_DELEGATE)
7111 entry->decoder=(DecodeImageHandler *) ReadMNGImage;
7112 entry->encoder=(EncodeImageHandler *) WriteMNGImage;
7115 entry->magick=(IsImageFormatHandler *) IsMNG;
7116 entry->description=ConstantString("Multiple-image Network Graphics");
7118 if (*version != '\0')
7119 entry->version=ConstantString(version);
7121 entry->module=ConstantString("PNG");
7122 entry->note=ConstantString(MNGNote);
7123 (void) RegisterMagickInfo(entry);
7125 entry=SetMagickInfo("PNG");
7127 #if defined(MAGICKCORE_PNG_DELEGATE)
7128 entry->decoder=(DecodeImageHandler *) ReadPNGImage;
7129 entry->encoder=(EncodeImageHandler *) WritePNGImage;
7132 entry->magick=(IsImageFormatHandler *) IsPNG;
7133 entry->adjoin=MagickFalse;
7134 entry->description=ConstantString("Portable Network Graphics");
7135 entry->module=ConstantString("PNG");
7137 if (*version != '\0')
7138 entry->version=ConstantString(version);
7140 entry->note=ConstantString(PNGNote);
7141 (void) RegisterMagickInfo(entry);
7143 entry=SetMagickInfo("PNG8");
7145 #if defined(MAGICKCORE_PNG_DELEGATE)
7146 entry->decoder=(DecodeImageHandler *) ReadPNGImage;
7147 entry->encoder=(EncodeImageHandler *) WritePNGImage;
7150 entry->magick=(IsImageFormatHandler *) IsPNG;
7151 entry->adjoin=MagickFalse;
7152 entry->description=ConstantString(
7153 "8-bit indexed with optional binary transparency");
7154 entry->module=ConstantString("PNG");
7155 (void) RegisterMagickInfo(entry);
7157 entry=SetMagickInfo("PNG24");
7160 #if defined(ZLIB_VERSION)
7161 (void) ConcatenateMagickString(version,"zlib ",MaxTextExtent);
7162 (void) ConcatenateMagickString(version,ZLIB_VERSION,MaxTextExtent);
7164 if (LocaleCompare(ZLIB_VERSION,zlib_version) != 0)
7166 (void) ConcatenateMagickString(version,",",MaxTextExtent);
7167 (void) ConcatenateMagickString(version,zlib_version,MaxTextExtent);
7171 if (*version != '\0')
7172 entry->version=ConstantString(version);
7174 #if defined(MAGICKCORE_PNG_DELEGATE)
7175 entry->decoder=(DecodeImageHandler *) ReadPNGImage;
7176 entry->encoder=(EncodeImageHandler *) WritePNGImage;
7179 entry->magick=(IsImageFormatHandler *) IsPNG;
7180 entry->adjoin=MagickFalse;
7181 entry->description=ConstantString("opaque 24-bit RGB");
7182 entry->module=ConstantString("PNG");
7183 (void) RegisterMagickInfo(entry);
7185 entry=SetMagickInfo("PNG32");
7187 #if defined(MAGICKCORE_PNG_DELEGATE)
7188 entry->decoder=(DecodeImageHandler *) ReadPNGImage;
7189 entry->encoder=(EncodeImageHandler *) WritePNGImage;
7192 entry->magick=(IsImageFormatHandler *) IsPNG;
7193 entry->adjoin=MagickFalse;
7194 entry->description=ConstantString("opaque or transparent 32-bit RGBA");
7195 entry->module=ConstantString("PNG");
7196 (void) RegisterMagickInfo(entry);
7198 entry=SetMagickInfo("JNG");
7200 #if defined(JNG_SUPPORTED)
7201 #if defined(MAGICKCORE_PNG_DELEGATE)
7202 entry->decoder=(DecodeImageHandler *) ReadJNGImage;
7203 entry->encoder=(EncodeImageHandler *) WriteJNGImage;
7207 entry->magick=(IsImageFormatHandler *) IsJNG;
7208 entry->adjoin=MagickFalse;
7209 entry->description=ConstantString("JPEG Network Graphics");
7210 entry->module=ConstantString("PNG");
7211 entry->note=ConstantString(JNGNote);
7212 (void) RegisterMagickInfo(entry);
7214 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
7215 ping_semaphore=AllocateSemaphoreInfo();
7218 return(MagickImageCoderSignature);
7222 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7226 % U n r e g i s t e r P N G I m a g e %
7230 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7232 % UnregisterPNGImage() removes format registrations made by the
7233 % PNG module from the list of supported formats.
7235 % The format of the UnregisterPNGImage method is:
7237 % UnregisterPNGImage(void)
7240 ModuleExport void UnregisterPNGImage(void)
7242 (void) UnregisterMagickInfo("MNG");
7243 (void) UnregisterMagickInfo("PNG");
7244 (void) UnregisterMagickInfo("PNG8");
7245 (void) UnregisterMagickInfo("PNG24");
7246 (void) UnregisterMagickInfo("PNG32");
7247 (void) UnregisterMagickInfo("JNG");
7249 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
7250 if (ping_semaphore != (SemaphoreInfo *) NULL)
7251 DestroySemaphoreInfo(&ping_semaphore);
7255 #if defined(MAGICKCORE_PNG_DELEGATE)
7256 #if PNG_LIBPNG_VER > 10011
7258 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7262 % W r i t e M N G I m a g e %
7266 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7268 % WriteMNGImage() writes an image in the Portable Network Graphics
7269 % Group's "Multiple-image Network Graphics" encoded image format.
7271 % MNG support written by Glenn Randers-Pehrson, glennrp@image...
7273 % The format of the WriteMNGImage method is:
7275 % MagickBooleanType WriteMNGImage(const ImageInfo *image_info,
7276 % Image *image,ExceptionInfo *exception)
7278 % A description of each parameter follows.
7280 % o image_info: the image info.
7282 % o image: The image.
7284 % o exception: return any errors or warnings in this structure.
7286 % To do (as of version 5.5.2, November 26, 2002 -- glennrp -- see also
7287 % "To do" under ReadPNGImage):
7289 % Preserve all unknown and not-yet-handled known chunks found in input
7290 % PNG file and copy them into output PNG files according to the PNG
7293 % Write the iCCP chunk at MNG level when (icc profile length > 0)
7295 % Improve selection of color type (use indexed-colour or indexed-colour
7296 % with tRNS when 256 or fewer unique RGBA values are present).
7298 % Figure out what to do with "dispose=<restore-to-previous>" (dispose == 3)
7299 % This will be complicated if we limit ourselves to generating MNG-LC
7300 % files. For now we ignore disposal method 3 and simply overlay the next
7303 % Check for identical PLTE's or PLTE/tRNS combinations and use a
7304 % global MNG PLTE or PLTE/tRNS combination when appropriate.
7305 % [mostly done 15 June 1999 but still need to take care of tRNS]
7307 % Check for identical sRGB and replace with a global sRGB (and remove
7308 % gAMA/cHRM if sRGB is found; check for identical gAMA/cHRM and
7309 % replace with global gAMA/cHRM (or with sRGB if appropriate; replace
7310 % local gAMA/cHRM with local sRGB if appropriate).
7312 % Check for identical sBIT chunks and write global ones.
7314 % Provide option to skip writing the signature tEXt chunks.
7316 % Use signatures to detect identical objects and reuse the first
7317 % instance of such objects instead of writing duplicate objects.
7319 % Use a smaller-than-32k value of compression window size when
7322 % Encode JNG datastreams. Mostly done as of 5.5.2; need to write
7323 % ancillary text chunks and save profiles.
7325 % Provide an option to force LC files (to ensure exact framing rate)
7328 % Provide an option to force VLC files instead of LC, even when offsets
7329 % are present. This will involve expanding the embedded images with a
7330 % transparent region at the top and/or left.
7334 Magick_png_write_raw_profile(const ImageInfo *image_info,png_struct *ping,
7335 png_info *ping_info, unsigned char *profile_type, unsigned char
7336 *profile_description, unsigned char *profile_data, png_uint_32 length)
7355 hex[16]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
7357 if (LocaleNCompare((char *) profile_type+1, "ng-chunk-",9) == 0)
7360 if (image_info->verbose)
7362 (void) printf("writing raw profile: type=%s, length=%.20g\n",
7363 (char *) profile_type, (double) length);
7366 text=(png_textp) png_malloc(ping,(png_uint_32) sizeof(png_text));
7367 description_length=(png_uint_32) strlen((const char *) profile_description);
7368 allocated_length=(png_uint_32) (length*2 + (length >> 5) + 20
7369 + description_length);
7370 text[0].text=(png_charp) png_malloc(ping,allocated_length);
7371 text[0].key=(png_charp) png_malloc(ping, (png_uint_32) 80);
7372 text[0].key[0]='\0';
7373 (void) ConcatenateMagickString(text[0].key,
7374 "Raw profile type ",MaxTextExtent);
7375 (void) ConcatenateMagickString(text[0].key,(const char *) profile_type,62);
7379 (void) CopyMagickString(dp,(const char *) profile_description,
7381 dp+=description_length;
7383 (void) FormatLocaleString(dp,allocated_length-
7384 (png_size_t) (dp-text[0].text),"%8lu ",(unsigned long) length);
7387 for (i=0; i < (ssize_t) length; i++)
7391 *(dp++)=(char) hex[((*sp >> 4) & 0x0f)];
7392 *(dp++)=(char) hex[((*sp++ ) & 0x0f)];
7397 text[0].text_length=(png_size_t) (dp-text[0].text);
7398 text[0].compression=image_info->compression == NoCompression ||
7399 (image_info->compression == UndefinedCompression &&
7400 text[0].text_length < 128) ? -1 : 0;
7402 if (text[0].text_length <= allocated_length)
7403 png_set_text(ping,ping_info,text,1);
7405 png_free(ping,text[0].text);
7406 png_free(ping,text[0].key);
7407 png_free(ping,text);
7410 static MagickBooleanType Magick_png_write_chunk_from_profile(Image *image,
7411 const char *string, MagickBooleanType logging)
7424 ResetImageProfileIterator(image);
7426 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
7428 profile=GetImageProfile(image,name);
7430 if (profile != (const StringInfo *) NULL)
7435 if (LocaleNCompare(name,string,11) == 0)
7437 if (logging != MagickFalse)
7438 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7439 " Found %s profile",name);
7441 ping_profile=CloneStringInfo(profile);
7442 data=GetStringInfoDatum(ping_profile),
7443 length=(png_uint_32) GetStringInfoLength(ping_profile);
7448 (void) WriteBlobMSBULong(image,length-5); /* data length */
7449 (void) WriteBlob(image,length-1,data+1);
7450 (void) WriteBlobMSBULong(image,crc32(0,data+1,(uInt) length-1));
7451 ping_profile=DestroyStringInfo(ping_profile);
7455 name=GetNextImageProfile(image);
7462 /* Write one PNG image */
7463 static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
7464 const ImageInfo *IMimage_info,Image *IMimage,ExceptionInfo *exception)
7488 ping_trans_alpha[256];
7516 ping_have_cheap_transparency,
7527 /* ping_exclude_EXIF, */
7530 /* ping_exclude_iTXt, */
7535 /* ping_exclude_tRNS, */
7537 ping_exclude_zCCP, /* hex-encoded iCCP */
7540 ping_preserve_colormap,
7541 ping_need_colortype_warning,
7565 ping_interlace_method,
7566 ping_compression_method,
7583 number_semitransparent,
7585 ping_pHYs_unit_type;
7588 ping_pHYs_x_resolution,
7589 ping_pHYs_y_resolution;
7591 logging=LogMagickEvent(CoderEvent,GetMagickModule(),
7592 " Enter WriteOnePNGImage()");
7594 image = CloneImage(IMimage,0,0,MagickFalse,exception);
7595 image_info=(ImageInfo *) CloneImageInfo(IMimage_info);
7596 if (image_info == (ImageInfo *) NULL)
7597 ThrowWriterException(ResourceLimitError, "MemoryAllocationFailed");
7599 /* Initialize some stuff */
7602 ping_interlace_method=0,
7603 ping_compression_method=0,
7604 ping_filter_method=0,
7607 ping_background.red = 0;
7608 ping_background.green = 0;
7609 ping_background.blue = 0;
7610 ping_background.gray = 0;
7611 ping_background.index = 0;
7613 ping_trans_color.red=0;
7614 ping_trans_color.green=0;
7615 ping_trans_color.blue=0;
7616 ping_trans_color.gray=0;
7618 ping_pHYs_unit_type = 0;
7619 ping_pHYs_x_resolution = 0;
7620 ping_pHYs_y_resolution = 0;
7622 ping_have_blob=MagickFalse;
7623 ping_have_color=MagickTrue;
7624 ping_have_non_bw=MagickTrue;
7625 ping_have_PLTE=MagickFalse;
7626 ping_have_bKGD=MagickFalse;
7627 ping_have_pHYs=MagickFalse;
7628 ping_have_tRNS=MagickFalse;
7630 ping_exclude_bKGD=mng_info->ping_exclude_bKGD;
7631 ping_exclude_cHRM=mng_info->ping_exclude_cHRM;
7632 ping_exclude_date=mng_info->ping_exclude_date;
7633 /* ping_exclude_EXIF=mng_info->ping_exclude_EXIF; */
7634 ping_exclude_gAMA=mng_info->ping_exclude_gAMA;
7635 ping_exclude_iCCP=mng_info->ping_exclude_iCCP;
7636 /* ping_exclude_iTXt=mng_info->ping_exclude_iTXt; */
7637 ping_exclude_oFFs=mng_info->ping_exclude_oFFs;
7638 ping_exclude_pHYs=mng_info->ping_exclude_pHYs;
7639 ping_exclude_sRGB=mng_info->ping_exclude_sRGB;
7640 ping_exclude_tEXt=mng_info->ping_exclude_tEXt;
7641 /* ping_exclude_tRNS=mng_info->ping_exclude_tRNS; */
7642 ping_exclude_vpAg=mng_info->ping_exclude_vpAg;
7643 ping_exclude_zCCP=mng_info->ping_exclude_zCCP; /* hex-encoded iCCP in zTXt */
7644 ping_exclude_zTXt=mng_info->ping_exclude_zTXt;
7646 ping_preserve_colormap = mng_info->ping_preserve_colormap;
7647 ping_need_colortype_warning = MagickFalse;
7649 /* Recognize the ICC sRGB profile and convert it to the sRGB chunk,
7650 * i.e., eliminate the ICC profile and set image->rendering_intent.
7651 * Note that this will not involve any changes to the actual pixels
7652 * but merely passes information to applications that read the resulting
7655 if (ping_exclude_sRGB == MagickFalse)
7663 ResetImageProfileIterator(image);
7664 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
7666 profile=GetImageProfile(image,name);
7668 if (profile != (StringInfo *) NULL)
7670 if ((LocaleCompare(name,"ICC") == 0) ||
7671 (LocaleCompare(name,"ICM") == 0))
7676 /* 0: not a known sRGB profile
7677 * 1: HP-Microsoft sRGB v2
7678 * 2: ICC sRGB v4 perceptual
7679 * 3: ICC sRGB v2 perceptual no black-compensation
7682 check_crc[4] = {0, 0xf29e526dUL, 0xbbef7812UL, 0x427ebb21UL},
7683 check_len[4] = {0, 3144, 60960, 3052};
7692 length=(png_uint_32) GetStringInfoLength(profile);
7694 for (icheck=3; icheck > 0; icheck--)
7696 if (length == check_len[icheck])
7698 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7699 " Got a %lu-byte ICC profile (potentially sRGB)",
7700 (unsigned long) length);
7702 data=GetStringInfoDatum(profile);
7703 profile_crc=crc32(0,data,length);
7705 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7706 " with crc=%8x",(unsigned int) profile_crc);
7708 if (profile_crc == check_crc[icheck])
7710 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7712 if (image->rendering_intent==UndefinedIntent)
7713 image->rendering_intent=PerceptualIntent;
7719 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7720 " Got a %lu-byte ICC profile",
7721 (unsigned long) length);
7724 name=GetNextImageProfile(image);
7729 number_semitransparent = 0;
7730 number_transparent = 0;
7732 if (logging != MagickFalse)
7734 if (image->storage_class == UndefinedClass)
7735 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7736 " storage_class=UndefinedClass");
7737 if (image->storage_class == DirectClass)
7738 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7739 " storage_class=DirectClass");
7740 if (image->storage_class == PseudoClass)
7741 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7742 " storage_class=PseudoClass");
7745 if (image->storage_class == PseudoClass &&
7746 (mng_info->write_png8 || mng_info->write_png24 || mng_info->write_png32 ||
7747 (mng_info->write_png_colortype != 0 &&
7748 mng_info->write_png_colortype != 4)))
7750 (void) SyncImage(image,exception);
7751 image->storage_class = DirectClass;
7754 if (ping_preserve_colormap == MagickFalse)
7756 if (image->storage_class != PseudoClass && image->colormap != NULL)
7758 /* Free the bogus colormap; it can cause trouble later */
7759 if (logging != MagickFalse)
7760 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7761 " Freeing bogus colormap");
7762 (void) RelinquishMagickMemory(image->colormap);
7763 image->colormap=NULL;
7767 if (IssRGBColorspace(image->colorspace) == MagickFalse)
7768 (void) TransformImageColorspace(image,sRGBColorspace,exception);
7771 Sometimes we get PseudoClass images whose RGB values don't match
7772 the colors in the colormap. This code syncs the RGB values.
7774 if (image->depth <= 8 && image->taint && image->storage_class == PseudoClass)
7775 (void) SyncImage(image,exception);
7777 #if (MAGICKCORE_QUANTUM_DEPTH == 8)
7778 if (image->depth > 8)
7780 if (logging != MagickFalse)
7781 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7782 " Reducing PNG bit depth to 8 since this is a Q8 build.");
7788 /* Respect the -depth option */
7789 if (image->depth < MAGICKCORE_QUANTUM_DEPTH)
7794 if (image->depth > 8)
7796 #if MAGICKCORE_QUANTUM_DEPTH > 16
7797 /* Scale to 16-bit */
7798 LBR16PacketRGBO(image->background_color);
7800 for (y=0; y < (ssize_t) image->rows; y++)
7802 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
7804 if (r == (Quantum *) NULL)
7807 for (x=0; x < (ssize_t) image->columns; x++)
7810 r+=GetPixelChannels(image);
7813 if (SyncAuthenticPixels(image,exception) == MagickFalse)
7817 if (image->storage_class == PseudoClass && image->colormap != NULL)
7819 for (i=0; i < (ssize_t) image->colors; i++)
7821 LBR16PacketRGBO(image->colormap[i]);
7824 #endif /* MAGICKCORE_QUANTUM_DEPTH > 16 */
7827 else if (image->depth > 4)
7829 #if MAGICKCORE_QUANTUM_DEPTH > 8
7830 /* Scale to 8-bit */
7831 LBR08PacketRGBO(image->background_color);
7833 for (y=0; y < (ssize_t) image->rows; y++)
7835 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
7837 if (r == (Quantum *) NULL)
7840 for (x=0; x < (ssize_t) image->columns; x++)
7843 r+=GetPixelChannels(image);
7846 if (SyncAuthenticPixels(image,exception) == MagickFalse)
7850 if (image->storage_class == PseudoClass && image->colormap != NULL)
7852 for (i=0; i < (ssize_t) image->colors; i++)
7854 LBR08PacketRGBO(image->colormap[i]);
7857 #endif /* MAGICKCORE_QUANTUM_DEPTH > 8 */
7860 if (image->depth > 2)
7862 /* Scale to 4-bit */
7863 LBR04PacketRGBO(image->background_color);
7865 for (y=0; y < (ssize_t) image->rows; y++)
7867 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
7869 if (r == (Quantum *) NULL)
7872 for (x=0; x < (ssize_t) image->columns; x++)
7875 r+=GetPixelChannels(image);
7878 if (SyncAuthenticPixels(image,exception) == MagickFalse)
7882 if (image->storage_class == PseudoClass && image->colormap != NULL)
7884 for (i=0; i < (ssize_t) image->colors; i++)
7886 LBR04PacketRGBO(image->colormap[i]);
7891 else if (image->depth > 1)
7893 /* Scale to 2-bit */
7894 LBR02PacketRGBO(image->background_color);
7896 for (y=0; y < (ssize_t) image->rows; y++)
7898 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
7900 if (r == (Quantum *) NULL)
7903 for (x=0; x < (ssize_t) image->columns; x++)
7906 r+=GetPixelChannels(image);
7909 if (SyncAuthenticPixels(image,exception) == MagickFalse)
7913 if (image->storage_class == PseudoClass && image->colormap != NULL)
7915 for (i=0; i < (ssize_t) image->colors; i++)
7917 LBR02PacketRGBO(image->colormap[i]);
7923 /* Scale to 1-bit */
7924 LBR01PacketRGBO(image->background_color);
7926 for (y=0; y < (ssize_t) image->rows; y++)
7928 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
7930 if (r == (Quantum *) NULL)
7933 for (x=0; x < (ssize_t) image->columns; x++)
7936 r+=GetPixelChannels(image);
7939 if (SyncAuthenticPixels(image,exception) == MagickFalse)
7943 if (image->storage_class == PseudoClass && image->colormap != NULL)
7945 for (i=0; i < (ssize_t) image->colors; i++)
7947 LBR01PacketRGBO(image->colormap[i]);
7953 /* To do: set to next higher multiple of 8 */
7954 if (image->depth < 8)
7957 #if (MAGICKCORE_QUANTUM_DEPTH > 16)
7958 /* PNG does not handle depths greater than 16 so reduce it even
7961 if (image->depth > 8)
7965 #if (MAGICKCORE_QUANTUM_DEPTH > 8)
7966 if (image->depth > 8)
7968 /* To do: fill low byte properly */
7972 if (image->depth == 16 && mng_info->write_png_depth != 16)
7973 if (mng_info->write_png8 || LosslessReduceDepthOK(image,exception) != MagickFalse)
7977 /* Normally we run this just once, but in the case of writing PNG8
7978 * we reduce the transparency to binary and run again, then if there
7979 * are still too many colors we reduce to a simple 4-4-4-1, then 3-3-3-1
7980 * RGBA palette and run again, and then to a simple 3-3-2-1 RGBA
7981 * palette. Then (To do) we take care of a final reduction that is only
7982 * needed if there are still 256 colors present and one of them has both
7983 * transparent and opaque instances.
7986 tried_332 = MagickFalse;
7987 tried_333 = MagickFalse;
7988 tried_444 = MagickFalse;
7994 * Sometimes we get DirectClass images that have 256 colors or fewer.
7995 * This code will build a colormap.
7997 * Also, sometimes we get PseudoClass images with an out-of-date
7998 * colormap. This code will replace the colormap with a new one.
7999 * Sometimes we get PseudoClass images that have more than 256 colors.
8000 * This code will delete the colormap and change the image to
8003 * If image->matte is MagickFalse, we ignore the alpha channel
8004 * even though it sometimes contains left-over non-opaque values.
8006 * Also we gather some information (number of opaque, transparent,
8007 * and semitransparent pixels, and whether the image has any non-gray
8008 * pixels or only black-and-white pixels) that we might need later.
8010 * Even if the user wants to force GrayAlpha or RGBA (colortype 4 or 6)
8011 * we need to check for bogus non-opaque values, at least.
8019 semitransparent[260],
8022 register const Quantum
8029 if (logging != MagickFalse)
8030 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8031 " Enter BUILD_PALETTE:");
8033 if (logging != MagickFalse)
8035 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8036 " image->columns=%.20g",(double) image->columns);
8037 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8038 " image->rows=%.20g",(double) image->rows);
8039 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8040 " image->matte=%.20g",(double) image->matte);
8041 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8042 " image->depth=%.20g",(double) image->depth);
8044 if (image->storage_class == PseudoClass && image->colormap != NULL)
8046 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8047 " Original colormap:");
8048 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8049 " i (red,green,blue,alpha)");
8051 for (i=0; i < 256; i++)
8053 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8054 " %d (%d,%d,%d,%d)",
8056 (int) image->colormap[i].red,
8057 (int) image->colormap[i].green,
8058 (int) image->colormap[i].blue,
8059 (int) image->colormap[i].alpha);
8062 for (i=image->colors - 10; i < (ssize_t) image->colors; i++)
8066 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8067 " %d (%d,%d,%d,%d)",
8069 (int) image->colormap[i].red,
8070 (int) image->colormap[i].green,
8071 (int) image->colormap[i].blue,
8072 (int) image->colormap[i].alpha);
8077 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8078 " image->colors=%d",(int) image->colors);
8080 if (image->colors == 0)
8081 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8082 " (zero means unknown)");
8084 if (ping_preserve_colormap == MagickFalse)
8085 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8086 " Regenerate the colormap");
8091 number_semitransparent = 0;
8092 number_transparent = 0;
8094 for (y=0; y < (ssize_t) image->rows; y++)
8096 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8098 if (q == (Quantum *) NULL)
8101 for (x=0; x < (ssize_t) image->columns; x++)
8103 if (image->matte == MagickFalse ||
8104 GetPixelAlpha(image,q) == OpaqueAlpha)
8106 if (number_opaque < 259)
8108 if (number_opaque == 0)
8110 GetPixelInfoPixel(image, q, opaque);
8111 opaque[0].alpha=OpaqueAlpha;
8115 for (i=0; i< (ssize_t) number_opaque; i++)
8117 if (IsPixelEquivalent(image,q, opaque+i))
8121 if (i == (ssize_t) number_opaque && number_opaque < 259)
8124 GetPixelInfoPixel(image, q, opaque+i);
8125 opaque[i].alpha=OpaqueAlpha;
8129 else if (GetPixelAlpha(image,q) == TransparentAlpha)
8131 if (number_transparent < 259)
8133 if (number_transparent == 0)
8135 GetPixelInfoPixel(image, q, transparent);
8136 ping_trans_color.red=(unsigned short)
8137 GetPixelRed(image,q);
8138 ping_trans_color.green=(unsigned short)
8139 GetPixelGreen(image,q);
8140 ping_trans_color.blue=(unsigned short)
8141 GetPixelBlue(image,q);
8142 ping_trans_color.gray=(unsigned short)
8143 GetPixelRed(image,q);
8144 number_transparent = 1;
8147 for (i=0; i< (ssize_t) number_transparent; i++)
8149 if (IsPixelEquivalent(image,q, transparent+i))
8153 if (i == (ssize_t) number_transparent &&
8154 number_transparent < 259)
8156 number_transparent++;
8157 GetPixelInfoPixel(image,q,transparent+i);
8163 if (number_semitransparent < 259)
8165 if (number_semitransparent == 0)
8167 GetPixelInfoPixel(image,q,semitransparent);
8168 number_semitransparent = 1;
8171 for (i=0; i< (ssize_t) number_semitransparent; i++)
8173 if (IsPixelEquivalent(image,q, semitransparent+i)
8174 && GetPixelAlpha(image,q) ==
8175 semitransparent[i].alpha)
8179 if (i == (ssize_t) number_semitransparent &&
8180 number_semitransparent < 259)
8182 number_semitransparent++;
8183 GetPixelInfoPixel(image, q, semitransparent+i);
8187 q+=GetPixelChannels(image);
8191 if (mng_info->write_png8 == MagickFalse &&
8192 ping_exclude_bKGD == MagickFalse)
8194 /* Add the background color to the palette, if it
8195 * isn't already there.
8197 if (logging != MagickFalse)
8199 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8200 " Check colormap for background (%d,%d,%d)",
8201 (int) image->background_color.red,
8202 (int) image->background_color.green,
8203 (int) image->background_color.blue);
8205 for (i=0; i<number_opaque; i++)
8207 if (opaque[i].red == image->background_color.red &&
8208 opaque[i].green == image->background_color.green &&
8209 opaque[i].blue == image->background_color.blue)
8212 if (number_opaque < 259 && i == number_opaque)
8214 opaque[i] = image->background_color;
8215 ping_background.index = i;
8216 if (logging != MagickFalse)
8218 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8219 " background_color index is %d",(int) i);
8223 else if (logging != MagickFalse)
8224 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8225 " No room in the colormap to add background color");
8228 image_colors=number_opaque+number_transparent+number_semitransparent;
8230 if (mng_info->write_png8 != MagickFalse && image_colors > 256)
8232 /* No room for the background color; remove it. */
8237 if (logging != MagickFalse)
8239 if (image_colors > 256)
8240 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8241 " image has more than 256 colors");
8244 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8245 " image has %d colors",image_colors);
8248 if (ping_preserve_colormap != MagickFalse)
8251 if (mng_info->write_png_colortype != 7) /* We won't need this info */
8253 ping_have_color=MagickFalse;
8254 ping_have_non_bw=MagickFalse;
8256 if(image_colors > 256)
8258 for (y=0; y < (ssize_t) image->rows; y++)
8260 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8262 if (q == (Quantum *) NULL)
8266 for (x=0; x < (ssize_t) image->columns; x++)
8268 if (GetPixelRed(image,s) != GetPixelGreen(image,s) ||
8269 GetPixelRed(image,s) != GetPixelBlue(image,s))
8271 ping_have_color=MagickTrue;
8272 ping_have_non_bw=MagickTrue;
8275 s+=GetPixelChannels(image);
8278 if (ping_have_color != MagickFalse)
8281 /* Worst case is black-and-white; we are looking at every
8285 if (ping_have_non_bw == MagickFalse)
8288 for (x=0; x < (ssize_t) image->columns; x++)
8290 if (GetPixelRed(image,s) != 0 &&
8291 GetPixelRed(image,s) != QuantumRange)
8293 ping_have_non_bw=MagickTrue;
8296 s+=GetPixelChannels(image);
8303 if (image_colors < 257)
8309 * Initialize image colormap.
8312 if (logging != MagickFalse)
8313 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8314 " Sort the new colormap");
8316 /* Sort palette, transparent first */;
8320 for (i=0; i<number_transparent; i++)
8321 colormap[n++] = transparent[i];
8323 for (i=0; i<number_semitransparent; i++)
8324 colormap[n++] = semitransparent[i];
8326 for (i=0; i<number_opaque; i++)
8327 colormap[n++] = opaque[i];
8329 ping_background.index +=
8330 (number_transparent + number_semitransparent);
8332 /* image_colors < 257; search the colormap instead of the pixels
8333 * to get ping_have_color and ping_have_non_bw
8337 if (ping_have_color == MagickFalse)
8339 if (colormap[i].red != colormap[i].green ||
8340 colormap[i].red != colormap[i].blue)
8342 ping_have_color=MagickTrue;
8343 ping_have_non_bw=MagickTrue;
8348 if (ping_have_non_bw == MagickFalse)
8350 if (colormap[i].red != 0 && colormap[i].red != QuantumRange)
8351 ping_have_non_bw=MagickTrue;
8355 if ((mng_info->ping_exclude_tRNS == MagickFalse ||
8356 (number_transparent == 0 && number_semitransparent == 0)) &&
8357 (((mng_info->write_png_colortype-1) ==
8358 PNG_COLOR_TYPE_PALETTE) ||
8359 (mng_info->write_png_colortype == 0)))
8361 if (logging != MagickFalse)
8363 if (n != (ssize_t) image_colors)
8364 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8365 " image_colors (%d) and n (%d) don't match",
8368 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8369 " AcquireImageColormap");
8372 image->colors = image_colors;
8374 if (AcquireImageColormap(image,image_colors,exception) ==
8376 ThrowWriterException(ResourceLimitError,
8377 "MemoryAllocationFailed");
8379 for (i=0; i< (ssize_t) image_colors; i++)
8380 image->colormap[i] = colormap[i];
8382 if (logging != MagickFalse)
8384 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8385 " image->colors=%d (%d)",
8386 (int) image->colors, image_colors);
8388 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8389 " Update the pixel indexes");
8392 /* Sync the pixel indices with the new colormap */
8394 for (y=0; y < (ssize_t) image->rows; y++)
8396 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8398 if (q == (Quantum *) NULL)
8401 for (x=0; x < (ssize_t) image->columns; x++)
8403 for (i=0; i< (ssize_t) image_colors; i++)
8405 if ((image->matte == MagickFalse ||
8406 image->colormap[i].alpha == GetPixelAlpha(image,q)) &&
8407 image->colormap[i].red == GetPixelRed(image,q) &&
8408 image->colormap[i].green == GetPixelGreen(image,q) &&
8409 image->colormap[i].blue == GetPixelBlue(image,q))
8411 SetPixelIndex(image,i,q);
8415 q+=GetPixelChannels(image);
8418 if (SyncAuthenticPixels(image,exception) == MagickFalse)
8424 if (logging != MagickFalse)
8426 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8427 " image->colors=%d", (int) image->colors);
8429 if (image->colormap != NULL)
8431 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8432 " i (red,green,blue,alpha)");
8434 for (i=0; i < (ssize_t) image->colors; i++)
8436 if (i < 300 || i >= (ssize_t) image->colors - 10)
8438 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8439 " %d (%d,%d,%d,%d)",
8441 (int) image->colormap[i].red,
8442 (int) image->colormap[i].green,
8443 (int) image->colormap[i].blue,
8444 (int) image->colormap[i].alpha);
8449 if (number_transparent < 257)
8450 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8451 " number_transparent = %d",
8452 number_transparent);
8455 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8456 " number_transparent > 256");
8458 if (number_opaque < 257)
8459 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8460 " number_opaque = %d",
8464 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8465 " number_opaque > 256");
8467 if (number_semitransparent < 257)
8468 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8469 " number_semitransparent = %d",
8470 number_semitransparent);
8473 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8474 " number_semitransparent > 256");
8476 if (ping_have_non_bw == MagickFalse)
8477 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8478 " All pixels and the background are black or white");
8480 else if (ping_have_color == MagickFalse)
8481 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8482 " All pixels and the background are gray");
8485 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8486 " At least one pixel or the background is non-gray");
8488 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8489 " Exit BUILD_PALETTE:");
8492 if (mng_info->write_png8 == MagickFalse)
8495 /* Make any reductions necessary for the PNG8 format */
8496 if (image_colors <= 256 &&
8497 image_colors != 0 && image->colormap != NULL &&
8498 number_semitransparent == 0 &&
8499 number_transparent <= 1)
8502 /* PNG8 can't have semitransparent colors so we threshold the
8503 * opacity to 0 or OpaqueOpacity, and PNG8 can only have one
8504 * transparent color so if more than one is transparent we merge
8505 * them into image->background_color.
8507 if (number_semitransparent != 0 || number_transparent > 1)
8509 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8510 " Thresholding the alpha channel to binary");
8512 for (y=0; y < (ssize_t) image->rows; y++)
8514 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8516 if (r == (Quantum *) NULL)
8519 for (x=0; x < (ssize_t) image->columns; x++)
8521 if (GetPixelAlpha(image,r) < OpaqueAlpha/2)
8523 SetPixelInfoPixel(image,&image->background_color,r);
8524 SetPixelAlpha(image,TransparentAlpha,r);
8527 SetPixelAlpha(image,OpaqueAlpha,r);
8528 r+=GetPixelChannels(image);
8531 if (SyncAuthenticPixels(image,exception) == MagickFalse)
8534 if (image_colors != 0 && image_colors <= 256 &&
8535 image->colormap != NULL)
8536 for (i=0; i<image_colors; i++)
8537 image->colormap[i].alpha =
8538 (image->colormap[i].alpha > TransparentAlpha/2 ?
8539 TransparentAlpha : OpaqueAlpha);
8544 /* PNG8 can't have more than 256 colors so we quantize the pixels and
8545 * background color to the 4-4-4-1, 3-3-3-1 or 3-3-2-1 palette. If the
8546 * image is mostly gray, the 4-4-4-1 palette is likely to end up with 256
8549 if (tried_444 == MagickFalse && (image_colors == 0 || image_colors > 256))
8551 if (logging != MagickFalse)
8552 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8553 " Quantizing the background color to 4-4-4");
8555 tried_444 = MagickTrue;
8557 LBR04PacketRGB(image->background_color);
8559 if (logging != MagickFalse)
8560 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8561 " Quantizing the pixel colors to 4-4-4");
8563 if (image->colormap == NULL)
8565 for (y=0; y < (ssize_t) image->rows; y++)
8567 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8569 if (r == (Quantum *) NULL)
8572 for (x=0; x < (ssize_t) image->columns; x++)
8574 if (GetPixelAlpha(image,r) == OpaqueAlpha)
8576 r+=GetPixelChannels(image);
8579 if (SyncAuthenticPixels(image,exception) == MagickFalse)
8584 else /* Should not reach this; colormap already exists and
8587 if (logging != MagickFalse)
8588 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8589 " Quantizing the colormap to 4-4-4");
8591 for (i=0; i<image_colors; i++)
8593 LBR04PacketRGB(image->colormap[i]);
8599 if (tried_333 == MagickFalse && (image_colors == 0 || image_colors > 256))
8601 if (logging != MagickFalse)
8602 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8603 " Quantizing the background color to 3-3-3");
8605 tried_333 = MagickTrue;
8607 LBR03PacketRGB(image->background_color);
8609 if (logging != MagickFalse)
8610 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8611 " Quantizing the pixel colors to 3-3-3-1");
8613 if (image->colormap == NULL)
8615 for (y=0; y < (ssize_t) image->rows; y++)
8617 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8619 if (r == (Quantum *) NULL)
8622 for (x=0; x < (ssize_t) image->columns; x++)
8624 if (GetPixelAlpha(image,r) == OpaqueAlpha)
8626 r+=GetPixelChannels(image);
8629 if (SyncAuthenticPixels(image,exception) == MagickFalse)
8634 else /* Should not reach this; colormap already exists and
8637 if (logging != MagickFalse)
8638 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8639 " Quantizing the colormap to 3-3-3-1");
8640 for (i=0; i<image_colors; i++)
8642 LBR03PacketRGB(image->colormap[i]);
8648 if (tried_332 == MagickFalse && (image_colors == 0 || image_colors > 256))
8650 if (logging != MagickFalse)
8651 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8652 " Quantizing the background color to 3-3-2");
8654 tried_332 = MagickTrue;
8656 /* Red and green were already done so we only quantize the blue
8660 LBR02PacketBlue(image->background_color);
8662 if (logging != MagickFalse)
8663 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8664 " Quantizing the pixel colors to 3-3-2-1");
8666 if (image->colormap == NULL)
8668 for (y=0; y < (ssize_t) image->rows; y++)
8670 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8672 if (r == (Quantum *) NULL)
8675 for (x=0; x < (ssize_t) image->columns; x++)
8677 if (GetPixelAlpha(image,r) == OpaqueAlpha)
8679 r+=GetPixelChannels(image);
8682 if (SyncAuthenticPixels(image,exception) == MagickFalse)
8687 else /* Should not reach this; colormap already exists and
8690 if (logging != MagickFalse)
8691 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8692 " Quantizing the colormap to 3-3-2-1");
8693 for (i=0; i<image_colors; i++)
8695 LBR02PacketBlue(image->colormap[i]);
8702 if (image_colors == 0 || image_colors > 256)
8704 /* Take care of special case with 256 colors + 1 transparent
8705 * color. We don't need to quantize to 2-3-2-1; we only need to
8706 * eliminate one color, so we'll merge the two darkest red
8707 * colors (0x49, 0, 0) -> (0x24, 0, 0).
8709 if (ScaleQuantumToChar(image->background_color.red) == 0x49 &&
8710 ScaleQuantumToChar(image->background_color.green) == 0x00 &&
8711 ScaleQuantumToChar(image->background_color.blue) == 0x00)
8713 image->background_color.red=ScaleCharToQuantum(0x24);
8716 if (image->colormap == NULL)
8718 for (y=0; y < (ssize_t) image->rows; y++)
8720 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8722 if (r == (Quantum *) NULL)
8725 for (x=0; x < (ssize_t) image->columns; x++)
8727 if (ScaleQuantumToChar(GetPixelRed(image,r)) == 0x49 &&
8728 ScaleQuantumToChar(GetPixelGreen(image,r)) == 0x00 &&
8729 ScaleQuantumToChar(GetPixelBlue(image,r)) == 0x00 &&
8730 GetPixelAlpha(image,r) == OpaqueAlpha)
8732 SetPixelRed(image,ScaleCharToQuantum(0x24),r);
8734 r+=GetPixelChannels(image);
8737 if (SyncAuthenticPixels(image,exception) == MagickFalse)
8745 for (i=0; i<image_colors; i++)
8747 if (ScaleQuantumToChar(image->colormap[i].red) == 0x49 &&
8748 ScaleQuantumToChar(image->colormap[i].green) == 0x00 &&
8749 ScaleQuantumToChar(image->colormap[i].blue) == 0x00)
8751 image->colormap[i].red=ScaleCharToQuantum(0x24);
8757 /* END OF BUILD_PALETTE */
8759 /* If we are excluding the tRNS chunk and there is transparency,
8760 * then we must write a Gray-Alpha (color-type 4) or RGBA (color-type 6)
8763 if (mng_info->ping_exclude_tRNS != MagickFalse &&
8764 (number_transparent != 0 || number_semitransparent != 0))
8766 unsigned int colortype=mng_info->write_png_colortype;
8768 if (ping_have_color == MagickFalse)
8769 mng_info->write_png_colortype = 5;
8772 mng_info->write_png_colortype = 7;
8774 if (colortype != 0 &&
8775 mng_info->write_png_colortype != colortype)
8776 ping_need_colortype_warning=MagickTrue;
8780 /* See if cheap transparency is possible. It is only possible
8781 * when there is a single transparent color, no semitransparent
8782 * color, and no opaque color that has the same RGB components
8783 * as the transparent color. We only need this information if
8784 * we are writing a PNG with colortype 0 or 2, and we have not
8785 * excluded the tRNS chunk.
8787 if (number_transparent == 1 &&
8788 mng_info->write_png_colortype < 4)
8790 ping_have_cheap_transparency = MagickTrue;
8792 if (number_semitransparent != 0)
8793 ping_have_cheap_transparency = MagickFalse;
8795 else if (image_colors == 0 || image_colors > 256 ||
8796 image->colormap == NULL)
8798 register const Quantum
8801 for (y=0; y < (ssize_t) image->rows; y++)
8803 q=GetVirtualPixels(image,0,y,image->columns,1, exception);
8805 if (q == (Quantum *) NULL)
8808 for (x=0; x < (ssize_t) image->columns; x++)
8810 if (GetPixelAlpha(image,q) != TransparentAlpha &&
8811 (unsigned short) GetPixelRed(image,q) ==
8812 ping_trans_color.red &&
8813 (unsigned short) GetPixelGreen(image,q) ==
8814 ping_trans_color.green &&
8815 (unsigned short) GetPixelBlue(image,q) ==
8816 ping_trans_color.blue)
8818 ping_have_cheap_transparency = MagickFalse;
8822 q+=GetPixelChannels(image);
8825 if (ping_have_cheap_transparency == MagickFalse)
8831 /* Assuming that image->colormap[0] is the one transparent color
8832 * and that all others are opaque.
8834 if (image_colors > 1)
8835 for (i=1; i<image_colors; i++)
8836 if (image->colormap[i].red == image->colormap[0].red &&
8837 image->colormap[i].green == image->colormap[0].green &&
8838 image->colormap[i].blue == image->colormap[0].blue)
8840 ping_have_cheap_transparency = MagickFalse;
8845 if (logging != MagickFalse)
8847 if (ping_have_cheap_transparency == MagickFalse)
8848 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8849 " Cheap transparency is not possible.");
8852 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8853 " Cheap transparency is possible.");
8857 ping_have_cheap_transparency = MagickFalse;
8859 image_depth=image->depth;
8861 quantum_info = (QuantumInfo *) NULL;
8863 image_colors=(int) image->colors;
8864 image_matte=image->matte;
8866 mng_info->IsPalette=image->storage_class == PseudoClass &&
8867 image_colors <= 256 && image->colormap != NULL;
8869 if ((mng_info->write_png_colortype == 4 || mng_info->write_png8) &&
8870 (image->colors == 0 || image->colormap == NULL))
8872 image_info=DestroyImageInfo(image_info);
8873 image=DestroyImage(image);
8874 (void) ThrowMagickException(exception,GetMagickModule(),CoderError,
8875 "Cannot write PNG8 or color-type 3; colormap is NULL",
8876 "`%s'",IMimage->filename);
8877 return(MagickFalse);
8881 Allocate the PNG structures
8883 #ifdef PNG_USER_MEM_SUPPORTED
8884 error_info.image=image;
8885 error_info.exception=exception;
8886 ping=png_create_write_struct_2(PNG_LIBPNG_VER_STRING,&error_info,
8887 MagickPNGErrorHandler,MagickPNGWarningHandler,(void *) NULL,
8888 (png_malloc_ptr) Magick_png_malloc,(png_free_ptr) Magick_png_free);
8891 ping=png_create_write_struct(PNG_LIBPNG_VER_STRING,&error_info,
8892 MagickPNGErrorHandler,MagickPNGWarningHandler);
8895 if (ping == (png_struct *) NULL)
8896 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
8898 ping_info=png_create_info_struct(ping);
8900 if (ping_info == (png_info *) NULL)
8902 png_destroy_write_struct(&ping,(png_info **) NULL);
8903 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
8906 png_set_write_fn(ping,image,png_put_data,png_flush_data);
8907 ping_pixels=(unsigned char *) NULL;
8909 if (setjmp(png_jmpbuf(ping)))
8915 if (image_info->verbose)
8916 (void) printf("PNG write has failed.\n");
8918 png_destroy_write_struct(&ping,&ping_info);
8919 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
8920 UnlockSemaphoreInfo(ping_semaphore);
8923 if (ping_pixels != (unsigned char *) NULL)
8924 ping_pixels=(unsigned char *) RelinquishMagickMemory(ping_pixels);
8926 if (quantum_info != (QuantumInfo *) NULL)
8927 quantum_info=DestroyQuantumInfo(quantum_info);
8929 if (ping_have_blob != MagickFalse)
8930 (void) CloseBlob(image);
8931 image_info=DestroyImageInfo(image_info);
8932 image=DestroyImage(image);
8933 return(MagickFalse);
8936 /* { For navigation to end of SETJMP-protected block. Within this
8937 * block, use png_error() instead of Throwing an Exception, to ensure
8938 * that libpng is able to clean up, and that the semaphore is unlocked.
8941 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
8942 LockSemaphoreInfo(ping_semaphore);
8946 Prepare PNG for writing.
8948 #if defined(PNG_MNG_FEATURES_SUPPORTED)
8949 if (mng_info->write_mng)
8950 (void) png_permit_mng_features(ping,PNG_ALL_MNG_FEATURES);
8953 # ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
8954 if (mng_info->write_mng)
8955 png_permit_empty_plte(ping,MagickTrue);
8962 ping_width=(png_uint_32) image->columns;
8963 ping_height=(png_uint_32) image->rows;
8965 if (mng_info->write_png8 || mng_info->write_png24 || mng_info->write_png32)
8968 if (mng_info->write_png_depth != 0)
8969 image_depth=mng_info->write_png_depth;
8971 /* Adjust requested depth to next higher valid depth if necessary */
8972 if (image_depth > 8)
8975 if ((image_depth > 4) && (image_depth < 8))
8978 if (image_depth == 3)
8981 if (logging != MagickFalse)
8983 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8984 " width=%.20g",(double) ping_width);
8985 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8986 " height=%.20g",(double) ping_height);
8987 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8988 " image_matte=%.20g",(double) image->matte);
8989 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8990 " image->depth=%.20g",(double) image->depth);
8991 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8992 " Tentative ping_bit_depth=%.20g",(double) image_depth);
8995 save_image_depth=image_depth;
8996 ping_bit_depth=(png_byte) save_image_depth;
8999 #if defined(PNG_pHYs_SUPPORTED)
9000 if (ping_exclude_pHYs == MagickFalse)
9002 if ((image->resolution.x != 0) && (image->resolution.y != 0) &&
9003 (!mng_info->write_mng || !mng_info->equal_physs))
9005 if (logging != MagickFalse)
9006 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9007 " Setting up pHYs chunk");
9009 if (image->units == PixelsPerInchResolution)
9011 ping_pHYs_unit_type=PNG_RESOLUTION_METER;
9012 ping_pHYs_x_resolution=
9013 (png_uint_32) ((100.0*image->resolution.x+0.5)/2.54);
9014 ping_pHYs_y_resolution=
9015 (png_uint_32) ((100.0*image->resolution.y+0.5)/2.54);
9018 else if (image->units == PixelsPerCentimeterResolution)
9020 ping_pHYs_unit_type=PNG_RESOLUTION_METER;
9021 ping_pHYs_x_resolution=(png_uint_32) (100.0*image->resolution.x+0.5);
9022 ping_pHYs_y_resolution=(png_uint_32) (100.0*image->resolution.y+0.5);
9027 ping_pHYs_unit_type=PNG_RESOLUTION_UNKNOWN;
9028 ping_pHYs_x_resolution=(png_uint_32) image->resolution.x;
9029 ping_pHYs_y_resolution=(png_uint_32) image->resolution.y;
9032 if (logging != MagickFalse)
9033 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9034 " Set up PNG pHYs chunk: xres: %.20g, yres: %.20g, units: %d.",
9035 (double) ping_pHYs_x_resolution,(double) ping_pHYs_y_resolution,
9036 (int) ping_pHYs_unit_type);
9037 ping_have_pHYs = MagickTrue;
9042 if (ping_exclude_bKGD == MagickFalse)
9044 if ((!mng_info->adjoin || !mng_info->equal_backgrounds))
9050 if (ping_bit_depth == 8)
9053 if (ping_bit_depth == 4)
9056 if (ping_bit_depth == 2)
9059 if (ping_bit_depth == 1)
9062 ping_background.red=(png_uint_16)
9063 (ScaleQuantumToShort(image->background_color.red) & mask);
9065 ping_background.green=(png_uint_16)
9066 (ScaleQuantumToShort(image->background_color.green) & mask);
9068 ping_background.blue=(png_uint_16)
9069 (ScaleQuantumToShort(image->background_color.blue) & mask);
9071 ping_background.gray=(png_uint_16) ping_background.green;
9074 if (logging != MagickFalse)
9076 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9077 " Setting up bKGD chunk (1)");
9078 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9079 " background_color index is %d",
9080 (int) ping_background.index);
9082 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9083 " ping_bit_depth=%d",ping_bit_depth);
9086 ping_have_bKGD = MagickTrue;
9090 Select the color type.
9095 if (mng_info->IsPalette && mng_info->write_png8)
9098 /* To do: make this a function cause it's used twice, except
9099 for reducing the sample depth from 8. */
9101 number_colors=image_colors;
9103 ping_have_tRNS=MagickFalse;
9108 ping_color_type=(png_byte) PNG_COLOR_TYPE_PALETTE;
9110 if (logging != MagickFalse)
9111 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9112 " Setting up PLTE chunk with %d colors (%d)",
9113 number_colors, image_colors);
9115 for (i=0; i < (ssize_t) number_colors; i++)
9117 palette[i].red=ScaleQuantumToChar(image->colormap[i].red);
9118 palette[i].green=ScaleQuantumToChar(image->colormap[i].green);
9119 palette[i].blue=ScaleQuantumToChar(image->colormap[i].blue);
9120 if (logging != MagickFalse)
9121 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9122 #if MAGICKCORE_QUANTUM_DEPTH == 8
9123 " %3ld (%3d,%3d,%3d)",
9125 " %5ld (%5d,%5d,%5d)",
9127 (long) i,palette[i].red,palette[i].green,palette[i].blue);
9131 ping_have_PLTE=MagickTrue;
9132 image_depth=ping_bit_depth;
9135 if (matte != MagickFalse)
9138 Identify which colormap entry is transparent.
9140 assert(number_colors <= 256);
9141 assert(image->colormap != NULL);
9143 for (i=0; i < (ssize_t) number_transparent; i++)
9144 ping_trans_alpha[i]=0;
9147 ping_num_trans=(unsigned short) (number_transparent +
9148 number_semitransparent);
9150 if (ping_num_trans == 0)
9151 ping_have_tRNS=MagickFalse;
9154 ping_have_tRNS=MagickTrue;
9157 if (ping_exclude_bKGD == MagickFalse)
9160 * Identify which colormap entry is the background color.
9163 for (i=0; i < (ssize_t) MagickMax(1L*number_colors-1L,1L); i++)
9164 if (IsPNGColorEqual(ping_background,image->colormap[i]))
9167 ping_background.index=(png_byte) i;
9169 if (logging != MagickFalse)
9171 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9172 " background_color index is %d",
9173 (int) ping_background.index);
9176 } /* end of write_png8 */
9178 else if (mng_info->write_png24 || mng_info->write_png_colortype == 3)
9180 image_matte=MagickFalse;
9181 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB;
9184 else if (mng_info->write_png32 || mng_info->write_png_colortype == 7)
9186 image_matte=MagickTrue;
9187 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB_ALPHA;
9190 else /* mng_info->write_pngNN not specified */
9192 image_depth=ping_bit_depth;
9194 if (mng_info->write_png_colortype != 0)
9196 ping_color_type=(png_byte) mng_info->write_png_colortype-1;
9198 if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA ||
9199 ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA)
9200 image_matte=MagickTrue;
9203 image_matte=MagickFalse;
9205 if (logging != MagickFalse)
9206 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9207 " PNG colortype %d was specified:",(int) ping_color_type);
9210 else /* write_png_colortype not specified */
9212 if (logging != MagickFalse)
9213 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9214 " Selecting PNG colortype:");
9216 ping_color_type=(png_byte) ((matte != MagickFalse)?
9217 PNG_COLOR_TYPE_RGB_ALPHA:PNG_COLOR_TYPE_RGB);
9219 if (image_info->type == TrueColorType)
9221 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB;
9222 image_matte=MagickFalse;
9225 if (image_info->type == TrueColorMatteType)
9227 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB_ALPHA;
9228 image_matte=MagickTrue;
9231 if (image_info->type == PaletteType ||
9232 image_info->type == PaletteMatteType)
9233 ping_color_type=(png_byte) PNG_COLOR_TYPE_PALETTE;
9235 if (mng_info->write_png_colortype == 0 &&
9236 (image_info->type == UndefinedType ||
9237 image_info->type == OptimizeType))
9239 if (ping_have_color == MagickFalse)
9241 if (image_matte == MagickFalse)
9243 ping_color_type=(png_byte) PNG_COLOR_TYPE_GRAY;
9244 image_matte=MagickFalse;
9249 ping_color_type=(png_byte) PNG_COLOR_TYPE_GRAY_ALPHA;
9250 image_matte=MagickTrue;
9255 if (image_matte == MagickFalse)
9257 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB;
9258 image_matte=MagickFalse;
9263 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGBA;
9264 image_matte=MagickTrue;
9271 if (logging != MagickFalse)
9272 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9273 " Selected PNG colortype=%d",ping_color_type);
9275 if (ping_bit_depth < 8)
9277 if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA ||
9278 ping_color_type == PNG_COLOR_TYPE_RGB ||
9279 ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA)
9283 old_bit_depth=ping_bit_depth;
9285 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
9287 if (image->matte == MagickFalse && ping_have_non_bw == MagickFalse)
9291 if (ping_color_type == PNG_COLOR_TYPE_PALETTE)
9296 if (image->colors == 0)
9299 png_error(ping,"image has 0 colors");
9302 while ((int) (one << ping_bit_depth) < (ssize_t) image_colors)
9303 ping_bit_depth <<= 1;
9306 if (logging != MagickFalse)
9308 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9309 " Number of colors: %.20g",(double) image_colors);
9311 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9312 " Tentative PNG bit depth: %d",ping_bit_depth);
9315 if (ping_bit_depth < (int) mng_info->write_png_depth)
9316 ping_bit_depth = mng_info->write_png_depth;
9319 image_depth=ping_bit_depth;
9321 if (logging != MagickFalse)
9323 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9324 " Tentative PNG color type: %s (%.20g)",
9325 PngColorTypeToString(ping_color_type),
9326 (double) ping_color_type);
9328 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9329 " image_info->type: %.20g",(double) image_info->type);
9331 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9332 " image_depth: %.20g",(double) image_depth);
9334 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9336 " image->depth: %.20g",(double) image->depth);
9338 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9339 " ping_bit_depth: %.20g",(double) ping_bit_depth);
9342 if (matte != MagickFalse)
9344 if (mng_info->IsPalette)
9346 if (mng_info->write_png_colortype == 0)
9348 ping_color_type=PNG_COLOR_TYPE_GRAY_ALPHA;
9350 if (ping_have_color != MagickFalse)
9351 ping_color_type=PNG_COLOR_TYPE_RGBA;
9355 * Determine if there is any transparent color.
9357 if (number_transparent + number_semitransparent == 0)
9360 No transparent pixels are present. Change 4 or 6 to 0 or 2.
9363 image_matte=MagickFalse;
9365 if (mng_info->write_png_colortype == 0)
9366 ping_color_type&=0x03;
9376 if (ping_bit_depth == 8)
9379 if (ping_bit_depth == 4)
9382 if (ping_bit_depth == 2)
9385 if (ping_bit_depth == 1)
9388 ping_trans_color.red=(png_uint_16)
9389 (ScaleQuantumToShort(image->colormap[0].red) & mask);
9391 ping_trans_color.green=(png_uint_16)
9392 (ScaleQuantumToShort(image->colormap[0].green) & mask);
9394 ping_trans_color.blue=(png_uint_16)
9395 (ScaleQuantumToShort(image->colormap[0].blue) & mask);
9397 ping_trans_color.gray=(png_uint_16)
9398 (ScaleQuantumToShort(GetPixelInfoIntensity(
9399 image->colormap)) & mask);
9401 ping_trans_color.index=(png_byte) 0;
9403 ping_have_tRNS=MagickTrue;
9406 if (ping_have_tRNS != MagickFalse)
9409 * Determine if there is one and only one transparent color
9410 * and if so if it is fully transparent.
9412 if (ping_have_cheap_transparency == MagickFalse)
9413 ping_have_tRNS=MagickFalse;
9416 if (ping_have_tRNS != MagickFalse)
9418 if (mng_info->write_png_colortype == 0)
9419 ping_color_type &= 0x03; /* changes 4 or 6 to 0 or 2 */
9421 if (image_depth == 8)
9423 ping_trans_color.red&=0xff;
9424 ping_trans_color.green&=0xff;
9425 ping_trans_color.blue&=0xff;
9426 ping_trans_color.gray&=0xff;
9432 if (image_depth == 8)
9434 ping_trans_color.red&=0xff;
9435 ping_trans_color.green&=0xff;
9436 ping_trans_color.blue&=0xff;
9437 ping_trans_color.gray&=0xff;
9444 if (ping_have_tRNS != MagickFalse)
9445 image_matte=MagickFalse;
9447 if ((mng_info->IsPalette) &&
9448 mng_info->write_png_colortype-1 != PNG_COLOR_TYPE_PALETTE &&
9449 ping_have_color == MagickFalse &&
9450 (image_matte == MagickFalse || image_depth >= 8))
9454 if (image_matte != MagickFalse)
9455 ping_color_type=PNG_COLOR_TYPE_GRAY_ALPHA;
9457 else if (mng_info->write_png_colortype-1 != PNG_COLOR_TYPE_GRAY_ALPHA)
9459 ping_color_type=PNG_COLOR_TYPE_GRAY;
9461 if (save_image_depth == 16 && image_depth == 8)
9463 if (logging != MagickFalse)
9465 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9466 " Scaling ping_trans_color (0)");
9468 ping_trans_color.gray*=0x0101;
9472 if (image_depth > MAGICKCORE_QUANTUM_DEPTH)
9473 image_depth=MAGICKCORE_QUANTUM_DEPTH;
9475 if ((image_colors == 0) ||
9476 ((ssize_t) (image_colors-1) > (ssize_t) MaxColormapSize))
9477 image_colors=(int) (one << image_depth);
9479 if (image_depth > 8)
9485 if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
9487 if(!mng_info->write_png_depth)
9491 while ((int) (one << ping_bit_depth)
9492 < (ssize_t) image_colors)
9493 ping_bit_depth <<= 1;
9497 else if (ping_color_type ==
9498 PNG_COLOR_TYPE_GRAY && image_colors < 17 &&
9499 mng_info->IsPalette)
9501 /* Check if grayscale is reducible */
9504 depth_4_ok=MagickTrue,
9505 depth_2_ok=MagickTrue,
9506 depth_1_ok=MagickTrue;
9508 for (i=0; i < (ssize_t) image_colors; i++)
9513 intensity=ScaleQuantumToChar(image->colormap[i].red);
9515 if ((intensity & 0x0f) != ((intensity & 0xf0) >> 4))
9516 depth_4_ok=depth_2_ok=depth_1_ok=MagickFalse;
9517 else if ((intensity & 0x03) != ((intensity & 0x0c) >> 2))
9518 depth_2_ok=depth_1_ok=MagickFalse;
9519 else if ((intensity & 0x01) != ((intensity & 0x02) >> 1))
9520 depth_1_ok=MagickFalse;
9523 if (depth_1_ok && mng_info->write_png_depth <= 1)
9526 else if (depth_2_ok && mng_info->write_png_depth <= 2)
9529 else if (depth_4_ok && mng_info->write_png_depth <= 4)
9534 image_depth=ping_bit_depth;
9539 if (mng_info->IsPalette)
9541 number_colors=image_colors;
9543 if (image_depth <= 8)
9548 ping_color_type=(png_byte) PNG_COLOR_TYPE_PALETTE;
9550 if (mng_info->have_write_global_plte && matte == MagickFalse)
9552 png_set_PLTE(ping,ping_info,NULL,0);
9554 if (logging != MagickFalse)
9555 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9556 " Setting up empty PLTE chunk");
9561 for (i=0; i < (ssize_t) number_colors; i++)
9563 palette[i].red=ScaleQuantumToChar(image->colormap[i].red);
9564 palette[i].green=ScaleQuantumToChar(image->colormap[i].green);
9565 palette[i].blue=ScaleQuantumToChar(image->colormap[i].blue);
9568 if (logging != MagickFalse)
9569 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9570 " Setting up PLTE chunk with %d colors",
9573 ping_have_PLTE=MagickTrue;
9576 /* color_type is PNG_COLOR_TYPE_PALETTE */
9577 if (mng_info->write_png_depth == 0)
9585 while ((one << ping_bit_depth) < (size_t) number_colors)
9586 ping_bit_depth <<= 1;
9591 if (matte != MagickFalse)
9594 * Set up trans_colors array.
9596 assert(number_colors <= 256);
9598 ping_num_trans=(unsigned short) (number_transparent +
9599 number_semitransparent);
9601 if (ping_num_trans == 0)
9602 ping_have_tRNS=MagickFalse;
9606 if (logging != MagickFalse)
9608 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9609 " Scaling ping_trans_color (1)");
9611 ping_have_tRNS=MagickTrue;
9613 for (i=0; i < ping_num_trans; i++)
9615 ping_trans_alpha[i]= (png_byte)
9616 ScaleQuantumToChar(image->colormap[i].alpha);
9626 if (image_depth < 8)
9629 if ((save_image_depth == 16) && (image_depth == 8))
9631 if (logging != MagickFalse)
9633 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9634 " Scaling ping_trans_color from (%d,%d,%d)",
9635 (int) ping_trans_color.red,
9636 (int) ping_trans_color.green,
9637 (int) ping_trans_color.blue);
9640 ping_trans_color.red*=0x0101;
9641 ping_trans_color.green*=0x0101;
9642 ping_trans_color.blue*=0x0101;
9643 ping_trans_color.gray*=0x0101;
9645 if (logging != MagickFalse)
9647 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9649 (int) ping_trans_color.red,
9650 (int) ping_trans_color.green,
9651 (int) ping_trans_color.blue);
9656 if (ping_bit_depth < (ssize_t) mng_info->write_png_depth)
9657 ping_bit_depth = (ssize_t) mng_info->write_png_depth;
9660 Adjust background and transparency samples in sub-8-bit grayscale files.
9662 if (ping_bit_depth < 8 && ping_color_type ==
9663 PNG_COLOR_TYPE_GRAY)
9671 maxval=(png_uint_16) ((one << ping_bit_depth)-1);
9673 if (ping_exclude_bKGD == MagickFalse)
9676 ping_background.gray=(png_uint_16) ((maxval/65535.)*
9677 (ScaleQuantumToShort(((GetPixelInfoIntensity(
9678 &image->background_color))) +.5)));
9680 if (logging != MagickFalse)
9681 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9682 " Setting up bKGD chunk (2)");
9683 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9684 " background_color index is %d",
9685 (int) ping_background.index);
9687 ping_have_bKGD = MagickTrue;
9690 if (logging != MagickFalse)
9691 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9692 " Scaling ping_trans_color.gray from %d",
9693 (int)ping_trans_color.gray);
9695 ping_trans_color.gray=(png_uint_16) ((maxval/255.)*(
9696 ping_trans_color.gray)+.5);
9698 if (logging != MagickFalse)
9699 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9700 " to %d", (int)ping_trans_color.gray);
9703 if (ping_exclude_bKGD == MagickFalse)
9705 if (mng_info->IsPalette && (int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
9708 Identify which colormap entry is the background color.
9711 number_colors=image_colors;
9713 for (i=0; i < (ssize_t) MagickMax(1L*number_colors,1L); i++)
9714 if (IsPNGColorEqual(image->background_color,image->colormap[i]))
9717 ping_background.index=(png_byte) i;
9719 if (logging != MagickFalse)
9721 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9722 " Setting up bKGD chunk with index=%d",(int) i);
9725 if (i < (ssize_t) number_colors)
9727 ping_have_bKGD = MagickTrue;
9729 if (logging != MagickFalse)
9731 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9732 " background =(%d,%d,%d)",
9733 (int) ping_background.red,
9734 (int) ping_background.green,
9735 (int) ping_background.blue);
9739 else /* Can't happen */
9741 if (logging != MagickFalse)
9742 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9743 " No room in PLTE to add bKGD color");
9744 ping_have_bKGD = MagickFalse;
9749 if (logging != MagickFalse)
9750 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9751 " PNG color type: %s (%d)", PngColorTypeToString(ping_color_type),
9754 Initialize compression level and filtering.
9756 if (logging != MagickFalse)
9758 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9759 " Setting up deflate compression");
9761 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9762 " Compression buffer size: 32768");
9765 png_set_compression_buffer_size(ping,32768L);
9767 if (logging != MagickFalse)
9768 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9769 " Compression mem level: 9");
9771 png_set_compression_mem_level(ping, 9);
9773 /* Untangle the "-quality" setting:
9775 Undefined is 0; the default is used.
9780 0: Use Z_HUFFMAN_ONLY strategy with the
9781 zlib default compression level
9783 1-9: the zlib compression level
9787 0-4: the PNG filter method
9789 5: libpng adaptive filtering if compression level > 5
9790 libpng filter type "none" if compression level <= 5
9791 or if image is grayscale or palette
9793 6: libpng adaptive filtering
9795 7: "LOCO" filtering (intrapixel differing) if writing
9796 a MNG, othewise "none". Did not work in IM-6.7.0-9
9797 and earlier because of a missing "else".
9799 8: Z_RLE strategy, all filters
9800 Unused prior to IM-6.7.0-10, was same as 6
9802 9: Z_RLE strategy, no PNG filters
9803 Unused prior to IM-6.7.0-10, was same as 6
9805 Note that using the -quality option, not all combinations of
9806 PNG filter type, zlib compression level, and zlib compression
9807 strategy are possible. This will be addressed soon in a
9808 release that accomodates "-define png:compression-strategy", etc.
9812 quality=image->quality == UndefinedCompressionQuality ? 75UL :
9817 if (mng_info->write_png_compression_strategy == 0)
9818 mng_info->write_png_compression_strategy = Z_HUFFMAN_ONLY+1;
9821 else if (mng_info->write_png_compression_level == 0)
9826 level=(int) MagickMin((ssize_t) quality/10,9);
9828 mng_info->write_png_compression_level = level+1;
9831 if (mng_info->write_png_compression_strategy == 0)
9833 if ((quality %10) == 8 || (quality %10) == 9)
9834 mng_info->write_png_compression_strategy=Z_RLE;
9837 if (mng_info->write_png_compression_filter == 0)
9838 mng_info->write_png_compression_filter=((int) quality % 10) + 1;
9840 if (logging != MagickFalse)
9842 if (mng_info->write_png_compression_level)
9843 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9844 " Compression level: %d",
9845 (int) mng_info->write_png_compression_level-1);
9847 if (mng_info->write_png_compression_strategy)
9848 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9849 " Compression strategy: %d",
9850 (int) mng_info->write_png_compression_strategy-1);
9852 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9853 " Setting up filtering");
9855 if (mng_info->write_png_compression_filter == 6)
9856 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9857 " Base filter method: ADAPTIVE");
9858 else if (mng_info->write_png_compression_filter == 0 ||
9859 mng_info->write_png_compression_filter == 1)
9860 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9861 " Base filter method: NONE");
9863 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9864 " Base filter method: %d",
9865 (int) mng_info->write_png_compression_filter-1);
9868 if (mng_info->write_png_compression_level != 0)
9869 png_set_compression_level(ping,mng_info->write_png_compression_level-1);
9871 if (mng_info->write_png_compression_filter == 6)
9873 if (((int) ping_color_type == PNG_COLOR_TYPE_GRAY) ||
9874 ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE) ||
9876 png_set_filter(ping,PNG_FILTER_TYPE_BASE,PNG_NO_FILTERS);
9878 png_set_filter(ping,PNG_FILTER_TYPE_BASE,PNG_ALL_FILTERS);
9880 else if (mng_info->write_png_compression_filter == 7 ||
9881 mng_info->write_png_compression_filter == 10)
9882 png_set_filter(ping,PNG_FILTER_TYPE_BASE,PNG_ALL_FILTERS);
9884 else if (mng_info->write_png_compression_filter == 8)
9886 #if defined(PNG_MNG_FEATURES_SUPPORTED) && defined(PNG_INTRAPIXEL_DIFFERENCING)
9887 if (mng_info->write_mng)
9889 if (((int) ping_color_type == PNG_COLOR_TYPE_RGB) ||
9890 ((int) ping_color_type == PNG_COLOR_TYPE_RGBA))
9891 ping_filter_method=PNG_INTRAPIXEL_DIFFERENCING;
9894 png_set_filter(ping,PNG_FILTER_TYPE_BASE,PNG_NO_FILTERS);
9897 else if (mng_info->write_png_compression_filter == 9)
9898 png_set_filter(ping,PNG_FILTER_TYPE_BASE,PNG_NO_FILTERS);
9900 else if (mng_info->write_png_compression_filter != 0)
9901 png_set_filter(ping,PNG_FILTER_TYPE_BASE,
9902 mng_info->write_png_compression_filter-1);
9904 if (mng_info->write_png_compression_strategy != 0)
9905 png_set_compression_strategy(ping,
9906 mng_info->write_png_compression_strategy-1);
9908 /* Only write the iCCP chunk if we are not writing the sRGB chunk. */
9909 if (ping_exclude_sRGB != MagickFalse ||
9910 (image->rendering_intent == UndefinedIntent))
9912 if ((ping_exclude_tEXt == MagickFalse ||
9913 ping_exclude_zTXt == MagickFalse) &&
9914 (ping_exclude_iCCP == MagickFalse || ping_exclude_zCCP == MagickFalse))
9916 ResetImageProfileIterator(image);
9917 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
9919 profile=GetImageProfile(image,name);
9921 if (profile != (StringInfo *) NULL)
9923 #ifdef PNG_WRITE_iCCP_SUPPORTED
9924 if ((LocaleCompare(name,"ICC") == 0) ||
9925 (LocaleCompare(name,"ICM") == 0))
9928 if (ping_exclude_iCCP == MagickFalse)
9930 png_set_iCCP(ping,ping_info,(png_charp) name,0,
9931 #if (PNG_LIBPNG_VER < 10500)
9932 (png_charp) GetStringInfoDatum(profile),
9934 (png_const_bytep) GetStringInfoDatum(profile),
9936 (png_uint_32) GetStringInfoLength(profile));
9942 if (ping_exclude_zCCP == MagickFalse)
9944 Magick_png_write_raw_profile(image_info,ping,ping_info,
9945 (unsigned char *) name,(unsigned char *) name,
9946 GetStringInfoDatum(profile),
9947 (png_uint_32) GetStringInfoLength(profile));
9951 if (logging != MagickFalse)
9952 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9953 " Setting up text chunk with %s profile",name);
9955 name=GetNextImageProfile(image);
9960 #if defined(PNG_WRITE_sRGB_SUPPORTED)
9961 if ((mng_info->have_write_global_srgb == 0) &&
9962 (image->rendering_intent != UndefinedIntent))
9964 if (ping_exclude_sRGB == MagickFalse)
9967 Note image rendering intent.
9969 if (logging != MagickFalse)
9970 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9971 " Setting up sRGB chunk");
9973 (void) png_set_sRGB(ping,ping_info,(
9974 Magick_RenderingIntent_to_PNG_RenderingIntent(
9975 image->rendering_intent)));
9979 if ((!mng_info->write_mng) || (!png_get_valid(ping,ping_info,PNG_INFO_sRGB)))
9982 if (ping_exclude_gAMA == MagickFalse &&
9983 (ping_exclude_sRGB == MagickFalse ||
9984 (image->gamma < .45 || image->gamma > .46)))
9986 if ((mng_info->have_write_global_gama == 0) && (image->gamma != 0.0))
9990 To do: check for cHRM+gAMA == sRGB, and write sRGB instead.
9992 if (logging != MagickFalse)
9993 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9994 " Setting up gAMA chunk");
9996 png_set_gAMA(ping,ping_info,image->gamma);
10000 if (ping_exclude_cHRM == MagickFalse)
10002 if ((mng_info->have_write_global_chrm == 0) &&
10003 (image->chromaticity.red_primary.x != 0.0))
10006 Note image chromaticity.
10007 To do: check for cHRM+gAMA == sRGB, and write sRGB instead.
10015 wp=image->chromaticity.white_point;
10016 rp=image->chromaticity.red_primary;
10017 gp=image->chromaticity.green_primary;
10018 bp=image->chromaticity.blue_primary;
10020 if (logging != MagickFalse)
10021 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10022 " Setting up cHRM chunk");
10024 png_set_cHRM(ping,ping_info,wp.x,wp.y,rp.x,rp.y,gp.x,gp.y,
10030 ping_interlace_method=image_info->interlace != NoInterlace;
10032 if (mng_info->write_mng)
10033 png_set_sig_bytes(ping,8);
10035 /* Bail out if cannot meet defined png:bit-depth or png:color-type */
10037 if (mng_info->write_png_colortype != 0)
10039 if (mng_info->write_png_colortype-1 == PNG_COLOR_TYPE_GRAY)
10040 if (ping_have_color != MagickFalse)
10042 ping_color_type = PNG_COLOR_TYPE_RGB;
10044 if (ping_bit_depth < 8)
10048 if (mng_info->write_png_colortype-1 == PNG_COLOR_TYPE_GRAY_ALPHA)
10049 if (ping_have_color != MagickFalse)
10050 ping_color_type = PNG_COLOR_TYPE_RGB_ALPHA;
10053 if (ping_need_colortype_warning != MagickFalse ||
10054 ((mng_info->write_png_depth &&
10055 (int) mng_info->write_png_depth != ping_bit_depth) ||
10056 (mng_info->write_png_colortype &&
10057 ((int) mng_info->write_png_colortype-1 != ping_color_type &&
10058 mng_info->write_png_colortype != 7 &&
10059 !(mng_info->write_png_colortype == 5 && ping_color_type == 0)))))
10061 if (logging != MagickFalse)
10063 if (ping_need_colortype_warning != MagickFalse)
10065 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10066 " Image has transparency but tRNS chunk was excluded");
10069 if (mng_info->write_png_depth)
10071 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10072 " Defined png:bit-depth=%u, Computed depth=%u",
10073 mng_info->write_png_depth,
10077 if (mng_info->write_png_colortype)
10079 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10080 " Defined png:color-type=%u, Computed color type=%u",
10081 mng_info->write_png_colortype-1,
10087 "Cannot write image with defined png:bit-depth or png:color-type.");
10090 if (image_matte != MagickFalse && image->matte == MagickFalse)
10092 /* Add an opaque matte channel */
10093 image->matte = MagickTrue;
10094 (void) SetImageAlpha(image,OpaqueAlpha,exception);
10096 if (logging != MagickFalse)
10097 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10098 " Added an opaque matte channel");
10101 if (number_transparent != 0 || number_semitransparent != 0)
10103 if (ping_color_type < 4)
10105 ping_have_tRNS=MagickTrue;
10106 if (logging != MagickFalse)
10107 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10108 " Setting ping_have_tRNS=MagickTrue.");
10112 if (logging != MagickFalse)
10113 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10114 " Writing PNG header chunks");
10116 png_set_IHDR(ping,ping_info,ping_width,ping_height,
10117 ping_bit_depth,ping_color_type,
10118 ping_interlace_method,ping_compression_method,
10119 ping_filter_method);
10121 if (ping_color_type == 3 && ping_have_PLTE != MagickFalse)
10123 png_set_PLTE(ping,ping_info,palette,number_colors);
10125 if (logging != MagickFalse)
10127 for (i=0; i< (ssize_t) number_colors; i++)
10129 if (i < ping_num_trans)
10130 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10131 " PLTE[%d] = (%d,%d,%d), tRNS[%d] = (%d)",
10133 (int) palette[i].red,
10134 (int) palette[i].green,
10135 (int) palette[i].blue,
10137 (int) ping_trans_alpha[i]);
10139 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10140 " PLTE[%d] = (%d,%d,%d)",
10142 (int) palette[i].red,
10143 (int) palette[i].green,
10144 (int) palette[i].blue);
10149 if (ping_exclude_bKGD == MagickFalse)
10151 if (ping_have_bKGD != MagickFalse)
10153 png_set_bKGD(ping,ping_info,&ping_background);
10156 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10157 " Setting up bKGD chunk");
10158 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10159 " background color = (%d,%d,%d)",
10160 (int) ping_background.red,
10161 (int) ping_background.green,
10162 (int) ping_background.blue);
10163 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10164 " index = %d, gray=%d",
10165 (int) ping_background.index,
10166 (int) ping_background.gray);
10171 if (ping_exclude_pHYs == MagickFalse)
10173 if (ping_have_pHYs != MagickFalse)
10175 png_set_pHYs(ping,ping_info,
10176 ping_pHYs_x_resolution,
10177 ping_pHYs_y_resolution,
10178 ping_pHYs_unit_type);
10182 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10183 " Setting up pHYs chunk");
10184 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10185 " x_resolution=%lu",
10186 (unsigned long) ping_pHYs_x_resolution);
10187 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10188 " y_resolution=%lu",
10189 (unsigned long) ping_pHYs_y_resolution);
10190 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10192 (unsigned long) ping_pHYs_unit_type);
10197 #if defined(PNG_oFFs_SUPPORTED)
10198 if (ping_exclude_oFFs == MagickFalse)
10200 if (image->page.x || image->page.y)
10202 png_set_oFFs(ping,ping_info,(png_int_32) image->page.x,
10203 (png_int_32) image->page.y, 0);
10205 if (logging != MagickFalse)
10206 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10207 " Setting up oFFs chunk with x=%d, y=%d, units=0",
10208 (int) image->page.x, (int) image->page.y);
10213 if (mng_info->need_blob != MagickFalse)
10215 if (OpenBlob(image_info,image,WriteBinaryBlobMode,exception) ==
10217 png_error(ping,"WriteBlob Failed");
10219 ping_have_blob=MagickTrue;
10222 png_write_info_before_PLTE(ping, ping_info);
10224 if (ping_have_tRNS != MagickFalse && ping_color_type < 4)
10226 if (logging != MagickFalse)
10228 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10229 " Calling png_set_tRNS with num_trans=%d",ping_num_trans);
10232 if (ping_color_type == 3)
10233 (void) png_set_tRNS(ping, ping_info,
10240 (void) png_set_tRNS(ping, ping_info,
10243 &ping_trans_color);
10245 if (logging != MagickFalse)
10247 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10248 " tRNS color =(%d,%d,%d)",
10249 (int) ping_trans_color.red,
10250 (int) ping_trans_color.green,
10251 (int) ping_trans_color.blue);
10256 /* write any png-chunk-b profiles */
10257 (void) Magick_png_write_chunk_from_profile(image,"PNG-chunk-b",logging);
10259 png_write_info(ping,ping_info);
10261 /* write any PNG-chunk-m profiles */
10262 (void) Magick_png_write_chunk_from_profile(image,"PNG-chunk-m",logging);
10264 if (ping_exclude_vpAg == MagickFalse)
10266 if ((image->page.width != 0 && image->page.width != image->columns) ||
10267 (image->page.height != 0 && image->page.height != image->rows))
10272 (void) WriteBlobMSBULong(image,9L); /* data length=8 */
10273 PNGType(chunk,mng_vpAg);
10274 LogPNGChunk(logging,mng_vpAg,9L);
10275 PNGLong(chunk+4,(png_uint_32) image->page.width);
10276 PNGLong(chunk+8,(png_uint_32) image->page.height);
10277 chunk[12]=0; /* unit = pixels */
10278 (void) WriteBlob(image,13,chunk);
10279 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
10283 #if (PNG_LIBPNG_VER == 10206)
10284 /* avoid libpng-1.2.6 bug by setting PNG_HAVE_IDAT flag */
10285 #define PNG_HAVE_IDAT 0x04
10286 ping->mode |= PNG_HAVE_IDAT;
10287 #undef PNG_HAVE_IDAT
10290 png_set_packing(ping);
10294 rowbytes=image->columns;
10295 if (image_depth > 8)
10297 switch (ping_color_type)
10299 case PNG_COLOR_TYPE_RGB:
10303 case PNG_COLOR_TYPE_GRAY_ALPHA:
10307 case PNG_COLOR_TYPE_RGBA:
10315 if (logging != MagickFalse)
10317 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10318 " Writing PNG image data");
10320 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10321 " Allocating %.20g bytes of memory for pixels",(double) rowbytes);
10323 ping_pixels=(unsigned char *) AcquireQuantumMemory(rowbytes,
10324 sizeof(*ping_pixels));
10326 if (ping_pixels == (unsigned char *) NULL)
10327 png_error(ping,"Allocation of memory for pixels failed");
10330 Initialize image scanlines.
10332 quantum_info=AcquireQuantumInfo(image_info,image);
10333 if (quantum_info == (QuantumInfo *) NULL)
10334 png_error(ping,"Memory allocation for quantum_info failed");
10335 quantum_info->format=UndefinedQuantumFormat;
10336 quantum_info->depth=image_depth;
10337 num_passes=png_set_interlace_handling(ping);
10339 if ((!mng_info->write_png8 && !mng_info->write_png24 &&
10340 !mng_info->write_png32) &&
10341 (mng_info->IsPalette ||
10342 (image_info->type == BilevelType)) &&
10343 image_matte == MagickFalse &&
10344 ping_have_non_bw == MagickFalse)
10346 /* Palette, Bilevel, or Opaque Monochrome */
10347 register const Quantum
10350 quantum_info->depth=8;
10351 for (pass=0; pass < num_passes; pass++)
10354 Convert PseudoClass image to a PNG monochrome image.
10356 for (y=0; y < (ssize_t) image->rows; y++)
10358 if (logging != MagickFalse && y == 0)
10359 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10360 " Writing row of pixels (0)");
10362 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
10364 if (p == (const Quantum *) NULL)
10367 if (mng_info->IsPalette)
10369 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10370 quantum_info,GrayQuantum,ping_pixels,exception);
10371 if (mng_info->write_png_colortype-1 == PNG_COLOR_TYPE_PALETTE &&
10372 mng_info->write_png_depth &&
10373 mng_info->write_png_depth != old_bit_depth)
10375 /* Undo pixel scaling */
10376 for (i=0; i < (ssize_t) image->columns; i++)
10377 *(ping_pixels+i)=(unsigned char) (*(ping_pixels+i)
10378 >> (8-old_bit_depth));
10384 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10385 quantum_info,RedQuantum,ping_pixels,exception);
10388 if (mng_info->write_png_colortype-1 != PNG_COLOR_TYPE_PALETTE)
10389 for (i=0; i < (ssize_t) image->columns; i++)
10390 *(ping_pixels+i)=(unsigned char) ((*(ping_pixels+i) > 127) ?
10393 if (logging != MagickFalse && y == 0)
10394 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10395 " Writing row of pixels (1)");
10397 png_write_row(ping,ping_pixels);
10399 if (image->previous == (Image *) NULL)
10401 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
10402 if (status == MagickFalse)
10408 else /* Not Palette, Bilevel, or Opaque Monochrome */
10410 if ((!mng_info->write_png8 && !mng_info->write_png24 &&
10411 !mng_info->write_png32) &&
10412 (image_matte != MagickFalse ||
10413 (ping_bit_depth >= MAGICKCORE_QUANTUM_DEPTH)) &&
10414 (mng_info->IsPalette) && ping_have_color == MagickFalse)
10416 register const Quantum
10419 for (pass=0; pass < num_passes; pass++)
10422 for (y=0; y < (ssize_t) image->rows; y++)
10424 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
10426 if (p == (const Quantum *) NULL)
10429 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
10431 if (mng_info->IsPalette)
10432 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10433 quantum_info,GrayQuantum,ping_pixels,exception);
10436 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10437 quantum_info,RedQuantum,ping_pixels,exception);
10439 if (logging != MagickFalse && y == 0)
10440 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10441 " Writing GRAY PNG pixels (2)");
10444 else /* PNG_COLOR_TYPE_GRAY_ALPHA */
10446 if (logging != MagickFalse && y == 0)
10447 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10448 " Writing GRAY_ALPHA PNG pixels (2)");
10450 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10451 quantum_info,GrayAlphaQuantum,ping_pixels,exception);
10454 if (logging != MagickFalse && y == 0)
10455 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10456 " Writing row of pixels (2)");
10458 png_write_row(ping,ping_pixels);
10461 if (image->previous == (Image *) NULL)
10463 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
10464 if (status == MagickFalse)
10472 register const Quantum
10475 for (pass=0; pass < num_passes; pass++)
10477 if ((image_depth > 8) || (mng_info->write_png24 ||
10478 mng_info->write_png32 ||
10479 (!mng_info->write_png8 && !mng_info->IsPalette)))
10481 for (y=0; y < (ssize_t) image->rows; y++)
10483 p=GetVirtualPixels(image,0,y,image->columns,1,
10486 if (p == (const Quantum *) NULL)
10489 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
10491 if (image->storage_class == DirectClass)
10492 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10493 quantum_info,RedQuantum,ping_pixels,exception);
10496 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10497 quantum_info,GrayQuantum,ping_pixels,exception);
10500 else if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
10502 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10503 quantum_info,GrayAlphaQuantum,ping_pixels,
10506 if (logging != MagickFalse && y == 0)
10507 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10508 " Writing GRAY_ALPHA PNG pixels (3)");
10511 else if (image_matte != MagickFalse)
10512 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10513 quantum_info,RGBAQuantum,ping_pixels,exception);
10516 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10517 quantum_info,RGBQuantum,ping_pixels,exception);
10519 if (logging != MagickFalse && y == 0)
10520 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10521 " Writing row of pixels (3)");
10523 png_write_row(ping,ping_pixels);
10528 /* not ((image_depth > 8) || (mng_info->write_png24 ||
10529 mng_info->write_png32 ||
10530 (!mng_info->write_png8 && !mng_info->IsPalette))) */
10532 if ((ping_color_type != PNG_COLOR_TYPE_GRAY) &&
10533 (ping_color_type != PNG_COLOR_TYPE_GRAY_ALPHA))
10535 if (logging != MagickFalse)
10536 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10537 " pass %d, Image Is not GRAY or GRAY_ALPHA",pass);
10539 quantum_info->depth=8;
10543 for (y=0; y < (ssize_t) image->rows; y++)
10545 if (logging != MagickFalse && y == 0)
10546 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10547 " pass %d, Image Is RGB, 16-bit GRAY, or GRAY_ALPHA",pass);
10549 p=GetVirtualPixels(image,0,y,image->columns,1, exception);
10551 if (p == (const Quantum *) NULL)
10554 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
10556 quantum_info->depth=image->depth;
10558 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10559 quantum_info,GrayQuantum,ping_pixels,exception);
10562 else if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
10564 if (logging != MagickFalse && y == 0)
10565 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10566 " Writing GRAY_ALPHA PNG pixels (4)");
10568 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10569 quantum_info,GrayAlphaQuantum,ping_pixels,
10575 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10576 quantum_info,IndexQuantum,ping_pixels,exception);
10578 if (logging != MagickFalse && y <= 2)
10580 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10581 " Writing row of non-gray pixels (4)");
10583 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10584 " ping_pixels[0]=%d,ping_pixels[1]=%d",
10585 (int)ping_pixels[0],(int)ping_pixels[1]);
10588 png_write_row(ping,ping_pixels);
10592 if (image->previous == (Image *) NULL)
10594 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
10595 if (status == MagickFalse)
10602 if (quantum_info != (QuantumInfo *) NULL)
10603 quantum_info=DestroyQuantumInfo(quantum_info);
10605 if (logging != MagickFalse)
10607 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10608 " Wrote PNG image data");
10610 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10611 " Width: %.20g",(double) ping_width);
10613 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10614 " Height: %.20g",(double) ping_height);
10616 if (mng_info->write_png_depth)
10618 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10619 " Defined png:bit-depth: %d",mng_info->write_png_depth);
10622 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10623 " PNG bit-depth written: %d",ping_bit_depth);
10625 if (mng_info->write_png_colortype)
10627 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10628 " Defined png:color-type: %d",mng_info->write_png_colortype-1);
10631 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10632 " PNG color-type written: %d",ping_color_type);
10634 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10635 " PNG Interlace method: %d",ping_interlace_method);
10638 Generate text chunks after IDAT.
10640 if (ping_exclude_tEXt == MagickFalse || ping_exclude_zTXt == MagickFalse)
10642 ResetImagePropertyIterator(image);
10643 property=GetNextImageProperty(image);
10644 while (property != (const char *) NULL)
10649 value=GetImageProperty(image,property,exception);
10651 /* Don't write any "png:" properties; those are just for "identify" */
10652 if (LocaleNCompare(property,"png:",4) != 0 &&
10654 /* Suppress density and units if we wrote a pHYs chunk */
10655 (ping_exclude_pHYs != MagickFalse ||
10656 LocaleCompare(property,"density") != 0 ||
10657 LocaleCompare(property,"units") != 0) &&
10659 /* Suppress the IM-generated Date:create and Date:modify */
10660 (ping_exclude_date == MagickFalse ||
10661 LocaleNCompare(property, "Date:",5) != 0))
10663 if (value != (const char *) NULL)
10665 text=(png_textp) png_malloc(ping,(png_uint_32) sizeof(png_text));
10666 text[0].key=(char *) property;
10667 text[0].text=(char *) value;
10668 text[0].text_length=strlen(value);
10670 if (ping_exclude_tEXt != MagickFalse)
10671 text[0].compression=PNG_TEXT_COMPRESSION_zTXt;
10673 else if (ping_exclude_zTXt != MagickFalse)
10674 text[0].compression=PNG_TEXT_COMPRESSION_NONE;
10678 text[0].compression=image_info->compression == NoCompression ||
10679 (image_info->compression == UndefinedCompression &&
10680 text[0].text_length < 128) ? PNG_TEXT_COMPRESSION_NONE :
10681 PNG_TEXT_COMPRESSION_zTXt ;
10684 if (logging != MagickFalse)
10686 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10687 " Setting up text chunk");
10689 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10690 " keyword: %s",text[0].key);
10693 png_set_text(ping,ping_info,text,1);
10694 png_free(ping,text);
10697 property=GetNextImageProperty(image);
10701 /* write any PNG-chunk-e profiles */
10702 (void) Magick_png_write_chunk_from_profile(image,"PNG-chunk-e",logging);
10704 if (logging != MagickFalse)
10705 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10706 " Writing PNG end info");
10708 png_write_end(ping,ping_info);
10710 if (mng_info->need_fram && (int) image->dispose == BackgroundDispose)
10712 if (mng_info->page.x || mng_info->page.y ||
10713 (ping_width != mng_info->page.width) ||
10714 (ping_height != mng_info->page.height))
10720 Write FRAM 4 with clipping boundaries followed by FRAM 1.
10722 (void) WriteBlobMSBULong(image,27L); /* data length=27 */
10723 PNGType(chunk,mng_FRAM);
10724 LogPNGChunk(logging,mng_FRAM,27L);
10726 chunk[5]=0; /* frame name separator (no name) */
10727 chunk[6]=1; /* flag for changing delay, for next frame only */
10728 chunk[7]=0; /* flag for changing frame timeout */
10729 chunk[8]=1; /* flag for changing frame clipping for next frame */
10730 chunk[9]=0; /* flag for changing frame sync_id */
10731 PNGLong(chunk+10,(png_uint_32) (0L)); /* temporary 0 delay */
10732 chunk[14]=0; /* clipping boundaries delta type */
10733 PNGLong(chunk+15,(png_uint_32) (mng_info->page.x)); /* left cb */
10735 (png_uint_32) (mng_info->page.x + ping_width));
10736 PNGLong(chunk+23,(png_uint_32) (mng_info->page.y)); /* top cb */
10738 (png_uint_32) (mng_info->page.y + ping_height));
10739 (void) WriteBlob(image,31,chunk);
10740 (void) WriteBlobMSBULong(image,crc32(0,chunk,31));
10741 mng_info->old_framing_mode=4;
10742 mng_info->framing_mode=1;
10746 mng_info->framing_mode=3;
10748 if (mng_info->write_mng && !mng_info->need_fram &&
10749 ((int) image->dispose == 3))
10750 png_error(ping, "Cannot convert GIF with disposal method 3 to MNG-LC");
10753 Free PNG resources.
10756 png_destroy_write_struct(&ping,&ping_info);
10758 ping_pixels=(unsigned char *) RelinquishMagickMemory(ping_pixels);
10760 if (ping_have_blob != MagickFalse)
10761 (void) CloseBlob(image);
10763 image_info=DestroyImageInfo(image_info);
10764 image=DestroyImage(image);
10766 /* Store bit depth actually written */
10767 s[0]=(char) ping_bit_depth;
10770 (void) SetImageProperty(IMimage,"png:bit-depth-written",s,exception);
10772 if (logging != MagickFalse)
10773 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10774 " exit WriteOnePNGImage()");
10776 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
10777 UnlockSemaphoreInfo(ping_semaphore);
10780 /* } for navigation to beginning of SETJMP-protected block. Revert to
10781 * Throwing an Exception when an error occurs.
10784 return(MagickTrue);
10785 /* End write one PNG image */
10790 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10794 % W r i t e P N G I m a g e %
10798 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10800 % WritePNGImage() writes a Portable Network Graphics (PNG) or
10801 % Multiple-image Network Graphics (MNG) image file.
10803 % MNG support written by Glenn Randers-Pehrson, glennrp@image...
10805 % The format of the WritePNGImage method is:
10807 % MagickBooleanType WritePNGImage(const ImageInfo *image_info,
10808 % Image *image,ExceptionInfo *exception)
10810 % A description of each parameter follows:
10812 % o image_info: the image info.
10814 % o image: The image.
10816 % o exception: return any errors or warnings in this structure.
10818 % Returns MagickTrue on success, MagickFalse on failure.
10820 % Communicating with the PNG encoder:
10822 % While the datastream written is always in PNG format and normally would
10823 % be given the "png" file extension, this method also writes the following
10824 % pseudo-formats which are subsets of png:
10826 % o PNG8: An 8-bit indexed PNG datastream is written. If the image has
10827 % a depth greater than 8, the depth is reduced. If transparency
10828 % is present, the tRNS chunk must only have values 0 and 255
10829 % (i.e., transparency is binary: fully opaque or fully
10830 % transparent). If other values are present they will be
10831 % 50%-thresholded to binary transparency. If more than 256
10832 % colors are present, they will be quantized to the 4-4-4-1,
10833 % 3-3-3-1, or 3-3-2-1 palette. The underlying RGB color
10834 % of any resulting fully-transparent pixels is changed to
10835 % the image's background color.
10837 % If you want better quantization or dithering of the colors
10838 % or alpha than that, you need to do it before calling the
10839 % PNG encoder. The pixels contain 8-bit indices even if
10840 % they could be represented with 1, 2, or 4 bits. Grayscale
10841 % images will be written as indexed PNG files even though the
10842 % PNG grayscale type might be slightly more efficient. Please
10843 % note that writing to the PNG8 format may result in loss
10844 % of color and alpha data.
10846 % o PNG24: An 8-bit per sample RGB PNG datastream is written. The tRNS
10847 % chunk can be present to convey binary transparency by naming
10848 % one of the colors as transparent. The only loss incurred
10849 % is reduction of sample depth to 8. If the image has more
10850 % than one transparent color, has semitransparent pixels, or
10851 % has an opaque pixel with the same RGB components as the
10852 % transparent color, an image is not written.
10854 % o PNG32: An 8-bit per sample RGBA PNG is written. Partial
10855 % transparency is permitted, i.e., the alpha sample for
10856 % each pixel can have any value from 0 to 255. The alpha
10857 % channel is present even if the image is fully opaque.
10858 % The only loss in data is the reduction of the sample depth
10861 % o -define: For more precise control of the PNG output, you can use the
10862 % Image options "png:bit-depth" and "png:color-type". These
10863 % can be set from the commandline with "-define" and also
10864 % from the application programming interfaces. The options
10865 % are case-independent and are converted to lowercase before
10866 % being passed to this encoder.
10868 % png:color-type can be 0, 2, 3, 4, or 6.
10870 % When png:color-type is 0 (Grayscale), png:bit-depth can
10871 % be 1, 2, 4, 8, or 16.
10873 % When png:color-type is 2 (RGB), png:bit-depth can
10876 % When png:color-type is 3 (Indexed), png:bit-depth can
10877 % be 1, 2, 4, or 8. This refers to the number of bits
10878 % used to store the index. The color samples always have
10879 % bit-depth 8 in indexed PNG files.
10881 % When png:color-type is 4 (Gray-Matte) or 6 (RGB-Matte),
10882 % png:bit-depth can be 8 or 16.
10884 % If the image cannot be written without loss with the requested bit-depth
10885 % and color-type, a PNG file will not be written, and the encoder will
10886 % return MagickFalse.
10888 % Since image encoders should not be responsible for the "heavy lifting",
10889 % the user should make sure that ImageMagick has already reduced the
10890 % image depth and number of colors and limit transparency to binary
10891 % transparency prior to attempting to write the image with depth, color,
10892 % or transparency limitations.
10894 % Note that another definition, "png:bit-depth-written" exists, but it
10895 % is not intended for external use. It is only used internally by the
10896 % PNG encoder to inform the JNG encoder of the depth of the alpha channel.
10898 % It is possible to request that the PNG encoder write previously-formatted
10899 % ancillary chunks in the output PNG file, using the "-profile" commandline
10900 % option as shown below or by setting the profile via a programming
10903 % -profile PNG-chunk-x:<file>
10905 % where x is a location flag and <file> is a file containing the chunk
10906 % name in the first 4 bytes, then a colon (":"), followed by the chunk data.
10907 % This encoder will compute the chunk length and CRC, so those must not
10908 % be included in the file.
10910 % "x" can be "b" (before PLTE), "m" (middle, i.e., between PLTE and IDAT),
10911 % or "e" (end, i.e., after IDAT). If you want to write multiple chunks
10912 % of the same type, then add a short unique string after the "x" to prevent
10913 % subsequent profiles from overwriting the preceding ones, e.g.,
10915 % -profile PNG-chunk-b01:file01 -profile PNG-chunk-b02:file02
10917 % As of version 6.6.6 the following optimizations are always done:
10919 % o 32-bit depth is reduced to 16.
10920 % o 16-bit depth is reduced to 8 if all pixels contain samples whose
10921 % high byte and low byte are identical.
10922 % o Palette is sorted to remove unused entries and to put a
10923 % transparent color first, if BUILD_PNG_PALETTE is defined.
10924 % o Opaque matte channel is removed when writing an indexed PNG.
10925 % o Grayscale images are reduced to 1, 2, or 4 bit depth if
10926 % this can be done without loss and a larger bit depth N was not
10927 % requested via the "-define png:bit-depth=N" option.
10928 % o If matte channel is present but only one transparent color is
10929 % present, RGB+tRNS is written instead of RGBA
10930 % o Opaque matte channel is removed (or added, if color-type 4 or 6
10931 % was requested when converting an opaque image).
10933 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10935 static MagickBooleanType WritePNGImage(const ImageInfo *image_info,
10936 Image *image,ExceptionInfo *exception)
10941 have_mng_structure,
10957 assert(image_info != (const ImageInfo *) NULL);
10958 assert(image_info->signature == MagickSignature);
10959 assert(image != (Image *) NULL);
10960 assert(image->signature == MagickSignature);
10961 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
10962 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter WritePNGImage()");
10964 Allocate a MngInfo structure.
10966 have_mng_structure=MagickFalse;
10967 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
10969 if (mng_info == (MngInfo *) NULL)
10970 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
10973 Initialize members of the MngInfo structure.
10975 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
10976 mng_info->image=image;
10977 mng_info->equal_backgrounds=MagickTrue;
10978 have_mng_structure=MagickTrue;
10980 /* See if user has requested a specific PNG subformat */
10982 mng_info->write_png8=LocaleCompare(image_info->magick,"PNG8") == 0;
10983 mng_info->write_png24=LocaleCompare(image_info->magick,"PNG24") == 0;
10984 mng_info->write_png32=LocaleCompare(image_info->magick,"PNG32") == 0;
10986 value=GetImageOption(image_info,"png:format");
10988 if (value != (char *) NULL)
10990 if (LocaleCompare(value,"png8") == 0)
10992 mng_info->write_png8 = MagickTrue;
10993 mng_info->write_png24 = MagickFalse;
10994 mng_info->write_png32 = MagickFalse;
10997 else if (LocaleCompare(value,"png24") == 0)
10999 mng_info->write_png8 = MagickFalse;
11000 mng_info->write_png24 = MagickTrue;
11001 mng_info->write_png32 = MagickFalse;
11004 else if (LocaleCompare(value,"png32") == 0)
11006 mng_info->write_png8 = MagickFalse;
11007 mng_info->write_png24 = MagickFalse;
11008 mng_info->write_png32 = MagickTrue;
11011 if (mng_info->write_png8)
11013 mng_info->write_png_colortype = /* 3 */ 4;
11014 mng_info->write_png_depth = 8;
11018 if (mng_info->write_png24)
11020 mng_info->write_png_colortype = /* 2 */ 3;
11021 mng_info->write_png_depth = 8;
11024 if (image->matte == MagickTrue)
11025 (void) SetImageType(image,TrueColorMatteType,exception);
11028 (void) SetImageType(image,TrueColorType,exception);
11030 (void) SyncImage(image,exception);
11033 if (mng_info->write_png32)
11035 mng_info->write_png_colortype = /* 6 */ 7;
11036 mng_info->write_png_depth = 8;
11039 if (image->matte == MagickTrue)
11040 (void) SetImageType(image,TrueColorMatteType,exception);
11043 (void) SetImageType(image,TrueColorType,exception);
11045 (void) SyncImage(image,exception);
11048 value=GetImageOption(image_info,"png:bit-depth");
11050 if (value != (char *) NULL)
11052 if (LocaleCompare(value,"1") == 0)
11053 mng_info->write_png_depth = 1;
11055 else if (LocaleCompare(value,"2") == 0)
11056 mng_info->write_png_depth = 2;
11058 else if (LocaleCompare(value,"4") == 0)
11059 mng_info->write_png_depth = 4;
11061 else if (LocaleCompare(value,"8") == 0)
11062 mng_info->write_png_depth = 8;
11064 else if (LocaleCompare(value,"16") == 0)
11065 mng_info->write_png_depth = 16;
11068 (void) ThrowMagickException(exception,
11069 GetMagickModule(),CoderWarning,
11070 "ignoring invalid defined png:bit-depth",
11073 if (logging != MagickFalse)
11074 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11075 " png:bit-depth=%d was defined.\n",mng_info->write_png_depth);
11078 value=GetImageOption(image_info,"png:color-type");
11080 if (value != (char *) NULL)
11082 /* We must store colortype+1 because 0 is a valid colortype */
11083 if (LocaleCompare(value,"0") == 0)
11084 mng_info->write_png_colortype = 1;
11086 else if (LocaleCompare(value,"1") == 0)
11087 mng_info->write_png_colortype = 2;
11089 else if (LocaleCompare(value,"2") == 0)
11090 mng_info->write_png_colortype = 3;
11092 else if (LocaleCompare(value,"3") == 0)
11093 mng_info->write_png_colortype = 4;
11095 else if (LocaleCompare(value,"4") == 0)
11096 mng_info->write_png_colortype = 5;
11098 else if (LocaleCompare(value,"6") == 0)
11099 mng_info->write_png_colortype = 7;
11102 (void) ThrowMagickException(exception,
11103 GetMagickModule(),CoderWarning,
11104 "ignoring invalid defined png:color-type",
11107 if (logging != MagickFalse)
11108 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11109 " png:color-type=%d was defined.\n",mng_info->write_png_colortype-1);
11112 /* Check for chunks to be excluded:
11114 * The default is to not exclude any known chunks except for any
11115 * listed in the "unused_chunks" array, above.
11117 * Chunks can be listed for exclusion via a "png:exclude-chunk"
11118 * define (in the image properties or in the image artifacts)
11119 * or via a mng_info member. For convenience, in addition
11120 * to or instead of a comma-separated list of chunks, the
11121 * "exclude-chunk" string can be simply "all" or "none".
11123 * The exclude-chunk define takes priority over the mng_info.
11125 * A "png:include-chunk" define takes priority over both the
11126 * mng_info and the "png:exclude-chunk" define. Like the
11127 * "exclude-chunk" string, it can define "all" or "none" as
11128 * well as a comma-separated list. Chunks that are unknown to
11129 * ImageMagick are always excluded, regardless of their "copy-safe"
11130 * status according to the PNG specification, and even if they
11131 * appear in the "include-chunk" list. Such defines appearing among
11132 * the image options take priority over those found among the image
11135 * Finally, all chunks listed in the "unused_chunks" array are
11136 * automatically excluded, regardless of the other instructions
11139 * if you exclude sRGB but not gAMA (recommended), then sRGB chunk
11140 * will not be written and the gAMA chunk will only be written if it
11141 * is not between .45 and .46, or approximately (1.0/2.2).
11143 * If you exclude tRNS and the image has transparency, the colortype
11144 * is forced to be 4 or 6 (GRAY_ALPHA or RGB_ALPHA).
11146 * The -strip option causes StripImage() to set the png:include-chunk
11147 * artifact to "none,trns,gama".
11150 mng_info->ping_exclude_bKGD=MagickFalse;
11151 mng_info->ping_exclude_cHRM=MagickFalse;
11152 mng_info->ping_exclude_date=MagickFalse;
11153 mng_info->ping_exclude_EXIF=MagickFalse; /* hex-encoded EXIF in zTXt */
11154 mng_info->ping_exclude_gAMA=MagickFalse;
11155 mng_info->ping_exclude_iCCP=MagickFalse;
11156 /* mng_info->ping_exclude_iTXt=MagickFalse; */
11157 mng_info->ping_exclude_oFFs=MagickFalse;
11158 mng_info->ping_exclude_pHYs=MagickFalse;
11159 mng_info->ping_exclude_sRGB=MagickFalse;
11160 mng_info->ping_exclude_tEXt=MagickFalse;
11161 mng_info->ping_exclude_tRNS=MagickFalse;
11162 mng_info->ping_exclude_vpAg=MagickFalse;
11163 mng_info->ping_exclude_zCCP=MagickFalse; /* hex-encoded iCCP in zTXt */
11164 mng_info->ping_exclude_zTXt=MagickFalse;
11166 mng_info->ping_preserve_colormap=MagickFalse;
11168 value=GetImageArtifact(image,"png:preserve-colormap");
11170 value=GetImageOption(image_info,"png:preserve-colormap");
11172 mng_info->ping_preserve_colormap=MagickTrue;
11174 /* Thes compression-level, compression-strategy, and compression-filter
11175 * defines take precedence over values from the -quality option.
11177 value=GetImageArtifact(image,"png:compression-level");
11179 value=GetImageOption(image_info,"png:compression-level");
11182 /* We have to add 1 to everything because 0 is a valid input,
11183 * and we want to use 0 (the default) to mean undefined.
11185 if (LocaleCompare(value,"0") == 0)
11186 mng_info->write_png_compression_level = 1;
11188 else if (LocaleCompare(value,"1") == 0)
11189 mng_info->write_png_compression_level = 2;
11191 else if (LocaleCompare(value,"2") == 0)
11192 mng_info->write_png_compression_level = 3;
11194 else if (LocaleCompare(value,"3") == 0)
11195 mng_info->write_png_compression_level = 4;
11197 else if (LocaleCompare(value,"4") == 0)
11198 mng_info->write_png_compression_level = 5;
11200 else if (LocaleCompare(value,"5") == 0)
11201 mng_info->write_png_compression_level = 6;
11203 else if (LocaleCompare(value,"6") == 0)
11204 mng_info->write_png_compression_level = 7;
11206 else if (LocaleCompare(value,"7") == 0)
11207 mng_info->write_png_compression_level = 8;
11209 else if (LocaleCompare(value,"8") == 0)
11210 mng_info->write_png_compression_level = 9;
11212 else if (LocaleCompare(value,"9") == 0)
11213 mng_info->write_png_compression_level = 10;
11216 (void) ThrowMagickException(exception,
11217 GetMagickModule(),CoderWarning,
11218 "ignoring invalid defined png:compression-level",
11222 value=GetImageArtifact(image,"png:compression-strategy");
11224 value=GetImageOption(image_info,"png:compression-strategy");
11228 if (LocaleCompare(value,"0") == 0)
11229 mng_info->write_png_compression_strategy = Z_DEFAULT_STRATEGY+1;
11231 else if (LocaleCompare(value,"1") == 0)
11232 mng_info->write_png_compression_strategy = Z_FILTERED+1;
11234 else if (LocaleCompare(value,"2") == 0)
11235 mng_info->write_png_compression_strategy = Z_HUFFMAN_ONLY+1;
11237 else if (LocaleCompare(value,"3") == 0)
11238 #ifdef Z_RLE /* Z_RLE was added to zlib-1.2.0 */
11239 mng_info->write_png_compression_strategy = Z_RLE+1;
11241 mng_info->write_png_compression_strategy = Z_DEFAULT_STRATEGY+1;
11244 else if (LocaleCompare(value,"4") == 0)
11245 #ifdef Z_FIXED /* Z_FIXED was added to zlib-1.2.2.2 */
11246 mng_info->write_png_compression_strategy = Z_FIXED+1;
11248 mng_info->write_png_compression_strategy = Z_DEFAULT_STRATEGY+1;
11252 (void) ThrowMagickException(exception,
11253 GetMagickModule(),CoderWarning,
11254 "ignoring invalid defined png:compression-strategy",
11258 value=GetImageArtifact(image,"png:compression-filter");
11260 value=GetImageOption(image_info,"png:compression-filter");
11264 /* To do: combinations of filters allowed by libpng
11265 * masks 0x08 through 0xf8
11267 * Implement this as a comma-separated list of 0,1,2,3,4,5
11268 * where 5 is a special case meaning PNG_ALL_FILTERS.
11271 if (LocaleCompare(value,"0") == 0)
11272 mng_info->write_png_compression_filter = 1;
11274 if (LocaleCompare(value,"1") == 0)
11275 mng_info->write_png_compression_filter = 2;
11277 else if (LocaleCompare(value,"2") == 0)
11278 mng_info->write_png_compression_filter = 3;
11280 else if (LocaleCompare(value,"3") == 0)
11281 mng_info->write_png_compression_filter = 4;
11283 else if (LocaleCompare(value,"4") == 0)
11284 mng_info->write_png_compression_filter = 5;
11286 else if (LocaleCompare(value,"5") == 0)
11287 mng_info->write_png_compression_filter = 6;
11290 (void) ThrowMagickException(exception,
11291 GetMagickModule(),CoderWarning,
11292 "ignoring invalid defined png:compression-filter",
11296 excluding=MagickFalse;
11298 for (source=0; source<1; source++)
11302 value=GetImageArtifact(image,"png:exclude-chunk");
11305 value=GetImageArtifact(image,"png:exclude-chunks");
11309 value=GetImageOption(image_info,"png:exclude-chunk");
11312 value=GetImageOption(image_info,"png:exclude-chunks");
11321 excluding=MagickTrue;
11323 if (logging != MagickFalse)
11326 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11327 " png:exclude-chunk=%s found in image artifacts.\n", value);
11329 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11330 " png:exclude-chunk=%s found in image properties.\n", value);
11333 last=strlen(value);
11335 for (i=0; i<(int) last; i+=5)
11338 if (LocaleNCompare(value+i,"all",3) == 0)
11340 mng_info->ping_exclude_bKGD=MagickTrue;
11341 mng_info->ping_exclude_cHRM=MagickTrue;
11342 mng_info->ping_exclude_date=MagickTrue;
11343 mng_info->ping_exclude_EXIF=MagickTrue;
11344 mng_info->ping_exclude_gAMA=MagickTrue;
11345 mng_info->ping_exclude_iCCP=MagickTrue;
11346 /* mng_info->ping_exclude_iTXt=MagickTrue; */
11347 mng_info->ping_exclude_oFFs=MagickTrue;
11348 mng_info->ping_exclude_pHYs=MagickTrue;
11349 mng_info->ping_exclude_sRGB=MagickTrue;
11350 mng_info->ping_exclude_tEXt=MagickTrue;
11351 mng_info->ping_exclude_tRNS=MagickTrue;
11352 mng_info->ping_exclude_vpAg=MagickTrue;
11353 mng_info->ping_exclude_zCCP=MagickTrue;
11354 mng_info->ping_exclude_zTXt=MagickTrue;
11358 if (LocaleNCompare(value+i,"none",4) == 0)
11360 mng_info->ping_exclude_bKGD=MagickFalse;
11361 mng_info->ping_exclude_cHRM=MagickFalse;
11362 mng_info->ping_exclude_date=MagickFalse;
11363 mng_info->ping_exclude_EXIF=MagickFalse;
11364 mng_info->ping_exclude_gAMA=MagickFalse;
11365 mng_info->ping_exclude_iCCP=MagickFalse;
11366 /* mng_info->ping_exclude_iTXt=MagickFalse; */
11367 mng_info->ping_exclude_oFFs=MagickFalse;
11368 mng_info->ping_exclude_pHYs=MagickFalse;
11369 mng_info->ping_exclude_sRGB=MagickFalse;
11370 mng_info->ping_exclude_tEXt=MagickFalse;
11371 mng_info->ping_exclude_tRNS=MagickFalse;
11372 mng_info->ping_exclude_vpAg=MagickFalse;
11373 mng_info->ping_exclude_zCCP=MagickFalse;
11374 mng_info->ping_exclude_zTXt=MagickFalse;
11377 if (LocaleNCompare(value+i,"bkgd",4) == 0)
11378 mng_info->ping_exclude_bKGD=MagickTrue;
11380 if (LocaleNCompare(value+i,"chrm",4) == 0)
11381 mng_info->ping_exclude_cHRM=MagickTrue;
11383 if (LocaleNCompare(value+i,"date",4) == 0)
11384 mng_info->ping_exclude_date=MagickTrue;
11386 if (LocaleNCompare(value+i,"exif",4) == 0)
11387 mng_info->ping_exclude_EXIF=MagickTrue;
11389 if (LocaleNCompare(value+i,"gama",4) == 0)
11390 mng_info->ping_exclude_gAMA=MagickTrue;
11392 if (LocaleNCompare(value+i,"iccp",4) == 0)
11393 mng_info->ping_exclude_iCCP=MagickTrue;
11396 if (LocaleNCompare(value+i,"itxt",4) == 0)
11397 mng_info->ping_exclude_iTXt=MagickTrue;
11400 if (LocaleNCompare(value+i,"gama",4) == 0)
11401 mng_info->ping_exclude_gAMA=MagickTrue;
11403 if (LocaleNCompare(value+i,"offs",4) == 0)
11404 mng_info->ping_exclude_oFFs=MagickTrue;
11406 if (LocaleNCompare(value+i,"phys",4) == 0)
11407 mng_info->ping_exclude_pHYs=MagickTrue;
11409 if (LocaleNCompare(value+i,"srgb",4) == 0)
11410 mng_info->ping_exclude_sRGB=MagickTrue;
11412 if (LocaleNCompare(value+i,"text",4) == 0)
11413 mng_info->ping_exclude_tEXt=MagickTrue;
11415 if (LocaleNCompare(value+i,"trns",4) == 0)
11416 mng_info->ping_exclude_tRNS=MagickTrue;
11418 if (LocaleNCompare(value+i,"vpag",4) == 0)
11419 mng_info->ping_exclude_vpAg=MagickTrue;
11421 if (LocaleNCompare(value+i,"zccp",4) == 0)
11422 mng_info->ping_exclude_zCCP=MagickTrue;
11424 if (LocaleNCompare(value+i,"ztxt",4) == 0)
11425 mng_info->ping_exclude_zTXt=MagickTrue;
11431 for (source=0; source<1; source++)
11435 value=GetImageArtifact(image,"png:include-chunk");
11438 value=GetImageArtifact(image,"png:include-chunks");
11442 value=GetImageOption(image_info,"png:include-chunk");
11445 value=GetImageOption(image_info,"png:include-chunks");
11453 excluding=MagickTrue;
11455 if (logging != MagickFalse)
11458 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11459 " png:include-chunk=%s found in image artifacts.\n", value);
11461 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11462 " png:include-chunk=%s found in image properties.\n", value);
11465 last=strlen(value);
11467 for (i=0; i<(int) last; i+=5)
11469 if (LocaleNCompare(value+i,"all",3) == 0)
11471 mng_info->ping_exclude_bKGD=MagickFalse;
11472 mng_info->ping_exclude_cHRM=MagickFalse;
11473 mng_info->ping_exclude_date=MagickFalse;
11474 mng_info->ping_exclude_EXIF=MagickFalse;
11475 mng_info->ping_exclude_gAMA=MagickFalse;
11476 mng_info->ping_exclude_iCCP=MagickFalse;
11477 /* mng_info->ping_exclude_iTXt=MagickFalse; */
11478 mng_info->ping_exclude_oFFs=MagickFalse;
11479 mng_info->ping_exclude_pHYs=MagickFalse;
11480 mng_info->ping_exclude_sRGB=MagickFalse;
11481 mng_info->ping_exclude_tEXt=MagickFalse;
11482 mng_info->ping_exclude_tRNS=MagickFalse;
11483 mng_info->ping_exclude_vpAg=MagickFalse;
11484 mng_info->ping_exclude_zCCP=MagickFalse;
11485 mng_info->ping_exclude_zTXt=MagickFalse;
11489 if (LocaleNCompare(value+i,"none",4) == 0)
11491 mng_info->ping_exclude_bKGD=MagickTrue;
11492 mng_info->ping_exclude_cHRM=MagickTrue;
11493 mng_info->ping_exclude_date=MagickTrue;
11494 mng_info->ping_exclude_EXIF=MagickTrue;
11495 mng_info->ping_exclude_gAMA=MagickTrue;
11496 mng_info->ping_exclude_iCCP=MagickTrue;
11497 /* mng_info->ping_exclude_iTXt=MagickTrue; */
11498 mng_info->ping_exclude_oFFs=MagickTrue;
11499 mng_info->ping_exclude_pHYs=MagickTrue;
11500 mng_info->ping_exclude_sRGB=MagickTrue;
11501 mng_info->ping_exclude_tEXt=MagickTrue;
11502 mng_info->ping_exclude_tRNS=MagickTrue;
11503 mng_info->ping_exclude_vpAg=MagickTrue;
11504 mng_info->ping_exclude_zCCP=MagickTrue;
11505 mng_info->ping_exclude_zTXt=MagickTrue;
11508 if (LocaleNCompare(value+i,"bkgd",4) == 0)
11509 mng_info->ping_exclude_bKGD=MagickFalse;
11511 if (LocaleNCompare(value+i,"chrm",4) == 0)
11512 mng_info->ping_exclude_cHRM=MagickFalse;
11514 if (LocaleNCompare(value+i,"date",4) == 0)
11515 mng_info->ping_exclude_date=MagickFalse;
11517 if (LocaleNCompare(value+i,"exif",4) == 0)
11518 mng_info->ping_exclude_EXIF=MagickFalse;
11520 if (LocaleNCompare(value+i,"gama",4) == 0)
11521 mng_info->ping_exclude_gAMA=MagickFalse;
11523 if (LocaleNCompare(value+i,"iccp",4) == 0)
11524 mng_info->ping_exclude_iCCP=MagickFalse;
11527 if (LocaleNCompare(value+i,"itxt",4) == 0)
11528 mng_info->ping_exclude_iTXt=MagickFalse;
11531 if (LocaleNCompare(value+i,"gama",4) == 0)
11532 mng_info->ping_exclude_gAMA=MagickFalse;
11534 if (LocaleNCompare(value+i,"offs",4) == 0)
11535 mng_info->ping_exclude_oFFs=MagickFalse;
11537 if (LocaleNCompare(value+i,"phys",4) == 0)
11538 mng_info->ping_exclude_pHYs=MagickFalse;
11540 if (LocaleNCompare(value+i,"srgb",4) == 0)
11541 mng_info->ping_exclude_sRGB=MagickFalse;
11543 if (LocaleNCompare(value+i,"text",4) == 0)
11544 mng_info->ping_exclude_tEXt=MagickFalse;
11546 if (LocaleNCompare(value+i,"trns",4) == 0)
11547 mng_info->ping_exclude_tRNS=MagickFalse;
11549 if (LocaleNCompare(value+i,"vpag",4) == 0)
11550 mng_info->ping_exclude_vpAg=MagickFalse;
11552 if (LocaleNCompare(value+i,"zccp",4) == 0)
11553 mng_info->ping_exclude_zCCP=MagickFalse;
11555 if (LocaleNCompare(value+i,"ztxt",4) == 0)
11556 mng_info->ping_exclude_zTXt=MagickFalse;
11562 if (excluding != MagickFalse && logging != MagickFalse)
11564 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11565 " Chunks to be excluded from the output png:");
11566 if (mng_info->ping_exclude_bKGD != MagickFalse)
11567 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11569 if (mng_info->ping_exclude_cHRM != MagickFalse)
11570 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11572 if (mng_info->ping_exclude_date != MagickFalse)
11573 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11575 if (mng_info->ping_exclude_EXIF != MagickFalse)
11576 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11578 if (mng_info->ping_exclude_gAMA != MagickFalse)
11579 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11581 if (mng_info->ping_exclude_iCCP != MagickFalse)
11582 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11585 if (mng_info->ping_exclude_iTXt != MagickFalse)
11586 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11589 if (mng_info->ping_exclude_oFFs != MagickFalse)
11590 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11592 if (mng_info->ping_exclude_pHYs != MagickFalse)
11593 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11595 if (mng_info->ping_exclude_sRGB != MagickFalse)
11596 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11598 if (mng_info->ping_exclude_tEXt != MagickFalse)
11599 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11601 if (mng_info->ping_exclude_tRNS != MagickFalse)
11602 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11604 if (mng_info->ping_exclude_vpAg != MagickFalse)
11605 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11607 if (mng_info->ping_exclude_zCCP != MagickFalse)
11608 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11610 if (mng_info->ping_exclude_zTXt != MagickFalse)
11611 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11615 mng_info->need_blob = MagickTrue;
11617 status=WriteOnePNGImage(mng_info,image_info,image,exception);
11619 MngInfoFreeStruct(mng_info,&have_mng_structure);
11621 if (logging != MagickFalse)
11622 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit WritePNGImage()");
11627 #if defined(JNG_SUPPORTED)
11629 /* Write one JNG image */
11630 static MagickBooleanType WriteOneJNGImage(MngInfo *mng_info,
11631 const ImageInfo *image_info,Image *image,ExceptionInfo *exception)
11652 jng_alpha_compression_method,
11653 jng_alpha_sample_depth,
11661 logging=LogMagickEvent(CoderEvent,GetMagickModule(),
11662 " Enter WriteOneJNGImage()");
11664 blob=(unsigned char *) NULL;
11665 jpeg_image=(Image *) NULL;
11666 jpeg_image_info=(ImageInfo *) NULL;
11669 transparent=image_info->type==GrayscaleMatteType ||
11670 image_info->type==TrueColorMatteType || image->matte != MagickFalse;
11672 jng_quality=image_info->quality == 0UL ? 75UL : image_info->quality%1000;
11674 jng_alpha_compression_method=image->compression==JPEGCompression? 8 : 0;
11676 jng_alpha_quality=image_info->quality == 0UL ? 75UL :
11677 image_info->quality;
11679 if (jng_alpha_quality >= 1000)
11680 jng_alpha_quality /= 1000;
11686 /* Create JPEG blob, image, and image_info */
11687 if (logging != MagickFalse)
11688 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11689 " Creating jpeg_image_info for alpha.");
11691 jpeg_image_info=(ImageInfo *) CloneImageInfo(image_info);
11693 if (jpeg_image_info == (ImageInfo *) NULL)
11694 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
11696 if (logging != MagickFalse)
11697 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11698 " Creating jpeg_image.");
11700 jpeg_image=SeparateImage(image,AlphaChannel,exception);
11701 if (jpeg_image == (Image *) NULL)
11702 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
11703 (void) CopyMagickString(jpeg_image->magick,"JPEG",MaxTextExtent);
11704 jpeg_image->matte=MagickFalse;
11705 jpeg_image->quality=jng_alpha_quality;
11706 jpeg_image_info->type=GrayscaleType;
11707 (void) SetImageType(jpeg_image,GrayscaleType,exception);
11708 (void) AcquireUniqueFilename(jpeg_image->filename);
11709 (void) FormatLocaleString(jpeg_image_info->filename,MaxTextExtent,
11710 "%s",jpeg_image->filename);
11714 jng_alpha_compression_method=0;
11716 jng_alpha_sample_depth=0;
11719 /* To do: check bit depth of PNG alpha channel */
11721 /* Check if image is grayscale. */
11722 if (image_info->type != TrueColorMatteType && image_info->type !=
11723 TrueColorType && ImageIsGray(image,exception))
11726 if (logging != MagickFalse)
11728 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11729 " JNG Quality = %d",(int) jng_quality);
11730 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11731 " JNG Color Type = %d",jng_color_type);
11734 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11735 " JNG Alpha Compression = %d",jng_alpha_compression_method);
11736 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11737 " JNG Alpha Depth = %d",jng_alpha_sample_depth);
11738 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11739 " JNG Alpha Quality = %d",(int) jng_alpha_quality);
11745 if (jng_alpha_compression_method==0)
11750 /* Encode alpha as a grayscale PNG blob */
11751 status=OpenBlob(jpeg_image_info,jpeg_image,WriteBinaryBlobMode,
11753 if (logging != MagickFalse)
11754 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11755 " Creating PNG blob.");
11758 (void) CopyMagickString(jpeg_image_info->magick,"PNG",MaxTextExtent);
11759 (void) CopyMagickString(jpeg_image->magick,"PNG",MaxTextExtent);
11760 jpeg_image_info->interlace=NoInterlace;
11762 /* Exclude all ancillary chunks */
11763 (void) SetImageArtifact(jpeg_image,"png:exclude-chunks","all");
11765 blob=ImageToBlob(jpeg_image_info,jpeg_image,&length,
11768 /* Retrieve sample depth used */
11769 value=GetImageProperty(jpeg_image,"png:bit-depth-written",exception);
11770 if (value != (char *) NULL)
11771 jng_alpha_sample_depth= (unsigned int) value[0];
11775 /* Encode alpha as a grayscale JPEG blob */
11777 status=OpenBlob(jpeg_image_info,jpeg_image,WriteBinaryBlobMode,
11780 (void) CopyMagickString(jpeg_image_info->magick,"JPEG",MaxTextExtent);
11781 (void) CopyMagickString(jpeg_image->magick,"JPEG",MaxTextExtent);
11782 jpeg_image_info->interlace=NoInterlace;
11783 if (logging != MagickFalse)
11784 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11785 " Creating blob.");
11786 blob=ImageToBlob(jpeg_image_info,jpeg_image,&length,
11788 jng_alpha_sample_depth=8;
11790 if (logging != MagickFalse)
11791 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11792 " Successfully read jpeg_image into a blob, length=%.20g.",
11796 /* Destroy JPEG image and image_info */
11797 jpeg_image=DestroyImage(jpeg_image);
11798 (void) RelinquishUniqueFileResource(jpeg_image_info->filename);
11799 jpeg_image_info=DestroyImageInfo(jpeg_image_info);
11802 /* Write JHDR chunk */
11803 (void) WriteBlobMSBULong(image,16L); /* chunk data length=16 */
11804 PNGType(chunk,mng_JHDR);
11805 LogPNGChunk(logging,mng_JHDR,16L);
11806 PNGLong(chunk+4,(png_uint_32) image->columns);
11807 PNGLong(chunk+8,(png_uint_32) image->rows);
11808 chunk[12]=jng_color_type;
11809 chunk[13]=8; /* sample depth */
11810 chunk[14]=8; /*jng_image_compression_method */
11811 chunk[15]=(unsigned char) (image_info->interlace == NoInterlace ? 0 : 8);
11812 chunk[16]=jng_alpha_sample_depth;
11813 chunk[17]=jng_alpha_compression_method;
11814 chunk[18]=0; /*jng_alpha_filter_method */
11815 chunk[19]=0; /*jng_alpha_interlace_method */
11816 (void) WriteBlob(image,20,chunk);
11817 (void) WriteBlobMSBULong(image,crc32(0,chunk,20));
11818 if (logging != MagickFalse)
11820 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11821 " JNG width:%15lu",(unsigned long) image->columns);
11823 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11824 " JNG height:%14lu",(unsigned long) image->rows);
11826 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11827 " JNG color type:%10d",jng_color_type);
11829 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11830 " JNG sample depth:%8d",8);
11832 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11833 " JNG compression:%9d",8);
11835 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11836 " JNG interlace:%11d",0);
11838 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11839 " JNG alpha depth:%9d",jng_alpha_sample_depth);
11841 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11842 " JNG alpha compression:%3d",jng_alpha_compression_method);
11844 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11845 " JNG alpha filter:%8d",0);
11847 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11848 " JNG alpha interlace:%5d",0);
11851 /* Write any JNG-chunk-b profiles */
11852 (void) Magick_png_write_chunk_from_profile(image,"JNG-chunk-b",logging);
11855 Write leading ancillary chunks
11861 Write JNG bKGD chunk
11872 if (jng_color_type == 8 || jng_color_type == 12)
11876 (void) WriteBlobMSBULong(image,(size_t) (num_bytes-4L));
11877 PNGType(chunk,mng_bKGD);
11878 LogPNGChunk(logging,mng_bKGD,(size_t) (num_bytes-4L));
11879 red=ScaleQuantumToChar(image->background_color.red);
11880 green=ScaleQuantumToChar(image->background_color.green);
11881 blue=ScaleQuantumToChar(image->background_color.blue);
11888 (void) WriteBlob(image,(size_t) num_bytes,chunk);
11889 (void) WriteBlobMSBULong(image,crc32(0,chunk,(uInt) num_bytes));
11892 if ((image->colorspace == sRGBColorspace || image->rendering_intent))
11895 Write JNG sRGB chunk
11897 (void) WriteBlobMSBULong(image,1L);
11898 PNGType(chunk,mng_sRGB);
11899 LogPNGChunk(logging,mng_sRGB,1L);
11901 if (image->rendering_intent != UndefinedIntent)
11902 chunk[4]=(unsigned char)
11903 Magick_RenderingIntent_to_PNG_RenderingIntent(
11904 (image->rendering_intent));
11907 chunk[4]=(unsigned char)
11908 Magick_RenderingIntent_to_PNG_RenderingIntent(
11909 (PerceptualIntent));
11911 (void) WriteBlob(image,5,chunk);
11912 (void) WriteBlobMSBULong(image,crc32(0,chunk,5));
11916 if (image->gamma != 0.0)
11919 Write JNG gAMA chunk
11921 (void) WriteBlobMSBULong(image,4L);
11922 PNGType(chunk,mng_gAMA);
11923 LogPNGChunk(logging,mng_gAMA,4L);
11924 PNGLong(chunk+4,(png_uint_32) (100000*image->gamma+0.5));
11925 (void) WriteBlob(image,8,chunk);
11926 (void) WriteBlobMSBULong(image,crc32(0,chunk,8));
11929 if ((mng_info->equal_chrms == MagickFalse) &&
11930 (image->chromaticity.red_primary.x != 0.0))
11936 Write JNG cHRM chunk
11938 (void) WriteBlobMSBULong(image,32L);
11939 PNGType(chunk,mng_cHRM);
11940 LogPNGChunk(logging,mng_cHRM,32L);
11941 primary=image->chromaticity.white_point;
11942 PNGLong(chunk+4,(png_uint_32) (100000*primary.x+0.5));
11943 PNGLong(chunk+8,(png_uint_32) (100000*primary.y+0.5));
11944 primary=image->chromaticity.red_primary;
11945 PNGLong(chunk+12,(png_uint_32) (100000*primary.x+0.5));
11946 PNGLong(chunk+16,(png_uint_32) (100000*primary.y+0.5));
11947 primary=image->chromaticity.green_primary;
11948 PNGLong(chunk+20,(png_uint_32) (100000*primary.x+0.5));
11949 PNGLong(chunk+24,(png_uint_32) (100000*primary.y+0.5));
11950 primary=image->chromaticity.blue_primary;
11951 PNGLong(chunk+28,(png_uint_32) (100000*primary.x+0.5));
11952 PNGLong(chunk+32,(png_uint_32) (100000*primary.y+0.5));
11953 (void) WriteBlob(image,36,chunk);
11954 (void) WriteBlobMSBULong(image,crc32(0,chunk,36));
11958 if (image->resolution.x && image->resolution.y && !mng_info->equal_physs)
11961 Write JNG pHYs chunk
11963 (void) WriteBlobMSBULong(image,9L);
11964 PNGType(chunk,mng_pHYs);
11965 LogPNGChunk(logging,mng_pHYs,9L);
11966 if (image->units == PixelsPerInchResolution)
11968 PNGLong(chunk+4,(png_uint_32)
11969 (image->resolution.x*100.0/2.54+0.5));
11971 PNGLong(chunk+8,(png_uint_32)
11972 (image->resolution.y*100.0/2.54+0.5));
11979 if (image->units == PixelsPerCentimeterResolution)
11981 PNGLong(chunk+4,(png_uint_32)
11982 (image->resolution.x*100.0+0.5));
11984 PNGLong(chunk+8,(png_uint_32)
11985 (image->resolution.y*100.0+0.5));
11992 PNGLong(chunk+4,(png_uint_32) (image->resolution.x+0.5));
11993 PNGLong(chunk+8,(png_uint_32) (image->resolution.y+0.5));
11997 (void) WriteBlob(image,13,chunk);
11998 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
12001 if (mng_info->write_mng == 0 && (image->page.x || image->page.y))
12004 Write JNG oFFs chunk
12006 (void) WriteBlobMSBULong(image,9L);
12007 PNGType(chunk,mng_oFFs);
12008 LogPNGChunk(logging,mng_oFFs,9L);
12009 PNGsLong(chunk+4,(ssize_t) (image->page.x));
12010 PNGsLong(chunk+8,(ssize_t) (image->page.y));
12012 (void) WriteBlob(image,13,chunk);
12013 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
12015 if (mng_info->write_mng == 0 && (image->page.width || image->page.height))
12017 (void) WriteBlobMSBULong(image,9L); /* data length=8 */
12018 PNGType(chunk,mng_vpAg);
12019 LogPNGChunk(logging,mng_vpAg,9L);
12020 PNGLong(chunk+4,(png_uint_32) image->page.width);
12021 PNGLong(chunk+8,(png_uint_32) image->page.height);
12022 chunk[12]=0; /* unit = pixels */
12023 (void) WriteBlob(image,13,chunk);
12024 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
12030 if (jng_alpha_compression_method==0)
12038 /* Write IDAT chunk header */
12039 if (logging != MagickFalse)
12040 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12041 " Write IDAT chunks from blob, length=%.20g.",(double)
12044 /* Copy IDAT chunks */
12047 for (i=8; i<(ssize_t) length; i+=len+12)
12049 len=(*p<<24)|((*(p+1))<<16)|((*(p+2))<<8)|(*(p+3));
12052 if (*(p)==73 && *(p+1)==68 && *(p+2)==65 && *(p+3)==84) /* IDAT */
12054 /* Found an IDAT chunk. */
12055 (void) WriteBlobMSBULong(image,(size_t) len);
12056 LogPNGChunk(logging,mng_IDAT,(size_t) len);
12057 (void) WriteBlob(image,(size_t) len+4,p);
12058 (void) WriteBlobMSBULong(image,
12059 crc32(0,p,(uInt) len+4));
12064 if (logging != MagickFalse)
12065 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12066 " Skipping %c%c%c%c chunk, length=%.20g.",
12067 *(p),*(p+1),*(p+2),*(p+3),(double) len);
12074 /* Write JDAA chunk header */
12075 if (logging != MagickFalse)
12076 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12077 " Write JDAA chunk, length=%.20g.",(double) length);
12078 (void) WriteBlobMSBULong(image,(size_t) length);
12079 PNGType(chunk,mng_JDAA);
12080 LogPNGChunk(logging,mng_JDAA,length);
12081 /* Write JDAT chunk(s) data */
12082 (void) WriteBlob(image,4,chunk);
12083 (void) WriteBlob(image,length,blob);
12084 (void) WriteBlobMSBULong(image,crc32(crc32(0,chunk,4),blob,
12087 blob=(unsigned char *) RelinquishMagickMemory(blob);
12090 /* Encode image as a JPEG blob */
12091 if (logging != MagickFalse)
12092 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12093 " Creating jpeg_image_info.");
12094 jpeg_image_info=(ImageInfo *) CloneImageInfo(image_info);
12095 if (jpeg_image_info == (ImageInfo *) NULL)
12096 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
12098 if (logging != MagickFalse)
12099 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12100 " Creating jpeg_image.");
12102 jpeg_image=CloneImage(image,0,0,MagickTrue,exception);
12103 if (jpeg_image == (Image *) NULL)
12104 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
12105 (void) CopyMagickString(jpeg_image->magick,"JPEG",MaxTextExtent);
12107 (void) AcquireUniqueFilename(jpeg_image->filename);
12108 (void) FormatLocaleString(jpeg_image_info->filename,MaxTextExtent,"%s",
12109 jpeg_image->filename);
12111 status=OpenBlob(jpeg_image_info,jpeg_image,WriteBinaryBlobMode,
12114 if (logging != MagickFalse)
12115 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12116 " Created jpeg_image, %.20g x %.20g.",(double) jpeg_image->columns,
12117 (double) jpeg_image->rows);
12119 if (jng_color_type == 8 || jng_color_type == 12)
12120 jpeg_image_info->type=GrayscaleType;
12122 jpeg_image_info->quality=jng_quality;
12123 jpeg_image->quality=jng_quality;
12124 (void) CopyMagickString(jpeg_image_info->magick,"JPEG",MaxTextExtent);
12125 (void) CopyMagickString(jpeg_image->magick,"JPEG",MaxTextExtent);
12127 if (logging != MagickFalse)
12128 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12129 " Creating blob.");
12131 blob=ImageToBlob(jpeg_image_info,jpeg_image,&length,exception);
12133 if (logging != MagickFalse)
12135 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12136 " Successfully read jpeg_image into a blob, length=%.20g.",
12139 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12140 " Write JDAT chunk, length=%.20g.",(double) length);
12143 /* Write JDAT chunk(s) */
12144 (void) WriteBlobMSBULong(image,(size_t) length);
12145 PNGType(chunk,mng_JDAT);
12146 LogPNGChunk(logging,mng_JDAT,length);
12147 (void) WriteBlob(image,4,chunk);
12148 (void) WriteBlob(image,length,blob);
12149 (void) WriteBlobMSBULong(image,crc32(crc32(0,chunk,4),blob,(uInt) length));
12151 jpeg_image=DestroyImage(jpeg_image);
12152 (void) RelinquishUniqueFileResource(jpeg_image_info->filename);
12153 jpeg_image_info=DestroyImageInfo(jpeg_image_info);
12154 blob=(unsigned char *) RelinquishMagickMemory(blob);
12156 /* Write any JNG-chunk-e profiles */
12157 (void) Magick_png_write_chunk_from_profile(image,"JNG-chunk-e",logging);
12159 /* Write IEND chunk */
12160 (void) WriteBlobMSBULong(image,0L);
12161 PNGType(chunk,mng_IEND);
12162 LogPNGChunk(logging,mng_IEND,0);
12163 (void) WriteBlob(image,4,chunk);
12164 (void) WriteBlobMSBULong(image,crc32(0,chunk,4));
12166 if (logging != MagickFalse)
12167 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12168 " exit WriteOneJNGImage()");
12175 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12179 % W r i t e J N G I m a g e %
12183 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12185 % WriteJNGImage() writes a JPEG Network Graphics (JNG) image file.
12187 % JNG support written by Glenn Randers-Pehrson, glennrp@image...
12189 % The format of the WriteJNGImage method is:
12191 % MagickBooleanType WriteJNGImage(const ImageInfo *image_info,
12192 % Image *image,ExceptionInfo *exception)
12194 % A description of each parameter follows:
12196 % o image_info: the image info.
12198 % o image: The image.
12200 % o exception: return any errors or warnings in this structure.
12202 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12204 static MagickBooleanType WriteJNGImage(const ImageInfo *image_info,Image *image,
12205 ExceptionInfo *exception)
12208 have_mng_structure,
12218 assert(image_info != (const ImageInfo *) NULL);
12219 assert(image_info->signature == MagickSignature);
12220 assert(image != (Image *) NULL);
12221 assert(image->signature == MagickSignature);
12222 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
12223 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter WriteJNGImage()");
12224 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
12225 if (status == MagickFalse)
12229 Allocate a MngInfo structure.
12231 have_mng_structure=MagickFalse;
12232 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
12233 if (mng_info == (MngInfo *) NULL)
12234 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
12236 Initialize members of the MngInfo structure.
12238 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
12239 mng_info->image=image;
12240 have_mng_structure=MagickTrue;
12242 (void) WriteBlob(image,8,(const unsigned char *) "\213JNG\r\n\032\n");
12244 status=WriteOneJNGImage(mng_info,image_info,image,exception);
12245 (void) CloseBlob(image);
12247 (void) CatchImageException(image);
12248 MngInfoFreeStruct(mng_info,&have_mng_structure);
12249 if (logging != MagickFalse)
12250 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit WriteJNGImage()");
12255 static MagickBooleanType WriteMNGImage(const ImageInfo *image_info,Image *image,
12256 ExceptionInfo *exception)
12265 have_mng_structure,
12268 volatile MagickBooleanType
12280 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
12281 defined(PNG_MNG_FEATURES_SUPPORTED)
12284 all_images_are_gray,
12294 volatile unsigned int
12305 #if (PNG_LIBPNG_VER < 10200)
12306 if (image_info->verbose)
12307 printf("Your PNG library (libpng-%s) is rather old.\n",
12308 PNG_LIBPNG_VER_STRING);
12314 assert(image_info != (const ImageInfo *) NULL);
12315 assert(image_info->signature == MagickSignature);
12316 assert(image != (Image *) NULL);
12317 assert(image->signature == MagickSignature);
12318 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
12319 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter WriteMNGImage()");
12320 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
12321 if (status == MagickFalse)
12325 Allocate a MngInfo structure.
12327 have_mng_structure=MagickFalse;
12328 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
12329 if (mng_info == (MngInfo *) NULL)
12330 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
12332 Initialize members of the MngInfo structure.
12334 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
12335 mng_info->image=image;
12336 have_mng_structure=MagickTrue;
12337 write_mng=LocaleCompare(image_info->magick,"MNG") == 0;
12340 * See if user has requested a specific PNG subformat to be used
12341 * for all of the PNGs in the MNG being written, e.g.,
12343 * convert *.png png8:animation.mng
12345 * To do: check -define png:bit_depth and png:color_type as well,
12346 * or perhaps use mng:bit_depth and mng:color_type instead for
12350 mng_info->write_png8=LocaleCompare(image_info->magick,"PNG8") == 0;
12351 mng_info->write_png24=LocaleCompare(image_info->magick,"PNG24") == 0;
12352 mng_info->write_png32=LocaleCompare(image_info->magick,"PNG32") == 0;
12354 write_jng=MagickFalse;
12355 if (image_info->compression == JPEGCompression)
12356 write_jng=MagickTrue;
12358 mng_info->adjoin=image_info->adjoin &&
12359 (GetNextImageInList(image) != (Image *) NULL) && write_mng;
12361 if (logging != MagickFalse)
12363 /* Log some info about the input */
12367 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12368 " Checking input image(s)");
12370 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12371 " Image_info depth: %.20g",(double) image_info->depth);
12373 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12374 " Type: %d",image_info->type);
12377 for (p=image; p != (Image *) NULL; p=GetNextImageInList(p))
12379 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12380 " Scene: %.20g",(double) scene++);
12382 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12383 " Image depth: %.20g",(double) p->depth);
12386 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12390 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12393 if (p->storage_class == PseudoClass)
12394 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12395 " Storage class: PseudoClass");
12398 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12399 " Storage class: DirectClass");
12402 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12403 " Number of colors: %.20g",(double) p->colors);
12406 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12407 " Number of colors: unspecified");
12409 if (mng_info->adjoin == MagickFalse)
12414 use_global_plte=MagickFalse;
12415 all_images_are_gray=MagickFalse;
12416 #ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
12417 need_local_plte=MagickTrue;
12419 need_defi=MagickFalse;
12420 need_matte=MagickFalse;
12421 mng_info->framing_mode=1;
12422 mng_info->old_framing_mode=1;
12425 if (image_info->page != (char *) NULL)
12428 Determine image bounding box.
12430 SetGeometry(image,&mng_info->page);
12431 (void) ParseMetaGeometry(image_info->page,&mng_info->page.x,
12432 &mng_info->page.y,&mng_info->page.width,&mng_info->page.height);
12444 mng_info->page=image->page;
12445 need_geom=MagickTrue;
12446 if (mng_info->page.width || mng_info->page.height)
12447 need_geom=MagickFalse;
12449 Check all the scenes.
12451 initial_delay=image->delay;
12452 need_iterations=MagickFalse;
12453 mng_info->equal_chrms=image->chromaticity.red_primary.x != 0.0;
12454 mng_info->equal_physs=MagickTrue,
12455 mng_info->equal_gammas=MagickTrue;
12456 mng_info->equal_srgbs=MagickTrue;
12457 mng_info->equal_backgrounds=MagickTrue;
12459 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
12460 defined(PNG_MNG_FEATURES_SUPPORTED)
12461 all_images_are_gray=MagickTrue;
12462 mng_info->equal_palettes=MagickFalse;
12463 need_local_plte=MagickFalse;
12465 for (next_image=image; next_image != (Image *) NULL; )
12469 if ((next_image->columns+next_image->page.x) > mng_info->page.width)
12470 mng_info->page.width=next_image->columns+next_image->page.x;
12472 if ((next_image->rows+next_image->page.y) > mng_info->page.height)
12473 mng_info->page.height=next_image->rows+next_image->page.y;
12476 if (next_image->page.x || next_image->page.y)
12477 need_defi=MagickTrue;
12479 if (next_image->matte)
12480 need_matte=MagickTrue;
12482 if ((int) next_image->dispose >= BackgroundDispose)
12483 if (next_image->matte || next_image->page.x || next_image->page.y ||
12484 ((next_image->columns < mng_info->page.width) &&
12485 (next_image->rows < mng_info->page.height)))
12486 mng_info->need_fram=MagickTrue;
12488 if (next_image->iterations)
12489 need_iterations=MagickTrue;
12491 final_delay=next_image->delay;
12493 if (final_delay != initial_delay || final_delay > 1UL*
12494 next_image->ticks_per_second)
12495 mng_info->need_fram=1;
12497 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
12498 defined(PNG_MNG_FEATURES_SUPPORTED)
12500 check for global palette possibility.
12502 if (image->matte != MagickFalse)
12503 need_local_plte=MagickTrue;
12505 if (need_local_plte == 0)
12507 if (ImageIsGray(image,exception) == MagickFalse)
12508 all_images_are_gray=MagickFalse;
12509 mng_info->equal_palettes=PalettesAreEqual(image,next_image);
12510 if (use_global_plte == 0)
12511 use_global_plte=mng_info->equal_palettes;
12512 need_local_plte=!mng_info->equal_palettes;
12515 if (GetNextImageInList(next_image) != (Image *) NULL)
12517 if (next_image->background_color.red !=
12518 next_image->next->background_color.red ||
12519 next_image->background_color.green !=
12520 next_image->next->background_color.green ||
12521 next_image->background_color.blue !=
12522 next_image->next->background_color.blue)
12523 mng_info->equal_backgrounds=MagickFalse;
12525 if (next_image->gamma != next_image->next->gamma)
12526 mng_info->equal_gammas=MagickFalse;
12528 if (next_image->rendering_intent !=
12529 next_image->next->rendering_intent)
12530 mng_info->equal_srgbs=MagickFalse;
12532 if ((next_image->units != next_image->next->units) ||
12533 (next_image->resolution.x != next_image->next->resolution.x) ||
12534 (next_image->resolution.y != next_image->next->resolution.y))
12535 mng_info->equal_physs=MagickFalse;
12537 if (mng_info->equal_chrms)
12539 if (next_image->chromaticity.red_primary.x !=
12540 next_image->next->chromaticity.red_primary.x ||
12541 next_image->chromaticity.red_primary.y !=
12542 next_image->next->chromaticity.red_primary.y ||
12543 next_image->chromaticity.green_primary.x !=
12544 next_image->next->chromaticity.green_primary.x ||
12545 next_image->chromaticity.green_primary.y !=
12546 next_image->next->chromaticity.green_primary.y ||
12547 next_image->chromaticity.blue_primary.x !=
12548 next_image->next->chromaticity.blue_primary.x ||
12549 next_image->chromaticity.blue_primary.y !=
12550 next_image->next->chromaticity.blue_primary.y ||
12551 next_image->chromaticity.white_point.x !=
12552 next_image->next->chromaticity.white_point.x ||
12553 next_image->chromaticity.white_point.y !=
12554 next_image->next->chromaticity.white_point.y)
12555 mng_info->equal_chrms=MagickFalse;
12559 next_image=GetNextImageInList(next_image);
12561 if (image_count < 2)
12563 mng_info->equal_backgrounds=MagickFalse;
12564 mng_info->equal_chrms=MagickFalse;
12565 mng_info->equal_gammas=MagickFalse;
12566 mng_info->equal_srgbs=MagickFalse;
12567 mng_info->equal_physs=MagickFalse;
12568 use_global_plte=MagickFalse;
12569 #ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
12570 need_local_plte=MagickTrue;
12572 need_iterations=MagickFalse;
12575 if (mng_info->need_fram == MagickFalse)
12578 Only certain framing rates 100/n are exactly representable without
12579 the FRAM chunk but we'll allow some slop in VLC files
12581 if (final_delay == 0)
12583 if (need_iterations != MagickFalse)
12586 It's probably a GIF with loop; don't run it *too* fast.
12588 if (mng_info->adjoin)
12591 (void) ThrowMagickException(exception,GetMagickModule(),
12593 "input has zero delay between all frames; assuming",
12598 mng_info->ticks_per_second=0;
12600 if (final_delay != 0)
12601 mng_info->ticks_per_second=(png_uint_32)
12602 (image->ticks_per_second/final_delay);
12603 if (final_delay > 50)
12604 mng_info->ticks_per_second=2;
12606 if (final_delay > 75)
12607 mng_info->ticks_per_second=1;
12609 if (final_delay > 125)
12610 mng_info->need_fram=MagickTrue;
12612 if (need_defi && final_delay > 2 && (final_delay != 4) &&
12613 (final_delay != 5) && (final_delay != 10) && (final_delay != 20) &&
12614 (final_delay != 25) && (final_delay != 50) && (final_delay !=
12615 1UL*image->ticks_per_second))
12616 mng_info->need_fram=MagickTrue; /* make it exact; cannot be VLC */
12619 if (mng_info->need_fram != MagickFalse)
12620 mng_info->ticks_per_second=1UL*image->ticks_per_second;
12622 If pseudocolor, we should also check to see if all the
12623 palettes are identical and write a global PLTE if they are.
12627 Write the MNG version 1.0 signature and MHDR chunk.
12629 (void) WriteBlob(image,8,(const unsigned char *) "\212MNG\r\n\032\n");
12630 (void) WriteBlobMSBULong(image,28L); /* chunk data length=28 */
12631 PNGType(chunk,mng_MHDR);
12632 LogPNGChunk(logging,mng_MHDR,28L);
12633 PNGLong(chunk+4,(png_uint_32) mng_info->page.width);
12634 PNGLong(chunk+8,(png_uint_32) mng_info->page.height);
12635 PNGLong(chunk+12,mng_info->ticks_per_second);
12636 PNGLong(chunk+16,0L); /* layer count=unknown */
12637 PNGLong(chunk+20,0L); /* frame count=unknown */
12638 PNGLong(chunk+24,0L); /* play time=unknown */
12643 if (need_defi || mng_info->need_fram || use_global_plte)
12644 PNGLong(chunk+28,27L); /* simplicity=LC+JNG */
12647 PNGLong(chunk+28,25L); /* simplicity=VLC+JNG */
12652 if (need_defi || mng_info->need_fram || use_global_plte)
12653 PNGLong(chunk+28,19L); /* simplicity=LC+JNG, no transparency */
12656 PNGLong(chunk+28,17L); /* simplicity=VLC+JNG, no transparency */
12664 if (need_defi || mng_info->need_fram || use_global_plte)
12665 PNGLong(chunk+28,11L); /* simplicity=LC */
12668 PNGLong(chunk+28,9L); /* simplicity=VLC */
12673 if (need_defi || mng_info->need_fram || use_global_plte)
12674 PNGLong(chunk+28,3L); /* simplicity=LC, no transparency */
12677 PNGLong(chunk+28,1L); /* simplicity=VLC, no transparency */
12680 (void) WriteBlob(image,32,chunk);
12681 (void) WriteBlobMSBULong(image,crc32(0,chunk,32));
12682 option=GetImageOption(image_info,"mng:need-cacheoff");
12683 if (option != (const char *) NULL)
12689 Write "nEED CACHEOFF" to turn playback caching off for streaming MNG.
12691 PNGType(chunk,mng_nEED);
12692 length=CopyMagickString((char *) chunk+4,"CACHEOFF",20);
12693 (void) WriteBlobMSBULong(image,(size_t) length);
12694 LogPNGChunk(logging,mng_nEED,(size_t) length);
12696 (void) WriteBlob(image,length,chunk);
12697 (void) WriteBlobMSBULong(image,crc32(0,chunk,(uInt) length));
12699 if ((GetPreviousImageInList(image) == (Image *) NULL) &&
12700 (GetNextImageInList(image) != (Image *) NULL) &&
12701 (image->iterations != 1))
12704 Write MNG TERM chunk
12706 (void) WriteBlobMSBULong(image,10L); /* data length=10 */
12707 PNGType(chunk,mng_TERM);
12708 LogPNGChunk(logging,mng_TERM,10L);
12709 chunk[4]=3; /* repeat animation */
12710 chunk[5]=0; /* show last frame when done */
12711 PNGLong(chunk+6,(png_uint_32) (mng_info->ticks_per_second*
12712 final_delay/MagickMax(image->ticks_per_second,1)));
12714 if (image->iterations == 0)
12715 PNGLong(chunk+10,PNG_UINT_31_MAX);
12718 PNGLong(chunk+10,(png_uint_32) image->iterations);
12720 if (logging != MagickFalse)
12722 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12723 " TERM delay: %.20g",(double) (mng_info->ticks_per_second*
12724 final_delay/MagickMax(image->ticks_per_second,1)));
12726 if (image->iterations == 0)
12727 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12728 " TERM iterations: %.20g",(double) PNG_UINT_31_MAX);
12731 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12732 " Image iterations: %.20g",(double) image->iterations);
12734 (void) WriteBlob(image,14,chunk);
12735 (void) WriteBlobMSBULong(image,crc32(0,chunk,14));
12738 To do: check for cHRM+gAMA == sRGB, and write sRGB instead.
12740 if ((image->colorspace == sRGBColorspace || image->rendering_intent) &&
12741 mng_info->equal_srgbs)
12744 Write MNG sRGB chunk
12746 (void) WriteBlobMSBULong(image,1L);
12747 PNGType(chunk,mng_sRGB);
12748 LogPNGChunk(logging,mng_sRGB,1L);
12750 if (image->rendering_intent != UndefinedIntent)
12751 chunk[4]=(unsigned char)
12752 Magick_RenderingIntent_to_PNG_RenderingIntent(
12753 (image->rendering_intent));
12756 chunk[4]=(unsigned char)
12757 Magick_RenderingIntent_to_PNG_RenderingIntent(
12758 (PerceptualIntent));
12760 (void) WriteBlob(image,5,chunk);
12761 (void) WriteBlobMSBULong(image,crc32(0,chunk,5));
12762 mng_info->have_write_global_srgb=MagickTrue;
12767 if (image->gamma && mng_info->equal_gammas)
12770 Write MNG gAMA chunk
12772 (void) WriteBlobMSBULong(image,4L);
12773 PNGType(chunk,mng_gAMA);
12774 LogPNGChunk(logging,mng_gAMA,4L);
12775 PNGLong(chunk+4,(png_uint_32) (100000*image->gamma+0.5));
12776 (void) WriteBlob(image,8,chunk);
12777 (void) WriteBlobMSBULong(image,crc32(0,chunk,8));
12778 mng_info->have_write_global_gama=MagickTrue;
12780 if (mng_info->equal_chrms)
12786 Write MNG cHRM chunk
12788 (void) WriteBlobMSBULong(image,32L);
12789 PNGType(chunk,mng_cHRM);
12790 LogPNGChunk(logging,mng_cHRM,32L);
12791 primary=image->chromaticity.white_point;
12792 PNGLong(chunk+4,(png_uint_32) (100000*primary.x+0.5));
12793 PNGLong(chunk+8,(png_uint_32) (100000*primary.y+0.5));
12794 primary=image->chromaticity.red_primary;
12795 PNGLong(chunk+12,(png_uint_32) (100000*primary.x+0.5));
12796 PNGLong(chunk+16,(png_uint_32) (100000*primary.y+0.5));
12797 primary=image->chromaticity.green_primary;
12798 PNGLong(chunk+20,(png_uint_32) (100000*primary.x+0.5));
12799 PNGLong(chunk+24,(png_uint_32) (100000*primary.y+0.5));
12800 primary=image->chromaticity.blue_primary;
12801 PNGLong(chunk+28,(png_uint_32) (100000*primary.x+0.5));
12802 PNGLong(chunk+32,(png_uint_32) (100000*primary.y+0.5));
12803 (void) WriteBlob(image,36,chunk);
12804 (void) WriteBlobMSBULong(image,crc32(0,chunk,36));
12805 mng_info->have_write_global_chrm=MagickTrue;
12808 if (image->resolution.x && image->resolution.y && mng_info->equal_physs)
12811 Write MNG pHYs chunk
12813 (void) WriteBlobMSBULong(image,9L);
12814 PNGType(chunk,mng_pHYs);
12815 LogPNGChunk(logging,mng_pHYs,9L);
12817 if (image->units == PixelsPerInchResolution)
12819 PNGLong(chunk+4,(png_uint_32)
12820 (image->resolution.x*100.0/2.54+0.5));
12822 PNGLong(chunk+8,(png_uint_32)
12823 (image->resolution.y*100.0/2.54+0.5));
12830 if (image->units == PixelsPerCentimeterResolution)
12832 PNGLong(chunk+4,(png_uint_32)
12833 (image->resolution.x*100.0+0.5));
12835 PNGLong(chunk+8,(png_uint_32)
12836 (image->resolution.y*100.0+0.5));
12843 PNGLong(chunk+4,(png_uint_32) (image->resolution.x+0.5));
12844 PNGLong(chunk+8,(png_uint_32) (image->resolution.y+0.5));
12848 (void) WriteBlob(image,13,chunk);
12849 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
12852 Write MNG BACK chunk and global bKGD chunk, if the image is transparent
12853 or does not cover the entire frame.
12855 if (write_mng && (image->matte || image->page.x > 0 ||
12856 image->page.y > 0 || (image->page.width &&
12857 (image->page.width+image->page.x < mng_info->page.width))
12858 || (image->page.height && (image->page.height+image->page.y
12859 < mng_info->page.height))))
12861 (void) WriteBlobMSBULong(image,6L);
12862 PNGType(chunk,mng_BACK);
12863 LogPNGChunk(logging,mng_BACK,6L);
12864 red=ScaleQuantumToShort(image->background_color.red);
12865 green=ScaleQuantumToShort(image->background_color.green);
12866 blue=ScaleQuantumToShort(image->background_color.blue);
12867 PNGShort(chunk+4,red);
12868 PNGShort(chunk+6,green);
12869 PNGShort(chunk+8,blue);
12870 (void) WriteBlob(image,10,chunk);
12871 (void) WriteBlobMSBULong(image,crc32(0,chunk,10));
12872 if (mng_info->equal_backgrounds)
12874 (void) WriteBlobMSBULong(image,6L);
12875 PNGType(chunk,mng_bKGD);
12876 LogPNGChunk(logging,mng_bKGD,6L);
12877 (void) WriteBlob(image,10,chunk);
12878 (void) WriteBlobMSBULong(image,crc32(0,chunk,10));
12882 #ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
12883 if ((need_local_plte == MagickFalse) &&
12884 (image->storage_class == PseudoClass) &&
12885 (all_images_are_gray == MagickFalse))
12891 Write MNG PLTE chunk
12893 data_length=3*image->colors;
12894 (void) WriteBlobMSBULong(image,data_length);
12895 PNGType(chunk,mng_PLTE);
12896 LogPNGChunk(logging,mng_PLTE,data_length);
12898 for (i=0; i < (ssize_t) image->colors; i++)
12900 chunk[4+i*3]=(unsigned char) (ScaleQuantumToChar(
12901 image->colormap[i].red) & 0xff);
12902 chunk[5+i*3]=(unsigned char) (ScaleQuantumToChar(
12903 image->colormap[i].green) & 0xff);
12904 chunk[6+i*3]=(unsigned char) (ScaleQuantumToChar(
12905 image->colormap[i].blue) & 0xff);
12908 (void) WriteBlob(image,data_length+4,chunk);
12909 (void) WriteBlobMSBULong(image,crc32(0,chunk,(uInt) (data_length+4)));
12910 mng_info->have_write_global_plte=MagickTrue;
12916 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
12917 defined(PNG_MNG_FEATURES_SUPPORTED)
12918 mng_info->equal_palettes=MagickFalse;
12922 if (mng_info->adjoin)
12924 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
12925 defined(PNG_MNG_FEATURES_SUPPORTED)
12927 If we aren't using a global palette for the entire MNG, check to
12928 see if we can use one for two or more consecutive images.
12930 if (need_local_plte && use_global_plte && !all_images_are_gray)
12932 if (mng_info->IsPalette)
12935 When equal_palettes is true, this image has the same palette
12936 as the previous PseudoClass image
12938 mng_info->have_write_global_plte=mng_info->equal_palettes;
12939 mng_info->equal_palettes=PalettesAreEqual(image,image->next);
12940 if (mng_info->equal_palettes && !mng_info->have_write_global_plte)
12943 Write MNG PLTE chunk
12948 data_length=3*image->colors;
12949 (void) WriteBlobMSBULong(image,data_length);
12950 PNGType(chunk,mng_PLTE);
12951 LogPNGChunk(logging,mng_PLTE,data_length);
12953 for (i=0; i < (ssize_t) image->colors; i++)
12955 chunk[4+i*3]=ScaleQuantumToChar(image->colormap[i].red);
12956 chunk[5+i*3]=ScaleQuantumToChar(image->colormap[i].green);
12957 chunk[6+i*3]=ScaleQuantumToChar(image->colormap[i].blue);
12960 (void) WriteBlob(image,data_length+4,chunk);
12961 (void) WriteBlobMSBULong(image,crc32(0,chunk,
12962 (uInt) (data_length+4)));
12963 mng_info->have_write_global_plte=MagickTrue;
12967 mng_info->have_write_global_plte=MagickFalse;
12978 previous_x=mng_info->page.x;
12979 previous_y=mng_info->page.y;
12986 mng_info->page=image->page;
12987 if ((mng_info->page.x != previous_x) ||
12988 (mng_info->page.y != previous_y))
12990 (void) WriteBlobMSBULong(image,12L); /* data length=12 */
12991 PNGType(chunk,mng_DEFI);
12992 LogPNGChunk(logging,mng_DEFI,12L);
12993 chunk[4]=0; /* object 0 MSB */
12994 chunk[5]=0; /* object 0 LSB */
12995 chunk[6]=0; /* visible */
12996 chunk[7]=0; /* abstract */
12997 PNGLong(chunk+8,(png_uint_32) mng_info->page.x);
12998 PNGLong(chunk+12,(png_uint_32) mng_info->page.y);
12999 (void) WriteBlob(image,16,chunk);
13000 (void) WriteBlobMSBULong(image,crc32(0,chunk,16));
13005 mng_info->write_mng=write_mng;
13007 if ((int) image->dispose >= 3)
13008 mng_info->framing_mode=3;
13010 if (mng_info->need_fram && mng_info->adjoin &&
13011 ((image->delay != mng_info->delay) ||
13012 (mng_info->framing_mode != mng_info->old_framing_mode)))
13014 if (image->delay == mng_info->delay)
13017 Write a MNG FRAM chunk with the new framing mode.
13019 (void) WriteBlobMSBULong(image,1L); /* data length=1 */
13020 PNGType(chunk,mng_FRAM);
13021 LogPNGChunk(logging,mng_FRAM,1L);
13022 chunk[4]=(unsigned char) mng_info->framing_mode;
13023 (void) WriteBlob(image,5,chunk);
13024 (void) WriteBlobMSBULong(image,crc32(0,chunk,5));
13029 Write a MNG FRAM chunk with the delay.
13031 (void) WriteBlobMSBULong(image,10L); /* data length=10 */
13032 PNGType(chunk,mng_FRAM);
13033 LogPNGChunk(logging,mng_FRAM,10L);
13034 chunk[4]=(unsigned char) mng_info->framing_mode;
13035 chunk[5]=0; /* frame name separator (no name) */
13036 chunk[6]=2; /* flag for changing default delay */
13037 chunk[7]=0; /* flag for changing frame timeout */
13038 chunk[8]=0; /* flag for changing frame clipping */
13039 chunk[9]=0; /* flag for changing frame sync_id */
13040 PNGLong(chunk+10,(png_uint_32)
13041 ((mng_info->ticks_per_second*
13042 image->delay)/MagickMax(image->ticks_per_second,1)));
13043 (void) WriteBlob(image,14,chunk);
13044 (void) WriteBlobMSBULong(image,crc32(0,chunk,14));
13045 mng_info->delay=(png_uint_32) image->delay;
13047 mng_info->old_framing_mode=mng_info->framing_mode;
13050 #if defined(JNG_SUPPORTED)
13051 if (image_info->compression == JPEGCompression)
13056 if (logging != MagickFalse)
13057 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
13058 " Writing JNG object.");
13059 /* To do: specify the desired alpha compression method. */
13060 write_info=CloneImageInfo(image_info);
13061 write_info->compression=UndefinedCompression;
13062 status=WriteOneJNGImage(mng_info,write_info,image,exception);
13063 write_info=DestroyImageInfo(write_info);
13068 if (logging != MagickFalse)
13069 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
13070 " Writing PNG object.");
13072 mng_info->need_blob = MagickFalse;
13073 mng_info->ping_preserve_colormap = MagickFalse;
13075 /* We don't want any ancillary chunks written */
13076 mng_info->ping_exclude_bKGD=MagickTrue;
13077 mng_info->ping_exclude_cHRM=MagickTrue;
13078 mng_info->ping_exclude_date=MagickTrue;
13079 mng_info->ping_exclude_EXIF=MagickTrue;
13080 mng_info->ping_exclude_gAMA=MagickTrue;
13081 mng_info->ping_exclude_iCCP=MagickTrue;
13082 /* mng_info->ping_exclude_iTXt=MagickTrue; */
13083 mng_info->ping_exclude_oFFs=MagickTrue;
13084 mng_info->ping_exclude_pHYs=MagickTrue;
13085 mng_info->ping_exclude_sRGB=MagickTrue;
13086 mng_info->ping_exclude_tEXt=MagickTrue;
13087 mng_info->ping_exclude_tRNS=MagickTrue;
13088 mng_info->ping_exclude_vpAg=MagickTrue;
13089 mng_info->ping_exclude_zCCP=MagickTrue;
13090 mng_info->ping_exclude_zTXt=MagickTrue;
13092 status=WriteOnePNGImage(mng_info,image_info,image,exception);
13095 if (status == MagickFalse)
13097 MngInfoFreeStruct(mng_info,&have_mng_structure);
13098 (void) CloseBlob(image);
13099 return(MagickFalse);
13101 (void) CatchImageException(image);
13102 if (GetNextImageInList(image) == (Image *) NULL)
13104 image=SyncNextImageInList(image);
13105 status=SetImageProgress(image,SaveImagesTag,scene++,
13106 GetImageListLength(image));
13108 if (status == MagickFalse)
13111 } while (mng_info->adjoin);
13115 while (GetPreviousImageInList(image) != (Image *) NULL)
13116 image=GetPreviousImageInList(image);
13118 Write the MEND chunk.
13120 (void) WriteBlobMSBULong(image,0x00000000L);
13121 PNGType(chunk,mng_MEND);
13122 LogPNGChunk(logging,mng_MEND,0L);
13123 (void) WriteBlob(image,4,chunk);
13124 (void) WriteBlobMSBULong(image,crc32(0,chunk,4));
13127 Relinquish resources.
13129 (void) CloseBlob(image);
13130 MngInfoFreeStruct(mng_info,&have_mng_structure);
13132 if (logging != MagickFalse)
13133 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit WriteMNGImage()");
13135 return(MagickTrue);
13137 #else /* PNG_LIBPNG_VER > 10011 */
13139 static MagickBooleanType WritePNGImage(const ImageInfo *image_info,Image *image)
13142 printf("Your PNG library is too old: You have libpng-%s\n",
13143 PNG_LIBPNG_VER_STRING);
13145 ThrowBinaryException(CoderError,"PNG library is too old",
13146 image_info->filename);
13149 static MagickBooleanType WriteMNGImage(const ImageInfo *image_info,Image *image)
13151 return(WritePNGImage(image_info,image));
13153 #endif /* PNG_LIBPNG_VER > 10011 */