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)
1135 Magick_ColorType_from_PNG_ColorType(const int ping_colortype)
1137 switch (ping_colortype)
1155 return "UndefinedColorType";
1160 static inline ssize_t MagickMin(const ssize_t x,const ssize_t y)
1167 #endif /* PNG_LIBPNG_VER > 10011 */
1168 #endif /* MAGICKCORE_PNG_DELEGATE */
1171 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1179 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1181 % IsMNG() returns MagickTrue if the image format type, identified by the
1182 % magick string, is MNG.
1184 % The format of the IsMNG method is:
1186 % MagickBooleanType IsMNG(const unsigned char *magick,const size_t length)
1188 % A description of each parameter follows:
1190 % o magick: compare image format pattern against these bytes.
1192 % o length: Specifies the length of the magick string.
1196 static MagickBooleanType IsMNG(const unsigned char *magick,const size_t length)
1199 return(MagickFalse);
1201 if (memcmp(magick,"\212MNG\r\n\032\n",8) == 0)
1204 return(MagickFalse);
1208 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1216 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1218 % IsJNG() returns MagickTrue if the image format type, identified by the
1219 % magick string, is JNG.
1221 % The format of the IsJNG method is:
1223 % MagickBooleanType IsJNG(const unsigned char *magick,const size_t length)
1225 % A description of each parameter follows:
1227 % o magick: compare image format pattern against these bytes.
1229 % o length: Specifies the length of the magick string.
1233 static MagickBooleanType IsJNG(const unsigned char *magick,const size_t length)
1236 return(MagickFalse);
1238 if (memcmp(magick,"\213JNG\r\n\032\n",8) == 0)
1241 return(MagickFalse);
1245 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1253 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1255 % IsPNG() returns MagickTrue if the image format type, identified by the
1256 % magick string, is PNG.
1258 % The format of the IsPNG method is:
1260 % MagickBooleanType IsPNG(const unsigned char *magick,const size_t length)
1262 % A description of each parameter follows:
1264 % o magick: compare image format pattern against these bytes.
1266 % o length: Specifies the length of the magick string.
1269 static MagickBooleanType IsPNG(const unsigned char *magick,const size_t length)
1272 return(MagickFalse);
1274 if (memcmp(magick,"\211PNG\r\n\032\n",8) == 0)
1277 return(MagickFalse);
1280 #if defined(MAGICKCORE_PNG_DELEGATE)
1281 #if defined(__cplusplus) || defined(c_plusplus)
1285 #if (PNG_LIBPNG_VER > 10011)
1286 static size_t WriteBlobMSBULong(Image *image,const size_t value)
1291 assert(image != (Image *) NULL);
1292 assert(image->signature == MagickSignature);
1293 buffer[0]=(unsigned char) (value >> 24);
1294 buffer[1]=(unsigned char) (value >> 16);
1295 buffer[2]=(unsigned char) (value >> 8);
1296 buffer[3]=(unsigned char) value;
1297 return((size_t) WriteBlob(image,4,buffer));
1300 static void PNGLong(png_bytep p,png_uint_32 value)
1302 *p++=(png_byte) ((value >> 24) & 0xff);
1303 *p++=(png_byte) ((value >> 16) & 0xff);
1304 *p++=(png_byte) ((value >> 8) & 0xff);
1305 *p++=(png_byte) (value & 0xff);
1308 #if defined(JNG_SUPPORTED)
1309 static void PNGsLong(png_bytep p,png_int_32 value)
1311 *p++=(png_byte) ((value >> 24) & 0xff);
1312 *p++=(png_byte) ((value >> 16) & 0xff);
1313 *p++=(png_byte) ((value >> 8) & 0xff);
1314 *p++=(png_byte) (value & 0xff);
1318 static void PNGShort(png_bytep p,png_uint_16 value)
1320 *p++=(png_byte) ((value >> 8) & 0xff);
1321 *p++=(png_byte) (value & 0xff);
1324 static void PNGType(png_bytep p,png_bytep type)
1326 (void) CopyMagickMemory(p,type,4*sizeof(png_byte));
1329 static void LogPNGChunk(MagickBooleanType logging, png_bytep type,
1332 if (logging != MagickFalse)
1333 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1334 " Writing %c%c%c%c chunk, length: %.20g",
1335 type[0],type[1],type[2],type[3],(double) length);
1337 #endif /* PNG_LIBPNG_VER > 10011 */
1339 #if defined(__cplusplus) || defined(c_plusplus)
1343 #if PNG_LIBPNG_VER > 10011
1345 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1349 % R e a d P N G I m a g e %
1353 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1355 % ReadPNGImage() reads a Portable Network Graphics (PNG) or
1356 % Multiple-image Network Graphics (MNG) image file and returns it. It
1357 % allocates the memory necessary for the new Image structure and returns a
1358 % pointer to the new image or set of images.
1360 % MNG support written by Glenn Randers-Pehrson, glennrp@image...
1362 % The format of the ReadPNGImage method is:
1364 % Image *ReadPNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
1366 % A description of each parameter follows:
1368 % o image_info: the image info.
1370 % o exception: return any errors or warnings in this structure.
1372 % To do, more or less in chronological order (as of version 5.5.2,
1373 % November 26, 2002 -- glennrp -- see also "To do" under WriteMNGImage):
1375 % Get 16-bit cheap transparency working.
1377 % (At this point, PNG decoding is supposed to be in full MNG-LC compliance)
1379 % Preserve all unknown and not-yet-handled known chunks found in input
1380 % PNG file and copy them into output PNG files according to the PNG
1383 % (At this point, PNG encoding should be in full MNG compliance)
1385 % Provide options for choice of background to use when the MNG BACK
1386 % chunk is not present or is not mandatory (i.e., leave transparent,
1387 % user specified, MNG BACK, PNG bKGD)
1389 % Implement LOOP/ENDL [done, but could do discretionary loops more
1390 % efficiently by linking in the duplicate frames.].
1392 % Decode and act on the MHDR simplicity profile (offer option to reject
1393 % files or attempt to process them anyway when the profile isn't LC or VLC).
1395 % Upgrade to full MNG without Delta-PNG.
1397 % o BACK [done a while ago except for background image ID]
1398 % o MOVE [done 15 May 1999]
1399 % o CLIP [done 15 May 1999]
1400 % o DISC [done 19 May 1999]
1401 % o SAVE [partially done 19 May 1999 (marks objects frozen)]
1402 % o SEEK [partially done 19 May 1999 (discard function only)]
1406 % o MNG-level tEXt/iTXt/zTXt
1411 % o iTXt (wait for libpng implementation).
1413 % Use the scene signature to discover when an identical scene is
1414 % being reused, and just point to the original image->exception instead
1415 % of storing another set of pixels. This not specific to MNG
1416 % but could be applied generally.
1418 % Upgrade to full MNG with Delta-PNG.
1420 % JNG tEXt/iTXt/zTXt
1422 % We will not attempt to read files containing the CgBI chunk.
1423 % They are really Xcode files meant for display on the iPhone.
1424 % These are not valid PNG files and it is impossible to recover
1425 % the original PNG from files that have been converted to Xcode-PNG,
1426 % since irretrievable loss of color data has occurred due to the
1427 % use of premultiplied alpha.
1430 #if defined(__cplusplus) || defined(c_plusplus)
1435 This the function that does the actual reading of data. It is
1436 the same as the one supplied in libpng, except that it receives the
1437 datastream from the ReadBlob() function instead of standard input.
1439 static void png_get_data(png_structp png_ptr,png_bytep data,png_size_t length)
1444 image=(Image *) png_get_io_ptr(png_ptr);
1450 check=(png_size_t) ReadBlob(image,(size_t) length,data);
1451 if (check != length)
1456 (void) FormatLocaleString(msg,MaxTextExtent,
1457 "Expected %.20g bytes; found %.20g bytes",(double) length,
1459 png_warning(png_ptr,msg);
1460 png_error(png_ptr,"Read Exception");
1465 #if !defined(PNG_READ_EMPTY_PLTE_SUPPORTED) && \
1466 !defined(PNG_MNG_FEATURES_SUPPORTED)
1467 /* We use mng_get_data() instead of png_get_data() if we have a libpng
1468 * older than libpng-1.0.3a, which was the first to allow the empty
1469 * PLTE, or a newer libpng in which PNG_MNG_FEATURES_SUPPORTED was
1470 * ifdef'ed out. Earlier versions would crash if the bKGD chunk was
1471 * encountered after an empty PLTE, so we have to look ahead for bKGD
1472 * chunks and remove them from the datastream that is passed to libpng,
1473 * and store their contents for later use.
1475 static void mng_get_data(png_structp png_ptr,png_bytep data,png_size_t length)
1490 mng_info=(MngInfo *) png_get_io_ptr(png_ptr);
1491 image=(Image *) mng_info->image;
1492 while (mng_info->bytes_in_read_buffer && length)
1494 data[i]=mng_info->read_buffer[i];
1495 mng_info->bytes_in_read_buffer--;
1501 check=(png_size_t) ReadBlob(image,(size_t) length,(char *) data);
1503 if (check != length)
1504 png_error(png_ptr,"Read Exception");
1508 if ((data[0] == 0) && (data[1] == 0) && (data[2] == 0) &&
1511 check=(png_size_t) ReadBlob(image,(size_t) length,
1512 (char *) mng_info->read_buffer);
1513 mng_info->read_buffer[4]=0;
1514 mng_info->bytes_in_read_buffer=4;
1515 if (memcmp(mng_info->read_buffer,mng_PLTE,4) == 0)
1516 mng_info->found_empty_plte=MagickTrue;
1517 if (memcmp(mng_info->read_buffer,mng_IEND,4) == 0)
1519 mng_info->found_empty_plte=MagickFalse;
1520 mng_info->have_saved_bkgd_index=MagickFalse;
1524 if ((data[0] == 0) && (data[1] == 0) && (data[2] == 0) &&
1527 check=(png_size_t) ReadBlob(image,(size_t) length,
1528 (char *) mng_info->read_buffer);
1529 mng_info->read_buffer[4]=0;
1530 mng_info->bytes_in_read_buffer=4;
1531 if (memcmp(mng_info->read_buffer,mng_bKGD,4) == 0)
1532 if (mng_info->found_empty_plte)
1535 Skip the bKGD data byte and CRC.
1538 ReadBlob(image,5,(char *) mng_info->read_buffer);
1539 check=(png_size_t) ReadBlob(image,(size_t) length,
1540 (char *) mng_info->read_buffer);
1541 mng_info->saved_bkgd_index=mng_info->read_buffer[0];
1542 mng_info->have_saved_bkgd_index=MagickTrue;
1543 mng_info->bytes_in_read_buffer=0;
1551 static void png_put_data(png_structp png_ptr,png_bytep data,png_size_t length)
1556 image=(Image *) png_get_io_ptr(png_ptr);
1562 check=(png_size_t) WriteBlob(image,(size_t) length,data);
1564 if (check != length)
1565 png_error(png_ptr,"WriteBlob Failed");
1569 static void png_flush_data(png_structp png_ptr)
1574 #ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
1575 static int PalettesAreEqual(Image *a,Image *b)
1580 if ((a == (Image *) NULL) || (b == (Image *) NULL))
1581 return((int) MagickFalse);
1583 if (a->storage_class != PseudoClass || b->storage_class != PseudoClass)
1584 return((int) MagickFalse);
1586 if (a->colors != b->colors)
1587 return((int) MagickFalse);
1589 for (i=0; i < (ssize_t) a->colors; i++)
1591 if ((a->colormap[i].red != b->colormap[i].red) ||
1592 (a->colormap[i].green != b->colormap[i].green) ||
1593 (a->colormap[i].blue != b->colormap[i].blue))
1594 return((int) MagickFalse);
1597 return((int) MagickTrue);
1601 static void MngInfoDiscardObject(MngInfo *mng_info,int i)
1603 if (i && (i < MNG_MAX_OBJECTS) && (mng_info != (MngInfo *) NULL) &&
1604 mng_info->exists[i] && !mng_info->frozen[i])
1606 #ifdef MNG_OBJECT_BUFFERS
1607 if (mng_info->ob[i] != (MngBuffer *) NULL)
1609 if (mng_info->ob[i]->reference_count > 0)
1610 mng_info->ob[i]->reference_count--;
1612 if (mng_info->ob[i]->reference_count == 0)
1614 if (mng_info->ob[i]->image != (Image *) NULL)
1615 mng_info->ob[i]->image=DestroyImage(mng_info->ob[i]->image);
1617 mng_info->ob[i]=DestroyString(mng_info->ob[i]);
1620 mng_info->ob[i]=(MngBuffer *) NULL;
1622 mng_info->exists[i]=MagickFalse;
1623 mng_info->invisible[i]=MagickFalse;
1624 mng_info->viewable[i]=MagickFalse;
1625 mng_info->frozen[i]=MagickFalse;
1626 mng_info->x_off[i]=0;
1627 mng_info->y_off[i]=0;
1628 mng_info->object_clip[i].left=0;
1629 mng_info->object_clip[i].right=(ssize_t) PNG_UINT_31_MAX;
1630 mng_info->object_clip[i].top=0;
1631 mng_info->object_clip[i].bottom=(ssize_t) PNG_UINT_31_MAX;
1635 static void MngInfoFreeStruct(MngInfo *mng_info,
1636 MagickBooleanType *have_mng_structure)
1638 if (*have_mng_structure != MagickFalse && (mng_info != (MngInfo *) NULL))
1643 for (i=1; i < MNG_MAX_OBJECTS; i++)
1644 MngInfoDiscardObject(mng_info,i);
1646 if (mng_info->global_plte != (png_colorp) NULL)
1647 mng_info->global_plte=(png_colorp)
1648 RelinquishMagickMemory(mng_info->global_plte);
1650 mng_info=(MngInfo *) RelinquishMagickMemory(mng_info);
1651 *have_mng_structure=MagickFalse;
1655 static MngBox mng_minimum_box(MngBox box1,MngBox box2)
1661 if (box.left < box2.left)
1664 if (box.top < box2.top)
1667 if (box.right > box2.right)
1668 box.right=box2.right;
1670 if (box.bottom > box2.bottom)
1671 box.bottom=box2.bottom;
1676 static MngBox mng_read_box(MngBox previous_box,char delta_type,unsigned char *p)
1682 Read clipping boundaries from DEFI, CLIP, FRAM, or PAST chunk.
1684 box.left=(ssize_t) ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]);
1685 box.right=(ssize_t) ((p[4] << 24) | (p[5] << 16) | (p[6] << 8) | p[7]);
1686 box.top=(ssize_t) ((p[8] << 24) | (p[9] << 16) | (p[10] << 8) | p[11]);
1687 box.bottom=(ssize_t) ((p[12] << 24) | (p[13] << 16) | (p[14] << 8) | p[15]);
1688 if (delta_type != 0)
1690 box.left+=previous_box.left;
1691 box.right+=previous_box.right;
1692 box.top+=previous_box.top;
1693 box.bottom+=previous_box.bottom;
1699 static MngPair mng_read_pair(MngPair previous_pair,int delta_type,
1705 Read two ssize_ts from CLON, MOVE or PAST chunk
1707 pair.a=(long) ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]);
1708 pair.b=(long) ((p[4] << 24) | (p[5] << 16) | (p[6] << 8) | p[7]);
1710 if (delta_type != 0)
1712 pair.a+=previous_pair.a;
1713 pair.b+=previous_pair.b;
1719 static long mng_get_long(unsigned char *p)
1721 return((long) ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]));
1724 typedef struct _PNGErrorInfo
1733 static void MagickPNGErrorHandler(png_struct *ping,png_const_charp message)
1744 error_info=(PNGErrorInfo *) png_get_error_ptr(ping);
1745 image=error_info->image;
1746 exception=error_info->exception;
1748 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1749 " libpng-%s error: %s", PNG_LIBPNG_VER_STRING,message);
1751 (void) ThrowMagickException(exception,GetMagickModule(),CoderError,message,
1752 "`%s'",image->filename);
1754 #if (PNG_LIBPNG_VER < 10500)
1755 /* A warning about deprecated use of jmpbuf here is unavoidable if you
1756 * are building with libpng-1.4.x and can be ignored.
1758 longjmp(ping->jmpbuf,1);
1760 png_longjmp(ping,1);
1764 static void MagickPNGWarningHandler(png_struct *ping,png_const_charp message)
1775 if (LocaleCompare(message, "Missing PLTE before tRNS") == 0)
1776 png_error(ping, message);
1778 error_info=(PNGErrorInfo *) png_get_error_ptr(ping);
1779 image=error_info->image;
1780 exception=error_info->exception;
1781 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1782 " libpng-%s warning: %s", PNG_LIBPNG_VER_STRING,message);
1784 (void) ThrowMagickException(exception,GetMagickModule(),CoderWarning,
1785 message,"`%s'",image->filename);
1788 #ifdef PNG_USER_MEM_SUPPORTED
1789 static png_voidp Magick_png_malloc(png_structp png_ptr,png_uint_32 size)
1792 return((png_voidp) AcquireMagickMemory((size_t) size));
1796 Free a pointer. It is removed from the list at the same time.
1798 static png_free_ptr Magick_png_free(png_structp png_ptr,png_voidp ptr)
1801 ptr=RelinquishMagickMemory(ptr);
1802 return((png_free_ptr) NULL);
1806 #if defined(__cplusplus) || defined(c_plusplus)
1811 Magick_png_read_raw_profile(png_struct *ping,Image *image,
1812 const ImageInfo *image_info, png_textp text,int ii,ExceptionInfo *exception)
1817 register unsigned char
1831 unhex[103]={0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,
1832 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,
1833 0,0,0,0,0,0,0,0,0,1, 2,3,4,5,6,7,8,9,0,0,
1834 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,
1835 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,10,11,12,
1839 /* look for newline */
1843 /* look for length */
1844 while (*sp == '\0' || *sp == ' ' || *sp == '\n')
1847 length=(png_uint_32) StringToLong(sp);
1849 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1850 " length: %lu",(unsigned long) length);
1852 while (*sp != ' ' && *sp != '\n')
1855 /* allocate space */
1858 png_warning(ping,"invalid profile length");
1859 return(MagickFalse);
1862 profile=BlobToStringInfo((const void *) NULL,length);
1864 if (profile == (StringInfo *) NULL)
1866 png_warning(ping, "unable to copy profile");
1867 return(MagickFalse);
1870 /* copy profile, skipping white space and column 1 "=" signs */
1871 dp=GetStringInfoDatum(profile);
1874 for (i=0; i < (ssize_t) nibbles; i++)
1876 while (*sp < '0' || (*sp > '9' && *sp < 'a') || *sp > 'f')
1880 png_warning(ping, "ran out of profile data");
1881 profile=DestroyStringInfo(profile);
1882 return(MagickFalse);
1888 *dp=(unsigned char) (16*unhex[(int) *sp++]);
1891 (*dp++)+=unhex[(int) *sp++];
1894 We have already read "Raw profile type.
1896 (void) SetImageProfile(image,&text[ii].key[17],profile,exception);
1897 profile=DestroyStringInfo(profile);
1899 if (image_info->verbose)
1900 (void) printf(" Found a generic profile, type %s\n",&text[ii].key[17]);
1905 #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
1906 static int read_vpag_chunk_callback(png_struct *ping, png_unknown_chunkp chunk)
1912 /* The unknown chunk structure contains the chunk data:
1917 Note that libpng has already taken care of the CRC handling.
1921 if (chunk->name[0] != 118 || chunk->name[1] != 112 ||
1922 chunk->name[2] != 65 ||chunk-> name[3] != 103)
1923 return(0); /* Did not recognize */
1925 /* recognized vpAg */
1927 if (chunk->size != 9)
1928 return(-1); /* Error return */
1930 if (chunk->data[8] != 0)
1931 return(0); /* ImageMagick requires pixel units */
1933 image=(Image *) png_get_user_chunk_ptr(ping);
1935 image->page.width=(size_t) ((chunk->data[0] << 24) |
1936 (chunk->data[1] << 16) | (chunk->data[2] << 8) | chunk->data[3]);
1938 image->page.height=(size_t) ((chunk->data[4] << 24) |
1939 (chunk->data[5] << 16) | (chunk->data[6] << 8) | chunk->data[7]);
1941 /* Return one of the following: */
1942 /* return(-n); chunk had an error */
1943 /* return(0); did not recognize */
1944 /* return(n); success */
1952 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1956 % R e a d O n e P N G I m a g e %
1960 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1962 % ReadOnePNGImage() reads a Portable Network Graphics (PNG) image file
1963 % (minus the 8-byte signature) and returns it. It allocates the memory
1964 % necessary for the new Image structure and returns a pointer to the new
1967 % The format of the ReadOnePNGImage method is:
1969 % Image *ReadOnePNGImage(MngInfo *mng_info, const ImageInfo *image_info,
1970 % ExceptionInfo *exception)
1972 % A description of each parameter follows:
1974 % o mng_info: Specifies a pointer to a MngInfo structure.
1976 % o image_info: the image info.
1978 % o exception: return any errors or warnings in this structure.
1981 static Image *ReadOnePNGImage(MngInfo *mng_info,
1982 const ImageInfo *image_info, ExceptionInfo *exception)
1984 /* Read one PNG image */
1986 /* To do: Read the tIME chunk into the date:modify property */
1987 /* To do: Read the tEXt/Creation Time chunk into the date:create property */
2002 ping_interlace_method,
2003 ping_compression_method,
2054 register unsigned char
2071 #ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED
2072 png_byte unused_chunks[]=
2074 104, 73, 83, 84, (png_byte) '\0', /* hIST */
2075 105, 84, 88, 116, (png_byte) '\0', /* iTXt */
2076 112, 67, 65, 76, (png_byte) '\0', /* pCAL */
2077 115, 67, 65, 76, (png_byte) '\0', /* sCAL */
2078 115, 80, 76, 84, (png_byte) '\0', /* sPLT */
2079 116, 73, 77, 69, (png_byte) '\0', /* tIME */
2080 #ifdef PNG_APNG_SUPPORTED /* libpng was built with APNG patch; */
2081 /* ignore the APNG chunks */
2082 97, 99, 84, 76, (png_byte) '\0', /* acTL */
2083 102, 99, 84, 76, (png_byte) '\0', /* fcTL */
2084 102, 100, 65, 84, (png_byte) '\0', /* fdAT */
2089 logging=LogMagickEvent(CoderEvent,GetMagickModule(),
2090 " Enter ReadOnePNGImage()");
2092 #if (PNG_LIBPNG_VER < 10200)
2093 if (image_info->verbose)
2094 printf("Your PNG library (libpng-%s) is rather old.\n",
2095 PNG_LIBPNG_VER_STRING);
2098 #if (PNG_LIBPNG_VER >= 10400)
2099 # ifndef PNG_TRANSFORM_GRAY_TO_RGB /* Added at libpng-1.4.0beta67 */
2100 if (image_info->verbose)
2102 printf("Your PNG library (libpng-%s) is an old beta version.\n",
2103 PNG_LIBPNG_VER_STRING);
2104 printf("Please update it.\n");
2110 quantum_info = (QuantumInfo *) NULL;
2111 image=mng_info->image;
2113 if (logging != MagickFalse)
2114 (void)LogMagickEvent(CoderEvent,GetMagickModule(),
2115 " image->matte=%d",(int) image->matte);
2117 /* Set to an out-of-range color unless tRNS chunk is present */
2118 transparent_color.red=65537;
2119 transparent_color.green=65537;
2120 transparent_color.blue=65537;
2121 transparent_color.alpha=65537;
2126 num_raw_profiles = 0;
2129 Allocate the PNG structures
2131 #ifdef PNG_USER_MEM_SUPPORTED
2132 error_info.image=image;
2133 error_info.exception=exception;
2134 ping=png_create_read_struct_2(PNG_LIBPNG_VER_STRING,&error_info,
2135 MagickPNGErrorHandler,MagickPNGWarningHandler, NULL,
2136 (png_malloc_ptr) Magick_png_malloc,(png_free_ptr) Magick_png_free);
2138 ping=png_create_read_struct(PNG_LIBPNG_VER_STRING,&error_info,
2139 MagickPNGErrorHandler,MagickPNGWarningHandler);
2141 if (ping == (png_struct *) NULL)
2142 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2144 ping_info=png_create_info_struct(ping);
2146 if (ping_info == (png_info *) NULL)
2148 png_destroy_read_struct(&ping,(png_info **) NULL,(png_info **) NULL);
2149 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2152 end_info=png_create_info_struct(ping);
2154 if (end_info == (png_info *) NULL)
2156 png_destroy_read_struct(&ping,&ping_info,(png_info **) NULL);
2157 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2160 ping_pixels=(unsigned char *) NULL;
2162 if (setjmp(png_jmpbuf(ping)))
2165 PNG image is corrupt.
2167 png_destroy_read_struct(&ping,&ping_info,&end_info);
2169 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
2170 UnlockSemaphoreInfo(ping_semaphore);
2173 if (ping_pixels != (unsigned char *) NULL)
2174 ping_pixels=(unsigned char *) RelinquishMagickMemory(ping_pixels);
2176 if (logging != MagickFalse)
2177 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2178 " exit ReadOnePNGImage() with error.");
2180 if (image != (Image *) NULL)
2182 InheritException(exception,exception);
2186 return(GetFirstImageInList(image));
2189 /* { For navigation to end of SETJMP-protected block. Within this
2190 * block, use png_error() instead of Throwing an Exception, to ensure
2191 * that libpng is able to clean up, and that the semaphore is unlocked.
2194 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
2195 LockSemaphoreInfo(ping_semaphore);
2199 Prepare PNG for reading.
2202 mng_info->image_found++;
2203 png_set_sig_bytes(ping,8);
2205 if (LocaleCompare(image_info->magick,"MNG") == 0)
2207 #if defined(PNG_MNG_FEATURES_SUPPORTED)
2208 (void) png_permit_mng_features(ping,PNG_ALL_MNG_FEATURES);
2209 png_set_read_fn(ping,image,png_get_data);
2211 #if defined(PNG_READ_EMPTY_PLTE_SUPPORTED)
2212 png_permit_empty_plte(ping,MagickTrue);
2213 png_set_read_fn(ping,image,png_get_data);
2215 mng_info->image=image;
2216 mng_info->bytes_in_read_buffer=0;
2217 mng_info->found_empty_plte=MagickFalse;
2218 mng_info->have_saved_bkgd_index=MagickFalse;
2219 png_set_read_fn(ping,mng_info,mng_get_data);
2225 png_set_read_fn(ping,image,png_get_data);
2227 #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
2228 /* Ignore unused chunks and all unknown chunks except for vpAg */
2229 png_set_keep_unknown_chunks(ping, 1, NULL, 0);
2230 png_set_keep_unknown_chunks(ping, 2, mng_vpAg, 1);
2231 png_set_keep_unknown_chunks(ping, 1, unused_chunks,
2232 (int)sizeof(unused_chunks)/5);
2233 /* Callback for other unknown chunks */
2234 png_set_read_user_chunk_fn(ping, image, read_vpag_chunk_callback);
2237 #ifdef PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED
2238 /* Disable new libpng-1.5.10 feature */
2239 png_set_check_for_invalid_index (ping, 0);
2242 #if (PNG_LIBPNG_VER < 10400)
2243 # if defined(PNG_USE_PNGGCCRD) && defined(PNG_ASSEMBLER_CODE_SUPPORTED) && \
2244 (PNG_LIBPNG_VER >= 10200) && (PNG_LIBPNG_VER < 10220) && defined(__i386__)
2245 /* Disable thread-unsafe features of pnggccrd */
2246 if (png_access_version_number() >= 10200)
2248 png_uint_32 mmx_disable_mask=0;
2249 png_uint_32 asm_flags;
2251 mmx_disable_mask |= ( PNG_ASM_FLAG_MMX_READ_COMBINE_ROW \
2252 | PNG_ASM_FLAG_MMX_READ_FILTER_SUB \
2253 | PNG_ASM_FLAG_MMX_READ_FILTER_AVG \
2254 | PNG_ASM_FLAG_MMX_READ_FILTER_PAETH );
2255 asm_flags=png_get_asm_flags(ping);
2256 png_set_asm_flags(ping, asm_flags & ~mmx_disable_mask);
2261 png_read_info(ping,ping_info);
2263 png_get_IHDR(ping,ping_info,&ping_width,&ping_height,
2264 &ping_bit_depth,&ping_color_type,
2265 &ping_interlace_method,&ping_compression_method,
2266 &ping_filter_method);
2268 (void) png_get_tRNS(ping, ping_info, &ping_trans_alpha, &ping_num_trans,
2271 (void) png_get_bKGD(ping, ping_info, &ping_background);
2273 if (ping_bit_depth < 8)
2275 if (((int) ping_color_type == PNG_COLOR_TYPE_PALETTE))
2277 png_set_packing(ping);
2282 image->depth=ping_bit_depth;
2283 image->depth=GetImageQuantumDepth(image,MagickFalse);
2284 image->interlace=ping_interlace_method != 0 ? PNGInterlace : NoInterlace;
2285 if (((int) ping_color_type == PNG_COLOR_TYPE_GRAY) ||
2286 ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA))
2288 image->rendering_intent=UndefinedIntent;
2290 (void) ResetMagickMemory(&image->chromaticity,0,
2291 sizeof(image->chromaticity));
2293 if (logging != MagickFalse)
2295 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2296 " PNG width: %.20g, height: %.20g",
2297 (double) ping_width, (double) ping_height);
2299 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2300 " PNG color_type: %d, bit_depth: %d",
2301 ping_color_type, ping_bit_depth);
2303 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2304 " PNG compression_method: %d",
2305 ping_compression_method);
2307 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2308 " PNG interlace_method: %d, filter_method: %d",
2309 ping_interlace_method,ping_filter_method);
2312 #ifdef PNG_READ_iCCP_SUPPORTED
2313 if (png_get_valid(ping,ping_info,PNG_INFO_iCCP))
2318 #if (PNG_LIBPNG_VER < 10500)
2332 (void) png_get_iCCP(ping,ping_info,&name,(int *) &compression,&info,
2335 if (profile_length != 0)
2340 if (logging != MagickFalse)
2341 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2342 " Reading PNG iCCP chunk.");
2343 profile=BlobToStringInfo(info,profile_length);
2344 if (profile == (StringInfo *) NULL)
2346 png_warning(ping, "ICC profile is NULL");
2347 profile=DestroyStringInfo(profile);
2351 (void) SetImageProfile(image,"icc",profile,exception);
2352 profile=DestroyStringInfo(profile);
2357 #if defined(PNG_READ_sRGB_SUPPORTED)
2359 if (mng_info->have_global_srgb)
2361 image->rendering_intent=Magick_RenderingIntent_from_PNG_RenderingIntent
2362 (mng_info->global_srgb_intent);
2365 if (png_get_sRGB(ping,ping_info,&intent))
2367 image->rendering_intent=Magick_RenderingIntent_from_PNG_RenderingIntent
2370 if (logging != MagickFalse)
2371 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2372 " Reading PNG sRGB chunk: rendering_intent: %d",intent);
2377 if (!png_get_gAMA(ping,ping_info,&file_gamma))
2378 if (mng_info->have_global_gama)
2379 png_set_gAMA(ping,ping_info,mng_info->global_gamma);
2381 if (png_get_gAMA(ping,ping_info,&file_gamma))
2383 image->gamma=(float) file_gamma;
2384 if (logging != MagickFalse)
2385 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2386 " Reading PNG gAMA chunk: gamma: %f",file_gamma);
2389 if (!png_get_valid(ping,ping_info,PNG_INFO_cHRM))
2391 if (mng_info->have_global_chrm != MagickFalse)
2393 (void) png_set_cHRM(ping,ping_info,
2394 mng_info->global_chrm.white_point.x,
2395 mng_info->global_chrm.white_point.y,
2396 mng_info->global_chrm.red_primary.x,
2397 mng_info->global_chrm.red_primary.y,
2398 mng_info->global_chrm.green_primary.x,
2399 mng_info->global_chrm.green_primary.y,
2400 mng_info->global_chrm.blue_primary.x,
2401 mng_info->global_chrm.blue_primary.y);
2405 if (png_get_valid(ping,ping_info,PNG_INFO_cHRM))
2407 (void) png_get_cHRM(ping,ping_info,
2408 &image->chromaticity.white_point.x,
2409 &image->chromaticity.white_point.y,
2410 &image->chromaticity.red_primary.x,
2411 &image->chromaticity.red_primary.y,
2412 &image->chromaticity.green_primary.x,
2413 &image->chromaticity.green_primary.y,
2414 &image->chromaticity.blue_primary.x,
2415 &image->chromaticity.blue_primary.y);
2417 if (logging != MagickFalse)
2418 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2419 " Reading PNG cHRM chunk.");
2422 if (image->rendering_intent != UndefinedIntent)
2424 png_set_sRGB(ping,ping_info,
2425 Magick_RenderingIntent_to_PNG_RenderingIntent
2426 (image->rendering_intent));
2427 png_set_gAMA(ping,ping_info,1.000f/2.200f);
2428 png_set_cHRM(ping,ping_info,
2429 0.6400f, 0.3300f, 0.3000f, 0.6000f,
2430 0.1500f, 0.0600f, 0.3127f, 0.3290f);
2432 #if defined(PNG_oFFs_SUPPORTED)
2433 if (png_get_valid(ping,ping_info,PNG_INFO_oFFs))
2435 image->page.x=(ssize_t) png_get_x_offset_pixels(ping, ping_info);
2436 image->page.y=(ssize_t) png_get_y_offset_pixels(ping, ping_info);
2438 if (logging != MagickFalse)
2439 if (image->page.x || image->page.y)
2440 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2441 " Reading PNG oFFs chunk: x: %.20g, y: %.20g.",(double)
2442 image->page.x,(double) image->page.y);
2445 #if defined(PNG_pHYs_SUPPORTED)
2446 if (!png_get_valid(ping,ping_info,PNG_INFO_pHYs))
2448 if (mng_info->have_global_phys)
2450 png_set_pHYs(ping,ping_info,
2451 mng_info->global_x_pixels_per_unit,
2452 mng_info->global_y_pixels_per_unit,
2453 mng_info->global_phys_unit_type);
2457 if (png_get_valid(ping,ping_info,PNG_INFO_pHYs))
2460 Set image resolution.
2462 (void) png_get_pHYs(ping,ping_info,&x_resolution,&y_resolution,
2464 image->resolution.x=(double) x_resolution;
2465 image->resolution.y=(double) y_resolution;
2467 if (unit_type == PNG_RESOLUTION_METER)
2469 image->units=PixelsPerCentimeterResolution;
2470 image->resolution.x=(double) x_resolution/100.0;
2471 image->resolution.y=(double) y_resolution/100.0;
2474 if (logging != MagickFalse)
2475 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2476 " Reading PNG pHYs chunk: xres: %.20g, yres: %.20g, units: %d.",
2477 (double) x_resolution,(double) y_resolution,unit_type);
2481 if (png_get_valid(ping,ping_info,PNG_INFO_PLTE))
2486 (void) png_get_PLTE(ping,ping_info,&palette,&number_colors);
2488 if ((number_colors == 0) &&
2489 ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE))
2491 if (mng_info->global_plte_length)
2493 png_set_PLTE(ping,ping_info,mng_info->global_plte,
2494 (int) mng_info->global_plte_length);
2496 if (!png_get_valid(ping,ping_info,PNG_INFO_tRNS))
2498 if (mng_info->global_trns_length)
2501 "global tRNS has more entries than global PLTE");
2505 png_set_tRNS(ping,ping_info,mng_info->global_trns,
2506 (int) mng_info->global_trns_length,NULL);
2509 #ifdef PNG_READ_bKGD_SUPPORTED
2511 #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
2512 mng_info->have_saved_bkgd_index ||
2514 png_get_valid(ping,ping_info,PNG_INFO_bKGD))
2519 #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
2520 if (mng_info->have_saved_bkgd_index)
2521 background.index=mng_info->saved_bkgd_index;
2523 if (png_get_valid(ping, ping_info, PNG_INFO_bKGD))
2524 background.index=ping_background->index;
2526 background.red=(png_uint_16)
2527 mng_info->global_plte[background.index].red;
2529 background.green=(png_uint_16)
2530 mng_info->global_plte[background.index].green;
2532 background.blue=(png_uint_16)
2533 mng_info->global_plte[background.index].blue;
2535 background.gray=(png_uint_16)
2536 mng_info->global_plte[background.index].green;
2538 png_set_bKGD(ping,ping_info,&background);
2543 png_error(ping,"No global PLTE in file");
2547 #ifdef PNG_READ_bKGD_SUPPORTED
2548 if (mng_info->have_global_bkgd &&
2549 (!png_get_valid(ping,ping_info,PNG_INFO_bKGD)))
2550 image->background_color=mng_info->mng_global_bkgd;
2552 if (png_get_valid(ping,ping_info,PNG_INFO_bKGD))
2558 Set image background color.
2560 if (logging != MagickFalse)
2561 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2562 " Reading PNG bKGD chunk.");
2564 /* Scale background components to 16-bit, then scale
2567 if (logging != MagickFalse)
2568 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2569 " raw ping_background=(%d,%d,%d).",ping_background->red,
2570 ping_background->green,ping_background->blue);
2574 if (ping_bit_depth == 1)
2577 else if (ping_bit_depth == 2)
2580 else if (ping_bit_depth == 4)
2583 if (ping_bit_depth <= 8)
2586 ping_background->red *= bkgd_scale;
2587 ping_background->green *= bkgd_scale;
2588 ping_background->blue *= bkgd_scale;
2590 if (logging != MagickFalse)
2592 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2593 " bkgd_scale=%d.",bkgd_scale);
2595 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2596 " ping_background=(%d,%d,%d).",ping_background->red,
2597 ping_background->green,ping_background->blue);
2600 image->background_color.red=
2601 ScaleShortToQuantum(ping_background->red);
2603 image->background_color.green=
2604 ScaleShortToQuantum(ping_background->green);
2606 image->background_color.blue=
2607 ScaleShortToQuantum(ping_background->blue);
2609 image->background_color.alpha=OpaqueAlpha;
2611 if (logging != MagickFalse)
2612 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2613 " image->background_color=(%.20g,%.20g,%.20g).",
2614 (double) image->background_color.red,
2615 (double) image->background_color.green,
2616 (double) image->background_color.blue);
2618 #endif /* PNG_READ_bKGD_SUPPORTED */
2620 if (png_get_valid(ping,ping_info,PNG_INFO_tRNS))
2623 Image has a tRNS chunk.
2631 if (logging != MagickFalse)
2632 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2633 " Reading PNG tRNS chunk.");
2635 max_sample = (int) ((one << ping_bit_depth) - 1);
2637 if ((ping_color_type == PNG_COLOR_TYPE_GRAY &&
2638 (int)ping_trans_color->gray > max_sample) ||
2639 (ping_color_type == PNG_COLOR_TYPE_RGB &&
2640 ((int)ping_trans_color->red > max_sample ||
2641 (int)ping_trans_color->green > max_sample ||
2642 (int)ping_trans_color->blue > max_sample)))
2644 if (logging != MagickFalse)
2645 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2646 " Ignoring PNG tRNS chunk with out-of-range sample.");
2647 png_free_data(ping, ping_info, PNG_FREE_TRNS, 0);
2648 png_set_invalid(ping,ping_info,PNG_INFO_tRNS);
2649 image->matte=MagickFalse;
2656 scale_to_short = 65535L/((1UL << ping_bit_depth)-1);
2658 /* Scale transparent_color to short */
2659 transparent_color.red= scale_to_short*ping_trans_color->red;
2660 transparent_color.green= scale_to_short*ping_trans_color->green;
2661 transparent_color.blue= scale_to_short*ping_trans_color->blue;
2662 transparent_color.alpha= scale_to_short*ping_trans_color->gray;
2664 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
2666 if (logging != MagickFalse)
2668 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2669 " Raw tRNS graylevel is %d.",ping_trans_color->gray);
2671 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2672 " scaled graylevel is %.20g.",transparent_color.alpha);
2674 transparent_color.red=transparent_color.alpha;
2675 transparent_color.green=transparent_color.alpha;
2676 transparent_color.blue=transparent_color.alpha;
2680 #if defined(PNG_READ_sBIT_SUPPORTED)
2681 if (mng_info->have_global_sbit)
2683 if (!png_get_valid(ping,ping_info,PNG_INFO_sBIT))
2684 png_set_sBIT(ping,ping_info,&mng_info->global_sbit);
2687 num_passes=png_set_interlace_handling(ping);
2689 png_read_update_info(ping,ping_info);
2691 ping_rowbytes=png_get_rowbytes(ping,ping_info);
2694 Initialize image structure.
2696 mng_info->image_box.left=0;
2697 mng_info->image_box.right=(ssize_t) ping_width;
2698 mng_info->image_box.top=0;
2699 mng_info->image_box.bottom=(ssize_t) ping_height;
2700 if (mng_info->mng_type == 0)
2702 mng_info->mng_width=ping_width;
2703 mng_info->mng_height=ping_height;
2704 mng_info->frame=mng_info->image_box;
2705 mng_info->clip=mng_info->image_box;
2710 image->page.y=mng_info->y_off[mng_info->object_id];
2713 image->compression=ZipCompression;
2714 image->columns=ping_width;
2715 image->rows=ping_height;
2717 if (((int) ping_color_type == PNG_COLOR_TYPE_GRAY) ||
2718 ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA))
2720 if (!png_get_valid(ping,ping_info,PNG_INFO_gAMA) &&
2721 !png_get_valid(ping,ping_info,PNG_INFO_cHRM) &&
2722 !png_get_valid(ping,ping_info,PNG_INFO_sRGB))
2724 /* Set image->gamma to 1.0, image->rendering_intent to Undefined,
2725 * and reset image->chromaticity.
2727 SetImageColorspace(image,GRAYColorspace,exception);
2731 if (((int) ping_color_type == PNG_COLOR_TYPE_PALETTE) ||
2732 ((int) ping_color_type == PNG_COLOR_TYPE_GRAY))
2737 image->storage_class=PseudoClass;
2739 image->colors=one << ping_bit_depth;
2740 #if (MAGICKCORE_QUANTUM_DEPTH == 8)
2741 if (image->colors > 256)
2744 if (image->colors > 65536L)
2745 image->colors=65536L;
2747 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)
2774 (void) png_get_PLTE(ping,ping_info,&palette,&number_colors);
2776 for (i=0; i < (ssize_t) number_colors; i++)
2778 image->colormap[i].red=ScaleCharToQuantum(palette[i].red);
2779 image->colormap[i].green=ScaleCharToQuantum(palette[i].green);
2780 image->colormap[i].blue=ScaleCharToQuantum(palette[i].blue);
2783 for ( ; i < (ssize_t) image->colors; i++)
2785 image->colormap[i].red=0;
2786 image->colormap[i].green=0;
2787 image->colormap[i].blue=0;
2796 scale=(QuantumRange/((1UL << ping_bit_depth)-1));
2801 for (i=0; i < (ssize_t) image->colors; i++)
2803 image->colormap[i].red=(Quantum) (i*scale);
2804 image->colormap[i].green=(Quantum) (i*scale);
2805 image->colormap[i].blue=(Quantum) (i*scale);
2810 /* Set some properties for reporting by "identify" */
2815 /* encode ping_width, ping_height, ping_bit_depth, ping_color_type,
2816 ping_interlace_method in value */
2818 (void) FormatLocaleString(msg,MaxTextExtent,
2819 "%d, %d",(int) ping_width, (int) ping_height);
2820 (void) SetImageProperty(image,"png:IHDR.width,height ",msg,exception);
2822 (void) FormatLocaleString(msg,MaxTextExtent,"%d",(int) ping_bit_depth);
2823 (void) SetImageProperty(image,"png:IHDR.bit_depth ",msg,exception);
2825 (void) FormatLocaleString(msg,MaxTextExtent,"%d (%s)",
2826 (int) ping_color_type,
2827 Magick_ColorType_from_PNG_ColorType((int)ping_color_type));
2828 (void) SetImageProperty(image,"png:IHDR.color_type ",msg,exception);
2830 if (ping_interlace_method == 0)
2832 (void) FormatLocaleString(msg,MaxTextExtent,"%d (Not interlaced)",
2833 (int) ping_interlace_method);
2835 else if (ping_interlace_method == 1)
2837 (void) FormatLocaleString(msg,MaxTextExtent,"%d (Adam7 method)",
2838 (int) ping_interlace_method);
2842 (void) FormatLocaleString(msg,MaxTextExtent,"%d (Unknown method)",
2843 (int) ping_interlace_method);
2845 (void) SetImageProperty(image,"png:IHDR.interlace_method",msg,exception);
2847 if (number_colors != 0)
2849 (void) FormatLocaleString(msg,MaxTextExtent,"%d",
2850 (int) number_colors);
2851 (void) SetImageProperty(image,"png:PLTE.number_colors ",msg,
2857 Read image scanlines.
2859 if (image->delay != 0)
2860 mng_info->scenes_found++;
2862 if ((mng_info->mng_type == 0 && (image->ping != MagickFalse)) || (
2863 (image_info->number_scenes != 0) && (mng_info->scenes_found > (ssize_t)
2864 (image_info->first_scene+image_info->number_scenes))))
2866 /* This happens later in non-ping decodes */
2867 if (png_get_valid(ping,ping_info,PNG_INFO_tRNS))
2868 image->storage_class=DirectClass;
2870 if (logging != MagickFalse)
2871 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2872 " Skipping PNG image data for scene %.20g",(double)
2873 mng_info->scenes_found-1);
2874 png_destroy_read_struct(&ping,&ping_info,&end_info);
2876 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
2877 UnlockSemaphoreInfo(ping_semaphore);
2880 if (logging != MagickFalse)
2881 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2882 " exit ReadOnePNGImage().");
2887 if (logging != MagickFalse)
2888 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2889 " Reading PNG IDAT chunk(s)");
2892 ping_pixels=(unsigned char *) AcquireQuantumMemory(image->rows,
2893 ping_rowbytes*sizeof(*ping_pixels));
2896 ping_pixels=(unsigned char *) AcquireQuantumMemory(ping_rowbytes,
2897 sizeof(*ping_pixels));
2899 if (ping_pixels == (unsigned char *) NULL)
2900 png_error(ping,"Memory allocation failed");
2902 if (logging != MagickFalse)
2903 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2904 " Converting PNG pixels to pixel packets");
2906 Convert PNG pixels to pixel packets.
2908 quantum_info=AcquireQuantumInfo(image_info,image);
2910 if (quantum_info == (QuantumInfo *) NULL)
2911 png_error(ping,"Failed to allocate quantum_info");
2916 found_transparent_pixel;
2918 found_transparent_pixel=MagickFalse;
2920 if (image->storage_class == DirectClass)
2922 for (pass=0; pass < num_passes; pass++)
2925 Convert image to DirectClass pixel packets.
2927 #if (MAGICKCORE_QUANTUM_DEPTH == 8)
2931 depth=(ssize_t) ping_bit_depth;
2933 image->matte=(((int) ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA) ||
2934 ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) ||
2935 (png_get_valid(ping,ping_info,PNG_INFO_tRNS))) ?
2936 MagickTrue : MagickFalse;
2938 for (y=0; y < (ssize_t) image->rows; y++)
2941 row_offset=ping_rowbytes*y;
2946 png_read_row(ping,ping_pixels+row_offset,NULL);
2947 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
2949 if (q == (Quantum *) NULL)
2952 if ((int) ping_color_type == PNG_COLOR_TYPE_GRAY)
2953 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
2954 GrayQuantum,ping_pixels+row_offset,exception);
2956 else if ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
2957 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
2958 GrayAlphaQuantum,ping_pixels+row_offset,exception);
2960 else if ((int) ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA)
2961 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
2962 RGBAQuantum,ping_pixels+row_offset,exception);
2964 else if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
2965 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
2966 IndexQuantum,ping_pixels+row_offset,exception);
2968 else /* ping_color_type == PNG_COLOR_TYPE_RGB */
2969 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
2970 RGBQuantum,ping_pixels+row_offset,exception);
2972 if (found_transparent_pixel == MagickFalse)
2974 /* Is there a transparent pixel in the row? */
2975 if (y== 0 && logging != MagickFalse)
2976 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2977 " Looking for cheap transparent pixel");
2979 for (x=(ssize_t) image->columns-1; x >= 0; x--)
2981 if ((ping_color_type == PNG_COLOR_TYPE_RGBA ||
2982 ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) &&
2983 (GetPixelAlpha(image,q) != OpaqueAlpha))
2985 if (logging != MagickFalse)
2986 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2989 found_transparent_pixel = MagickTrue;
2992 if ((ping_color_type == PNG_COLOR_TYPE_RGB ||
2993 ping_color_type == PNG_COLOR_TYPE_GRAY) &&
2994 (ScaleQuantumToShort(GetPixelRed(image,q)) ==
2995 transparent_color.red &&
2996 ScaleQuantumToShort(GetPixelGreen(image,q)) ==
2997 transparent_color.green &&
2998 ScaleQuantumToShort(GetPixelBlue(image,q)) ==
2999 transparent_color.blue))
3001 if (logging != MagickFalse)
3002 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3004 found_transparent_pixel = MagickTrue;
3007 q+=GetPixelChannels(image);
3011 if ((image->previous == (Image *) NULL) && (num_passes == 1))
3013 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
3016 if (status == MagickFalse)
3019 if (SyncAuthenticPixels(image,exception) == MagickFalse)
3023 if ((image->previous == (Image *) NULL) && (num_passes != 1))
3025 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
3026 if (status == MagickFalse)
3032 else /* image->storage_class != DirectClass */
3034 for (pass=0; pass < num_passes; pass++)
3043 Convert grayscale image to PseudoClass pixel packets.
3045 if (logging != MagickFalse)
3046 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3047 " Converting grayscale pixels to pixel packets");
3049 image->matte=ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA ?
3050 MagickTrue : MagickFalse;
3052 quantum_scanline=(Quantum *) AcquireQuantumMemory(image->columns,
3053 (image->matte ? 2 : 1)*sizeof(*quantum_scanline));
3055 if (quantum_scanline == (Quantum *) NULL)
3056 png_error(ping,"Memory allocation failed");
3058 for (y=0; y < (ssize_t) image->rows; y++)
3061 row_offset=ping_rowbytes*y;
3066 png_read_row(ping,ping_pixels+row_offset,NULL);
3067 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
3069 if (q == (Quantum *) NULL)
3072 p=ping_pixels+row_offset;
3075 switch (ping_bit_depth)
3082 for (x=(ssize_t) image->columns-7; x > 0; x-=8)
3084 for (bit=7; bit >= 0; bit--)
3085 *r++=(Quantum) ((*p) & (0x01 << bit) ? 0x01 : 0x00);
3089 if ((image->columns % 8) != 0)
3091 for (bit=7; bit >= (ssize_t) (8-(image->columns % 8)); bit--)
3092 *r++=(Quantum) ((*p) & (0x01 << bit) ? 0x01 : 0x00);
3100 for (x=(ssize_t) image->columns-3; x > 0; x-=4)
3102 *r++=(*p >> 6) & 0x03;
3103 *r++=(*p >> 4) & 0x03;
3104 *r++=(*p >> 2) & 0x03;
3108 if ((image->columns % 4) != 0)
3110 for (i=3; i >= (ssize_t) (4-(image->columns % 4)); i--)
3111 *r++=(Quantum) ((*p >> (i*2)) & 0x03);
3119 for (x=(ssize_t) image->columns-1; x > 0; x-=2)
3121 *r++=(*p >> 4) & 0x0f;
3125 if ((image->columns % 2) != 0)
3126 *r++=(*p++ >> 4) & 0x0f;
3133 if (ping_color_type == 4)
3134 for (x=(ssize_t) image->columns-1; x >= 0; x--)
3137 SetPixelAlpha(image,ScaleCharToQuantum((unsigned char) *p++),q);
3138 if (GetPixelAlpha(image,q) != OpaqueAlpha)
3139 found_transparent_pixel = MagickTrue;
3140 q+=GetPixelChannels(image);
3144 for (x=(ssize_t) image->columns-1; x >= 0; x--)
3152 for (x=(ssize_t) image->columns-1; x >= 0; x--)
3154 #if (MAGICKCORE_QUANTUM_DEPTH == 16) || (MAGICKCORE_QUANTUM_DEPTH == 32)
3158 if (image->colors > 256)
3159 quantum=((*p++) << 8);
3165 *r=ScaleShortToQuantum(quantum);
3168 if (ping_color_type == 4)
3170 if (image->colors > 256)
3171 quantum=((*p++) << 8);
3176 SetPixelAlpha(image,ScaleShortToQuantum(quantum),q);
3177 if (GetPixelAlpha(image,q) != OpaqueAlpha)
3178 found_transparent_pixel = MagickTrue;
3179 q+=GetPixelChannels(image);
3182 #else /* MAGICKCORE_QUANTUM_DEPTH == 8 */
3184 p++; /* strip low byte */
3186 if (ping_color_type == 4)
3188 SetPixelAlpha(image,*p++,q);
3189 if (GetPixelAlpha(image,q) != OpaqueAlpha)
3190 found_transparent_pixel = MagickTrue;
3192 q+=GetPixelChannels(image);
3205 Transfer image scanline.
3209 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
3211 if (q == (Quantum *) NULL)
3213 for (x=0; x < (ssize_t) image->columns; x++)
3215 SetPixelIndex(image,*r++,q);
3216 q+=GetPixelChannels(image);
3219 if (SyncAuthenticPixels(image,exception) == MagickFalse)
3222 if ((image->previous == (Image *) NULL) && (num_passes == 1))
3224 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
3227 if (status == MagickFalse)
3232 if ((image->previous == (Image *) NULL) && (num_passes != 1))
3234 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
3236 if (status == MagickFalse)
3240 quantum_scanline=(Quantum *) RelinquishMagickMemory(quantum_scanline);
3243 image->matte=found_transparent_pixel;
3245 if (logging != MagickFalse)
3247 if (found_transparent_pixel != MagickFalse)
3248 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3249 " Found transparent pixel");
3252 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3253 " No transparent pixel was found");
3255 ping_color_type&=0x03;
3260 if (quantum_info != (QuantumInfo *) NULL)
3261 quantum_info=DestroyQuantumInfo(quantum_info);
3263 if (image->storage_class == PseudoClass)
3269 image->matte=MagickFalse;
3270 (void) SyncImage(image,exception);
3274 png_read_end(ping,end_info);
3276 if (image_info->number_scenes != 0 && mng_info->scenes_found-1 <
3277 (ssize_t) image_info->first_scene && image->delay != 0)
3279 png_destroy_read_struct(&ping,&ping_info,&end_info);
3280 ping_pixels=(unsigned char *) RelinquishMagickMemory(ping_pixels);
3282 (void) SetImageBackgroundColor(image,exception);
3283 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
3284 UnlockSemaphoreInfo(ping_semaphore);
3286 if (logging != MagickFalse)
3287 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3288 " exit ReadOnePNGImage() early.");
3292 if (png_get_valid(ping,ping_info,PNG_INFO_tRNS))
3298 Image has a transparent background.
3300 storage_class=image->storage_class;
3301 image->matte=MagickTrue;
3303 /* Balfour fix from imagemagick discourse server, 5 Feb 2010 */
3305 if (storage_class == PseudoClass)
3307 if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
3309 for (x=0; x < ping_num_trans; x++)
3311 image->colormap[x].matte=MagickTrue;
3312 image->colormap[x].alpha =
3313 ScaleCharToQuantum((unsigned char)ping_trans_alpha[x]);
3317 else if (ping_color_type == PNG_COLOR_TYPE_GRAY)
3319 for (x=0; x < (int) image->colors; x++)
3321 if (ScaleQuantumToShort(image->colormap[x].red) ==
3322 transparent_color.alpha)
3324 image->colormap[x].matte=MagickTrue;
3325 image->colormap[x].alpha = (Quantum) TransparentAlpha;
3329 (void) SyncImage(image,exception);
3332 #if 1 /* Should have already been done above, but glennrp problem P10
3337 for (y=0; y < (ssize_t) image->rows; y++)
3339 image->storage_class=storage_class;
3340 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
3342 if (q == (Quantum *) NULL)
3346 /* Caution: on a Q8 build, this does not distinguish between
3347 * 16-bit colors that differ only in the low byte
3349 for (x=(ssize_t) image->columns-1; x >= 0; x--)
3351 if (ScaleQuantumToShort(GetPixelRed(image,q)) ==
3352 transparent_color.red &&
3353 ScaleQuantumToShort(GetPixelGreen(image,q)) ==
3354 transparent_color.green &&
3355 ScaleQuantumToShort(GetPixelBlue(image,q)) ==
3356 transparent_color.blue)
3358 SetPixelAlpha(image,TransparentAlpha,q);
3361 #if 0 /* I have not found a case where this is needed. */
3364 SetPixelAlpha(image,q)=(Quantum) OpaqueAlpha;
3368 q+=GetPixelChannels(image);
3371 if (SyncAuthenticPixels(image,exception) == MagickFalse)
3377 image->storage_class=DirectClass;
3380 for (j = 0; j < 2; j++)
3383 status = png_get_text(ping,ping_info,&text,&num_text) != 0 ?
3384 MagickTrue : MagickFalse;
3386 status = png_get_text(ping,end_info,&text,&num_text) != 0 ?
3387 MagickTrue : MagickFalse;
3389 if (status != MagickFalse)
3390 for (i=0; i < (ssize_t) num_text; i++)
3392 /* Check for a profile */
3394 if (logging != MagickFalse)
3395 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3396 " Reading PNG text chunk");
3398 if (memcmp(text[i].key, "Raw profile type ",17) == 0)
3400 (void) Magick_png_read_raw_profile(ping,image,image_info,text,
3410 length=text[i].text_length;
3411 value=(char *) AcquireQuantumMemory(length+MaxTextExtent,
3413 if (value == (char *) NULL)
3415 png_error(ping,"Memory allocation failed");
3419 (void) ConcatenateMagickString(value,text[i].text,length+2);
3421 /* Don't save "density" or "units" property if we have a pHYs
3424 if (!png_get_valid(ping,ping_info,PNG_INFO_pHYs) ||
3425 (LocaleCompare(text[i].key,"density") != 0 &&
3426 LocaleCompare(text[i].key,"units") != 0))
3427 (void) SetImageProperty(image,text[i].key,value,exception);
3429 if (logging != MagickFalse)
3431 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3432 " length: %lu",(unsigned long) length);
3433 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3434 " Keyword: %s",text[i].key);
3437 value=DestroyString(value);
3440 num_text_total += num_text;
3443 #ifdef MNG_OBJECT_BUFFERS
3445 Store the object if necessary.
3447 if (object_id && !mng_info->frozen[object_id])
3449 if (mng_info->ob[object_id] == (MngBuffer *) NULL)
3452 create a new object buffer.
3454 mng_info->ob[object_id]=(MngBuffer *)
3455 AcquireMagickMemory(sizeof(MngBuffer));
3457 if (mng_info->ob[object_id] != (MngBuffer *) NULL)
3459 mng_info->ob[object_id]->image=(Image *) NULL;
3460 mng_info->ob[object_id]->reference_count=1;
3464 if ((mng_info->ob[object_id] == (MngBuffer *) NULL) ||
3465 mng_info->ob[object_id]->frozen)
3467 if (mng_info->ob[object_id] == (MngBuffer *) NULL)
3468 png_error(ping,"Memory allocation failed");
3470 if (mng_info->ob[object_id]->frozen)
3471 png_error(ping,"Cannot overwrite frozen MNG object buffer");
3477 if (mng_info->ob[object_id]->image != (Image *) NULL)
3478 mng_info->ob[object_id]->image=DestroyImage
3479 (mng_info->ob[object_id]->image);
3481 mng_info->ob[object_id]->image=CloneImage(image,0,0,MagickTrue,
3484 if (mng_info->ob[object_id]->image != (Image *) NULL)
3485 mng_info->ob[object_id]->image->file=(FILE *) NULL;
3488 png_error(ping, "Cloning image for object buffer failed");
3490 if (ping_width > 250000L || ping_height > 250000L)
3491 png_error(ping,"PNG Image dimensions are too large.");
3493 mng_info->ob[object_id]->width=ping_width;
3494 mng_info->ob[object_id]->height=ping_height;
3495 mng_info->ob[object_id]->color_type=ping_color_type;
3496 mng_info->ob[object_id]->sample_depth=ping_bit_depth;
3497 mng_info->ob[object_id]->interlace_method=ping_interlace_method;
3498 mng_info->ob[object_id]->compression_method=
3499 ping_compression_method;
3500 mng_info->ob[object_id]->filter_method=ping_filter_method;
3502 if (png_get_valid(ping,ping_info,PNG_INFO_PLTE))
3508 Copy the PLTE to the object buffer.
3510 png_get_PLTE(ping,ping_info,&plte,&number_colors);
3511 mng_info->ob[object_id]->plte_length=number_colors;
3513 for (i=0; i < number_colors; i++)
3515 mng_info->ob[object_id]->plte[i]=plte[i];
3520 mng_info->ob[object_id]->plte_length=0;
3525 /* Set image->matte to MagickTrue if the input colortype supports
3526 * alpha or if a valid tRNS chunk is present, no matter whether there
3527 * is actual transparency present.
3529 image->matte=(((int) ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA) ||
3530 ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) ||
3531 (png_get_valid(ping,ping_info,PNG_INFO_tRNS))) ?
3532 MagickTrue : MagickFalse;
3534 /* Set more properties for identify to retrieve */
3539 if (num_text_total != 0)
3541 /* libpng doesn't tell us whether they were tEXt, zTXt, or iTXt */
3542 (void) FormatLocaleString(msg,MaxTextExtent,
3543 "%d tEXt/zTXt/iTXt chunks were found", num_text_total);
3544 (void) SetImageProperty(image,"png:text ",msg,
3548 if (num_raw_profiles != 0)
3550 (void) FormatLocaleString(msg,MaxTextExtent,
3551 "%d were found", num_raw_profiles);
3552 (void) SetImageProperty(image,"png:text-encoded profiles",msg,
3556 if (png_get_valid(ping,ping_info,PNG_INFO_cHRM))
3558 (void) FormatLocaleString(msg,MaxTextExtent,"%s",
3559 "chunk was found (see Chromaticity, above)");
3560 (void) SetImageProperty(image,"png:cHRM ",msg,
3564 if (png_get_valid(ping,ping_info,PNG_INFO_bKGD))
3566 (void) FormatLocaleString(msg,MaxTextExtent,"%s",
3567 "chunk was found (see Background color, above)");
3568 (void) SetImageProperty(image,"png:bKGD ",msg,
3572 (void) FormatLocaleString(msg,MaxTextExtent,"%s",
3575 if (png_get_valid(ping,ping_info,PNG_INFO_iCCP))
3576 (void) SetImageProperty(image,"png:iCCP ",msg,
3579 if (png_get_valid(ping,ping_info,PNG_INFO_tRNS))
3580 (void) SetImageProperty(image,"png:tRNS ",msg,
3583 #if defined(PNG_sRGB_SUPPORTED)
3584 if (png_get_valid(ping,ping_info,PNG_INFO_sRGB))
3586 (void) FormatLocaleString(msg,MaxTextExtent,
3587 "intent=%d (See Rendering intent)", (int) intent);
3588 (void) SetImageProperty(image,"png:sRGB ",msg,
3593 if (png_get_valid(ping,ping_info,PNG_INFO_gAMA))
3595 (void) FormatLocaleString(msg,MaxTextExtent,
3596 "gamma=%.8g (See Gamma, above)",
3598 (void) SetImageProperty(image,"png:gAMA ",msg,
3602 #if defined(PNG_pHYs_SUPPORTED)
3603 if (png_get_valid(ping,ping_info,PNG_INFO_pHYs))
3605 (void) FormatLocaleString(msg,MaxTextExtent,
3606 "x_res=%.10g, y_res=%.10g, units=%d",
3607 (double) x_resolution,(double) y_resolution, unit_type);
3608 (void) SetImageProperty(image,"png:pHYs ",msg,
3613 #if defined(PNG_oFFs_SUPPORTED)
3614 if (png_get_valid(ping,ping_info,PNG_INFO_oFFs))
3616 (void) FormatLocaleString(msg,MaxTextExtent,"x_off=%.20g, y_off=%.20g",
3617 (double) image->page.x,(double) image->page.y);
3618 (void) SetImageProperty(image,"png:oFFs ",msg,
3623 if ((image->page.width != 0 && image->page.width != image->columns) ||
3624 (image->page.height != 0 && image->page.height != image->rows))
3626 (void) FormatLocaleString(msg,MaxTextExtent,
3627 "width=%.20g, height=%.20g",
3628 (double) image->page.width,(double) image->page.height);
3629 (void) SetImageProperty(image,"png:vpAg ",msg,
3635 Relinquish resources.
3637 png_destroy_read_struct(&ping,&ping_info,&end_info);
3639 ping_pixels=(unsigned char *) RelinquishMagickMemory(ping_pixels);
3641 if (logging != MagickFalse)
3642 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3643 " exit ReadOnePNGImage()");
3645 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
3646 UnlockSemaphoreInfo(ping_semaphore);
3649 /* } for navigation to beginning of SETJMP-protected block, revert to
3650 * Throwing an Exception when an error occurs.
3655 /* end of reading one PNG image */
3658 static Image *ReadPNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
3673 magic_number[MaxTextExtent];
3681 assert(image_info != (const ImageInfo *) NULL);
3682 assert(image_info->signature == MagickSignature);
3684 if (image_info->debug != MagickFalse)
3685 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
3686 image_info->filename);
3688 assert(exception != (ExceptionInfo *) NULL);
3689 assert(exception->signature == MagickSignature);
3690 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter ReadPNGImage()");
3691 image=AcquireImage(image_info,exception);
3692 mng_info=(MngInfo *) NULL;
3693 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
3695 if (status == MagickFalse)
3696 ThrowReaderException(FileOpenError,"UnableToOpenFile");
3699 Verify PNG signature.
3701 count=ReadBlob(image,8,(unsigned char *) magic_number);
3703 if (count < 8 || memcmp(magic_number,"\211PNG\r\n\032\n",8) != 0)
3704 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
3707 Allocate a MngInfo structure.
3709 have_mng_structure=MagickFalse;
3710 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
3712 if (mng_info == (MngInfo *) NULL)
3713 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
3716 Initialize members of the MngInfo structure.
3718 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
3719 mng_info->image=image;
3720 have_mng_structure=MagickTrue;
3723 image=ReadOnePNGImage(mng_info,image_info,exception);
3724 MngInfoFreeStruct(mng_info,&have_mng_structure);
3726 if (image == (Image *) NULL)
3728 if (previous != (Image *) NULL)
3730 if (previous->signature != MagickSignature)
3731 ThrowReaderException(CorruptImageError,"CorruptImage");
3733 (void) CloseBlob(previous);
3734 (void) DestroyImageList(previous);
3737 if (logging != MagickFalse)
3738 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3739 "exit ReadPNGImage() with error");
3741 return((Image *) NULL);
3744 (void) CloseBlob(image);
3746 if ((image->columns == 0) || (image->rows == 0))
3748 if (logging != MagickFalse)
3749 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3750 "exit ReadPNGImage() with error.");
3752 ThrowReaderException(CorruptImageError,"CorruptImage");
3755 if ((IssRGBColorspace(image->colorspace) != MagickFalse) &&
3756 (image->gamma == 1.0))
3757 SetImageColorspace(image,RGBColorspace,exception);
3759 if (LocaleCompare(image_info->magick,"PNG24") == 0)
3761 (void) SetImageType(image,TrueColorType,exception);
3762 image->matte=MagickFalse;
3765 if (LocaleCompare(image_info->magick,"PNG32") == 0)
3766 (void) SetImageType(image,TrueColorMatteType,exception);
3768 if (logging != MagickFalse)
3769 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3770 " page.w: %.20g, page.h: %.20g,page.x: %.20g, page.y: %.20g.",
3771 (double) image->page.width,(double) image->page.height,
3772 (double) image->page.x,(double) image->page.y);
3774 if (logging != MagickFalse)
3775 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit ReadPNGImage()");
3782 #if defined(JNG_SUPPORTED)
3784 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3788 % R e a d O n e J N G I m a g e %
3792 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3794 % ReadOneJNGImage() reads a JPEG Network Graphics (JNG) image file
3795 % (minus the 8-byte signature) and returns it. It allocates the memory
3796 % necessary for the new Image structure and returns a pointer to the new
3799 % JNG support written by Glenn Randers-Pehrson, glennrp@image...
3801 % The format of the ReadOneJNGImage method is:
3803 % Image *ReadOneJNGImage(MngInfo *mng_info, const ImageInfo *image_info,
3804 % ExceptionInfo *exception)
3806 % A description of each parameter follows:
3808 % o mng_info: Specifies a pointer to a MngInfo structure.
3810 % o image_info: the image info.
3812 % o exception: return any errors or warnings in this structure.
3815 static Image *ReadOneJNGImage(MngInfo *mng_info,
3816 const ImageInfo *image_info, ExceptionInfo *exception)
3843 jng_image_sample_depth,
3844 jng_image_compression_method,
3845 jng_image_interlace_method,
3846 jng_alpha_sample_depth,
3847 jng_alpha_compression_method,
3848 jng_alpha_filter_method,
3849 jng_alpha_interlace_method;
3851 register const Quantum
3861 register unsigned char
3872 jng_alpha_compression_method=0;
3873 jng_alpha_sample_depth=8;
3877 alpha_image=(Image *) NULL;
3878 color_image=(Image *) NULL;
3879 alpha_image_info=(ImageInfo *) NULL;
3880 color_image_info=(ImageInfo *) NULL;
3882 logging=LogMagickEvent(CoderEvent,GetMagickModule(),
3883 " Enter ReadOneJNGImage()");
3885 image=mng_info->image;
3887 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
3890 Allocate next image structure.
3892 if (logging != MagickFalse)
3893 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3894 " AcquireNextImage()");
3896 AcquireNextImage(image_info,image,exception);
3898 if (GetNextImageInList(image) == (Image *) NULL)
3899 return((Image *) NULL);
3901 image=SyncNextImageInList(image);
3903 mng_info->image=image;
3906 Signature bytes have already been read.
3909 read_JSEP=MagickFalse;
3910 reading_idat=MagickFalse;
3911 skip_to_iend=MagickFalse;
3915 type[MaxTextExtent];
3924 Read a new JNG chunk.
3926 status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
3927 2*GetBlobSize(image));
3929 if (status == MagickFalse)
3933 (void) ConcatenateMagickString(type,"errr",MaxTextExtent);
3934 length=ReadBlobMSBLong(image);
3935 count=(unsigned int) ReadBlob(image,4,(unsigned char *) type);
3937 if (logging != MagickFalse)
3938 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3939 " Reading JNG chunk type %c%c%c%c, length: %.20g",
3940 type[0],type[1],type[2],type[3],(double) length);
3942 if (length > PNG_UINT_31_MAX || count == 0)
3943 ThrowReaderException(CorruptImageError,"CorruptImage");
3946 chunk=(unsigned char *) NULL;
3950 chunk=(unsigned char *) AcquireQuantumMemory(length,sizeof(*chunk));
3952 if (chunk == (unsigned char *) NULL)
3953 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
3955 for (i=0; i < (ssize_t) length; i++)
3956 chunk[i]=(unsigned char) ReadBlobByte(image);
3961 (void) ReadBlobMSBLong(image); /* read crc word */
3966 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
3971 if (memcmp(type,mng_JHDR,4) == 0)
3975 jng_width=(size_t) ((p[0] << 24) | (p[1] << 16) |
3976 (p[2] << 8) | p[3]);
3977 jng_height=(size_t) ((p[4] << 24) | (p[5] << 16) |
3978 (p[6] << 8) | p[7]);
3979 jng_color_type=p[8];
3980 jng_image_sample_depth=p[9];
3981 jng_image_compression_method=p[10];
3982 jng_image_interlace_method=p[11];
3984 image->interlace=jng_image_interlace_method != 0 ? PNGInterlace :
3987 jng_alpha_sample_depth=p[12];
3988 jng_alpha_compression_method=p[13];
3989 jng_alpha_filter_method=p[14];
3990 jng_alpha_interlace_method=p[15];
3992 if (logging != MagickFalse)
3994 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3995 " jng_width: %16lu",(unsigned long) jng_width);
3997 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3998 " jng_width: %16lu",(unsigned long) jng_height);
4000 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4001 " jng_color_type: %16d",jng_color_type);
4003 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4004 " jng_image_sample_depth: %3d",
4005 jng_image_sample_depth);
4007 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4008 " jng_image_compression_method:%3d",
4009 jng_image_compression_method);
4011 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4012 " jng_image_interlace_method: %3d",
4013 jng_image_interlace_method);
4015 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4016 " jng_alpha_sample_depth: %3d",
4017 jng_alpha_sample_depth);
4019 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4020 " jng_alpha_compression_method:%3d",
4021 jng_alpha_compression_method);
4023 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4024 " jng_alpha_filter_method: %3d",
4025 jng_alpha_filter_method);
4027 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4028 " jng_alpha_interlace_method: %3d",
4029 jng_alpha_interlace_method);
4034 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4040 if ((reading_idat == MagickFalse) && (read_JSEP == MagickFalse) &&
4041 ((memcmp(type,mng_JDAT,4) == 0) || (memcmp(type,mng_JdAA,4) == 0) ||
4042 (memcmp(type,mng_IDAT,4) == 0) || (memcmp(type,mng_JDAA,4) == 0)))
4045 o create color_image
4046 o open color_blob, attached to color_image
4047 o if (color type has alpha)
4048 open alpha_blob, attached to alpha_image
4051 color_image_info=(ImageInfo *)AcquireMagickMemory(sizeof(ImageInfo));
4053 if (color_image_info == (ImageInfo *) NULL)
4054 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
4056 GetImageInfo(color_image_info);
4057 color_image=AcquireImage(color_image_info,exception);
4059 if (color_image == (Image *) NULL)
4060 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
4062 if (logging != MagickFalse)
4063 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4064 " Creating color_blob.");
4066 (void) AcquireUniqueFilename(color_image->filename);
4067 status=OpenBlob(color_image_info,color_image,WriteBinaryBlobMode,
4070 if (status == MagickFalse)
4071 return((Image *) NULL);
4073 if ((image_info->ping == MagickFalse) && (jng_color_type >= 12))
4075 alpha_image_info=(ImageInfo *)
4076 AcquireMagickMemory(sizeof(ImageInfo));
4078 if (alpha_image_info == (ImageInfo *) NULL)
4079 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
4081 GetImageInfo(alpha_image_info);
4082 alpha_image=AcquireImage(alpha_image_info,exception);
4084 if (alpha_image == (Image *) NULL)
4086 alpha_image=DestroyImage(alpha_image);
4087 ThrowReaderException(ResourceLimitError,
4088 "MemoryAllocationFailed");
4091 if (logging != MagickFalse)
4092 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4093 " Creating alpha_blob.");
4095 (void) AcquireUniqueFilename(alpha_image->filename);
4096 status=OpenBlob(alpha_image_info,alpha_image,WriteBinaryBlobMode,
4099 if (status == MagickFalse)
4100 return((Image *) NULL);
4102 if (jng_alpha_compression_method == 0)
4107 if (logging != MagickFalse)
4108 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4109 " Writing IHDR chunk to alpha_blob.");
4111 (void) WriteBlob(alpha_image,8,(const unsigned char *)
4112 "\211PNG\r\n\032\n");
4114 (void) WriteBlobMSBULong(alpha_image,13L);
4115 PNGType(data,mng_IHDR);
4116 LogPNGChunk(logging,mng_IHDR,13L);
4117 PNGLong(data+4,jng_width);
4118 PNGLong(data+8,jng_height);
4119 data[12]=jng_alpha_sample_depth;
4120 data[13]=0; /* color_type gray */
4121 data[14]=0; /* compression method 0 */
4122 data[15]=0; /* filter_method 0 */
4123 data[16]=0; /* interlace_method 0 */
4124 (void) WriteBlob(alpha_image,17,data);
4125 (void) WriteBlobMSBULong(alpha_image,crc32(0,data,17));
4128 reading_idat=MagickTrue;
4131 if (memcmp(type,mng_JDAT,4) == 0)
4133 /* Copy chunk to color_image->blob */
4135 if (logging != MagickFalse)
4136 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4137 " Copying JDAT chunk data to color_blob.");
4139 (void) WriteBlob(color_image,length,chunk);
4142 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4147 if (memcmp(type,mng_IDAT,4) == 0)
4152 /* Copy IDAT header and chunk data to alpha_image->blob */
4154 if (image_info->ping == MagickFalse)
4156 if (logging != MagickFalse)
4157 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4158 " Copying IDAT chunk data to alpha_blob.");
4160 (void) WriteBlobMSBULong(alpha_image,(size_t) length);
4161 PNGType(data,mng_IDAT);
4162 LogPNGChunk(logging,mng_IDAT,length);
4163 (void) WriteBlob(alpha_image,4,data);
4164 (void) WriteBlob(alpha_image,length,chunk);
4165 (void) WriteBlobMSBULong(alpha_image,
4166 crc32(crc32(0,data,4),chunk,(uInt) length));
4170 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4175 if ((memcmp(type,mng_JDAA,4) == 0) || (memcmp(type,mng_JdAA,4) == 0))
4177 /* Copy chunk data to alpha_image->blob */
4179 if (image_info->ping == MagickFalse)
4181 if (logging != MagickFalse)
4182 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4183 " Copying JDAA chunk data to alpha_blob.");
4185 (void) WriteBlob(alpha_image,length,chunk);
4189 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4194 if (memcmp(type,mng_JSEP,4) == 0)
4196 read_JSEP=MagickTrue;
4199 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4204 if (memcmp(type,mng_bKGD,4) == 0)
4208 image->background_color.red=ScaleCharToQuantum(p[1]);
4209 image->background_color.green=image->background_color.red;
4210 image->background_color.blue=image->background_color.red;
4215 image->background_color.red=ScaleCharToQuantum(p[1]);
4216 image->background_color.green=ScaleCharToQuantum(p[3]);
4217 image->background_color.blue=ScaleCharToQuantum(p[5]);
4220 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4224 if (memcmp(type,mng_gAMA,4) == 0)
4227 image->gamma=((float) mng_get_long(p))*0.00001;
4229 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4233 if (memcmp(type,mng_cHRM,4) == 0)
4237 image->chromaticity.white_point.x=0.00001*mng_get_long(p);
4238 image->chromaticity.white_point.y=0.00001*mng_get_long(&p[4]);
4239 image->chromaticity.red_primary.x=0.00001*mng_get_long(&p[8]);
4240 image->chromaticity.red_primary.y=0.00001*mng_get_long(&p[12]);
4241 image->chromaticity.green_primary.x=0.00001*mng_get_long(&p[16]);
4242 image->chromaticity.green_primary.y=0.00001*mng_get_long(&p[20]);
4243 image->chromaticity.blue_primary.x=0.00001*mng_get_long(&p[24]);
4244 image->chromaticity.blue_primary.y=0.00001*mng_get_long(&p[28]);
4247 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4251 if (memcmp(type,mng_sRGB,4) == 0)
4255 image->rendering_intent=
4256 Magick_RenderingIntent_from_PNG_RenderingIntent(p[0]);
4257 image->gamma=1.000f/2.200f;
4258 image->chromaticity.red_primary.x=0.6400f;
4259 image->chromaticity.red_primary.y=0.3300f;
4260 image->chromaticity.green_primary.x=0.3000f;
4261 image->chromaticity.green_primary.y=0.6000f;
4262 image->chromaticity.blue_primary.x=0.1500f;
4263 image->chromaticity.blue_primary.y=0.0600f;
4264 image->chromaticity.white_point.x=0.3127f;
4265 image->chromaticity.white_point.y=0.3290f;
4268 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4272 if (memcmp(type,mng_oFFs,4) == 0)
4276 image->page.x=(ssize_t) mng_get_long(p);
4277 image->page.y=(ssize_t) mng_get_long(&p[4]);
4279 if ((int) p[8] != 0)
4281 image->page.x/=10000;
4282 image->page.y/=10000;
4287 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4292 if (memcmp(type,mng_pHYs,4) == 0)
4296 image->resolution.x=(double) mng_get_long(p);
4297 image->resolution.y=(double) mng_get_long(&p[4]);
4298 if ((int) p[8] == PNG_RESOLUTION_METER)
4300 image->units=PixelsPerCentimeterResolution;
4301 image->resolution.x=image->resolution.x/100.0f;
4302 image->resolution.y=image->resolution.y/100.0f;
4306 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4311 if (memcmp(type,mng_iCCP,4) == 0)
4315 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4322 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4324 if (memcmp(type,mng_IEND,4))
4334 Finish up reading image data:
4336 o read main image from color_blob.
4340 o if (color_type has alpha)
4341 if alpha_encoding is PNG
4342 read secondary image from alpha_blob via ReadPNG
4343 if alpha_encoding is JPEG
4344 read secondary image from alpha_blob via ReadJPEG
4348 o copy intensity of secondary image into
4349 alpha samples of main image.
4351 o destroy the secondary image.
4354 (void) CloseBlob(color_image);
4356 if (logging != MagickFalse)
4357 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4358 " Reading jng_image from color_blob.");
4360 (void) FormatLocaleString(color_image_info->filename,MaxTextExtent,"%s",
4361 color_image->filename);
4363 color_image_info->ping=MagickFalse; /* To do: avoid this */
4364 jng_image=ReadImage(color_image_info,exception);
4366 if (jng_image == (Image *) NULL)
4367 return((Image *) NULL);
4369 (void) RelinquishUniqueFileResource(color_image->filename);
4370 color_image=DestroyImage(color_image);
4371 color_image_info=DestroyImageInfo(color_image_info);
4373 if (jng_image == (Image *) NULL)
4374 return((Image *) NULL);
4376 if (logging != MagickFalse)
4377 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4378 " Copying jng_image pixels to main image.");
4380 image->rows=jng_height;
4381 image->columns=jng_width;
4383 for (y=0; y < (ssize_t) image->rows; y++)
4385 s=GetVirtualPixels(jng_image,0,y,image->columns,1,exception);
4386 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
4387 for (x=(ssize_t) image->columns; x != 0; x--)
4389 SetPixelRed(image,GetPixelRed(jng_image,s),q);
4390 SetPixelGreen(image,GetPixelGreen(jng_image,s),q);
4391 SetPixelBlue(image,GetPixelBlue(jng_image,s),q);
4392 q+=GetPixelChannels(image);
4393 s+=GetPixelChannels(jng_image);
4396 if (SyncAuthenticPixels(image,exception) == MagickFalse)
4400 jng_image=DestroyImage(jng_image);
4402 if (image_info->ping == MagickFalse)
4404 if (jng_color_type >= 12)
4406 if (jng_alpha_compression_method == 0)
4410 (void) WriteBlobMSBULong(alpha_image,0x00000000L);
4411 PNGType(data,mng_IEND);
4412 LogPNGChunk(logging,mng_IEND,0L);
4413 (void) WriteBlob(alpha_image,4,data);
4414 (void) WriteBlobMSBULong(alpha_image,crc32(0,data,4));
4417 (void) CloseBlob(alpha_image);
4419 if (logging != MagickFalse)
4420 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4421 " Reading alpha from alpha_blob.");
4423 (void) FormatLocaleString(alpha_image_info->filename,MaxTextExtent,
4424 "%s",alpha_image->filename);
4426 jng_image=ReadImage(alpha_image_info,exception);
4428 if (jng_image != (Image *) NULL)
4429 for (y=0; y < (ssize_t) image->rows; y++)
4431 s=GetVirtualPixels(jng_image,0,y,image->columns,1,
4433 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
4435 if (image->matte != MagickFalse)
4436 for (x=(ssize_t) image->columns; x != 0; x--)
4438 SetPixelAlpha(image,GetPixelRed(jng_image,s),q);
4439 q+=GetPixelChannels(image);
4440 s+=GetPixelChannels(jng_image);
4444 for (x=(ssize_t) image->columns; x != 0; x--)
4446 SetPixelAlpha(image,GetPixelRed(jng_image,s),q);
4447 if (GetPixelAlpha(image,q) != OpaqueAlpha)
4448 image->matte=MagickTrue;
4449 q+=GetPixelChannels(image);
4450 s+=GetPixelChannels(jng_image);
4453 if (SyncAuthenticPixels(image,exception) == MagickFalse)
4456 (void) RelinquishUniqueFileResource(alpha_image->filename);
4457 alpha_image=DestroyImage(alpha_image);
4458 alpha_image_info=DestroyImageInfo(alpha_image_info);
4459 if (jng_image != (Image *) NULL)
4460 jng_image=DestroyImage(jng_image);
4464 /* Read the JNG image. */
4466 if (mng_info->mng_type == 0)
4468 mng_info->mng_width=jng_width;
4469 mng_info->mng_height=jng_height;
4472 if (image->page.width == 0 && image->page.height == 0)
4474 image->page.width=jng_width;
4475 image->page.height=jng_height;
4478 if (image->page.x == 0 && image->page.y == 0)
4480 image->page.x=mng_info->x_off[mng_info->object_id];
4481 image->page.y=mng_info->y_off[mng_info->object_id];
4486 image->page.y=mng_info->y_off[mng_info->object_id];
4489 mng_info->image_found++;
4490 status=SetImageProgress(image,LoadImagesTag,2*TellBlob(image),
4491 2*GetBlobSize(image));
4493 if (logging != MagickFalse)
4494 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4495 " exit ReadOneJNGImage()");
4501 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4505 % R e a d J N G I m a g e %
4509 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4511 % ReadJNGImage() reads a JPEG Network Graphics (JNG) image file
4512 % (including the 8-byte signature) and returns it. It allocates the memory
4513 % necessary for the new Image structure and returns a pointer to the new
4516 % JNG support written by Glenn Randers-Pehrson, glennrp@image...
4518 % The format of the ReadJNGImage method is:
4520 % Image *ReadJNGImage(const ImageInfo *image_info, ExceptionInfo
4523 % A description of each parameter follows:
4525 % o image_info: the image info.
4527 % o exception: return any errors or warnings in this structure.
4531 static Image *ReadJNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
4546 magic_number[MaxTextExtent];
4554 assert(image_info != (const ImageInfo *) NULL);
4555 assert(image_info->signature == MagickSignature);
4556 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image_info->filename);
4557 assert(exception != (ExceptionInfo *) NULL);
4558 assert(exception->signature == MagickSignature);
4559 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter ReadJNGImage()");
4560 image=AcquireImage(image_info,exception);
4561 mng_info=(MngInfo *) NULL;
4562 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
4564 if (status == MagickFalse)
4565 return((Image *) NULL);
4567 if (LocaleCompare(image_info->magick,"JNG") != 0)
4568 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
4570 /* Verify JNG signature. */
4572 count=(size_t) ReadBlob(image,8,(unsigned char *) magic_number);
4574 if (count < 8 || memcmp(magic_number,"\213JNG\r\n\032\n",8) != 0)
4575 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
4577 /* Allocate a MngInfo structure. */
4579 have_mng_structure=MagickFalse;
4580 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(*mng_info));
4582 if (mng_info == (MngInfo *) NULL)
4583 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
4585 /* Initialize members of the MngInfo structure. */
4587 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
4588 have_mng_structure=MagickTrue;
4590 mng_info->image=image;
4592 image=ReadOneJNGImage(mng_info,image_info,exception);
4593 MngInfoFreeStruct(mng_info,&have_mng_structure);
4595 if (image == (Image *) NULL)
4597 if (IsImageObject(previous) != MagickFalse)
4599 (void) CloseBlob(previous);
4600 (void) DestroyImageList(previous);
4603 if (logging != MagickFalse)
4604 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4605 "exit ReadJNGImage() with error");
4607 return((Image *) NULL);
4609 (void) CloseBlob(image);
4611 if (image->columns == 0 || image->rows == 0)
4613 if (logging != MagickFalse)
4614 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4615 "exit ReadJNGImage() with error");
4617 ThrowReaderException(CorruptImageError,"CorruptImage");
4620 if (logging != MagickFalse)
4621 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit ReadJNGImage()");
4627 static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
4630 page_geometry[MaxTextExtent];
4663 #if defined(MNG_INSERT_LAYERS)
4665 mng_background_color;
4668 register unsigned char
4683 #if defined(MNG_INSERT_LAYERS)
4688 volatile unsigned int
4689 #ifdef MNG_OBJECT_BUFFERS
4690 mng_background_object=0,
4692 mng_type=0; /* 0: PNG or JNG; 1: MNG; 2: MNG-LC; 3: MNG-VLC */
4695 default_frame_timeout,
4697 #if defined(MNG_INSERT_LAYERS)
4703 /* These delays are all measured in image ticks_per_second,
4704 * not in MNG ticks_per_second
4707 default_frame_delay,
4711 #if defined(MNG_INSERT_LAYERS)
4720 previous_fb.bottom=0;
4722 previous_fb.right=0;
4724 default_fb.bottom=0;
4728 /* Open image file. */
4730 assert(image_info != (const ImageInfo *) NULL);
4731 assert(image_info->signature == MagickSignature);
4732 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image_info->filename);
4733 assert(exception != (ExceptionInfo *) NULL);
4734 assert(exception->signature == MagickSignature);
4735 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter ReadMNGImage()");
4736 image=AcquireImage(image_info,exception);
4737 mng_info=(MngInfo *) NULL;
4738 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
4740 if (status == MagickFalse)
4741 return((Image *) NULL);
4743 first_mng_object=MagickFalse;
4745 have_mng_structure=MagickFalse;
4747 /* Allocate a MngInfo structure. */
4749 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
4751 if (mng_info == (MngInfo *) NULL)
4752 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
4754 /* Initialize members of the MngInfo structure. */
4756 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
4757 mng_info->image=image;
4758 have_mng_structure=MagickTrue;
4760 if (LocaleCompare(image_info->magick,"MNG") == 0)
4763 magic_number[MaxTextExtent];
4765 /* Verify MNG signature. */
4766 count=(size_t) ReadBlob(image,8,(unsigned char *) magic_number);
4767 if (memcmp(magic_number,"\212MNG\r\n\032\n",8) != 0)
4768 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
4770 /* Initialize some nonzero members of the MngInfo structure. */
4771 for (i=0; i < MNG_MAX_OBJECTS; i++)
4773 mng_info->object_clip[i].right=(ssize_t) PNG_UINT_31_MAX;
4774 mng_info->object_clip[i].bottom=(ssize_t) PNG_UINT_31_MAX;
4776 mng_info->exists[0]=MagickTrue;
4779 first_mng_object=MagickTrue;
4781 #if defined(MNG_INSERT_LAYERS)
4782 insert_layers=MagickFalse; /* should be False when converting or mogrifying */
4784 default_frame_delay=0;
4785 default_frame_timeout=0;
4788 mng_info->ticks_per_second=1UL*image->ticks_per_second;
4790 skip_to_iend=MagickFalse;
4791 term_chunk_found=MagickFalse;
4792 mng_info->framing_mode=1;
4793 #if defined(MNG_INSERT_LAYERS)
4794 mandatory_back=MagickFalse;
4796 #if defined(MNG_INSERT_LAYERS)
4797 mng_background_color=image->background_color;
4799 default_fb=mng_info->frame;
4800 previous_fb=mng_info->frame;
4804 type[MaxTextExtent];
4806 if (LocaleCompare(image_info->magick,"MNG") == 0)
4815 (void) ConcatenateMagickString(type,"errr",MaxTextExtent);
4816 length=ReadBlobMSBLong(image);
4817 count=(size_t) ReadBlob(image,4,(unsigned char *) type);
4819 if (logging != MagickFalse)
4820 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4821 " Reading MNG chunk type %c%c%c%c, length: %.20g",
4822 type[0],type[1],type[2],type[3],(double) length);
4824 if (length > PNG_UINT_31_MAX)
4828 ThrowReaderException(CorruptImageError,"CorruptImage");
4831 chunk=(unsigned char *) NULL;
4835 chunk=(unsigned char *) AcquireQuantumMemory(length,sizeof(*chunk));
4837 if (chunk == (unsigned char *) NULL)
4838 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
4840 for (i=0; i < (ssize_t) length; i++)
4841 chunk[i]=(unsigned char) ReadBlobByte(image);
4846 (void) ReadBlobMSBLong(image); /* read crc word */
4848 #if !defined(JNG_SUPPORTED)
4849 if (memcmp(type,mng_JHDR,4) == 0)
4851 skip_to_iend=MagickTrue;
4853 if (mng_info->jhdr_warning == 0)
4854 (void) ThrowMagickException(exception,GetMagickModule(),
4855 CoderError,"JNGCompressNotSupported","`%s'",image->filename);
4857 mng_info->jhdr_warning++;
4860 if (memcmp(type,mng_DHDR,4) == 0)
4862 skip_to_iend=MagickTrue;
4864 if (mng_info->dhdr_warning == 0)
4865 (void) ThrowMagickException(exception,GetMagickModule(),
4866 CoderError,"DeltaPNGNotSupported","`%s'",image->filename);
4868 mng_info->dhdr_warning++;
4870 if (memcmp(type,mng_MEND,4) == 0)
4875 if (memcmp(type,mng_IEND,4) == 0)
4876 skip_to_iend=MagickFalse;
4879 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4881 if (logging != MagickFalse)
4882 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4888 if (memcmp(type,mng_MHDR,4) == 0)
4890 mng_info->mng_width=(size_t) ((p[0] << 24) | (p[1] << 16) |
4891 (p[2] << 8) | p[3]);
4893 mng_info->mng_height=(size_t) ((p[4] << 24) | (p[5] << 16) |
4894 (p[6] << 8) | p[7]);
4896 if (logging != MagickFalse)
4898 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4899 " MNG width: %.20g",(double) mng_info->mng_width);
4900 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4901 " MNG height: %.20g",(double) mng_info->mng_height);
4905 mng_info->ticks_per_second=(size_t) mng_get_long(p);
4907 if (mng_info->ticks_per_second == 0)
4908 default_frame_delay=0;
4911 default_frame_delay=1UL*image->ticks_per_second/
4912 mng_info->ticks_per_second;
4914 frame_delay=default_frame_delay;
4920 simplicity=(size_t) mng_get_long(p);
4923 mng_type=1; /* Full MNG */
4925 if ((simplicity != 0) && ((simplicity | 11) == 11))
4926 mng_type=2; /* LC */
4928 if ((simplicity != 0) && ((simplicity | 9) == 9))
4929 mng_type=3; /* VLC */
4931 #if defined(MNG_INSERT_LAYERS)
4933 insert_layers=MagickTrue;
4935 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
4937 /* Allocate next image structure. */
4938 AcquireNextImage(image_info,image,exception);
4940 if (GetNextImageInList(image) == (Image *) NULL)
4941 return((Image *) NULL);
4943 image=SyncNextImageInList(image);
4944 mng_info->image=image;
4947 if ((mng_info->mng_width > 65535L) ||
4948 (mng_info->mng_height > 65535L))
4949 ThrowReaderException(ImageError,"WidthOrHeightExceedsLimit");
4951 (void) FormatLocaleString(page_geometry,MaxTextExtent,
4952 "%.20gx%.20g+0+0",(double) mng_info->mng_width,(double)
4953 mng_info->mng_height);
4955 mng_info->frame.left=0;
4956 mng_info->frame.right=(ssize_t) mng_info->mng_width;
4957 mng_info->frame.top=0;
4958 mng_info->frame.bottom=(ssize_t) mng_info->mng_height;
4959 mng_info->clip=default_fb=previous_fb=mng_info->frame;
4961 for (i=0; i < MNG_MAX_OBJECTS; i++)
4962 mng_info->object_clip[i]=mng_info->frame;
4964 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4968 if (memcmp(type,mng_TERM,4) == 0)
4979 final_delay=(png_uint_32) mng_get_long(&p[2]);
4980 mng_iterations=(png_uint_32) mng_get_long(&p[6]);
4982 if (mng_iterations == PNG_UINT_31_MAX)
4985 image->iterations=mng_iterations;
4986 term_chunk_found=MagickTrue;
4989 if (logging != MagickFalse)
4991 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4992 " repeat=%d",repeat);
4994 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4995 " final_delay=%.20g",(double) final_delay);
4997 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4998 " image->iterations=%.20g",(double) image->iterations);
5001 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5004 if (memcmp(type,mng_DEFI,4) == 0)
5007 (void) ThrowMagickException(exception,GetMagickModule(),
5008 CoderError,"DEFI chunk found in MNG-VLC datastream","`%s'",
5011 object_id=(p[0] << 8) | p[1];
5013 if (mng_type == 2 && object_id != 0)
5014 (void) ThrowMagickException(exception,GetMagickModule(),
5015 CoderError,"Nonzero object_id in MNG-LC datastream","`%s'",
5018 if (object_id > MNG_MAX_OBJECTS)
5021 Instead of using a warning we should allocate a larger
5022 MngInfo structure and continue.
5024 (void) ThrowMagickException(exception,GetMagickModule(),
5025 CoderError,"object id too large","`%s'",image->filename);
5026 object_id=MNG_MAX_OBJECTS;
5029 if (mng_info->exists[object_id])
5030 if (mng_info->frozen[object_id])
5032 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5033 (void) ThrowMagickException(exception,
5034 GetMagickModule(),CoderError,
5035 "DEFI cannot redefine a frozen MNG object","`%s'",
5040 mng_info->exists[object_id]=MagickTrue;
5043 mng_info->invisible[object_id]=p[2];
5046 Extract object offset info.
5050 mng_info->x_off[object_id]=(ssize_t) ((p[4] << 24) |
5051 (p[5] << 16) | (p[6] << 8) | p[7]);
5053 mng_info->y_off[object_id]=(ssize_t) ((p[8] << 24) |
5054 (p[9] << 16) | (p[10] << 8) | p[11]);
5056 if (logging != MagickFalse)
5058 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5059 " x_off[%d]: %.20g",object_id,(double)
5060 mng_info->x_off[object_id]);
5062 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5063 " y_off[%d]: %.20g",object_id,(double)
5064 mng_info->y_off[object_id]);
5069 Extract object clipping info.
5072 mng_info->object_clip[object_id]=mng_read_box(mng_info->frame,0,
5075 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5078 if (memcmp(type,mng_bKGD,4) == 0)
5080 mng_info->have_global_bkgd=MagickFalse;
5084 mng_info->mng_global_bkgd.red=
5085 ScaleShortToQuantum((unsigned short) ((p[0] << 8) | p[1]));
5087 mng_info->mng_global_bkgd.green=
5088 ScaleShortToQuantum((unsigned short) ((p[2] << 8) | p[3]));
5090 mng_info->mng_global_bkgd.blue=
5091 ScaleShortToQuantum((unsigned short) ((p[4] << 8) | p[5]));
5093 mng_info->have_global_bkgd=MagickTrue;
5096 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5099 if (memcmp(type,mng_BACK,4) == 0)
5101 #if defined(MNG_INSERT_LAYERS)
5103 mandatory_back=p[6];
5108 if (mandatory_back && length > 5)
5110 mng_background_color.red=
5111 ScaleShortToQuantum((unsigned short) ((p[0] << 8) | p[1]));
5113 mng_background_color.green=
5114 ScaleShortToQuantum((unsigned short) ((p[2] << 8) | p[3]));
5116 mng_background_color.blue=
5117 ScaleShortToQuantum((unsigned short) ((p[4] << 8) | p[5]));
5119 mng_background_color.alpha=OpaqueAlpha;
5122 #ifdef MNG_OBJECT_BUFFERS
5124 mng_background_object=(p[7] << 8) | p[8];
5127 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5131 if (memcmp(type,mng_PLTE,4) == 0)
5133 /* Read global PLTE. */
5135 if (length && (length < 769))
5137 if (mng_info->global_plte == (png_colorp) NULL)
5138 mng_info->global_plte=(png_colorp) AcquireQuantumMemory(256,
5139 sizeof(*mng_info->global_plte));
5141 for (i=0; i < (ssize_t) (length/3); i++)
5143 mng_info->global_plte[i].red=p[3*i];
5144 mng_info->global_plte[i].green=p[3*i+1];
5145 mng_info->global_plte[i].blue=p[3*i+2];
5148 mng_info->global_plte_length=(unsigned int) (length/3);
5151 for ( ; i < 256; i++)
5153 mng_info->global_plte[i].red=i;
5154 mng_info->global_plte[i].green=i;
5155 mng_info->global_plte[i].blue=i;
5159 mng_info->global_plte_length=256;
5162 mng_info->global_plte_length=0;
5164 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5168 if (memcmp(type,mng_tRNS,4) == 0)
5170 /* read global tRNS */
5173 for (i=0; i < (ssize_t) length; i++)
5174 mng_info->global_trns[i]=p[i];
5177 for ( ; i < 256; i++)
5178 mng_info->global_trns[i]=255;
5180 mng_info->global_trns_length=(unsigned int) length;
5181 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5184 if (memcmp(type,mng_gAMA,4) == 0)
5191 igamma=mng_get_long(p);
5192 mng_info->global_gamma=((float) igamma)*0.00001;
5193 mng_info->have_global_gama=MagickTrue;
5197 mng_info->have_global_gama=MagickFalse;
5199 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5203 if (memcmp(type,mng_cHRM,4) == 0)
5205 /* Read global cHRM */
5209 mng_info->global_chrm.white_point.x=0.00001*mng_get_long(p);
5210 mng_info->global_chrm.white_point.y=0.00001*mng_get_long(&p[4]);
5211 mng_info->global_chrm.red_primary.x=0.00001*mng_get_long(&p[8]);
5212 mng_info->global_chrm.red_primary.y=0.00001*
5213 mng_get_long(&p[12]);
5214 mng_info->global_chrm.green_primary.x=0.00001*
5215 mng_get_long(&p[16]);
5216 mng_info->global_chrm.green_primary.y=0.00001*
5217 mng_get_long(&p[20]);
5218 mng_info->global_chrm.blue_primary.x=0.00001*
5219 mng_get_long(&p[24]);
5220 mng_info->global_chrm.blue_primary.y=0.00001*
5221 mng_get_long(&p[28]);
5222 mng_info->have_global_chrm=MagickTrue;
5225 mng_info->have_global_chrm=MagickFalse;
5227 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5231 if (memcmp(type,mng_sRGB,4) == 0)
5238 mng_info->global_srgb_intent=
5239 Magick_RenderingIntent_from_PNG_RenderingIntent(p[0]);
5240 mng_info->have_global_srgb=MagickTrue;
5243 mng_info->have_global_srgb=MagickFalse;
5245 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5249 if (memcmp(type,mng_iCCP,4) == 0)
5257 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5262 if (memcmp(type,mng_FRAM,4) == 0)
5265 (void) ThrowMagickException(exception,GetMagickModule(),
5266 CoderError,"FRAM chunk found in MNG-VLC datastream","`%s'",
5269 if ((mng_info->framing_mode == 2) || (mng_info->framing_mode == 4))
5270 image->delay=frame_delay;
5272 frame_delay=default_frame_delay;
5273 frame_timeout=default_frame_timeout;
5278 mng_info->framing_mode=p[0];
5280 if (logging != MagickFalse)
5281 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5282 " Framing_mode=%d",mng_info->framing_mode);
5286 /* Note the delay and frame clipping boundaries. */
5288 p++; /* framing mode */
5290 while (*p && ((p-chunk) < (ssize_t) length))
5291 p++; /* frame name */
5293 p++; /* frame name terminator */
5295 if ((p-chunk) < (ssize_t) (length-4))
5302 change_delay=(*p++);
5303 change_timeout=(*p++);
5304 change_clipping=(*p++);
5305 p++; /* change_sync */
5309 frame_delay=1UL*image->ticks_per_second*
5312 if (mng_info->ticks_per_second != 0)
5313 frame_delay/=mng_info->ticks_per_second;
5316 frame_delay=PNG_UINT_31_MAX;
5318 if (change_delay == 2)
5319 default_frame_delay=frame_delay;
5323 if (logging != MagickFalse)
5324 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5325 " Framing_delay=%.20g",(double) frame_delay);
5330 frame_timeout=1UL*image->ticks_per_second*
5333 if (mng_info->ticks_per_second != 0)
5334 frame_timeout/=mng_info->ticks_per_second;
5337 frame_timeout=PNG_UINT_31_MAX;
5339 if (change_delay == 2)
5340 default_frame_timeout=frame_timeout;
5344 if (logging != MagickFalse)
5345 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5346 " Framing_timeout=%.20g",(double) frame_timeout);
5349 if (change_clipping)
5351 fb=mng_read_box(previous_fb,(char) p[0],&p[1]);
5355 if (logging != MagickFalse)
5356 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5357 " Frame_clip: L=%.20g R=%.20g T=%.20g B=%.20g",
5358 (double) fb.left,(double) fb.right,(double) fb.top,
5359 (double) fb.bottom);
5361 if (change_clipping == 2)
5367 mng_info->clip=mng_minimum_box(fb,mng_info->frame);
5369 subframe_width=(size_t) (mng_info->clip.right
5370 -mng_info->clip.left);
5372 subframe_height=(size_t) (mng_info->clip.bottom
5373 -mng_info->clip.top);
5375 Insert a background layer behind the frame if framing_mode is 4.
5377 #if defined(MNG_INSERT_LAYERS)
5378 if (logging != MagickFalse)
5379 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5380 " subframe_width=%.20g, subframe_height=%.20g",(double)
5381 subframe_width,(double) subframe_height);
5383 if (insert_layers && (mng_info->framing_mode == 4) &&
5384 (subframe_width) && (subframe_height))
5386 /* Allocate next image structure. */
5387 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
5389 AcquireNextImage(image_info,image,exception);
5391 if (GetNextImageInList(image) == (Image *) NULL)
5393 image=DestroyImageList(image);
5394 MngInfoFreeStruct(mng_info,&have_mng_structure);
5395 return((Image *) NULL);
5398 image=SyncNextImageInList(image);
5401 mng_info->image=image;
5403 if (term_chunk_found)
5405 image->start_loop=MagickTrue;
5406 image->iterations=mng_iterations;
5407 term_chunk_found=MagickFalse;
5411 image->start_loop=MagickFalse;
5413 image->columns=subframe_width;
5414 image->rows=subframe_height;
5415 image->page.width=subframe_width;
5416 image->page.height=subframe_height;
5417 image->page.x=mng_info->clip.left;
5418 image->page.y=mng_info->clip.top;
5419 image->background_color=mng_background_color;
5420 image->matte=MagickFalse;
5422 (void) SetImageBackgroundColor(image,exception);
5424 if (logging != MagickFalse)
5425 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5426 " Insert backgd layer, L=%.20g, R=%.20g T=%.20g, B=%.20g",
5427 (double) mng_info->clip.left,(double) mng_info->clip.right,
5428 (double) mng_info->clip.top,(double) mng_info->clip.bottom);
5431 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5434 if (memcmp(type,mng_CLIP,4) == 0)
5443 first_object=(p[0] << 8) | p[1];
5444 last_object=(p[2] << 8) | p[3];
5446 for (i=(int) first_object; i <= (int) last_object; i++)
5448 if (mng_info->exists[i] && !mng_info->frozen[i])
5453 box=mng_info->object_clip[i];
5454 mng_info->object_clip[i]=mng_read_box(box,(char) p[4],&p[5]);
5458 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5461 if (memcmp(type,mng_SAVE,4) == 0)
5463 for (i=1; i < MNG_MAX_OBJECTS; i++)
5464 if (mng_info->exists[i])
5466 mng_info->frozen[i]=MagickTrue;
5467 #ifdef MNG_OBJECT_BUFFERS
5468 if (mng_info->ob[i] != (MngBuffer *) NULL)
5469 mng_info->ob[i]->frozen=MagickTrue;
5474 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5479 if ((memcmp(type,mng_DISC,4) == 0) || (memcmp(type,mng_SEEK,4) == 0))
5481 /* Read DISC or SEEK. */
5483 if ((length == 0) || !memcmp(type,mng_SEEK,4))
5485 for (i=1; i < MNG_MAX_OBJECTS; i++)
5486 MngInfoDiscardObject(mng_info,i);
5494 for (j=0; j < (ssize_t) length; j+=2)
5496 i=p[j] << 8 | p[j+1];
5497 MngInfoDiscardObject(mng_info,i);
5502 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5507 if (memcmp(type,mng_MOVE,4) == 0)
5515 first_object=(p[0] << 8) | p[1];
5516 last_object=(p[2] << 8) | p[3];
5517 for (i=(ssize_t) first_object; i <= (ssize_t) last_object; i++)
5519 if (mng_info->exists[i] && !mng_info->frozen[i])
5527 old_pair.a=mng_info->x_off[i];
5528 old_pair.b=mng_info->y_off[i];
5529 new_pair=mng_read_pair(old_pair,(int) p[4],&p[5]);
5530 mng_info->x_off[i]=new_pair.a;
5531 mng_info->y_off[i]=new_pair.b;
5535 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5539 if (memcmp(type,mng_LOOP,4) == 0)
5541 ssize_t loop_iters=1;
5542 loop_level=chunk[0];
5543 mng_info->loop_active[loop_level]=1; /* mark loop active */
5545 /* Record starting point. */
5546 loop_iters=mng_get_long(&chunk[1]);
5548 if (logging != MagickFalse)
5549 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5550 " LOOP level %.20g has %.20g iterations ",(double) loop_level,
5551 (double) loop_iters);
5553 if (loop_iters == 0)
5554 skipping_loop=loop_level;
5558 mng_info->loop_jump[loop_level]=TellBlob(image);
5559 mng_info->loop_count[loop_level]=loop_iters;
5562 mng_info->loop_iteration[loop_level]=0;
5563 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5567 if (memcmp(type,mng_ENDL,4) == 0)
5569 loop_level=chunk[0];
5571 if (skipping_loop > 0)
5573 if (skipping_loop == loop_level)
5576 Found end of zero-iteration loop.
5579 mng_info->loop_active[loop_level]=0;
5585 if (mng_info->loop_active[loop_level] == 1)
5587 mng_info->loop_count[loop_level]--;
5588 mng_info->loop_iteration[loop_level]++;
5590 if (logging != MagickFalse)
5591 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5592 " ENDL: LOOP level %.20g has %.20g remaining iters ",
5593 (double) loop_level,(double)
5594 mng_info->loop_count[loop_level]);
5596 if (mng_info->loop_count[loop_level] != 0)
5598 offset=SeekBlob(image,mng_info->loop_jump[loop_level],
5602 ThrowReaderException(CorruptImageError,
5603 "ImproperImageHeader");
5614 mng_info->loop_active[loop_level]=0;
5616 for (i=0; i < loop_level; i++)
5617 if (mng_info->loop_active[i] == 1)
5618 last_level=(short) i;
5619 loop_level=last_level;
5624 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5628 if (memcmp(type,mng_CLON,4) == 0)
5630 if (mng_info->clon_warning == 0)
5631 (void) ThrowMagickException(exception,GetMagickModule(),
5632 CoderError,"CLON is not implemented yet","`%s'",
5635 mng_info->clon_warning++;
5638 if (memcmp(type,mng_MAGN,4) == 0)
5653 magn_first=(p[0] << 8) | p[1];
5659 magn_last=(p[2] << 8) | p[3];
5662 magn_last=magn_first;
5663 #ifndef MNG_OBJECT_BUFFERS
5664 if (magn_first || magn_last)
5665 if (mng_info->magn_warning == 0)
5667 (void) ThrowMagickException(exception,
5668 GetMagickModule(),CoderError,
5669 "MAGN is not implemented yet for nonzero objects",
5670 "`%s'",image->filename);
5672 mng_info->magn_warning++;
5682 magn_mx=(p[5] << 8) | p[6];
5691 magn_my=(p[7] << 8) | p[8];
5700 magn_ml=(p[9] << 8) | p[10];
5709 magn_mr=(p[11] << 8) | p[12];
5718 magn_mt=(p[13] << 8) | p[14];
5727 magn_mb=(p[15] << 8) | p[16];
5739 magn_methy=magn_methx;
5742 if (magn_methx > 5 || magn_methy > 5)
5743 if (mng_info->magn_warning == 0)
5745 (void) ThrowMagickException(exception,
5746 GetMagickModule(),CoderError,
5747 "Unknown MAGN method in MNG datastream","`%s'",
5750 mng_info->magn_warning++;
5752 #ifdef MNG_OBJECT_BUFFERS
5753 /* Magnify existing objects in the range magn_first to magn_last */
5755 if (magn_first == 0 || magn_last == 0)
5757 /* Save the magnification factors for object 0 */
5758 mng_info->magn_mb=magn_mb;
5759 mng_info->magn_ml=magn_ml;
5760 mng_info->magn_mr=magn_mr;
5761 mng_info->magn_mt=magn_mt;
5762 mng_info->magn_mx=magn_mx;
5763 mng_info->magn_my=magn_my;
5764 mng_info->magn_methx=magn_methx;
5765 mng_info->magn_methy=magn_methy;
5769 if (memcmp(type,mng_PAST,4) == 0)
5771 if (mng_info->past_warning == 0)
5772 (void) ThrowMagickException(exception,GetMagickModule(),
5773 CoderError,"PAST is not implemented yet","`%s'",
5776 mng_info->past_warning++;
5779 if (memcmp(type,mng_SHOW,4) == 0)
5781 if (mng_info->show_warning == 0)
5782 (void) ThrowMagickException(exception,GetMagickModule(),
5783 CoderError,"SHOW is not implemented yet","`%s'",
5786 mng_info->show_warning++;
5789 if (memcmp(type,mng_sBIT,4) == 0)
5792 mng_info->have_global_sbit=MagickFalse;
5796 mng_info->global_sbit.gray=p[0];
5797 mng_info->global_sbit.red=p[0];
5798 mng_info->global_sbit.green=p[1];
5799 mng_info->global_sbit.blue=p[2];
5800 mng_info->global_sbit.alpha=p[3];
5801 mng_info->have_global_sbit=MagickTrue;
5804 if (memcmp(type,mng_pHYs,4) == 0)
5808 mng_info->global_x_pixels_per_unit=
5809 (size_t) mng_get_long(p);
5810 mng_info->global_y_pixels_per_unit=
5811 (size_t) mng_get_long(&p[4]);
5812 mng_info->global_phys_unit_type=p[8];
5813 mng_info->have_global_phys=MagickTrue;
5817 mng_info->have_global_phys=MagickFalse;
5819 if (memcmp(type,mng_pHYg,4) == 0)
5821 if (mng_info->phyg_warning == 0)
5822 (void) ThrowMagickException(exception,GetMagickModule(),
5823 CoderError,"pHYg is not implemented.","`%s'",image->filename);
5825 mng_info->phyg_warning++;
5827 if (memcmp(type,mng_BASI,4) == 0)
5829 skip_to_iend=MagickTrue;
5831 if (mng_info->basi_warning == 0)
5832 (void) ThrowMagickException(exception,GetMagickModule(),
5833 CoderError,"BASI is not implemented yet","`%s'",
5836 mng_info->basi_warning++;
5837 #ifdef MNG_BASI_SUPPORTED
5838 basi_width=(size_t) ((p[0] << 24) | (p[1] << 16) |
5839 (p[2] << 8) | p[3]);
5840 basi_height=(size_t) ((p[4] << 24) | (p[5] << 16) |
5841 (p[6] << 8) | p[7]);
5842 basi_color_type=p[8];
5843 basi_compression_method=p[9];
5844 basi_filter_type=p[10];
5845 basi_interlace_method=p[11];
5847 basi_red=(p[12] << 8) & p[13];
5853 basi_green=(p[14] << 8) & p[15];
5859 basi_blue=(p[16] << 8) & p[17];
5865 basi_alpha=(p[18] << 8) & p[19];
5869 if (basi_sample_depth == 16)
5876 basi_viewable=p[20];
5882 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5886 if (memcmp(type,mng_IHDR,4)
5887 #if defined(JNG_SUPPORTED)
5888 && memcmp(type,mng_JHDR,4)
5892 /* Not an IHDR or JHDR chunk */
5894 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5899 if (logging != MagickFalse)
5900 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5901 " Processing %c%c%c%c chunk",type[0],type[1],type[2],type[3]);
5903 mng_info->exists[object_id]=MagickTrue;
5904 mng_info->viewable[object_id]=MagickTrue;
5906 if (mng_info->invisible[object_id])
5908 if (logging != MagickFalse)
5909 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5910 " Skipping invisible object");
5912 skip_to_iend=MagickTrue;
5913 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5916 #if defined(MNG_INSERT_LAYERS)
5918 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
5920 image_width=(size_t) mng_get_long(p);
5921 image_height=(size_t) mng_get_long(&p[4]);
5923 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5926 Insert a transparent background layer behind the entire animation
5927 if it is not full screen.
5929 #if defined(MNG_INSERT_LAYERS)
5930 if (insert_layers && mng_type && first_mng_object)
5932 if ((mng_info->clip.left > 0) || (mng_info->clip.top > 0) ||
5933 (image_width < mng_info->mng_width) ||
5934 (mng_info->clip.right < (ssize_t) mng_info->mng_width) ||
5935 (image_height < mng_info->mng_height) ||
5936 (mng_info->clip.bottom < (ssize_t) mng_info->mng_height))
5938 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
5941 Allocate next image structure.
5943 AcquireNextImage(image_info,image,exception);
5945 if (GetNextImageInList(image) == (Image *) NULL)
5947 image=DestroyImageList(image);
5948 MngInfoFreeStruct(mng_info,&have_mng_structure);
5949 return((Image *) NULL);
5952 image=SyncNextImageInList(image);
5954 mng_info->image=image;
5956 if (term_chunk_found)
5958 image->start_loop=MagickTrue;
5959 image->iterations=mng_iterations;
5960 term_chunk_found=MagickFalse;
5964 image->start_loop=MagickFalse;
5966 /* Make a background rectangle. */
5969 image->columns=mng_info->mng_width;
5970 image->rows=mng_info->mng_height;
5971 image->page.width=mng_info->mng_width;
5972 image->page.height=mng_info->mng_height;
5975 image->background_color=mng_background_color;
5976 (void) SetImageBackgroundColor(image,exception);
5977 if (logging != MagickFalse)
5978 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5979 " Inserted transparent background layer, W=%.20g, H=%.20g",
5980 (double) mng_info->mng_width,(double) mng_info->mng_height);
5984 Insert a background layer behind the upcoming image if
5985 framing_mode is 3, and we haven't already inserted one.
5987 if (insert_layers && (mng_info->framing_mode == 3) &&
5988 (subframe_width) && (subframe_height) && (simplicity == 0 ||
5989 (simplicity & 0x08)))
5991 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
5994 Allocate next image structure.
5996 AcquireNextImage(image_info,image,exception);
5998 if (GetNextImageInList(image) == (Image *) NULL)
6000 image=DestroyImageList(image);
6001 MngInfoFreeStruct(mng_info,&have_mng_structure);
6002 return((Image *) NULL);
6005 image=SyncNextImageInList(image);
6008 mng_info->image=image;
6010 if (term_chunk_found)
6012 image->start_loop=MagickTrue;
6013 image->iterations=mng_iterations;
6014 term_chunk_found=MagickFalse;
6018 image->start_loop=MagickFalse;
6021 image->columns=subframe_width;
6022 image->rows=subframe_height;
6023 image->page.width=subframe_width;
6024 image->page.height=subframe_height;
6025 image->page.x=mng_info->clip.left;
6026 image->page.y=mng_info->clip.top;
6027 image->background_color=mng_background_color;
6028 image->matte=MagickFalse;
6029 (void) SetImageBackgroundColor(image,exception);
6031 if (logging != MagickFalse)
6032 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6033 " Insert background layer, L=%.20g, R=%.20g T=%.20g, B=%.20g",
6034 (double) mng_info->clip.left,(double) mng_info->clip.right,
6035 (double) mng_info->clip.top,(double) mng_info->clip.bottom);
6037 #endif /* MNG_INSERT_LAYERS */
6038 first_mng_object=MagickFalse;
6040 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
6043 Allocate next image structure.
6045 AcquireNextImage(image_info,image,exception);
6047 if (GetNextImageInList(image) == (Image *) NULL)
6049 image=DestroyImageList(image);
6050 MngInfoFreeStruct(mng_info,&have_mng_structure);
6051 return((Image *) NULL);
6054 image=SyncNextImageInList(image);
6056 mng_info->image=image;
6057 status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
6058 GetBlobSize(image));
6060 if (status == MagickFalse)
6063 if (term_chunk_found)
6065 image->start_loop=MagickTrue;
6066 term_chunk_found=MagickFalse;
6070 image->start_loop=MagickFalse;
6072 if (mng_info->framing_mode == 1 || mng_info->framing_mode == 3)
6074 image->delay=frame_delay;
6075 frame_delay=default_frame_delay;
6081 image->page.width=mng_info->mng_width;
6082 image->page.height=mng_info->mng_height;
6083 image->page.x=mng_info->x_off[object_id];
6084 image->page.y=mng_info->y_off[object_id];
6085 image->iterations=mng_iterations;
6088 Seek back to the beginning of the IHDR or JHDR chunk's length field.
6091 if (logging != MagickFalse)
6092 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6093 " Seeking back to beginning of %c%c%c%c chunk",type[0],type[1],
6096 offset=SeekBlob(image,-((ssize_t) length+12),SEEK_CUR);
6099 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
6103 mng_info->image=image;
6104 mng_info->mng_type=mng_type;
6105 mng_info->object_id=object_id;
6107 if (memcmp(type,mng_IHDR,4) == 0)
6108 image=ReadOnePNGImage(mng_info,image_info,exception);
6110 #if defined(JNG_SUPPORTED)
6112 image=ReadOneJNGImage(mng_info,image_info,exception);
6115 if (image == (Image *) NULL)
6117 if (IsImageObject(previous) != MagickFalse)
6119 (void) DestroyImageList(previous);
6120 (void) CloseBlob(previous);
6123 MngInfoFreeStruct(mng_info,&have_mng_structure);
6124 return((Image *) NULL);
6127 if (image->columns == 0 || image->rows == 0)
6129 (void) CloseBlob(image);
6130 image=DestroyImageList(image);
6131 MngInfoFreeStruct(mng_info,&have_mng_structure);
6132 return((Image *) NULL);
6135 mng_info->image=image;
6142 if (mng_info->magn_methx || mng_info->magn_methy)
6148 if (logging != MagickFalse)
6149 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6150 " Processing MNG MAGN chunk");
6152 if (mng_info->magn_methx == 1)
6154 magnified_width=mng_info->magn_ml;
6156 if (image->columns > 1)
6157 magnified_width += mng_info->magn_mr;
6159 if (image->columns > 2)
6160 magnified_width += (png_uint_32)
6161 ((image->columns-2)*(mng_info->magn_mx));
6166 magnified_width=(png_uint_32) image->columns;
6168 if (image->columns > 1)
6169 magnified_width += mng_info->magn_ml-1;
6171 if (image->columns > 2)
6172 magnified_width += mng_info->magn_mr-1;
6174 if (image->columns > 3)
6175 magnified_width += (png_uint_32)
6176 ((image->columns-3)*(mng_info->magn_mx-1));
6179 if (mng_info->magn_methy == 1)
6181 magnified_height=mng_info->magn_mt;
6183 if (image->rows > 1)
6184 magnified_height += mng_info->magn_mb;
6186 if (image->rows > 2)
6187 magnified_height += (png_uint_32)
6188 ((image->rows-2)*(mng_info->magn_my));
6193 magnified_height=(png_uint_32) image->rows;
6195 if (image->rows > 1)
6196 magnified_height += mng_info->magn_mt-1;
6198 if (image->rows > 2)
6199 magnified_height += mng_info->magn_mb-1;
6201 if (image->rows > 3)
6202 magnified_height += (png_uint_32)
6203 ((image->rows-3)*(mng_info->magn_my-1));
6206 if (magnified_height > image->rows ||
6207 magnified_width > image->columns)
6234 /* Allocate next image structure. */
6236 if (logging != MagickFalse)
6237 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6238 " Allocate magnified image");
6240 AcquireNextImage(image_info,image,exception);
6242 if (GetNextImageInList(image) == (Image *) NULL)
6244 image=DestroyImageList(image);
6245 MngInfoFreeStruct(mng_info,&have_mng_structure);
6246 return((Image *) NULL);
6249 large_image=SyncNextImageInList(image);
6251 large_image->columns=magnified_width;
6252 large_image->rows=magnified_height;
6254 magn_methx=mng_info->magn_methx;
6255 magn_methy=mng_info->magn_methy;
6257 #if (MAGICKCORE_QUANTUM_DEPTH > 16)
6258 #define QM unsigned short
6259 if (magn_methx != 1 || magn_methy != 1)
6262 Scale pixels to unsigned shorts to prevent
6263 overflow of intermediate values of interpolations
6265 for (y=0; y < (ssize_t) image->rows; y++)
6267 q=GetAuthenticPixels(image,0,y,image->columns,1,
6270 for (x=(ssize_t) image->columns-1; x >= 0; x--)
6272 SetPixelRed(image,ScaleQuantumToShort(
6273 GetPixelRed(image,q)),q);
6274 SetPixelGreen(image,ScaleQuantumToShort(
6275 GetPixelGreen(image,q)),q);
6276 SetPixelBlue(image,ScaleQuantumToShort(
6277 GetPixelBlue(image,q)),q);
6278 SetPixelAlpha(image,ScaleQuantumToShort(
6279 GetPixelAlpha(image,q)),q);
6280 q+=GetPixelChannels(image);
6283 if (SyncAuthenticPixels(image,exception) == MagickFalse)
6291 if (image->matte != MagickFalse)
6292 (void) SetImageBackgroundColor(large_image,exception);
6296 large_image->background_color.alpha=OpaqueAlpha;
6297 (void) SetImageBackgroundColor(large_image,exception);
6299 if (magn_methx == 4)
6302 if (magn_methx == 5)
6305 if (magn_methy == 4)
6308 if (magn_methy == 5)
6312 /* magnify the rows into the right side of the large image */
6314 if (logging != MagickFalse)
6315 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6316 " Magnify the rows to %.20g",(double) large_image->rows);
6317 m=(ssize_t) mng_info->magn_mt;
6319 length=(size_t) image->columns*GetPixelChannels(image);
6320 next=(Quantum *) AcquireQuantumMemory(length,sizeof(*next));
6321 prev=(Quantum *) AcquireQuantumMemory(length,sizeof(*prev));
6323 if ((prev == (Quantum *) NULL) ||
6324 (next == (Quantum *) NULL))
6326 image=DestroyImageList(image);
6327 MngInfoFreeStruct(mng_info,&have_mng_structure);
6328 ThrowReaderException(ResourceLimitError,
6329 "MemoryAllocationFailed");
6332 n=GetAuthenticPixels(image,0,0,image->columns,1,exception);
6333 (void) CopyMagickMemory(next,n,length);
6335 for (y=0; y < (ssize_t) image->rows; y++)
6338 m=(ssize_t) mng_info->magn_mt;
6340 else if (magn_methy > 1 && y == (ssize_t) image->rows-2)
6341 m=(ssize_t) mng_info->magn_mb;
6343 else if (magn_methy <= 1 && y == (ssize_t) image->rows-1)
6344 m=(ssize_t) mng_info->magn_mb;
6346 else if (magn_methy > 1 && y == (ssize_t) image->rows-1)
6350 m=(ssize_t) mng_info->magn_my;
6356 if (y < (ssize_t) image->rows-1)
6358 n=GetAuthenticPixels(image,0,y+1,image->columns,1,
6360 (void) CopyMagickMemory(next,n,length);
6363 for (i=0; i < m; i++, yy++)
6368 assert(yy < (ssize_t) large_image->rows);
6371 q=GetAuthenticPixels(large_image,0,yy,large_image->columns,
6373 q+=(large_image->columns-image->columns)*
6374 GetPixelChannels(large_image);
6376 for (x=(ssize_t) image->columns-1; x >= 0; x--)
6378 /* To do: get color as function of indexes[x] */
6380 if (image->storage_class == PseudoClass)
6385 if (magn_methy <= 1)
6387 /* replicate previous */
6388 SetPixelRed(large_image,GetPixelRed(image,pixels),q);
6389 SetPixelGreen(large_image,GetPixelGreen(image,
6391 SetPixelBlue(large_image,GetPixelBlue(image,
6393 SetPixelAlpha(large_image,GetPixelAlpha(image,
6397 else if (magn_methy == 2 || magn_methy == 4)
6401 SetPixelRed(large_image,GetPixelRed(image,
6403 SetPixelGreen(large_image,GetPixelGreen(image,
6405 SetPixelBlue(large_image,GetPixelBlue(image,
6407 SetPixelAlpha(large_image,GetPixelAlpha(image,
6414 SetPixelRed(large_image,((QM) (((ssize_t)
6415 (2*i*(GetPixelRed(image,n)
6416 -GetPixelRed(image,pixels)+m))/
6418 +GetPixelRed(image,pixels)))),q);
6419 SetPixelGreen(large_image,((QM) (((ssize_t)
6420 (2*i*(GetPixelGreen(image,n)
6421 -GetPixelGreen(image,pixels)+m))/
6423 +GetPixelGreen(image,pixels)))),q);
6424 SetPixelBlue(large_image,((QM) (((ssize_t)
6425 (2*i*(GetPixelBlue(image,n)
6426 -GetPixelBlue(image,pixels)+m))/
6428 +GetPixelBlue(image,pixels)))),q);
6430 if (image->matte != MagickFalse)
6431 SetPixelAlpha(large_image, ((QM) (((ssize_t)
6432 (2*i*(GetPixelAlpha(image,n)
6433 -GetPixelAlpha(image,pixels)+m))
6435 GetPixelAlpha(image,pixels)))),q);
6438 if (magn_methy == 4)
6440 /* Replicate nearest */
6441 if (i <= ((m+1) << 1))
6442 SetPixelAlpha(large_image,GetPixelAlpha(image,
6445 SetPixelAlpha(large_image,GetPixelAlpha(image,
6450 else /* if (magn_methy == 3 || magn_methy == 5) */
6452 /* Replicate nearest */
6453 if (i <= ((m+1) << 1))
6455 SetPixelRed(large_image,GetPixelRed(image,
6457 SetPixelGreen(large_image,GetPixelGreen(image,
6459 SetPixelBlue(large_image,GetPixelBlue(image,
6461 SetPixelAlpha(large_image,GetPixelAlpha(image,
6467 SetPixelRed(large_image,GetPixelRed(image,n),q);
6468 SetPixelGreen(large_image,GetPixelGreen(image,n),
6470 SetPixelBlue(large_image,GetPixelBlue(image,n),
6472 SetPixelAlpha(large_image,GetPixelAlpha(image,n),
6476 if (magn_methy == 5)
6478 SetPixelAlpha(large_image,(QM) (((ssize_t) (2*i*
6479 (GetPixelAlpha(image,n)
6480 -GetPixelAlpha(image,pixels))
6481 +m))/((ssize_t) (m*2))
6482 +GetPixelAlpha(image,pixels)),q);
6485 n+=GetPixelChannels(image);
6486 q+=GetPixelChannels(large_image);
6487 pixels+=GetPixelChannels(image);
6490 if (SyncAuthenticPixels(large_image,exception) == 0)
6496 prev=(Quantum *) RelinquishMagickMemory(prev);
6497 next=(Quantum *) RelinquishMagickMemory(next);
6499 length=image->columns;
6501 if (logging != MagickFalse)
6502 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6503 " Delete original image");
6505 DeleteImageFromList(&image);
6509 mng_info->image=image;
6511 /* magnify the columns */
6512 if (logging != MagickFalse)
6513 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6514 " Magnify the columns to %.20g",(double) image->columns);
6516 for (y=0; y < (ssize_t) image->rows; y++)
6521 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
6522 pixels=q+(image->columns-length)*GetPixelChannels(image);
6523 n=pixels+GetPixelChannels(image);
6525 for (x=(ssize_t) (image->columns-length);
6526 x < (ssize_t) image->columns; x++)
6528 /* To do: Rewrite using Get/Set***PixelChannel() */
6530 if (x == (ssize_t) (image->columns-length))
6531 m=(ssize_t) mng_info->magn_ml;
6533 else if (magn_methx > 1 && x == (ssize_t) image->columns-2)
6534 m=(ssize_t) mng_info->magn_mr;
6536 else if (magn_methx <= 1 && x == (ssize_t) image->columns-1)
6537 m=(ssize_t) mng_info->magn_mr;
6539 else if (magn_methx > 1 && x == (ssize_t) image->columns-1)
6543 m=(ssize_t) mng_info->magn_mx;
6545 for (i=0; i < m; i++)
6547 if (magn_methx <= 1)
6549 /* replicate previous */
6550 SetPixelRed(image,GetPixelRed(image,pixels),q);
6551 SetPixelGreen(image,GetPixelGreen(image,pixels),q);
6552 SetPixelBlue(image,GetPixelBlue(image,pixels),q);
6553 SetPixelAlpha(image,GetPixelAlpha(image,pixels),q);
6556 else if (magn_methx == 2 || magn_methx == 4)
6560 SetPixelRed(image,GetPixelRed(image,pixels),q);
6561 SetPixelGreen(image,GetPixelGreen(image,pixels),q);
6562 SetPixelBlue(image,GetPixelBlue(image,pixels),q);
6563 SetPixelAlpha(image,GetPixelAlpha(image,pixels),q);
6566 /* To do: Rewrite using Get/Set***PixelChannel() */
6570 SetPixelRed(image,(QM) ((2*i*(
6571 GetPixelRed(image,n)
6572 -GetPixelRed(image,pixels))+m)
6574 GetPixelRed(image,pixels)),q);
6576 SetPixelGreen(image,(QM) ((2*i*(
6577 GetPixelGreen(image,n)
6578 -GetPixelGreen(image,pixels))+m)
6580 GetPixelGreen(image,pixels)),q);
6582 SetPixelBlue(image,(QM) ((2*i*(
6583 GetPixelBlue(image,n)
6584 -GetPixelBlue(image,pixels))+m)
6586 GetPixelBlue(image,pixels)),q);
6587 if (image->matte != MagickFalse)
6588 SetPixelAlpha(image,(QM) ((2*i*(
6589 GetPixelAlpha(image,n)
6590 -GetPixelAlpha(image,pixels))+m)
6592 GetPixelAlpha(image,pixels)),q);
6595 if (magn_methx == 4)
6597 /* Replicate nearest */
6598 if (i <= ((m+1) << 1))
6600 SetPixelAlpha(image,
6601 GetPixelAlpha(image,pixels)+0,q);
6605 SetPixelAlpha(image,
6606 GetPixelAlpha(image,n)+0,q);
6611 else /* if (magn_methx == 3 || magn_methx == 5) */
6613 /* Replicate nearest */
6614 if (i <= ((m+1) << 1))
6616 SetPixelRed(image,GetPixelRed(image,pixels),q);
6617 SetPixelGreen(image,GetPixelGreen(image,pixels),q);
6618 SetPixelBlue(image,GetPixelBlue(image,pixels),q);
6619 SetPixelAlpha(image,GetPixelAlpha(image,pixels),q);
6624 SetPixelRed(image,GetPixelRed(image,n),q);
6625 SetPixelGreen(image,GetPixelGreen(image,n),q);
6626 SetPixelBlue(image,GetPixelBlue(image,n),q);
6627 SetPixelAlpha(image,GetPixelAlpha(image,n),q);
6630 if (magn_methx == 5)
6633 SetPixelAlpha(image,
6634 (QM) ((2*i*( GetPixelAlpha(image,n)
6635 -GetPixelAlpha(image,pixels))+m)/
6637 +GetPixelAlpha(image,pixels)),q);
6640 q+=GetPixelChannels(image);
6642 n+=GetPixelChannels(image);
6643 p+=GetPixelChannels(image);
6646 if (SyncAuthenticPixels(image,exception) == MagickFalse)
6649 #if (MAGICKCORE_QUANTUM_DEPTH > 16)
6650 if (magn_methx != 1 || magn_methy != 1)
6653 Rescale pixels to Quantum
6655 for (y=0; y < (ssize_t) image->rows; y++)
6657 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
6659 for (x=(ssize_t) image->columns-1; x >= 0; x--)
6661 SetPixelRed(image,ScaleShortToQuantum(
6662 GetPixelRed(image,q)),q);
6663 SetPixelGreen(image,ScaleShortToQuantum(
6664 GetPixelGreen(image,q)),q);
6665 SetPixelBlue(image,ScaleShortToQuantum(
6666 GetPixelBlue(image,q)),q);
6667 SetPixelAlpha(image,ScaleShortToQuantum(
6668 GetPixelAlpha(image,q)),q);
6669 q+=GetPixelChannels(image);
6672 if (SyncAuthenticPixels(image,exception) == MagickFalse)
6677 if (logging != MagickFalse)
6678 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6679 " Finished MAGN processing");
6684 Crop_box is with respect to the upper left corner of the MNG.
6686 crop_box.left=mng_info->image_box.left+mng_info->x_off[object_id];
6687 crop_box.right=mng_info->image_box.right+mng_info->x_off[object_id];
6688 crop_box.top=mng_info->image_box.top+mng_info->y_off[object_id];
6689 crop_box.bottom=mng_info->image_box.bottom+mng_info->y_off[object_id];
6690 crop_box=mng_minimum_box(crop_box,mng_info->clip);
6691 crop_box=mng_minimum_box(crop_box,mng_info->frame);
6692 crop_box=mng_minimum_box(crop_box,mng_info->object_clip[object_id]);
6693 if ((crop_box.left != (mng_info->image_box.left
6694 +mng_info->x_off[object_id])) ||
6695 (crop_box.right != (mng_info->image_box.right
6696 +mng_info->x_off[object_id])) ||
6697 (crop_box.top != (mng_info->image_box.top
6698 +mng_info->y_off[object_id])) ||
6699 (crop_box.bottom != (mng_info->image_box.bottom
6700 +mng_info->y_off[object_id])))
6702 if (logging != MagickFalse)
6703 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6704 " Crop the PNG image");
6706 if ((crop_box.left < crop_box.right) &&
6707 (crop_box.top < crop_box.bottom))
6716 Crop_info is with respect to the upper left corner of
6719 crop_info.x=(crop_box.left-mng_info->x_off[object_id]);
6720 crop_info.y=(crop_box.top-mng_info->y_off[object_id]);
6721 crop_info.width=(size_t) (crop_box.right-crop_box.left);
6722 crop_info.height=(size_t) (crop_box.bottom-crop_box.top);
6723 image->page.width=image->columns;
6724 image->page.height=image->rows;
6727 im=CropImage(image,&crop_info,exception);
6729 if (im != (Image *) NULL)
6731 image->columns=im->columns;
6732 image->rows=im->rows;
6733 im=DestroyImage(im);
6734 image->page.width=image->columns;
6735 image->page.height=image->rows;
6736 image->page.x=crop_box.left;
6737 image->page.y=crop_box.top;
6744 No pixels in crop area. The MNG spec still requires
6745 a layer, though, so make a single transparent pixel in
6746 the top left corner.
6751 (void) SetImageBackgroundColor(image,exception);
6752 image->page.width=1;
6753 image->page.height=1;
6758 #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
6759 image=mng_info->image;
6763 #if (MAGICKCORE_QUANTUM_DEPTH > 16)
6764 /* PNG does not handle depths greater than 16 so reduce it even
6767 if (image->depth > 16)
6771 #if (MAGICKCORE_QUANTUM_DEPTH > 8)
6772 if (image->depth > 8)
6774 /* To do: fill low byte properly */
6778 if (LosslessReduceDepthOK(image,exception) != MagickFalse)
6782 if (image_info->number_scenes != 0)
6784 if (mng_info->scenes_found >
6785 (ssize_t) (image_info->first_scene+image_info->number_scenes))
6789 if (logging != MagickFalse)
6790 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6791 " Finished reading image datastream.");
6793 } while (LocaleCompare(image_info->magick,"MNG") == 0);
6795 (void) CloseBlob(image);
6797 if (logging != MagickFalse)
6798 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6799 " Finished reading all image datastreams.");
6801 #if defined(MNG_INSERT_LAYERS)
6802 if (insert_layers && !mng_info->image_found && (mng_info->mng_width) &&
6803 (mng_info->mng_height))
6806 Insert a background layer if nothing else was found.
6808 if (logging != MagickFalse)
6809 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6810 " No images found. Inserting a background layer.");
6812 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
6815 Allocate next image structure.
6817 AcquireNextImage(image_info,image,exception);
6818 if (GetNextImageInList(image) == (Image *) NULL)
6820 image=DestroyImageList(image);
6821 MngInfoFreeStruct(mng_info,&have_mng_structure);
6823 if (logging != MagickFalse)
6824 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6825 " Allocation failed, returning NULL.");
6827 return((Image *) NULL);
6829 image=SyncNextImageInList(image);
6831 image->columns=mng_info->mng_width;
6832 image->rows=mng_info->mng_height;
6833 image->page.width=mng_info->mng_width;
6834 image->page.height=mng_info->mng_height;
6837 image->background_color=mng_background_color;
6838 image->matte=MagickFalse;
6840 if (image_info->ping == MagickFalse)
6841 (void) SetImageBackgroundColor(image,exception);
6843 mng_info->image_found++;
6846 image->iterations=mng_iterations;
6848 if (mng_iterations == 1)
6849 image->start_loop=MagickTrue;
6851 while (GetPreviousImageInList(image) != (Image *) NULL)
6854 if (image_count > 10*mng_info->image_found)
6856 if (logging != MagickFalse)
6857 (void) LogMagickEvent(CoderEvent,GetMagickModule()," No beginning");
6859 (void) ThrowMagickException(exception,GetMagickModule(),
6860 CoderError,"Linked list is corrupted, beginning of list not found",
6861 "`%s'",image_info->filename);
6863 return((Image *) NULL);
6866 image=GetPreviousImageInList(image);
6868 if (GetNextImageInList(image) == (Image *) NULL)
6870 if (logging != MagickFalse)
6871 (void) LogMagickEvent(CoderEvent,GetMagickModule()," Corrupt list");
6873 (void) ThrowMagickException(exception,GetMagickModule(),
6874 CoderError,"Linked list is corrupted; next_image is NULL","`%s'",
6875 image_info->filename);
6879 if (mng_info->ticks_per_second && mng_info->image_found > 1 &&
6880 GetNextImageInList(image) ==
6883 if (logging != MagickFalse)
6884 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6885 " First image null");
6887 (void) ThrowMagickException(exception,GetMagickModule(),
6888 CoderError,"image->next for first image is NULL but shouldn't be.",
6889 "`%s'",image_info->filename);
6892 if (mng_info->image_found == 0)
6894 if (logging != MagickFalse)
6895 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6896 " No visible images found.");
6898 (void) ThrowMagickException(exception,GetMagickModule(),
6899 CoderError,"No visible images in file","`%s'",image_info->filename);
6901 if (image != (Image *) NULL)
6902 image=DestroyImageList(image);
6904 MngInfoFreeStruct(mng_info,&have_mng_structure);
6905 return((Image *) NULL);
6908 if (mng_info->ticks_per_second)
6909 final_delay=1UL*MagickMax(image->ticks_per_second,1L)*
6910 final_delay/mng_info->ticks_per_second;
6913 image->start_loop=MagickTrue;
6915 /* Find final nonzero image delay */
6916 final_image_delay=0;
6918 while (GetNextImageInList(image) != (Image *) NULL)
6921 final_image_delay=image->delay;
6923 image=GetNextImageInList(image);
6926 if (final_delay < final_image_delay)
6927 final_delay=final_image_delay;
6929 image->delay=final_delay;
6931 if (logging != MagickFalse)
6932 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6933 " image->delay=%.20g, final_delay=%.20g",(double) image->delay,
6934 (double) final_delay);
6936 if (logging != MagickFalse)
6942 image=GetFirstImageInList(image);
6944 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6945 " Before coalesce:");
6947 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6948 " scene 0 delay=%.20g",(double) image->delay);
6950 while (GetNextImageInList(image) != (Image *) NULL)
6952 image=GetNextImageInList(image);
6953 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6954 " scene %.20g delay=%.20g",(double) scene++,(double) image->delay);
6958 image=GetFirstImageInList(image);
6959 #ifdef MNG_COALESCE_LAYERS
6969 if (logging != MagickFalse)
6970 (void) LogMagickEvent(CoderEvent,GetMagickModule()," Coalesce Images");
6973 next_image=CoalesceImages(image,exception);
6975 if (next_image == (Image *) NULL)
6976 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
6978 image=DestroyImageList(image);
6981 for (next=image; next != (Image *) NULL; next=next_image)
6983 next->page.width=mng_info->mng_width;
6984 next->page.height=mng_info->mng_height;
6987 next->scene=scene++;
6988 next_image=GetNextImageInList(next);
6990 if (next_image == (Image *) NULL)
6993 if (next->delay == 0)
6996 next_image->previous=GetPreviousImageInList(next);
6997 if (GetPreviousImageInList(next) == (Image *) NULL)
7000 next->previous->next=next_image;
7001 next=DestroyImage(next);
7007 while (GetNextImageInList(image) != (Image *) NULL)
7008 image=GetNextImageInList(image);
7010 image->dispose=BackgroundDispose;
7012 if (logging != MagickFalse)
7018 image=GetFirstImageInList(image);
7020 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7021 " After coalesce:");
7023 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7024 " scene 0 delay=%.20g dispose=%.20g",(double) image->delay,
7025 (double) image->dispose);
7027 while (GetNextImageInList(image) != (Image *) NULL)
7029 image=GetNextImageInList(image);
7031 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7032 " scene %.20g delay=%.20g dispose=%.20g",(double) scene++,
7033 (double) image->delay,(double) image->dispose);
7037 image=GetFirstImageInList(image);
7038 MngInfoFreeStruct(mng_info,&have_mng_structure);
7039 have_mng_structure=MagickFalse;
7041 if (logging != MagickFalse)
7042 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit ReadMNGImage()");
7044 return(GetFirstImageInList(image));
7046 #else /* PNG_LIBPNG_VER > 10011 */
7047 static Image *ReadPNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
7049 printf("Your PNG library is too old: You have libpng-%s\n",
7050 PNG_LIBPNG_VER_STRING);
7052 (void) ThrowMagickException(exception,GetMagickModule(),CoderError,
7053 "PNG library is too old","`%s'",image_info->filename);
7055 return(Image *) NULL;
7058 static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
7060 return(ReadPNGImage(image_info,exception));
7062 #endif /* PNG_LIBPNG_VER > 10011 */
7066 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7070 % R e g i s t e r P N G I m a g e %
7074 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7076 % RegisterPNGImage() adds properties for the PNG image format to
7077 % the list of supported formats. The properties include the image format
7078 % tag, a method to read and/or write the format, whether the format
7079 % supports the saving of more than one frame to the same file or blob,
7080 % whether the format supports native in-memory I/O, and a brief
7081 % description of the format.
7083 % The format of the RegisterPNGImage method is:
7085 % size_t RegisterPNGImage(void)
7088 ModuleExport size_t RegisterPNGImage(void)
7091 version[MaxTextExtent];
7099 "See http://www.libpng.org/ for details about the PNG format."
7104 "See http://www.libpng.org/pub/mng/ for details about the JNG\n"
7110 "See http://www.libpng.org/pub/mng/ for details about the MNG\n"
7116 #if defined(PNG_LIBPNG_VER_STRING)
7117 (void) ConcatenateMagickString(version,"libpng ",MaxTextExtent);
7118 (void) ConcatenateMagickString(version,PNG_LIBPNG_VER_STRING,MaxTextExtent);
7120 if (LocaleCompare(PNG_LIBPNG_VER_STRING,png_get_header_ver(NULL)) != 0)
7122 (void) ConcatenateMagickString(version,",",MaxTextExtent);
7123 (void) ConcatenateMagickString(version,png_get_libpng_ver(NULL),
7128 entry=SetMagickInfo("MNG");
7129 entry->seekable_stream=MagickTrue; /* To do: eliminate this. */
7131 #if defined(MAGICKCORE_PNG_DELEGATE)
7132 entry->decoder=(DecodeImageHandler *) ReadMNGImage;
7133 entry->encoder=(EncodeImageHandler *) WriteMNGImage;
7136 entry->magick=(IsImageFormatHandler *) IsMNG;
7137 entry->description=ConstantString("Multiple-image Network Graphics");
7139 if (*version != '\0')
7140 entry->version=ConstantString(version);
7142 entry->module=ConstantString("PNG");
7143 entry->note=ConstantString(MNGNote);
7144 (void) RegisterMagickInfo(entry);
7146 entry=SetMagickInfo("PNG");
7148 #if defined(MAGICKCORE_PNG_DELEGATE)
7149 entry->decoder=(DecodeImageHandler *) ReadPNGImage;
7150 entry->encoder=(EncodeImageHandler *) WritePNGImage;
7153 entry->magick=(IsImageFormatHandler *) IsPNG;
7154 entry->adjoin=MagickFalse;
7155 entry->description=ConstantString("Portable Network Graphics");
7156 entry->module=ConstantString("PNG");
7158 if (*version != '\0')
7159 entry->version=ConstantString(version);
7161 entry->note=ConstantString(PNGNote);
7162 (void) RegisterMagickInfo(entry);
7164 entry=SetMagickInfo("PNG8");
7166 #if defined(MAGICKCORE_PNG_DELEGATE)
7167 entry->decoder=(DecodeImageHandler *) ReadPNGImage;
7168 entry->encoder=(EncodeImageHandler *) WritePNGImage;
7171 entry->magick=(IsImageFormatHandler *) IsPNG;
7172 entry->adjoin=MagickFalse;
7173 entry->description=ConstantString(
7174 "8-bit indexed with optional binary transparency");
7175 entry->module=ConstantString("PNG");
7176 (void) RegisterMagickInfo(entry);
7178 entry=SetMagickInfo("PNG24");
7181 #if defined(ZLIB_VERSION)
7182 (void) ConcatenateMagickString(version,"zlib ",MaxTextExtent);
7183 (void) ConcatenateMagickString(version,ZLIB_VERSION,MaxTextExtent);
7185 if (LocaleCompare(ZLIB_VERSION,zlib_version) != 0)
7187 (void) ConcatenateMagickString(version,",",MaxTextExtent);
7188 (void) ConcatenateMagickString(version,zlib_version,MaxTextExtent);
7192 if (*version != '\0')
7193 entry->version=ConstantString(version);
7195 #if defined(MAGICKCORE_PNG_DELEGATE)
7196 entry->decoder=(DecodeImageHandler *) ReadPNGImage;
7197 entry->encoder=(EncodeImageHandler *) WritePNGImage;
7200 entry->magick=(IsImageFormatHandler *) IsPNG;
7201 entry->adjoin=MagickFalse;
7202 entry->description=ConstantString("opaque 24-bit RGB");
7203 entry->module=ConstantString("PNG");
7204 (void) RegisterMagickInfo(entry);
7206 entry=SetMagickInfo("PNG32");
7208 #if defined(MAGICKCORE_PNG_DELEGATE)
7209 entry->decoder=(DecodeImageHandler *) ReadPNGImage;
7210 entry->encoder=(EncodeImageHandler *) WritePNGImage;
7213 entry->magick=(IsImageFormatHandler *) IsPNG;
7214 entry->adjoin=MagickFalse;
7215 entry->description=ConstantString("opaque or transparent 32-bit RGBA");
7216 entry->module=ConstantString("PNG");
7217 (void) RegisterMagickInfo(entry);
7219 entry=SetMagickInfo("JNG");
7221 #if defined(JNG_SUPPORTED)
7222 #if defined(MAGICKCORE_PNG_DELEGATE)
7223 entry->decoder=(DecodeImageHandler *) ReadJNGImage;
7224 entry->encoder=(EncodeImageHandler *) WriteJNGImage;
7228 entry->magick=(IsImageFormatHandler *) IsJNG;
7229 entry->adjoin=MagickFalse;
7230 entry->description=ConstantString("JPEG Network Graphics");
7231 entry->module=ConstantString("PNG");
7232 entry->note=ConstantString(JNGNote);
7233 (void) RegisterMagickInfo(entry);
7235 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
7236 ping_semaphore=AllocateSemaphoreInfo();
7239 return(MagickImageCoderSignature);
7243 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7247 % U n r e g i s t e r P N G I m a g e %
7251 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7253 % UnregisterPNGImage() removes format registrations made by the
7254 % PNG module from the list of supported formats.
7256 % The format of the UnregisterPNGImage method is:
7258 % UnregisterPNGImage(void)
7261 ModuleExport void UnregisterPNGImage(void)
7263 (void) UnregisterMagickInfo("MNG");
7264 (void) UnregisterMagickInfo("PNG");
7265 (void) UnregisterMagickInfo("PNG8");
7266 (void) UnregisterMagickInfo("PNG24");
7267 (void) UnregisterMagickInfo("PNG32");
7268 (void) UnregisterMagickInfo("JNG");
7270 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
7271 if (ping_semaphore != (SemaphoreInfo *) NULL)
7272 DestroySemaphoreInfo(&ping_semaphore);
7276 #if defined(MAGICKCORE_PNG_DELEGATE)
7277 #if PNG_LIBPNG_VER > 10011
7279 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7283 % W r i t e M N G I m a g e %
7287 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7289 % WriteMNGImage() writes an image in the Portable Network Graphics
7290 % Group's "Multiple-image Network Graphics" encoded image format.
7292 % MNG support written by Glenn Randers-Pehrson, glennrp@image...
7294 % The format of the WriteMNGImage method is:
7296 % MagickBooleanType WriteMNGImage(const ImageInfo *image_info,
7297 % Image *image,ExceptionInfo *exception)
7299 % A description of each parameter follows.
7301 % o image_info: the image info.
7303 % o image: The image.
7305 % o exception: return any errors or warnings in this structure.
7307 % To do (as of version 5.5.2, November 26, 2002 -- glennrp -- see also
7308 % "To do" under ReadPNGImage):
7310 % Preserve all unknown and not-yet-handled known chunks found in input
7311 % PNG file and copy them into output PNG files according to the PNG
7314 % Write the iCCP chunk at MNG level when (icc profile length > 0)
7316 % Improve selection of color type (use indexed-colour or indexed-colour
7317 % with tRNS when 256 or fewer unique RGBA values are present).
7319 % Figure out what to do with "dispose=<restore-to-previous>" (dispose == 3)
7320 % This will be complicated if we limit ourselves to generating MNG-LC
7321 % files. For now we ignore disposal method 3 and simply overlay the next
7324 % Check for identical PLTE's or PLTE/tRNS combinations and use a
7325 % global MNG PLTE or PLTE/tRNS combination when appropriate.
7326 % [mostly done 15 June 1999 but still need to take care of tRNS]
7328 % Check for identical sRGB and replace with a global sRGB (and remove
7329 % gAMA/cHRM if sRGB is found; check for identical gAMA/cHRM and
7330 % replace with global gAMA/cHRM (or with sRGB if appropriate; replace
7331 % local gAMA/cHRM with local sRGB if appropriate).
7333 % Check for identical sBIT chunks and write global ones.
7335 % Provide option to skip writing the signature tEXt chunks.
7337 % Use signatures to detect identical objects and reuse the first
7338 % instance of such objects instead of writing duplicate objects.
7340 % Use a smaller-than-32k value of compression window size when
7343 % Encode JNG datastreams. Mostly done as of 5.5.2; need to write
7344 % ancillary text chunks and save profiles.
7346 % Provide an option to force LC files (to ensure exact framing rate)
7349 % Provide an option to force VLC files instead of LC, even when offsets
7350 % are present. This will involve expanding the embedded images with a
7351 % transparent region at the top and/or left.
7355 Magick_png_write_raw_profile(const ImageInfo *image_info,png_struct *ping,
7356 png_info *ping_info, unsigned char *profile_type, unsigned char
7357 *profile_description, unsigned char *profile_data, png_uint_32 length)
7376 hex[16]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
7378 if (LocaleNCompare((char *) profile_type+1, "ng-chunk-",9) == 0)
7381 if (image_info->verbose)
7383 (void) printf("writing raw profile: type=%s, length=%.20g\n",
7384 (char *) profile_type, (double) length);
7387 text=(png_textp) png_malloc(ping,(png_uint_32) sizeof(png_text));
7388 description_length=(png_uint_32) strlen((const char *) profile_description);
7389 allocated_length=(png_uint_32) (length*2 + (length >> 5) + 20
7390 + description_length);
7391 text[0].text=(png_charp) png_malloc(ping,allocated_length);
7392 text[0].key=(png_charp) png_malloc(ping, (png_uint_32) 80);
7393 text[0].key[0]='\0';
7394 (void) ConcatenateMagickString(text[0].key,
7395 "Raw profile type ",MaxTextExtent);
7396 (void) ConcatenateMagickString(text[0].key,(const char *) profile_type,62);
7400 (void) CopyMagickString(dp,(const char *) profile_description,
7402 dp+=description_length;
7404 (void) FormatLocaleString(dp,allocated_length-
7405 (png_size_t) (dp-text[0].text),"%8lu ",(unsigned long) length);
7408 for (i=0; i < (ssize_t) length; i++)
7412 *(dp++)=(char) hex[((*sp >> 4) & 0x0f)];
7413 *(dp++)=(char) hex[((*sp++ ) & 0x0f)];
7418 text[0].text_length=(png_size_t) (dp-text[0].text);
7419 text[0].compression=image_info->compression == NoCompression ||
7420 (image_info->compression == UndefinedCompression &&
7421 text[0].text_length < 128) ? -1 : 0;
7423 if (text[0].text_length <= allocated_length)
7424 png_set_text(ping,ping_info,text,1);
7426 png_free(ping,text[0].text);
7427 png_free(ping,text[0].key);
7428 png_free(ping,text);
7431 static MagickBooleanType Magick_png_write_chunk_from_profile(Image *image,
7432 const char *string, MagickBooleanType logging)
7445 ResetImageProfileIterator(image);
7447 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
7449 profile=GetImageProfile(image,name);
7451 if (profile != (const StringInfo *) NULL)
7456 if (LocaleNCompare(name,string,11) == 0)
7458 if (logging != MagickFalse)
7459 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7460 " Found %s profile",name);
7462 ping_profile=CloneStringInfo(profile);
7463 data=GetStringInfoDatum(ping_profile),
7464 length=(png_uint_32) GetStringInfoLength(ping_profile);
7469 (void) WriteBlobMSBULong(image,length-5); /* data length */
7470 (void) WriteBlob(image,length-1,data+1);
7471 (void) WriteBlobMSBULong(image,crc32(0,data+1,(uInt) length-1));
7472 ping_profile=DestroyStringInfo(ping_profile);
7476 name=GetNextImageProfile(image);
7483 /* Write one PNG image */
7484 static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
7485 const ImageInfo *IMimage_info,Image *IMimage,ExceptionInfo *exception)
7509 ping_trans_alpha[256];
7537 ping_have_cheap_transparency,
7548 /* ping_exclude_EXIF, */
7551 /* ping_exclude_iTXt, */
7556 /* ping_exclude_tRNS, */
7558 ping_exclude_zCCP, /* hex-encoded iCCP */
7561 ping_preserve_colormap,
7562 ping_need_colortype_warning,
7586 ping_interlace_method,
7587 ping_compression_method,
7604 number_semitransparent,
7606 ping_pHYs_unit_type;
7609 ping_pHYs_x_resolution,
7610 ping_pHYs_y_resolution;
7612 logging=LogMagickEvent(CoderEvent,GetMagickModule(),
7613 " Enter WriteOnePNGImage()");
7615 image = CloneImage(IMimage,0,0,MagickFalse,exception);
7616 image_info=(ImageInfo *) CloneImageInfo(IMimage_info);
7617 if (image_info == (ImageInfo *) NULL)
7618 ThrowWriterException(ResourceLimitError, "MemoryAllocationFailed");
7620 /* Initialize some stuff */
7623 ping_interlace_method=0,
7624 ping_compression_method=0,
7625 ping_filter_method=0,
7628 ping_background.red = 0;
7629 ping_background.green = 0;
7630 ping_background.blue = 0;
7631 ping_background.gray = 0;
7632 ping_background.index = 0;
7634 ping_trans_color.red=0;
7635 ping_trans_color.green=0;
7636 ping_trans_color.blue=0;
7637 ping_trans_color.gray=0;
7639 ping_pHYs_unit_type = 0;
7640 ping_pHYs_x_resolution = 0;
7641 ping_pHYs_y_resolution = 0;
7643 ping_have_blob=MagickFalse;
7644 ping_have_color=MagickTrue;
7645 ping_have_non_bw=MagickTrue;
7646 ping_have_PLTE=MagickFalse;
7647 ping_have_bKGD=MagickFalse;
7648 ping_have_pHYs=MagickFalse;
7649 ping_have_tRNS=MagickFalse;
7651 ping_exclude_bKGD=mng_info->ping_exclude_bKGD;
7652 ping_exclude_cHRM=mng_info->ping_exclude_cHRM;
7653 ping_exclude_date=mng_info->ping_exclude_date;
7654 /* ping_exclude_EXIF=mng_info->ping_exclude_EXIF; */
7655 ping_exclude_gAMA=mng_info->ping_exclude_gAMA;
7656 ping_exclude_iCCP=mng_info->ping_exclude_iCCP;
7657 /* ping_exclude_iTXt=mng_info->ping_exclude_iTXt; */
7658 ping_exclude_oFFs=mng_info->ping_exclude_oFFs;
7659 ping_exclude_pHYs=mng_info->ping_exclude_pHYs;
7660 ping_exclude_sRGB=mng_info->ping_exclude_sRGB;
7661 ping_exclude_tEXt=mng_info->ping_exclude_tEXt;
7662 /* ping_exclude_tRNS=mng_info->ping_exclude_tRNS; */
7663 ping_exclude_vpAg=mng_info->ping_exclude_vpAg;
7664 ping_exclude_zCCP=mng_info->ping_exclude_zCCP; /* hex-encoded iCCP in zTXt */
7665 ping_exclude_zTXt=mng_info->ping_exclude_zTXt;
7667 ping_preserve_colormap = mng_info->ping_preserve_colormap;
7668 ping_need_colortype_warning = MagickFalse;
7670 /* Recognize the ICC sRGB profile and convert it to the sRGB chunk,
7671 * i.e., eliminate the ICC profile and set image->rendering_intent.
7672 * Note that this will not involve any changes to the actual pixels
7673 * but merely passes information to applications that read the resulting
7676 if (ping_exclude_sRGB == MagickFalse)
7684 ResetImageProfileIterator(image);
7685 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
7687 profile=GetImageProfile(image,name);
7689 if (profile != (StringInfo *) NULL)
7691 if ((LocaleCompare(name,"ICC") == 0) ||
7692 (LocaleCompare(name,"ICM") == 0))
7697 /* 0: not a known sRGB profile
7698 * 1: HP-Microsoft sRGB v2
7699 * 2: ICC sRGB v4 perceptual
7700 * 3: ICC sRGB v2 perceptual no black-compensation
7703 check_crc[4] = {0, 0xf29e526dUL, 0xbbef7812UL, 0x427ebb21UL},
7704 check_len[4] = {0, 3144, 60960, 3052};
7713 length=(png_uint_32) GetStringInfoLength(profile);
7715 for (icheck=3; icheck > 0; icheck--)
7717 if (length == check_len[icheck])
7719 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7720 " Got a %lu-byte ICC profile (potentially sRGB)",
7721 (unsigned long) length);
7723 data=GetStringInfoDatum(profile);
7724 profile_crc=crc32(0,data,length);
7726 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7727 " with crc=%8x",(unsigned int) profile_crc);
7729 if (profile_crc == check_crc[icheck])
7731 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7733 if (image->rendering_intent==UndefinedIntent)
7734 image->rendering_intent=PerceptualIntent;
7740 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7741 " Got a %lu-byte ICC profile",
7742 (unsigned long) length);
7745 name=GetNextImageProfile(image);
7750 number_semitransparent = 0;
7751 number_transparent = 0;
7753 if (logging != MagickFalse)
7755 if (image->storage_class == UndefinedClass)
7756 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7757 " storage_class=UndefinedClass");
7758 if (image->storage_class == DirectClass)
7759 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7760 " storage_class=DirectClass");
7761 if (image->storage_class == PseudoClass)
7762 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7763 " storage_class=PseudoClass");
7766 if (image->storage_class == PseudoClass &&
7767 (mng_info->write_png8 || mng_info->write_png24 || mng_info->write_png32 ||
7768 (mng_info->write_png_colortype != 0 &&
7769 mng_info->write_png_colortype != 4)))
7771 (void) SyncImage(image,exception);
7772 image->storage_class = DirectClass;
7775 if (ping_preserve_colormap == MagickFalse)
7777 if (image->storage_class != PseudoClass && image->colormap != NULL)
7779 /* Free the bogus colormap; it can cause trouble later */
7780 if (logging != MagickFalse)
7781 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7782 " Freeing bogus colormap");
7783 (void) RelinquishMagickMemory(image->colormap);
7784 image->colormap=NULL;
7788 if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
7789 (void) TransformImageColorspace(image,sRGBColorspace,exception);
7792 Sometimes we get PseudoClass images whose RGB values don't match
7793 the colors in the colormap. This code syncs the RGB values.
7795 if (image->depth <= 8 && image->taint && image->storage_class == PseudoClass)
7796 (void) SyncImage(image,exception);
7798 #if (MAGICKCORE_QUANTUM_DEPTH == 8)
7799 if (image->depth > 8)
7801 if (logging != MagickFalse)
7802 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7803 " Reducing PNG bit depth to 8 since this is a Q8 build.");
7809 /* Respect the -depth option */
7810 if (image->depth < MAGICKCORE_QUANTUM_DEPTH)
7815 if (image->depth > 8)
7817 #if MAGICKCORE_QUANTUM_DEPTH > 16
7818 /* Scale to 16-bit */
7819 LBR16PacketRGBO(image->background_color);
7821 for (y=0; y < (ssize_t) image->rows; y++)
7823 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
7825 if (r == (Quantum *) NULL)
7828 for (x=0; x < (ssize_t) image->columns; x++)
7831 r+=GetPixelChannels(image);
7834 if (SyncAuthenticPixels(image,exception) == MagickFalse)
7838 if (image->storage_class == PseudoClass && image->colormap != NULL)
7840 for (i=0; i < (ssize_t) image->colors; i++)
7842 LBR16PacketRGBO(image->colormap[i]);
7845 #endif /* MAGICKCORE_QUANTUM_DEPTH > 16 */
7848 else if (image->depth > 4)
7850 #if MAGICKCORE_QUANTUM_DEPTH > 8
7851 /* Scale to 8-bit */
7852 LBR08PacketRGBO(image->background_color);
7854 for (y=0; y < (ssize_t) image->rows; y++)
7856 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
7858 if (r == (Quantum *) NULL)
7861 for (x=0; x < (ssize_t) image->columns; x++)
7864 r+=GetPixelChannels(image);
7867 if (SyncAuthenticPixels(image,exception) == MagickFalse)
7871 if (image->storage_class == PseudoClass && image->colormap != NULL)
7873 for (i=0; i < (ssize_t) image->colors; i++)
7875 LBR08PacketRGBO(image->colormap[i]);
7878 #endif /* MAGICKCORE_QUANTUM_DEPTH > 8 */
7881 if (image->depth > 2)
7883 /* Scale to 4-bit */
7884 LBR04PacketRGBO(image->background_color);
7886 for (y=0; y < (ssize_t) image->rows; y++)
7888 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
7890 if (r == (Quantum *) NULL)
7893 for (x=0; x < (ssize_t) image->columns; x++)
7896 r+=GetPixelChannels(image);
7899 if (SyncAuthenticPixels(image,exception) == MagickFalse)
7903 if (image->storage_class == PseudoClass && image->colormap != NULL)
7905 for (i=0; i < (ssize_t) image->colors; i++)
7907 LBR04PacketRGBO(image->colormap[i]);
7912 else if (image->depth > 1)
7914 /* Scale to 2-bit */
7915 LBR02PacketRGBO(image->background_color);
7917 for (y=0; y < (ssize_t) image->rows; y++)
7919 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
7921 if (r == (Quantum *) NULL)
7924 for (x=0; x < (ssize_t) image->columns; x++)
7927 r+=GetPixelChannels(image);
7930 if (SyncAuthenticPixels(image,exception) == MagickFalse)
7934 if (image->storage_class == PseudoClass && image->colormap != NULL)
7936 for (i=0; i < (ssize_t) image->colors; i++)
7938 LBR02PacketRGBO(image->colormap[i]);
7944 /* Scale to 1-bit */
7945 LBR01PacketRGBO(image->background_color);
7947 for (y=0; y < (ssize_t) image->rows; y++)
7949 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
7951 if (r == (Quantum *) NULL)
7954 for (x=0; x < (ssize_t) image->columns; x++)
7957 r+=GetPixelChannels(image);
7960 if (SyncAuthenticPixels(image,exception) == MagickFalse)
7964 if (image->storage_class == PseudoClass && image->colormap != NULL)
7966 for (i=0; i < (ssize_t) image->colors; i++)
7968 LBR01PacketRGBO(image->colormap[i]);
7974 /* To do: set to next higher multiple of 8 */
7975 if (image->depth < 8)
7978 #if (MAGICKCORE_QUANTUM_DEPTH > 16)
7979 /* PNG does not handle depths greater than 16 so reduce it even
7982 if (image->depth > 8)
7986 #if (MAGICKCORE_QUANTUM_DEPTH > 8)
7987 if (image->depth > 8)
7989 /* To do: fill low byte properly */
7993 if (image->depth == 16 && mng_info->write_png_depth != 16)
7994 if (mng_info->write_png8 || LosslessReduceDepthOK(image,exception) != MagickFalse)
7998 /* Normally we run this just once, but in the case of writing PNG8
7999 * we reduce the transparency to binary and run again, then if there
8000 * are still too many colors we reduce to a simple 4-4-4-1, then 3-3-3-1
8001 * RGBA palette and run again, and then to a simple 3-3-2-1 RGBA
8002 * palette. Then (To do) we take care of a final reduction that is only
8003 * needed if there are still 256 colors present and one of them has both
8004 * transparent and opaque instances.
8007 tried_332 = MagickFalse;
8008 tried_333 = MagickFalse;
8009 tried_444 = MagickFalse;
8015 * Sometimes we get DirectClass images that have 256 colors or fewer.
8016 * This code will build a colormap.
8018 * Also, sometimes we get PseudoClass images with an out-of-date
8019 * colormap. This code will replace the colormap with a new one.
8020 * Sometimes we get PseudoClass images that have more than 256 colors.
8021 * This code will delete the colormap and change the image to
8024 * If image->matte is MagickFalse, we ignore the alpha channel
8025 * even though it sometimes contains left-over non-opaque values.
8027 * Also we gather some information (number of opaque, transparent,
8028 * and semitransparent pixels, and whether the image has any non-gray
8029 * pixels or only black-and-white pixels) that we might need later.
8031 * Even if the user wants to force GrayAlpha or RGBA (colortype 4 or 6)
8032 * we need to check for bogus non-opaque values, at least.
8040 semitransparent[260],
8043 register const Quantum
8050 if (logging != MagickFalse)
8051 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8052 " Enter BUILD_PALETTE:");
8054 if (logging != MagickFalse)
8056 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8057 " image->columns=%.20g",(double) image->columns);
8058 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8059 " image->rows=%.20g",(double) image->rows);
8060 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8061 " image->matte=%.20g",(double) image->matte);
8062 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8063 " image->depth=%.20g",(double) image->depth);
8065 if (image->storage_class == PseudoClass && image->colormap != NULL)
8067 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8068 " Original colormap:");
8069 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8070 " i (red,green,blue,alpha)");
8072 for (i=0; i < 256; i++)
8074 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8075 " %d (%d,%d,%d,%d)",
8077 (int) image->colormap[i].red,
8078 (int) image->colormap[i].green,
8079 (int) image->colormap[i].blue,
8080 (int) image->colormap[i].alpha);
8083 for (i=image->colors - 10; i < (ssize_t) image->colors; i++)
8087 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8088 " %d (%d,%d,%d,%d)",
8090 (int) image->colormap[i].red,
8091 (int) image->colormap[i].green,
8092 (int) image->colormap[i].blue,
8093 (int) image->colormap[i].alpha);
8098 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8099 " image->colors=%d",(int) image->colors);
8101 if (image->colors == 0)
8102 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8103 " (zero means unknown)");
8105 if (ping_preserve_colormap == MagickFalse)
8106 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8107 " Regenerate the colormap");
8112 number_semitransparent = 0;
8113 number_transparent = 0;
8115 for (y=0; y < (ssize_t) image->rows; y++)
8117 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8119 if (q == (Quantum *) NULL)
8122 for (x=0; x < (ssize_t) image->columns; x++)
8124 if (image->matte == MagickFalse ||
8125 GetPixelAlpha(image,q) == OpaqueAlpha)
8127 if (number_opaque < 259)
8129 if (number_opaque == 0)
8131 GetPixelInfoPixel(image, q, opaque);
8132 opaque[0].alpha=OpaqueAlpha;
8136 for (i=0; i< (ssize_t) number_opaque; i++)
8138 if (IsPixelEquivalent(image,q, opaque+i))
8142 if (i == (ssize_t) number_opaque && number_opaque < 259)
8145 GetPixelInfoPixel(image, q, opaque+i);
8146 opaque[i].alpha=OpaqueAlpha;
8150 else if (GetPixelAlpha(image,q) == TransparentAlpha)
8152 if (number_transparent < 259)
8154 if (number_transparent == 0)
8156 GetPixelInfoPixel(image, q, transparent);
8157 ping_trans_color.red=(unsigned short)
8158 GetPixelRed(image,q);
8159 ping_trans_color.green=(unsigned short)
8160 GetPixelGreen(image,q);
8161 ping_trans_color.blue=(unsigned short)
8162 GetPixelBlue(image,q);
8163 ping_trans_color.gray=(unsigned short)
8164 GetPixelRed(image,q);
8165 number_transparent = 1;
8168 for (i=0; i< (ssize_t) number_transparent; i++)
8170 if (IsPixelEquivalent(image,q, transparent+i))
8174 if (i == (ssize_t) number_transparent &&
8175 number_transparent < 259)
8177 number_transparent++;
8178 GetPixelInfoPixel(image,q,transparent+i);
8184 if (number_semitransparent < 259)
8186 if (number_semitransparent == 0)
8188 GetPixelInfoPixel(image,q,semitransparent);
8189 number_semitransparent = 1;
8192 for (i=0; i< (ssize_t) number_semitransparent; i++)
8194 if (IsPixelEquivalent(image,q, semitransparent+i)
8195 && GetPixelAlpha(image,q) ==
8196 semitransparent[i].alpha)
8200 if (i == (ssize_t) number_semitransparent &&
8201 number_semitransparent < 259)
8203 number_semitransparent++;
8204 GetPixelInfoPixel(image, q, semitransparent+i);
8208 q+=GetPixelChannels(image);
8212 if (mng_info->write_png8 == MagickFalse &&
8213 ping_exclude_bKGD == MagickFalse)
8215 /* Add the background color to the palette, if it
8216 * isn't already there.
8218 if (logging != MagickFalse)
8220 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8221 " Check colormap for background (%d,%d,%d)",
8222 (int) image->background_color.red,
8223 (int) image->background_color.green,
8224 (int) image->background_color.blue);
8226 for (i=0; i<number_opaque; i++)
8228 if (opaque[i].red == image->background_color.red &&
8229 opaque[i].green == image->background_color.green &&
8230 opaque[i].blue == image->background_color.blue)
8233 if (number_opaque < 259 && i == number_opaque)
8235 opaque[i] = image->background_color;
8236 ping_background.index = i;
8238 if (logging != MagickFalse)
8240 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8241 " background_color index is %d",(int) i);
8245 else if (logging != MagickFalse)
8246 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8247 " No room in the colormap to add background color");
8250 image_colors=number_opaque+number_transparent+number_semitransparent;
8252 if (mng_info->write_png8 != MagickFalse && image_colors > 256)
8254 /* No room for the background color; remove it. */
8259 if (logging != MagickFalse)
8261 if (image_colors > 256)
8262 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8263 " image has more than 256 colors");
8266 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8267 " image has %d colors",image_colors);
8270 if (ping_preserve_colormap != MagickFalse)
8273 if (mng_info->write_png_colortype != 7) /* We won't need this info */
8275 ping_have_color=MagickFalse;
8276 if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
8277 ping_have_color=MagickTrue;
8278 ping_have_non_bw=MagickFalse;
8280 if(image_colors > 256)
8282 for (y=0; y < (ssize_t) image->rows; y++)
8284 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8286 if (q == (Quantum *) NULL)
8290 for (x=0; x < (ssize_t) image->columns; x++)
8292 if (GetPixelRed(image,s) != GetPixelGreen(image,s) ||
8293 GetPixelRed(image,s) != GetPixelBlue(image,s))
8295 ping_have_color=MagickTrue;
8296 ping_have_non_bw=MagickTrue;
8299 s+=GetPixelChannels(image);
8302 if (ping_have_color != MagickFalse)
8305 /* Worst case is black-and-white; we are looking at every
8309 if (ping_have_non_bw == MagickFalse)
8312 for (x=0; x < (ssize_t) image->columns; x++)
8314 if (GetPixelRed(image,s) != 0 &&
8315 GetPixelRed(image,s) != QuantumRange)
8317 ping_have_non_bw=MagickTrue;
8320 s+=GetPixelChannels(image);
8327 if (image_colors < 257)
8333 * Initialize image colormap.
8336 if (logging != MagickFalse)
8337 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8338 " Sort the new colormap");
8340 /* Sort palette, transparent first */;
8344 for (i=0; i<number_transparent; i++)
8345 colormap[n++] = transparent[i];
8347 for (i=0; i<number_semitransparent; i++)
8348 colormap[n++] = semitransparent[i];
8350 for (i=0; i<number_opaque; i++)
8351 colormap[n++] = opaque[i];
8353 ping_background.index +=
8354 (number_transparent + number_semitransparent);
8356 /* image_colors < 257; search the colormap instead of the pixels
8357 * to get ping_have_color and ping_have_non_bw
8361 if (ping_have_color == MagickFalse)
8363 if (colormap[i].red != colormap[i].green ||
8364 colormap[i].red != colormap[i].blue)
8366 ping_have_color=MagickTrue;
8367 ping_have_non_bw=MagickTrue;
8372 if (ping_have_non_bw == MagickFalse)
8374 if (colormap[i].red != 0 && colormap[i].red != QuantumRange)
8375 ping_have_non_bw=MagickTrue;
8379 if ((mng_info->ping_exclude_tRNS == MagickFalse ||
8380 (number_transparent == 0 && number_semitransparent == 0)) &&
8381 (((mng_info->write_png_colortype-1) ==
8382 PNG_COLOR_TYPE_PALETTE) ||
8383 (mng_info->write_png_colortype == 0)))
8385 if (logging != MagickFalse)
8387 if (n != (ssize_t) image_colors)
8388 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8389 " image_colors (%d) and n (%d) don't match",
8392 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8393 " AcquireImageColormap");
8396 image->colors = image_colors;
8398 if (AcquireImageColormap(image,image_colors,exception) ==
8400 ThrowWriterException(ResourceLimitError,
8401 "MemoryAllocationFailed");
8403 for (i=0; i< (ssize_t) image_colors; i++)
8404 image->colormap[i] = colormap[i];
8406 if (logging != MagickFalse)
8408 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8409 " image->colors=%d (%d)",
8410 (int) image->colors, image_colors);
8412 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8413 " Update the pixel indexes");
8416 /* Sync the pixel indices with the new colormap */
8418 for (y=0; y < (ssize_t) image->rows; y++)
8420 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8422 if (q == (Quantum *) NULL)
8425 for (x=0; x < (ssize_t) image->columns; x++)
8427 for (i=0; i< (ssize_t) image_colors; i++)
8429 if ((image->matte == MagickFalse ||
8430 image->colormap[i].alpha == GetPixelAlpha(image,q)) &&
8431 image->colormap[i].red == GetPixelRed(image,q) &&
8432 image->colormap[i].green == GetPixelGreen(image,q) &&
8433 image->colormap[i].blue == GetPixelBlue(image,q))
8435 SetPixelIndex(image,i,q);
8439 q+=GetPixelChannels(image);
8442 if (SyncAuthenticPixels(image,exception) == MagickFalse)
8448 if (logging != MagickFalse)
8450 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8451 " image->colors=%d", (int) image->colors);
8453 if (image->colormap != NULL)
8455 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8456 " i (red,green,blue,alpha)");
8458 for (i=0; i < (ssize_t) image->colors; i++)
8460 if (i < 300 || i >= (ssize_t) image->colors - 10)
8462 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8463 " %d (%d,%d,%d,%d)",
8465 (int) image->colormap[i].red,
8466 (int) image->colormap[i].green,
8467 (int) image->colormap[i].blue,
8468 (int) image->colormap[i].alpha);
8473 if (number_transparent < 257)
8474 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8475 " number_transparent = %d",
8476 number_transparent);
8479 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8480 " number_transparent > 256");
8482 if (number_opaque < 257)
8483 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8484 " number_opaque = %d",
8488 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8489 " number_opaque > 256");
8491 if (number_semitransparent < 257)
8492 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8493 " number_semitransparent = %d",
8494 number_semitransparent);
8497 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8498 " number_semitransparent > 256");
8500 if (ping_have_non_bw == MagickFalse)
8501 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8502 " All pixels and the background are black or white");
8504 else if (ping_have_color == MagickFalse)
8505 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8506 " All pixels and the background are gray");
8509 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8510 " At least one pixel or the background is non-gray");
8512 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8513 " Exit BUILD_PALETTE:");
8516 if (mng_info->write_png8 == MagickFalse)
8519 /* Make any reductions necessary for the PNG8 format */
8520 if (image_colors <= 256 &&
8521 image_colors != 0 && image->colormap != NULL &&
8522 number_semitransparent == 0 &&
8523 number_transparent <= 1)
8526 /* PNG8 can't have semitransparent colors so we threshold the
8527 * opacity to 0 or OpaqueOpacity, and PNG8 can only have one
8528 * transparent color so if more than one is transparent we merge
8529 * them into image->background_color.
8531 if (number_semitransparent != 0 || number_transparent > 1)
8533 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8534 " Thresholding the alpha channel to binary");
8536 for (y=0; y < (ssize_t) image->rows; y++)
8538 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8540 if (r == (Quantum *) NULL)
8543 for (x=0; x < (ssize_t) image->columns; x++)
8545 if (GetPixelAlpha(image,r) < OpaqueAlpha/2)
8547 SetPixelInfoPixel(image,&image->background_color,r);
8548 SetPixelAlpha(image,TransparentAlpha,r);
8551 SetPixelAlpha(image,OpaqueAlpha,r);
8552 r+=GetPixelChannels(image);
8555 if (SyncAuthenticPixels(image,exception) == MagickFalse)
8558 if (image_colors != 0 && image_colors <= 256 &&
8559 image->colormap != NULL)
8560 for (i=0; i<image_colors; i++)
8561 image->colormap[i].alpha =
8562 (image->colormap[i].alpha > TransparentAlpha/2 ?
8563 TransparentAlpha : OpaqueAlpha);
8568 /* PNG8 can't have more than 256 colors so we quantize the pixels and
8569 * background color to the 4-4-4-1, 3-3-3-1 or 3-3-2-1 palette. If the
8570 * image is mostly gray, the 4-4-4-1 palette is likely to end up with 256
8573 if (tried_444 == MagickFalse && (image_colors == 0 || image_colors > 256))
8575 if (logging != MagickFalse)
8576 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8577 " Quantizing the background color to 4-4-4");
8579 tried_444 = MagickTrue;
8581 LBR04PacketRGB(image->background_color);
8583 if (logging != MagickFalse)
8584 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8585 " Quantizing the pixel colors to 4-4-4");
8587 if (image->colormap == NULL)
8589 for (y=0; y < (ssize_t) image->rows; y++)
8591 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8593 if (r == (Quantum *) NULL)
8596 for (x=0; x < (ssize_t) image->columns; x++)
8598 if (GetPixelAlpha(image,r) == OpaqueAlpha)
8600 r+=GetPixelChannels(image);
8603 if (SyncAuthenticPixels(image,exception) == MagickFalse)
8608 else /* Should not reach this; colormap already exists and
8611 if (logging != MagickFalse)
8612 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8613 " Quantizing the colormap to 4-4-4");
8615 for (i=0; i<image_colors; i++)
8617 LBR04PacketRGB(image->colormap[i]);
8623 if (tried_333 == MagickFalse && (image_colors == 0 || image_colors > 256))
8625 if (logging != MagickFalse)
8626 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8627 " Quantizing the background color to 3-3-3");
8629 tried_333 = MagickTrue;
8631 LBR03PacketRGB(image->background_color);
8633 if (logging != MagickFalse)
8634 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8635 " Quantizing the pixel colors to 3-3-3-1");
8637 if (image->colormap == NULL)
8639 for (y=0; y < (ssize_t) image->rows; y++)
8641 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8643 if (r == (Quantum *) NULL)
8646 for (x=0; x < (ssize_t) image->columns; x++)
8648 if (GetPixelAlpha(image,r) == OpaqueAlpha)
8650 r+=GetPixelChannels(image);
8653 if (SyncAuthenticPixels(image,exception) == MagickFalse)
8658 else /* Should not reach this; colormap already exists and
8661 if (logging != MagickFalse)
8662 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8663 " Quantizing the colormap to 3-3-3-1");
8664 for (i=0; i<image_colors; i++)
8666 LBR03PacketRGB(image->colormap[i]);
8672 if (tried_332 == MagickFalse && (image_colors == 0 || image_colors > 256))
8674 if (logging != MagickFalse)
8675 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8676 " Quantizing the background color to 3-3-2");
8678 tried_332 = MagickTrue;
8680 /* Red and green were already done so we only quantize the blue
8684 LBR02PacketBlue(image->background_color);
8686 if (logging != MagickFalse)
8687 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8688 " Quantizing the pixel colors to 3-3-2-1");
8690 if (image->colormap == NULL)
8692 for (y=0; y < (ssize_t) image->rows; y++)
8694 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8696 if (r == (Quantum *) NULL)
8699 for (x=0; x < (ssize_t) image->columns; x++)
8701 if (GetPixelAlpha(image,r) == OpaqueAlpha)
8703 r+=GetPixelChannels(image);
8706 if (SyncAuthenticPixels(image,exception) == MagickFalse)
8711 else /* Should not reach this; colormap already exists and
8714 if (logging != MagickFalse)
8715 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8716 " Quantizing the colormap to 3-3-2-1");
8717 for (i=0; i<image_colors; i++)
8719 LBR02PacketBlue(image->colormap[i]);
8726 if (image_colors == 0 || image_colors > 256)
8728 /* Take care of special case with 256 colors + 1 transparent
8729 * color. We don't need to quantize to 2-3-2-1; we only need to
8730 * eliminate one color, so we'll merge the two darkest red
8731 * colors (0x49, 0, 0) -> (0x24, 0, 0).
8733 if (ScaleQuantumToChar(image->background_color.red) == 0x49 &&
8734 ScaleQuantumToChar(image->background_color.green) == 0x00 &&
8735 ScaleQuantumToChar(image->background_color.blue) == 0x00)
8737 image->background_color.red=ScaleCharToQuantum(0x24);
8740 if (image->colormap == NULL)
8742 for (y=0; y < (ssize_t) image->rows; y++)
8744 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8746 if (r == (Quantum *) NULL)
8749 for (x=0; x < (ssize_t) image->columns; x++)
8751 if (ScaleQuantumToChar(GetPixelRed(image,r)) == 0x49 &&
8752 ScaleQuantumToChar(GetPixelGreen(image,r)) == 0x00 &&
8753 ScaleQuantumToChar(GetPixelBlue(image,r)) == 0x00 &&
8754 GetPixelAlpha(image,r) == OpaqueAlpha)
8756 SetPixelRed(image,ScaleCharToQuantum(0x24),r);
8758 r+=GetPixelChannels(image);
8761 if (SyncAuthenticPixels(image,exception) == MagickFalse)
8769 for (i=0; i<image_colors; i++)
8771 if (ScaleQuantumToChar(image->colormap[i].red) == 0x49 &&
8772 ScaleQuantumToChar(image->colormap[i].green) == 0x00 &&
8773 ScaleQuantumToChar(image->colormap[i].blue) == 0x00)
8775 image->colormap[i].red=ScaleCharToQuantum(0x24);
8781 /* END OF BUILD_PALETTE */
8783 /* If we are excluding the tRNS chunk and there is transparency,
8784 * then we must write a Gray-Alpha (color-type 4) or RGBA (color-type 6)
8787 if (mng_info->ping_exclude_tRNS != MagickFalse &&
8788 (number_transparent != 0 || number_semitransparent != 0))
8790 unsigned int colortype=mng_info->write_png_colortype;
8792 if (ping_have_color == MagickFalse)
8793 mng_info->write_png_colortype = 5;
8796 mng_info->write_png_colortype = 7;
8798 if (colortype != 0 &&
8799 mng_info->write_png_colortype != colortype)
8800 ping_need_colortype_warning=MagickTrue;
8804 /* See if cheap transparency is possible. It is only possible
8805 * when there is a single transparent color, no semitransparent
8806 * color, and no opaque color that has the same RGB components
8807 * as the transparent color. We only need this information if
8808 * we are writing a PNG with colortype 0 or 2, and we have not
8809 * excluded the tRNS chunk.
8811 if (number_transparent == 1 &&
8812 mng_info->write_png_colortype < 4)
8814 ping_have_cheap_transparency = MagickTrue;
8816 if (number_semitransparent != 0)
8817 ping_have_cheap_transparency = MagickFalse;
8819 else if (image_colors == 0 || image_colors > 256 ||
8820 image->colormap == NULL)
8822 register const Quantum
8825 for (y=0; y < (ssize_t) image->rows; y++)
8827 q=GetVirtualPixels(image,0,y,image->columns,1, exception);
8829 if (q == (Quantum *) NULL)
8832 for (x=0; x < (ssize_t) image->columns; x++)
8834 if (GetPixelAlpha(image,q) != TransparentAlpha &&
8835 (unsigned short) GetPixelRed(image,q) ==
8836 ping_trans_color.red &&
8837 (unsigned short) GetPixelGreen(image,q) ==
8838 ping_trans_color.green &&
8839 (unsigned short) GetPixelBlue(image,q) ==
8840 ping_trans_color.blue)
8842 ping_have_cheap_transparency = MagickFalse;
8846 q+=GetPixelChannels(image);
8849 if (ping_have_cheap_transparency == MagickFalse)
8855 /* Assuming that image->colormap[0] is the one transparent color
8856 * and that all others are opaque.
8858 if (image_colors > 1)
8859 for (i=1; i<image_colors; i++)
8860 if (image->colormap[i].red == image->colormap[0].red &&
8861 image->colormap[i].green == image->colormap[0].green &&
8862 image->colormap[i].blue == image->colormap[0].blue)
8864 ping_have_cheap_transparency = MagickFalse;
8869 if (logging != MagickFalse)
8871 if (ping_have_cheap_transparency == MagickFalse)
8872 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8873 " Cheap transparency is not possible.");
8876 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8877 " Cheap transparency is possible.");
8881 ping_have_cheap_transparency = MagickFalse;
8883 image_depth=image->depth;
8885 quantum_info = (QuantumInfo *) NULL;
8887 image_colors=(int) image->colors;
8888 image_matte=image->matte;
8890 mng_info->IsPalette=image->storage_class == PseudoClass &&
8891 image_colors <= 256 && image->colormap != NULL;
8893 if ((mng_info->write_png_colortype == 4 || mng_info->write_png8) &&
8894 (image->colors == 0 || image->colormap == NULL))
8896 image_info=DestroyImageInfo(image_info);
8897 image=DestroyImage(image);
8898 (void) ThrowMagickException(exception,GetMagickModule(),CoderError,
8899 "Cannot write PNG8 or color-type 3; colormap is NULL",
8900 "`%s'",IMimage->filename);
8901 return(MagickFalse);
8905 Allocate the PNG structures
8907 #ifdef PNG_USER_MEM_SUPPORTED
8908 error_info.image=image;
8909 error_info.exception=exception;
8910 ping=png_create_write_struct_2(PNG_LIBPNG_VER_STRING,&error_info,
8911 MagickPNGErrorHandler,MagickPNGWarningHandler,(void *) NULL,
8912 (png_malloc_ptr) Magick_png_malloc,(png_free_ptr) Magick_png_free);
8915 ping=png_create_write_struct(PNG_LIBPNG_VER_STRING,&error_info,
8916 MagickPNGErrorHandler,MagickPNGWarningHandler);
8919 if (ping == (png_struct *) NULL)
8920 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
8922 ping_info=png_create_info_struct(ping);
8924 if (ping_info == (png_info *) NULL)
8926 png_destroy_write_struct(&ping,(png_info **) NULL);
8927 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
8930 png_set_write_fn(ping,image,png_put_data,png_flush_data);
8931 ping_pixels=(unsigned char *) NULL;
8933 if (setjmp(png_jmpbuf(ping)))
8939 if (image_info->verbose)
8940 (void) printf("PNG write has failed.\n");
8942 png_destroy_write_struct(&ping,&ping_info);
8943 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
8944 UnlockSemaphoreInfo(ping_semaphore);
8947 if (ping_pixels != (unsigned char *) NULL)
8948 ping_pixels=(unsigned char *) RelinquishMagickMemory(ping_pixels);
8950 if (quantum_info != (QuantumInfo *) NULL)
8951 quantum_info=DestroyQuantumInfo(quantum_info);
8953 if (ping_have_blob != MagickFalse)
8954 (void) CloseBlob(image);
8955 image_info=DestroyImageInfo(image_info);
8956 image=DestroyImage(image);
8957 return(MagickFalse);
8960 /* { For navigation to end of SETJMP-protected block. Within this
8961 * block, use png_error() instead of Throwing an Exception, to ensure
8962 * that libpng is able to clean up, and that the semaphore is unlocked.
8965 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
8966 LockSemaphoreInfo(ping_semaphore);
8970 Prepare PNG for writing.
8973 #if defined(PNG_MNG_FEATURES_SUPPORTED)
8974 if (mng_info->write_mng)
8976 (void) png_permit_mng_features(ping,PNG_ALL_MNG_FEATURES);
8977 # ifdef PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED
8978 /* Disable new libpng-1.5.10 feature when writing a MNG because
8979 * zero-length PLTE is OK
8981 png_set_check_for_invalid_index (ping, 0);
8986 # ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
8987 if (mng_info->write_mng)
8988 png_permit_empty_plte(ping,MagickTrue);
8995 ping_width=(png_uint_32) image->columns;
8996 ping_height=(png_uint_32) image->rows;
8998 if (mng_info->write_png8 || mng_info->write_png24 || mng_info->write_png32)
9001 if (mng_info->write_png_depth != 0)
9002 image_depth=mng_info->write_png_depth;
9004 /* Adjust requested depth to next higher valid depth if necessary */
9005 if (image_depth > 8)
9008 if ((image_depth > 4) && (image_depth < 8))
9011 if (image_depth == 3)
9014 if (logging != MagickFalse)
9016 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9017 " width=%.20g",(double) ping_width);
9018 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9019 " height=%.20g",(double) ping_height);
9020 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9021 " image_matte=%.20g",(double) image->matte);
9022 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9023 " image->depth=%.20g",(double) image->depth);
9024 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9025 " Tentative ping_bit_depth=%.20g",(double) image_depth);
9028 save_image_depth=image_depth;
9029 ping_bit_depth=(png_byte) save_image_depth;
9032 #if defined(PNG_pHYs_SUPPORTED)
9033 if (ping_exclude_pHYs == MagickFalse)
9035 if ((image->resolution.x != 0) && (image->resolution.y != 0) &&
9036 (!mng_info->write_mng || !mng_info->equal_physs))
9038 if (logging != MagickFalse)
9039 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9040 " Setting up pHYs chunk");
9042 if (image->units == PixelsPerInchResolution)
9044 ping_pHYs_unit_type=PNG_RESOLUTION_METER;
9045 ping_pHYs_x_resolution=
9046 (png_uint_32) ((100.0*image->resolution.x+0.5)/2.54);
9047 ping_pHYs_y_resolution=
9048 (png_uint_32) ((100.0*image->resolution.y+0.5)/2.54);
9051 else if (image->units == PixelsPerCentimeterResolution)
9053 ping_pHYs_unit_type=PNG_RESOLUTION_METER;
9054 ping_pHYs_x_resolution=(png_uint_32) (100.0*image->resolution.x+0.5);
9055 ping_pHYs_y_resolution=(png_uint_32) (100.0*image->resolution.y+0.5);
9060 ping_pHYs_unit_type=PNG_RESOLUTION_UNKNOWN;
9061 ping_pHYs_x_resolution=(png_uint_32) image->resolution.x;
9062 ping_pHYs_y_resolution=(png_uint_32) image->resolution.y;
9065 if (logging != MagickFalse)
9066 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9067 " Set up PNG pHYs chunk: xres: %.20g, yres: %.20g, units: %d.",
9068 (double) ping_pHYs_x_resolution,(double) ping_pHYs_y_resolution,
9069 (int) ping_pHYs_unit_type);
9070 ping_have_pHYs = MagickTrue;
9075 if (ping_exclude_bKGD == MagickFalse)
9077 if ((!mng_info->adjoin || !mng_info->equal_backgrounds))
9083 if (ping_bit_depth == 8)
9086 if (ping_bit_depth == 4)
9089 if (ping_bit_depth == 2)
9092 if (ping_bit_depth == 1)
9095 ping_background.red=(png_uint_16)
9096 (ScaleQuantumToShort(image->background_color.red) & mask);
9098 ping_background.green=(png_uint_16)
9099 (ScaleQuantumToShort(image->background_color.green) & mask);
9101 ping_background.blue=(png_uint_16)
9102 (ScaleQuantumToShort(image->background_color.blue) & mask);
9104 ping_background.gray=(png_uint_16) ping_background.green;
9107 if (logging != MagickFalse)
9109 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9110 " Setting up bKGD chunk (1)");
9111 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9112 " background_color index is %d",
9113 (int) ping_background.index);
9115 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9116 " ping_bit_depth=%d",ping_bit_depth);
9119 ping_have_bKGD = MagickTrue;
9123 Select the color type.
9128 if (mng_info->IsPalette && mng_info->write_png8)
9131 /* To do: make this a function cause it's used twice, except
9132 for reducing the sample depth from 8. */
9134 number_colors=image_colors;
9136 ping_have_tRNS=MagickFalse;
9141 ping_color_type=(png_byte) PNG_COLOR_TYPE_PALETTE;
9143 if (logging != MagickFalse)
9144 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9145 " Setting up PLTE chunk with %d colors (%d)",
9146 number_colors, image_colors);
9148 for (i=0; i < (ssize_t) number_colors; i++)
9150 palette[i].red=ScaleQuantumToChar(image->colormap[i].red);
9151 palette[i].green=ScaleQuantumToChar(image->colormap[i].green);
9152 palette[i].blue=ScaleQuantumToChar(image->colormap[i].blue);
9153 if (logging != MagickFalse)
9154 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9155 #if MAGICKCORE_QUANTUM_DEPTH == 8
9156 " %3ld (%3d,%3d,%3d)",
9158 " %5ld (%5d,%5d,%5d)",
9160 (long) i,palette[i].red,palette[i].green,palette[i].blue);
9164 ping_have_PLTE=MagickTrue;
9165 image_depth=ping_bit_depth;
9168 if (matte != MagickFalse)
9171 Identify which colormap entry is transparent.
9173 assert(number_colors <= 256);
9174 assert(image->colormap != NULL);
9176 for (i=0; i < (ssize_t) number_transparent; i++)
9177 ping_trans_alpha[i]=0;
9180 ping_num_trans=(unsigned short) (number_transparent +
9181 number_semitransparent);
9183 if (ping_num_trans == 0)
9184 ping_have_tRNS=MagickFalse;
9187 ping_have_tRNS=MagickTrue;
9190 if (ping_exclude_bKGD == MagickFalse)
9193 * Identify which colormap entry is the background color.
9196 for (i=0; i < (ssize_t) MagickMax(1L*number_colors-1L,1L); i++)
9197 if (IsPNGColorEqual(ping_background,image->colormap[i]))
9200 ping_background.index=(png_byte) i;
9202 if (logging != MagickFalse)
9204 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9205 " background_color index is %d",
9206 (int) ping_background.index);
9209 } /* end of write_png8 */
9211 else if (mng_info->write_png24 || mng_info->write_png_colortype == 3)
9213 image_matte=MagickFalse;
9214 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB;
9217 else if (mng_info->write_png32 || mng_info->write_png_colortype == 7)
9219 image_matte=MagickTrue;
9220 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB_ALPHA;
9223 else /* mng_info->write_pngNN not specified */
9225 image_depth=ping_bit_depth;
9227 if (mng_info->write_png_colortype != 0)
9229 ping_color_type=(png_byte) mng_info->write_png_colortype-1;
9231 if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA ||
9232 ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA)
9233 image_matte=MagickTrue;
9236 image_matte=MagickFalse;
9238 if (logging != MagickFalse)
9239 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9240 " PNG colortype %d was specified:",(int) ping_color_type);
9243 else /* write_png_colortype not specified */
9245 if (logging != MagickFalse)
9246 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9247 " Selecting PNG colortype:");
9249 ping_color_type=(png_byte) ((matte != MagickFalse)?
9250 PNG_COLOR_TYPE_RGB_ALPHA:PNG_COLOR_TYPE_RGB);
9252 if (image_info->type == TrueColorType)
9254 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB;
9255 image_matte=MagickFalse;
9258 if (image_info->type == TrueColorMatteType)
9260 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB_ALPHA;
9261 image_matte=MagickTrue;
9264 if (image_info->type == PaletteType ||
9265 image_info->type == PaletteMatteType)
9266 ping_color_type=(png_byte) PNG_COLOR_TYPE_PALETTE;
9268 if (mng_info->write_png_colortype == 0 &&
9269 (image_info->type == UndefinedType ||
9270 image_info->type == OptimizeType))
9272 if (ping_have_color == MagickFalse)
9274 if (image_matte == MagickFalse)
9276 ping_color_type=(png_byte) PNG_COLOR_TYPE_GRAY;
9277 image_matte=MagickFalse;
9282 ping_color_type=(png_byte) PNG_COLOR_TYPE_GRAY_ALPHA;
9283 image_matte=MagickTrue;
9288 if (image_matte == MagickFalse)
9290 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB;
9291 image_matte=MagickFalse;
9296 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGBA;
9297 image_matte=MagickTrue;
9304 if (logging != MagickFalse)
9305 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9306 " Selected PNG colortype=%d",ping_color_type);
9308 if (ping_bit_depth < 8)
9310 if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA ||
9311 ping_color_type == PNG_COLOR_TYPE_RGB ||
9312 ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA)
9316 old_bit_depth=ping_bit_depth;
9318 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
9320 if (image->matte == MagickFalse && ping_have_non_bw == MagickFalse)
9324 if (ping_color_type == PNG_COLOR_TYPE_PALETTE)
9329 if (image->colors == 0)
9332 png_error(ping,"image has 0 colors");
9335 while ((int) (one << ping_bit_depth) < (ssize_t) image_colors)
9336 ping_bit_depth <<= 1;
9339 if (logging != MagickFalse)
9341 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9342 " Number of colors: %.20g",(double) image_colors);
9344 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9345 " Tentative PNG bit depth: %d",ping_bit_depth);
9348 if (ping_bit_depth < (int) mng_info->write_png_depth)
9349 ping_bit_depth = mng_info->write_png_depth;
9352 image_depth=ping_bit_depth;
9354 if (logging != MagickFalse)
9356 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9357 " Tentative PNG color type: %s (%.20g)",
9358 PngColorTypeToString(ping_color_type),
9359 (double) ping_color_type);
9361 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9362 " image_info->type: %.20g",(double) image_info->type);
9364 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9365 " image_depth: %.20g",(double) image_depth);
9367 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9369 " image->depth: %.20g",(double) image->depth);
9371 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9372 " ping_bit_depth: %.20g",(double) ping_bit_depth);
9375 if (matte != MagickFalse)
9377 if (mng_info->IsPalette)
9379 if (mng_info->write_png_colortype == 0)
9381 ping_color_type=PNG_COLOR_TYPE_GRAY_ALPHA;
9383 if (ping_have_color != MagickFalse)
9384 ping_color_type=PNG_COLOR_TYPE_RGBA;
9388 * Determine if there is any transparent color.
9390 if (number_transparent + number_semitransparent == 0)
9393 No transparent pixels are present. Change 4 or 6 to 0 or 2.
9396 image_matte=MagickFalse;
9398 if (mng_info->write_png_colortype == 0)
9399 ping_color_type&=0x03;
9409 if (ping_bit_depth == 8)
9412 if (ping_bit_depth == 4)
9415 if (ping_bit_depth == 2)
9418 if (ping_bit_depth == 1)
9421 ping_trans_color.red=(png_uint_16)
9422 (ScaleQuantumToShort(image->colormap[0].red) & mask);
9424 ping_trans_color.green=(png_uint_16)
9425 (ScaleQuantumToShort(image->colormap[0].green) & mask);
9427 ping_trans_color.blue=(png_uint_16)
9428 (ScaleQuantumToShort(image->colormap[0].blue) & mask);
9430 ping_trans_color.gray=(png_uint_16)
9431 (ScaleQuantumToShort(GetPixelInfoIntensity(
9432 image->colormap)) & mask);
9434 ping_trans_color.index=(png_byte) 0;
9436 ping_have_tRNS=MagickTrue;
9439 if (ping_have_tRNS != MagickFalse)
9442 * Determine if there is one and only one transparent color
9443 * and if so if it is fully transparent.
9445 if (ping_have_cheap_transparency == MagickFalse)
9446 ping_have_tRNS=MagickFalse;
9449 if (ping_have_tRNS != MagickFalse)
9451 if (mng_info->write_png_colortype == 0)
9452 ping_color_type &= 0x03; /* changes 4 or 6 to 0 or 2 */
9454 if (image_depth == 8)
9456 ping_trans_color.red&=0xff;
9457 ping_trans_color.green&=0xff;
9458 ping_trans_color.blue&=0xff;
9459 ping_trans_color.gray&=0xff;
9465 if (image_depth == 8)
9467 ping_trans_color.red&=0xff;
9468 ping_trans_color.green&=0xff;
9469 ping_trans_color.blue&=0xff;
9470 ping_trans_color.gray&=0xff;
9477 if (ping_have_tRNS != MagickFalse)
9478 image_matte=MagickFalse;
9480 if ((mng_info->IsPalette) &&
9481 mng_info->write_png_colortype-1 != PNG_COLOR_TYPE_PALETTE &&
9482 ping_have_color == MagickFalse &&
9483 (image_matte == MagickFalse || image_depth >= 8))
9487 if (image_matte != MagickFalse)
9488 ping_color_type=PNG_COLOR_TYPE_GRAY_ALPHA;
9490 else if (mng_info->write_png_colortype-1 != PNG_COLOR_TYPE_GRAY_ALPHA)
9492 ping_color_type=PNG_COLOR_TYPE_GRAY;
9494 if (save_image_depth == 16 && image_depth == 8)
9496 if (logging != MagickFalse)
9498 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9499 " Scaling ping_trans_color (0)");
9501 ping_trans_color.gray*=0x0101;
9505 if (image_depth > MAGICKCORE_QUANTUM_DEPTH)
9506 image_depth=MAGICKCORE_QUANTUM_DEPTH;
9508 if ((image_colors == 0) ||
9509 ((ssize_t) (image_colors-1) > (ssize_t) MaxColormapSize))
9510 image_colors=(int) (one << image_depth);
9512 if (image_depth > 8)
9518 if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
9520 if(!mng_info->write_png_depth)
9524 while ((int) (one << ping_bit_depth)
9525 < (ssize_t) image_colors)
9526 ping_bit_depth <<= 1;
9530 else if (ping_color_type ==
9531 PNG_COLOR_TYPE_GRAY && image_colors < 17 &&
9532 mng_info->IsPalette)
9534 /* Check if grayscale is reducible */
9537 depth_4_ok=MagickTrue,
9538 depth_2_ok=MagickTrue,
9539 depth_1_ok=MagickTrue;
9541 for (i=0; i < (ssize_t) image_colors; i++)
9546 intensity=ScaleQuantumToChar(image->colormap[i].red);
9548 if ((intensity & 0x0f) != ((intensity & 0xf0) >> 4))
9549 depth_4_ok=depth_2_ok=depth_1_ok=MagickFalse;
9550 else if ((intensity & 0x03) != ((intensity & 0x0c) >> 2))
9551 depth_2_ok=depth_1_ok=MagickFalse;
9552 else if ((intensity & 0x01) != ((intensity & 0x02) >> 1))
9553 depth_1_ok=MagickFalse;
9556 if (depth_1_ok && mng_info->write_png_depth <= 1)
9559 else if (depth_2_ok && mng_info->write_png_depth <= 2)
9562 else if (depth_4_ok && mng_info->write_png_depth <= 4)
9567 image_depth=ping_bit_depth;
9572 if (mng_info->IsPalette)
9574 number_colors=image_colors;
9576 if (image_depth <= 8)
9581 ping_color_type=(png_byte) PNG_COLOR_TYPE_PALETTE;
9583 if (mng_info->have_write_global_plte && matte == MagickFalse)
9585 png_set_PLTE(ping,ping_info,NULL,0);
9587 if (logging != MagickFalse)
9588 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9589 " Setting up empty PLTE chunk");
9594 for (i=0; i < (ssize_t) number_colors; i++)
9596 palette[i].red=ScaleQuantumToChar(image->colormap[i].red);
9597 palette[i].green=ScaleQuantumToChar(image->colormap[i].green);
9598 palette[i].blue=ScaleQuantumToChar(image->colormap[i].blue);
9601 if (logging != MagickFalse)
9602 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9603 " Setting up PLTE chunk with %d colors",
9606 ping_have_PLTE=MagickTrue;
9609 /* color_type is PNG_COLOR_TYPE_PALETTE */
9610 if (mng_info->write_png_depth == 0)
9618 while ((one << ping_bit_depth) < (size_t) number_colors)
9619 ping_bit_depth <<= 1;
9624 if (matte != MagickFalse)
9627 * Set up trans_colors array.
9629 assert(number_colors <= 256);
9631 ping_num_trans=(unsigned short) (number_transparent +
9632 number_semitransparent);
9634 if (ping_num_trans == 0)
9635 ping_have_tRNS=MagickFalse;
9639 if (logging != MagickFalse)
9641 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9642 " Scaling ping_trans_color (1)");
9644 ping_have_tRNS=MagickTrue;
9646 for (i=0; i < ping_num_trans; i++)
9648 ping_trans_alpha[i]= (png_byte)
9649 ScaleQuantumToChar(image->colormap[i].alpha);
9659 if (image_depth < 8)
9662 if ((save_image_depth == 16) && (image_depth == 8))
9664 if (logging != MagickFalse)
9666 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9667 " Scaling ping_trans_color from (%d,%d,%d)",
9668 (int) ping_trans_color.red,
9669 (int) ping_trans_color.green,
9670 (int) ping_trans_color.blue);
9673 ping_trans_color.red*=0x0101;
9674 ping_trans_color.green*=0x0101;
9675 ping_trans_color.blue*=0x0101;
9676 ping_trans_color.gray*=0x0101;
9678 if (logging != MagickFalse)
9680 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9682 (int) ping_trans_color.red,
9683 (int) ping_trans_color.green,
9684 (int) ping_trans_color.blue);
9689 if (ping_bit_depth < (ssize_t) mng_info->write_png_depth)
9690 ping_bit_depth = (ssize_t) mng_info->write_png_depth;
9693 Adjust background and transparency samples in sub-8-bit grayscale files.
9695 if (ping_bit_depth < 8 && ping_color_type ==
9696 PNG_COLOR_TYPE_GRAY)
9704 maxval=(png_uint_16) ((one << ping_bit_depth)-1);
9706 if (ping_exclude_bKGD == MagickFalse)
9709 ping_background.gray=(png_uint_16) ((maxval/65535.)*
9710 (ScaleQuantumToShort(((GetPixelInfoIntensity(
9711 &image->background_color))) +.5)));
9713 if (logging != MagickFalse)
9714 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9715 " Setting up bKGD chunk (2)");
9716 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9717 " background_color index is %d",
9718 (int) ping_background.index);
9720 ping_have_bKGD = MagickTrue;
9723 if (logging != MagickFalse)
9724 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9725 " Scaling ping_trans_color.gray from %d",
9726 (int)ping_trans_color.gray);
9728 ping_trans_color.gray=(png_uint_16) ((maxval/255.)*(
9729 ping_trans_color.gray)+.5);
9731 if (logging != MagickFalse)
9732 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9733 " to %d", (int)ping_trans_color.gray);
9736 if (ping_exclude_bKGD == MagickFalse)
9738 if (mng_info->IsPalette && (int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
9741 Identify which colormap entry is the background color.
9744 number_colors=image_colors;
9746 for (i=0; i < (ssize_t) MagickMax(1L*number_colors,1L); i++)
9747 if (IsPNGColorEqual(image->background_color,image->colormap[i]))
9750 ping_background.index=(png_byte) i;
9752 if (logging != MagickFalse)
9754 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9755 " Setting up bKGD chunk with index=%d",(int) i);
9758 if (i < (ssize_t) number_colors)
9760 ping_have_bKGD = MagickTrue;
9762 if (logging != MagickFalse)
9764 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9765 " background =(%d,%d,%d)",
9766 (int) ping_background.red,
9767 (int) ping_background.green,
9768 (int) ping_background.blue);
9772 else /* Can't happen */
9774 if (logging != MagickFalse)
9775 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9776 " No room in PLTE to add bKGD color");
9777 ping_have_bKGD = MagickFalse;
9782 if (logging != MagickFalse)
9783 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9784 " PNG color type: %s (%d)", PngColorTypeToString(ping_color_type),
9787 Initialize compression level and filtering.
9789 if (logging != MagickFalse)
9791 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9792 " Setting up deflate compression");
9794 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9795 " Compression buffer size: 32768");
9798 png_set_compression_buffer_size(ping,32768L);
9800 if (logging != MagickFalse)
9801 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9802 " Compression mem level: 9");
9804 png_set_compression_mem_level(ping, 9);
9806 /* Untangle the "-quality" setting:
9808 Undefined is 0; the default is used.
9813 0: Use Z_HUFFMAN_ONLY strategy with the
9814 zlib default compression level
9816 1-9: the zlib compression level
9820 0-4: the PNG filter method
9822 5: libpng adaptive filtering if compression level > 5
9823 libpng filter type "none" if compression level <= 5
9824 or if image is grayscale or palette
9826 6: libpng adaptive filtering
9828 7: "LOCO" filtering (intrapixel differing) if writing
9829 a MNG, othewise "none". Did not work in IM-6.7.0-9
9830 and earlier because of a missing "else".
9832 8: Z_RLE strategy, all filters
9833 Unused prior to IM-6.7.0-10, was same as 6
9835 9: Z_RLE strategy, no PNG filters
9836 Unused prior to IM-6.7.0-10, was same as 6
9838 Note that using the -quality option, not all combinations of
9839 PNG filter type, zlib compression level, and zlib compression
9840 strategy are possible. This will be addressed soon in a
9841 release that accomodates "-define png:compression-strategy", etc.
9845 quality=image->quality == UndefinedCompressionQuality ? 75UL :
9850 if (mng_info->write_png_compression_strategy == 0)
9851 mng_info->write_png_compression_strategy = Z_HUFFMAN_ONLY+1;
9854 else if (mng_info->write_png_compression_level == 0)
9859 level=(int) MagickMin((ssize_t) quality/10,9);
9861 mng_info->write_png_compression_level = level+1;
9864 if (mng_info->write_png_compression_strategy == 0)
9866 if ((quality %10) == 8 || (quality %10) == 9)
9867 #ifdef Z_RLE /* Z_RLE was added to zlib-1.2.0 */
9868 mng_info->write_png_compression_strategy=Z_RLE+1;
9870 mng_info->write_png_compression_strategy = Z_DEFAULT_STRATEGY+1;
9874 if (mng_info->write_png_compression_filter == 0)
9875 mng_info->write_png_compression_filter=((int) quality % 10) + 1;
9877 if (logging != MagickFalse)
9879 if (mng_info->write_png_compression_level)
9880 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9881 " Compression level: %d",
9882 (int) mng_info->write_png_compression_level-1);
9884 if (mng_info->write_png_compression_strategy)
9885 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9886 " Compression strategy: %d",
9887 (int) mng_info->write_png_compression_strategy-1);
9889 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9890 " Setting up filtering");
9892 if (mng_info->write_png_compression_filter == 6)
9893 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9894 " Base filter method: ADAPTIVE");
9895 else if (mng_info->write_png_compression_filter == 0 ||
9896 mng_info->write_png_compression_filter == 1)
9897 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9898 " Base filter method: NONE");
9900 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9901 " Base filter method: %d",
9902 (int) mng_info->write_png_compression_filter-1);
9905 if (mng_info->write_png_compression_level != 0)
9906 png_set_compression_level(ping,mng_info->write_png_compression_level-1);
9908 if (mng_info->write_png_compression_filter == 6)
9910 if (((int) ping_color_type == PNG_COLOR_TYPE_GRAY) ||
9911 ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE) ||
9913 png_set_filter(ping,PNG_FILTER_TYPE_BASE,PNG_NO_FILTERS);
9915 png_set_filter(ping,PNG_FILTER_TYPE_BASE,PNG_ALL_FILTERS);
9917 else if (mng_info->write_png_compression_filter == 7 ||
9918 mng_info->write_png_compression_filter == 10)
9919 png_set_filter(ping,PNG_FILTER_TYPE_BASE,PNG_ALL_FILTERS);
9921 else if (mng_info->write_png_compression_filter == 8)
9923 #if defined(PNG_MNG_FEATURES_SUPPORTED) && defined(PNG_INTRAPIXEL_DIFFERENCING)
9924 if (mng_info->write_mng)
9926 if (((int) ping_color_type == PNG_COLOR_TYPE_RGB) ||
9927 ((int) ping_color_type == PNG_COLOR_TYPE_RGBA))
9928 ping_filter_method=PNG_INTRAPIXEL_DIFFERENCING;
9931 png_set_filter(ping,PNG_FILTER_TYPE_BASE,PNG_NO_FILTERS);
9934 else if (mng_info->write_png_compression_filter == 9)
9935 png_set_filter(ping,PNG_FILTER_TYPE_BASE,PNG_NO_FILTERS);
9937 else if (mng_info->write_png_compression_filter != 0)
9938 png_set_filter(ping,PNG_FILTER_TYPE_BASE,
9939 mng_info->write_png_compression_filter-1);
9941 if (mng_info->write_png_compression_strategy != 0)
9942 png_set_compression_strategy(ping,
9943 mng_info->write_png_compression_strategy-1);
9945 /* Only write the iCCP chunk if we are not writing the sRGB chunk. */
9946 if (ping_exclude_sRGB != MagickFalse ||
9947 (image->rendering_intent == UndefinedIntent))
9949 if ((ping_exclude_tEXt == MagickFalse ||
9950 ping_exclude_zTXt == MagickFalse) &&
9951 (ping_exclude_iCCP == MagickFalse || ping_exclude_zCCP == MagickFalse))
9953 ResetImageProfileIterator(image);
9954 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
9956 profile=GetImageProfile(image,name);
9958 if (profile != (StringInfo *) NULL)
9960 #ifdef PNG_WRITE_iCCP_SUPPORTED
9961 if ((LocaleCompare(name,"ICC") == 0) ||
9962 (LocaleCompare(name,"ICM") == 0))
9965 if (ping_exclude_iCCP == MagickFalse)
9967 png_set_iCCP(ping,ping_info,(png_charp) name,0,
9968 #if (PNG_LIBPNG_VER < 10500)
9969 (png_charp) GetStringInfoDatum(profile),
9971 (png_const_bytep) GetStringInfoDatum(profile),
9973 (png_uint_32) GetStringInfoLength(profile));
9979 if (ping_exclude_zCCP == MagickFalse)
9981 Magick_png_write_raw_profile(image_info,ping,ping_info,
9982 (unsigned char *) name,(unsigned char *) name,
9983 GetStringInfoDatum(profile),
9984 (png_uint_32) GetStringInfoLength(profile));
9988 if (logging != MagickFalse)
9989 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9990 " Setting up text chunk with %s profile",name);
9992 name=GetNextImageProfile(image);
9997 #if defined(PNG_WRITE_sRGB_SUPPORTED)
9998 if ((mng_info->have_write_global_srgb == 0) &&
9999 (image->rendering_intent != UndefinedIntent))
10001 if (ping_exclude_sRGB == MagickFalse)
10004 Note image rendering intent.
10006 if (logging != MagickFalse)
10007 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10008 " Setting up sRGB chunk");
10010 (void) png_set_sRGB(ping,ping_info,(
10011 Magick_RenderingIntent_to_PNG_RenderingIntent(
10012 image->rendering_intent)));
10016 if ((!mng_info->write_mng) || (!png_get_valid(ping,ping_info,PNG_INFO_sRGB)))
10019 if (ping_exclude_gAMA == MagickFalse &&
10020 (ping_exclude_sRGB == MagickFalse ||
10021 (image->gamma < .45 || image->gamma > .46)))
10023 if ((mng_info->have_write_global_gama == 0) && (image->gamma != 0.0))
10027 To do: check for cHRM+gAMA == sRGB, and write sRGB instead.
10029 if (logging != MagickFalse)
10030 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10031 " Setting up gAMA chunk");
10033 png_set_gAMA(ping,ping_info,image->gamma);
10037 if (ping_exclude_cHRM == MagickFalse)
10039 if ((mng_info->have_write_global_chrm == 0) &&
10040 (image->chromaticity.red_primary.x != 0.0))
10043 Note image chromaticity.
10044 To do: check for cHRM+gAMA == sRGB, and write sRGB instead.
10052 wp=image->chromaticity.white_point;
10053 rp=image->chromaticity.red_primary;
10054 gp=image->chromaticity.green_primary;
10055 bp=image->chromaticity.blue_primary;
10057 if (logging != MagickFalse)
10058 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10059 " Setting up cHRM chunk");
10061 png_set_cHRM(ping,ping_info,wp.x,wp.y,rp.x,rp.y,gp.x,gp.y,
10067 ping_interlace_method=image_info->interlace != NoInterlace;
10069 if (mng_info->write_mng)
10070 png_set_sig_bytes(ping,8);
10072 /* Bail out if cannot meet defined png:bit-depth or png:color-type */
10074 if (mng_info->write_png_colortype != 0)
10076 if (mng_info->write_png_colortype-1 == PNG_COLOR_TYPE_GRAY)
10077 if (ping_have_color != MagickFalse)
10079 ping_color_type = PNG_COLOR_TYPE_RGB;
10081 if (ping_bit_depth < 8)
10085 if (mng_info->write_png_colortype-1 == PNG_COLOR_TYPE_GRAY_ALPHA)
10086 if (ping_have_color != MagickFalse)
10087 ping_color_type = PNG_COLOR_TYPE_RGB_ALPHA;
10090 if (ping_need_colortype_warning != MagickFalse ||
10091 ((mng_info->write_png_depth &&
10092 (int) mng_info->write_png_depth != ping_bit_depth) ||
10093 (mng_info->write_png_colortype &&
10094 ((int) mng_info->write_png_colortype-1 != ping_color_type &&
10095 mng_info->write_png_colortype != 7 &&
10096 !(mng_info->write_png_colortype == 5 && ping_color_type == 0)))))
10098 if (logging != MagickFalse)
10100 if (ping_need_colortype_warning != MagickFalse)
10102 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10103 " Image has transparency but tRNS chunk was excluded");
10106 if (mng_info->write_png_depth)
10108 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10109 " Defined png:bit-depth=%u, Computed depth=%u",
10110 mng_info->write_png_depth,
10114 if (mng_info->write_png_colortype)
10116 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10117 " Defined png:color-type=%u, Computed color type=%u",
10118 mng_info->write_png_colortype-1,
10124 "Cannot write image with defined png:bit-depth or png:color-type.");
10127 if (image_matte != MagickFalse && image->matte == MagickFalse)
10129 /* Add an opaque matte channel */
10130 image->matte = MagickTrue;
10131 (void) SetImageAlpha(image,OpaqueAlpha,exception);
10133 if (logging != MagickFalse)
10134 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10135 " Added an opaque matte channel");
10138 if (number_transparent != 0 || number_semitransparent != 0)
10140 if (ping_color_type < 4)
10142 ping_have_tRNS=MagickTrue;
10143 if (logging != MagickFalse)
10144 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10145 " Setting ping_have_tRNS=MagickTrue.");
10149 if (logging != MagickFalse)
10150 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10151 " Writing PNG header chunks");
10153 png_set_IHDR(ping,ping_info,ping_width,ping_height,
10154 ping_bit_depth,ping_color_type,
10155 ping_interlace_method,ping_compression_method,
10156 ping_filter_method);
10158 if (ping_color_type == 3 && ping_have_PLTE != MagickFalse)
10160 png_set_PLTE(ping,ping_info,palette,number_colors);
10162 if (logging != MagickFalse)
10164 for (i=0; i< (ssize_t) number_colors; i++)
10166 if (i < ping_num_trans)
10167 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10168 " PLTE[%d] = (%d,%d,%d), tRNS[%d] = (%d)",
10170 (int) palette[i].red,
10171 (int) palette[i].green,
10172 (int) palette[i].blue,
10174 (int) ping_trans_alpha[i]);
10176 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10177 " PLTE[%d] = (%d,%d,%d)",
10179 (int) palette[i].red,
10180 (int) palette[i].green,
10181 (int) palette[i].blue);
10186 if (ping_exclude_bKGD == MagickFalse)
10188 if (ping_have_bKGD != MagickFalse)
10190 png_set_bKGD(ping,ping_info,&ping_background);
10193 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10194 " Setting up bKGD chunk");
10195 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10196 " background color = (%d,%d,%d)",
10197 (int) ping_background.red,
10198 (int) ping_background.green,
10199 (int) ping_background.blue);
10200 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10201 " index = %d, gray=%d",
10202 (int) ping_background.index,
10203 (int) ping_background.gray);
10208 if (ping_exclude_pHYs == MagickFalse)
10210 if (ping_have_pHYs != MagickFalse)
10212 png_set_pHYs(ping,ping_info,
10213 ping_pHYs_x_resolution,
10214 ping_pHYs_y_resolution,
10215 ping_pHYs_unit_type);
10219 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10220 " Setting up pHYs chunk");
10221 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10222 " x_resolution=%lu",
10223 (unsigned long) ping_pHYs_x_resolution);
10224 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10225 " y_resolution=%lu",
10226 (unsigned long) ping_pHYs_y_resolution);
10227 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10229 (unsigned long) ping_pHYs_unit_type);
10234 #if defined(PNG_oFFs_SUPPORTED)
10235 if (ping_exclude_oFFs == MagickFalse)
10237 if (image->page.x || image->page.y)
10239 png_set_oFFs(ping,ping_info,(png_int_32) image->page.x,
10240 (png_int_32) image->page.y, 0);
10242 if (logging != MagickFalse)
10243 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10244 " Setting up oFFs chunk with x=%d, y=%d, units=0",
10245 (int) image->page.x, (int) image->page.y);
10250 if (mng_info->need_blob != MagickFalse)
10252 if (OpenBlob(image_info,image,WriteBinaryBlobMode,exception) ==
10254 png_error(ping,"WriteBlob Failed");
10256 ping_have_blob=MagickTrue;
10259 png_write_info_before_PLTE(ping, ping_info);
10261 if (ping_have_tRNS != MagickFalse && ping_color_type < 4)
10263 if (logging != MagickFalse)
10265 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10266 " Calling png_set_tRNS with num_trans=%d",ping_num_trans);
10269 if (ping_color_type == 3)
10270 (void) png_set_tRNS(ping, ping_info,
10277 (void) png_set_tRNS(ping, ping_info,
10280 &ping_trans_color);
10282 if (logging != MagickFalse)
10284 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10285 " tRNS color =(%d,%d,%d)",
10286 (int) ping_trans_color.red,
10287 (int) ping_trans_color.green,
10288 (int) ping_trans_color.blue);
10293 /* write any png-chunk-b profiles */
10294 (void) Magick_png_write_chunk_from_profile(image,"PNG-chunk-b",logging);
10296 png_write_info(ping,ping_info);
10298 /* write any PNG-chunk-m profiles */
10299 (void) Magick_png_write_chunk_from_profile(image,"PNG-chunk-m",logging);
10301 if (ping_exclude_vpAg == MagickFalse)
10303 if ((image->page.width != 0 && image->page.width != image->columns) ||
10304 (image->page.height != 0 && image->page.height != image->rows))
10309 (void) WriteBlobMSBULong(image,9L); /* data length=8 */
10310 PNGType(chunk,mng_vpAg);
10311 LogPNGChunk(logging,mng_vpAg,9L);
10312 PNGLong(chunk+4,(png_uint_32) image->page.width);
10313 PNGLong(chunk+8,(png_uint_32) image->page.height);
10314 chunk[12]=0; /* unit = pixels */
10315 (void) WriteBlob(image,13,chunk);
10316 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
10320 #if (PNG_LIBPNG_VER == 10206)
10321 /* avoid libpng-1.2.6 bug by setting PNG_HAVE_IDAT flag */
10322 #define PNG_HAVE_IDAT 0x04
10323 ping->mode |= PNG_HAVE_IDAT;
10324 #undef PNG_HAVE_IDAT
10327 png_set_packing(ping);
10331 rowbytes=image->columns;
10332 if (image_depth > 8)
10334 switch (ping_color_type)
10336 case PNG_COLOR_TYPE_RGB:
10340 case PNG_COLOR_TYPE_GRAY_ALPHA:
10344 case PNG_COLOR_TYPE_RGBA:
10352 if (logging != MagickFalse)
10354 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10355 " Writing PNG image data");
10357 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10358 " Allocating %.20g bytes of memory for pixels",(double) rowbytes);
10360 ping_pixels=(unsigned char *) AcquireQuantumMemory(rowbytes,
10361 sizeof(*ping_pixels));
10363 if (ping_pixels == (unsigned char *) NULL)
10364 png_error(ping,"Allocation of memory for pixels failed");
10367 Initialize image scanlines.
10369 quantum_info=AcquireQuantumInfo(image_info,image);
10370 if (quantum_info == (QuantumInfo *) NULL)
10371 png_error(ping,"Memory allocation for quantum_info failed");
10372 quantum_info->format=UndefinedQuantumFormat;
10373 quantum_info->depth=image_depth;
10374 num_passes=png_set_interlace_handling(ping);
10376 if ((!mng_info->write_png8 && !mng_info->write_png24 &&
10377 !mng_info->write_png32) &&
10378 (mng_info->IsPalette ||
10379 (image_info->type == BilevelType)) &&
10380 image_matte == MagickFalse &&
10381 ping_have_non_bw == MagickFalse)
10383 /* Palette, Bilevel, or Opaque Monochrome */
10384 register const Quantum
10387 quantum_info->depth=8;
10388 for (pass=0; pass < num_passes; pass++)
10391 Convert PseudoClass image to a PNG monochrome image.
10393 for (y=0; y < (ssize_t) image->rows; y++)
10395 if (logging != MagickFalse && y == 0)
10396 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10397 " Writing row of pixels (0)");
10399 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
10401 if (p == (const Quantum *) NULL)
10404 if (mng_info->IsPalette)
10406 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10407 quantum_info,GrayQuantum,ping_pixels,exception);
10408 if (mng_info->write_png_colortype-1 == PNG_COLOR_TYPE_PALETTE &&
10409 mng_info->write_png_depth &&
10410 mng_info->write_png_depth != old_bit_depth)
10412 /* Undo pixel scaling */
10413 for (i=0; i < (ssize_t) image->columns; i++)
10414 *(ping_pixels+i)=(unsigned char) (*(ping_pixels+i)
10415 >> (8-old_bit_depth));
10421 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10422 quantum_info,RedQuantum,ping_pixels,exception);
10425 if (mng_info->write_png_colortype-1 != PNG_COLOR_TYPE_PALETTE)
10426 for (i=0; i < (ssize_t) image->columns; i++)
10427 *(ping_pixels+i)=(unsigned char) ((*(ping_pixels+i) > 127) ?
10430 if (logging != MagickFalse && y == 0)
10431 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10432 " Writing row of pixels (1)");
10434 png_write_row(ping,ping_pixels);
10436 if (image->previous == (Image *) NULL)
10438 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
10439 if (status == MagickFalse)
10445 else /* Not Palette, Bilevel, or Opaque Monochrome */
10447 if ((!mng_info->write_png8 && !mng_info->write_png24 &&
10448 !mng_info->write_png32) &&
10449 (image_matte != MagickFalse ||
10450 (ping_bit_depth >= MAGICKCORE_QUANTUM_DEPTH)) &&
10451 (mng_info->IsPalette) && ping_have_color == MagickFalse)
10453 register const Quantum
10456 for (pass=0; pass < num_passes; pass++)
10459 for (y=0; y < (ssize_t) image->rows; y++)
10461 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
10463 if (p == (const Quantum *) NULL)
10466 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
10468 if (mng_info->IsPalette)
10469 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10470 quantum_info,GrayQuantum,ping_pixels,exception);
10473 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10474 quantum_info,RedQuantum,ping_pixels,exception);
10476 if (logging != MagickFalse && y == 0)
10477 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10478 " Writing GRAY PNG pixels (2)");
10481 else /* PNG_COLOR_TYPE_GRAY_ALPHA */
10483 if (logging != MagickFalse && y == 0)
10484 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10485 " Writing GRAY_ALPHA PNG pixels (2)");
10487 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10488 quantum_info,GrayAlphaQuantum,ping_pixels,exception);
10491 if (logging != MagickFalse && y == 0)
10492 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10493 " Writing row of pixels (2)");
10495 png_write_row(ping,ping_pixels);
10498 if (image->previous == (Image *) NULL)
10500 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
10501 if (status == MagickFalse)
10509 register const Quantum
10512 for (pass=0; pass < num_passes; pass++)
10514 if ((image_depth > 8) || (mng_info->write_png24 ||
10515 mng_info->write_png32 ||
10516 (!mng_info->write_png8 && !mng_info->IsPalette)))
10518 for (y=0; y < (ssize_t) image->rows; y++)
10520 p=GetVirtualPixels(image,0,y,image->columns,1, exception);
10522 if (p == (const Quantum *) NULL)
10525 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
10527 if (image->storage_class == DirectClass)
10528 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10529 quantum_info,RedQuantum,ping_pixels,exception);
10532 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10533 quantum_info,GrayQuantum,ping_pixels,exception);
10536 else if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
10538 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10539 quantum_info,GrayAlphaQuantum,ping_pixels,
10542 if (logging != MagickFalse && y == 0)
10543 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10544 " Writing GRAY_ALPHA PNG pixels (3)");
10547 else if (image_matte != MagickFalse)
10548 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10549 quantum_info,RGBAQuantum,ping_pixels,exception);
10552 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10553 quantum_info,RGBQuantum,ping_pixels,exception);
10555 if (logging != MagickFalse && y == 0)
10556 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10557 " Writing row of pixels (3)");
10559 png_write_row(ping,ping_pixels);
10564 /* not ((image_depth > 8) || (mng_info->write_png24 ||
10565 mng_info->write_png32 ||
10566 (!mng_info->write_png8 && !mng_info->IsPalette))) */
10568 if ((ping_color_type != PNG_COLOR_TYPE_GRAY) &&
10569 (ping_color_type != PNG_COLOR_TYPE_GRAY_ALPHA))
10571 if (logging != MagickFalse)
10572 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10573 " pass %d, Image Is not GRAY or GRAY_ALPHA",pass);
10575 quantum_info->depth=8;
10579 for (y=0; y < (ssize_t) image->rows; y++)
10581 if (logging != MagickFalse && y == 0)
10582 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10583 " pass %d, Image Is RGB, 16-bit GRAY, or GRAY_ALPHA",pass);
10585 p=GetVirtualPixels(image,0,y,image->columns,1, exception);
10587 if (p == (const Quantum *) NULL)
10590 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
10592 quantum_info->depth=image->depth;
10594 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10595 quantum_info,GrayQuantum,ping_pixels,exception);
10598 else if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
10600 if (logging != MagickFalse && y == 0)
10601 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10602 " Writing GRAY_ALPHA PNG pixels (4)");
10604 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10605 quantum_info,GrayAlphaQuantum,ping_pixels,
10611 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10612 quantum_info,IndexQuantum,ping_pixels,exception);
10614 if (logging != MagickFalse && y <= 2)
10616 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10617 " Writing row of non-gray pixels (4)");
10619 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10620 " ping_pixels[0]=%d,ping_pixels[1]=%d",
10621 (int)ping_pixels[0],(int)ping_pixels[1]);
10624 png_write_row(ping,ping_pixels);
10628 if (image->previous == (Image *) NULL)
10630 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
10631 if (status == MagickFalse)
10638 if (quantum_info != (QuantumInfo *) NULL)
10639 quantum_info=DestroyQuantumInfo(quantum_info);
10641 if (logging != MagickFalse)
10643 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10644 " Wrote PNG image data");
10646 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10647 " Width: %.20g",(double) ping_width);
10649 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10650 " Height: %.20g",(double) ping_height);
10652 if (mng_info->write_png_depth)
10654 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10655 " Defined png:bit-depth: %d",mng_info->write_png_depth);
10658 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10659 " PNG bit-depth written: %d",ping_bit_depth);
10661 if (mng_info->write_png_colortype)
10663 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10664 " Defined png:color-type: %d",mng_info->write_png_colortype-1);
10667 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10668 " PNG color-type written: %d",ping_color_type);
10670 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10671 " PNG Interlace method: %d",ping_interlace_method);
10674 Generate text chunks after IDAT.
10676 if (ping_exclude_tEXt == MagickFalse || ping_exclude_zTXt == MagickFalse)
10678 ResetImagePropertyIterator(image);
10679 property=GetNextImageProperty(image);
10680 while (property != (const char *) NULL)
10685 value=GetImageProperty(image,property,exception);
10687 /* Don't write any "png:" properties; those are just for "identify" */
10688 if (LocaleNCompare(property,"png:",4) != 0 &&
10690 /* Suppress density and units if we wrote a pHYs chunk */
10691 (ping_exclude_pHYs != MagickFalse ||
10692 LocaleCompare(property,"density") != 0 ||
10693 LocaleCompare(property,"units") != 0) &&
10695 /* Suppress the IM-generated Date:create and Date:modify */
10696 (ping_exclude_date == MagickFalse ||
10697 LocaleNCompare(property, "Date:",5) != 0))
10699 if (value != (const char *) NULL)
10701 text=(png_textp) png_malloc(ping,(png_uint_32) sizeof(png_text));
10702 text[0].key=(char *) property;
10703 text[0].text=(char *) value;
10704 text[0].text_length=strlen(value);
10706 if (ping_exclude_tEXt != MagickFalse)
10707 text[0].compression=PNG_TEXT_COMPRESSION_zTXt;
10709 else if (ping_exclude_zTXt != MagickFalse)
10710 text[0].compression=PNG_TEXT_COMPRESSION_NONE;
10714 text[0].compression=image_info->compression == NoCompression ||
10715 (image_info->compression == UndefinedCompression &&
10716 text[0].text_length < 128) ? PNG_TEXT_COMPRESSION_NONE :
10717 PNG_TEXT_COMPRESSION_zTXt ;
10720 if (logging != MagickFalse)
10722 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10723 " Setting up text chunk");
10725 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10726 " keyword: %s",text[0].key);
10729 png_set_text(ping,ping_info,text,1);
10730 png_free(ping,text);
10733 property=GetNextImageProperty(image);
10737 /* write any PNG-chunk-e profiles */
10738 (void) Magick_png_write_chunk_from_profile(image,"PNG-chunk-e",logging);
10740 if (logging != MagickFalse)
10741 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10742 " Writing PNG end info");
10744 png_write_end(ping,ping_info);
10746 if (mng_info->need_fram && (int) image->dispose == BackgroundDispose)
10748 if (mng_info->page.x || mng_info->page.y ||
10749 (ping_width != mng_info->page.width) ||
10750 (ping_height != mng_info->page.height))
10756 Write FRAM 4 with clipping boundaries followed by FRAM 1.
10758 (void) WriteBlobMSBULong(image,27L); /* data length=27 */
10759 PNGType(chunk,mng_FRAM);
10760 LogPNGChunk(logging,mng_FRAM,27L);
10762 chunk[5]=0; /* frame name separator (no name) */
10763 chunk[6]=1; /* flag for changing delay, for next frame only */
10764 chunk[7]=0; /* flag for changing frame timeout */
10765 chunk[8]=1; /* flag for changing frame clipping for next frame */
10766 chunk[9]=0; /* flag for changing frame sync_id */
10767 PNGLong(chunk+10,(png_uint_32) (0L)); /* temporary 0 delay */
10768 chunk[14]=0; /* clipping boundaries delta type */
10769 PNGLong(chunk+15,(png_uint_32) (mng_info->page.x)); /* left cb */
10771 (png_uint_32) (mng_info->page.x + ping_width));
10772 PNGLong(chunk+23,(png_uint_32) (mng_info->page.y)); /* top cb */
10774 (png_uint_32) (mng_info->page.y + ping_height));
10775 (void) WriteBlob(image,31,chunk);
10776 (void) WriteBlobMSBULong(image,crc32(0,chunk,31));
10777 mng_info->old_framing_mode=4;
10778 mng_info->framing_mode=1;
10782 mng_info->framing_mode=3;
10784 if (mng_info->write_mng && !mng_info->need_fram &&
10785 ((int) image->dispose == 3))
10786 png_error(ping, "Cannot convert GIF with disposal method 3 to MNG-LC");
10789 Free PNG resources.
10792 png_destroy_write_struct(&ping,&ping_info);
10794 ping_pixels=(unsigned char *) RelinquishMagickMemory(ping_pixels);
10796 if (ping_have_blob != MagickFalse)
10797 (void) CloseBlob(image);
10799 image_info=DestroyImageInfo(image_info);
10800 image=DestroyImage(image);
10802 /* Store bit depth actually written */
10803 s[0]=(char) ping_bit_depth;
10806 (void) SetImageProperty(IMimage,"png:bit-depth-written",s,exception);
10808 if (logging != MagickFalse)
10809 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10810 " exit WriteOnePNGImage()");
10812 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
10813 UnlockSemaphoreInfo(ping_semaphore);
10816 /* } for navigation to beginning of SETJMP-protected block. Revert to
10817 * Throwing an Exception when an error occurs.
10820 return(MagickTrue);
10821 /* End write one PNG image */
10826 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10830 % W r i t e P N G I m a g e %
10834 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10836 % WritePNGImage() writes a Portable Network Graphics (PNG) or
10837 % Multiple-image Network Graphics (MNG) image file.
10839 % MNG support written by Glenn Randers-Pehrson, glennrp@image...
10841 % The format of the WritePNGImage method is:
10843 % MagickBooleanType WritePNGImage(const ImageInfo *image_info,
10844 % Image *image,ExceptionInfo *exception)
10846 % A description of each parameter follows:
10848 % o image_info: the image info.
10850 % o image: The image.
10852 % o exception: return any errors or warnings in this structure.
10854 % Returns MagickTrue on success, MagickFalse on failure.
10856 % Communicating with the PNG encoder:
10858 % While the datastream written is always in PNG format and normally would
10859 % be given the "png" file extension, this method also writes the following
10860 % pseudo-formats which are subsets of png:
10862 % o PNG8: An 8-bit indexed PNG datastream is written. If the image has
10863 % a depth greater than 8, the depth is reduced. If transparency
10864 % is present, the tRNS chunk must only have values 0 and 255
10865 % (i.e., transparency is binary: fully opaque or fully
10866 % transparent). If other values are present they will be
10867 % 50%-thresholded to binary transparency. If more than 256
10868 % colors are present, they will be quantized to the 4-4-4-1,
10869 % 3-3-3-1, or 3-3-2-1 palette. The underlying RGB color
10870 % of any resulting fully-transparent pixels is changed to
10871 % the image's background color.
10873 % If you want better quantization or dithering of the colors
10874 % or alpha than that, you need to do it before calling the
10875 % PNG encoder. The pixels contain 8-bit indices even if
10876 % they could be represented with 1, 2, or 4 bits. Grayscale
10877 % images will be written as indexed PNG files even though the
10878 % PNG grayscale type might be slightly more efficient. Please
10879 % note that writing to the PNG8 format may result in loss
10880 % of color and alpha data.
10882 % o PNG24: An 8-bit per sample RGB PNG datastream is written. The tRNS
10883 % chunk can be present to convey binary transparency by naming
10884 % one of the colors as transparent. The only loss incurred
10885 % is reduction of sample depth to 8. If the image has more
10886 % than one transparent color, has semitransparent pixels, or
10887 % has an opaque pixel with the same RGB components as the
10888 % transparent color, an image is not written.
10890 % o PNG32: An 8-bit per sample RGBA PNG is written. Partial
10891 % transparency is permitted, i.e., the alpha sample for
10892 % each pixel can have any value from 0 to 255. The alpha
10893 % channel is present even if the image is fully opaque.
10894 % The only loss in data is the reduction of the sample depth
10897 % o -define: For more precise control of the PNG output, you can use the
10898 % Image options "png:bit-depth" and "png:color-type". These
10899 % can be set from the commandline with "-define" and also
10900 % from the application programming interfaces. The options
10901 % are case-independent and are converted to lowercase before
10902 % being passed to this encoder.
10904 % png:color-type can be 0, 2, 3, 4, or 6.
10906 % When png:color-type is 0 (Grayscale), png:bit-depth can
10907 % be 1, 2, 4, 8, or 16.
10909 % When png:color-type is 2 (RGB), png:bit-depth can
10912 % When png:color-type is 3 (Indexed), png:bit-depth can
10913 % be 1, 2, 4, or 8. This refers to the number of bits
10914 % used to store the index. The color samples always have
10915 % bit-depth 8 in indexed PNG files.
10917 % When png:color-type is 4 (Gray-Matte) or 6 (RGB-Matte),
10918 % png:bit-depth can be 8 or 16.
10920 % If the image cannot be written without loss with the requested bit-depth
10921 % and color-type, a PNG file will not be written, and the encoder will
10922 % return MagickFalse.
10924 % Since image encoders should not be responsible for the "heavy lifting",
10925 % the user should make sure that ImageMagick has already reduced the
10926 % image depth and number of colors and limit transparency to binary
10927 % transparency prior to attempting to write the image with depth, color,
10928 % or transparency limitations.
10930 % Note that another definition, "png:bit-depth-written" exists, but it
10931 % is not intended for external use. It is only used internally by the
10932 % PNG encoder to inform the JNG encoder of the depth of the alpha channel.
10934 % It is possible to request that the PNG encoder write previously-formatted
10935 % ancillary chunks in the output PNG file, using the "-profile" commandline
10936 % option as shown below or by setting the profile via a programming
10939 % -profile PNG-chunk-x:<file>
10941 % where x is a location flag and <file> is a file containing the chunk
10942 % name in the first 4 bytes, then a colon (":"), followed by the chunk data.
10943 % This encoder will compute the chunk length and CRC, so those must not
10944 % be included in the file.
10946 % "x" can be "b" (before PLTE), "m" (middle, i.e., between PLTE and IDAT),
10947 % or "e" (end, i.e., after IDAT). If you want to write multiple chunks
10948 % of the same type, then add a short unique string after the "x" to prevent
10949 % subsequent profiles from overwriting the preceding ones, e.g.,
10951 % -profile PNG-chunk-b01:file01 -profile PNG-chunk-b02:file02
10953 % As of version 6.6.6 the following optimizations are always done:
10955 % o 32-bit depth is reduced to 16.
10956 % o 16-bit depth is reduced to 8 if all pixels contain samples whose
10957 % high byte and low byte are identical.
10958 % o Palette is sorted to remove unused entries and to put a
10959 % transparent color first, if BUILD_PNG_PALETTE is defined.
10960 % o Opaque matte channel is removed when writing an indexed PNG.
10961 % o Grayscale images are reduced to 1, 2, or 4 bit depth if
10962 % this can be done without loss and a larger bit depth N was not
10963 % requested via the "-define png:bit-depth=N" option.
10964 % o If matte channel is present but only one transparent color is
10965 % present, RGB+tRNS is written instead of RGBA
10966 % o Opaque matte channel is removed (or added, if color-type 4 or 6
10967 % was requested when converting an opaque image).
10969 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10971 static MagickBooleanType WritePNGImage(const ImageInfo *image_info,
10972 Image *image,ExceptionInfo *exception)
10977 have_mng_structure,
10993 assert(image_info != (const ImageInfo *) NULL);
10994 assert(image_info->signature == MagickSignature);
10995 assert(image != (Image *) NULL);
10996 assert(image->signature == MagickSignature);
10997 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
10998 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter WritePNGImage()");
11000 Allocate a MngInfo structure.
11002 have_mng_structure=MagickFalse;
11003 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
11005 if (mng_info == (MngInfo *) NULL)
11006 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
11009 Initialize members of the MngInfo structure.
11011 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
11012 mng_info->image=image;
11013 mng_info->equal_backgrounds=MagickTrue;
11014 have_mng_structure=MagickTrue;
11016 /* See if user has requested a specific PNG subformat */
11018 mng_info->write_png8=LocaleCompare(image_info->magick,"PNG8") == 0;
11019 mng_info->write_png24=LocaleCompare(image_info->magick,"PNG24") == 0;
11020 mng_info->write_png32=LocaleCompare(image_info->magick,"PNG32") == 0;
11022 value=GetImageOption(image_info,"png:format");
11024 if (value != (char *) NULL)
11026 if (LocaleCompare(value,"png8") == 0)
11028 mng_info->write_png8 = MagickTrue;
11029 mng_info->write_png24 = MagickFalse;
11030 mng_info->write_png32 = MagickFalse;
11033 else if (LocaleCompare(value,"png24") == 0)
11035 mng_info->write_png8 = MagickFalse;
11036 mng_info->write_png24 = MagickTrue;
11037 mng_info->write_png32 = MagickFalse;
11040 else if (LocaleCompare(value,"png32") == 0)
11042 mng_info->write_png8 = MagickFalse;
11043 mng_info->write_png24 = MagickFalse;
11044 mng_info->write_png32 = MagickTrue;
11047 if (mng_info->write_png8)
11049 mng_info->write_png_colortype = /* 3 */ 4;
11050 mng_info->write_png_depth = 8;
11054 if (mng_info->write_png24)
11056 mng_info->write_png_colortype = /* 2 */ 3;
11057 mng_info->write_png_depth = 8;
11060 if (image->matte == MagickTrue)
11061 (void) SetImageType(image,TrueColorMatteType,exception);
11064 (void) SetImageType(image,TrueColorType,exception);
11066 (void) SyncImage(image,exception);
11069 if (mng_info->write_png32)
11071 mng_info->write_png_colortype = /* 6 */ 7;
11072 mng_info->write_png_depth = 8;
11075 if (image->matte == MagickTrue)
11076 (void) SetImageType(image,TrueColorMatteType,exception);
11079 (void) SetImageType(image,TrueColorType,exception);
11081 (void) SyncImage(image,exception);
11084 value=GetImageOption(image_info,"png:bit-depth");
11086 if (value != (char *) NULL)
11088 if (LocaleCompare(value,"1") == 0)
11089 mng_info->write_png_depth = 1;
11091 else if (LocaleCompare(value,"2") == 0)
11092 mng_info->write_png_depth = 2;
11094 else if (LocaleCompare(value,"4") == 0)
11095 mng_info->write_png_depth = 4;
11097 else if (LocaleCompare(value,"8") == 0)
11098 mng_info->write_png_depth = 8;
11100 else if (LocaleCompare(value,"16") == 0)
11101 mng_info->write_png_depth = 16;
11104 (void) ThrowMagickException(exception,
11105 GetMagickModule(),CoderWarning,
11106 "ignoring invalid defined png:bit-depth",
11109 if (logging != MagickFalse)
11110 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11111 " png:bit-depth=%d was defined.\n",mng_info->write_png_depth);
11114 value=GetImageOption(image_info,"png:color-type");
11116 if (value != (char *) NULL)
11118 /* We must store colortype+1 because 0 is a valid colortype */
11119 if (LocaleCompare(value,"0") == 0)
11120 mng_info->write_png_colortype = 1;
11122 else if (LocaleCompare(value,"1") == 0)
11123 mng_info->write_png_colortype = 2;
11125 else if (LocaleCompare(value,"2") == 0)
11126 mng_info->write_png_colortype = 3;
11128 else if (LocaleCompare(value,"3") == 0)
11129 mng_info->write_png_colortype = 4;
11131 else if (LocaleCompare(value,"4") == 0)
11132 mng_info->write_png_colortype = 5;
11134 else if (LocaleCompare(value,"6") == 0)
11135 mng_info->write_png_colortype = 7;
11138 (void) ThrowMagickException(exception,
11139 GetMagickModule(),CoderWarning,
11140 "ignoring invalid defined png:color-type",
11143 if (logging != MagickFalse)
11144 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11145 " png:color-type=%d was defined.\n",mng_info->write_png_colortype-1);
11148 /* Check for chunks to be excluded:
11150 * The default is to not exclude any known chunks except for any
11151 * listed in the "unused_chunks" array, above.
11153 * Chunks can be listed for exclusion via a "png:exclude-chunk"
11154 * define (in the image properties or in the image artifacts)
11155 * or via a mng_info member. For convenience, in addition
11156 * to or instead of a comma-separated list of chunks, the
11157 * "exclude-chunk" string can be simply "all" or "none".
11159 * The exclude-chunk define takes priority over the mng_info.
11161 * A "png:include-chunk" define takes priority over both the
11162 * mng_info and the "png:exclude-chunk" define. Like the
11163 * "exclude-chunk" string, it can define "all" or "none" as
11164 * well as a comma-separated list. Chunks that are unknown to
11165 * ImageMagick are always excluded, regardless of their "copy-safe"
11166 * status according to the PNG specification, and even if they
11167 * appear in the "include-chunk" list. Such defines appearing among
11168 * the image options take priority over those found among the image
11171 * Finally, all chunks listed in the "unused_chunks" array are
11172 * automatically excluded, regardless of the other instructions
11175 * if you exclude sRGB but not gAMA (recommended), then sRGB chunk
11176 * will not be written and the gAMA chunk will only be written if it
11177 * is not between .45 and .46, or approximately (1.0/2.2).
11179 * If you exclude tRNS and the image has transparency, the colortype
11180 * is forced to be 4 or 6 (GRAY_ALPHA or RGB_ALPHA).
11182 * The -strip option causes StripImage() to set the png:include-chunk
11183 * artifact to "none,trns,gama".
11186 mng_info->ping_exclude_bKGD=MagickFalse;
11187 mng_info->ping_exclude_cHRM=MagickFalse;
11188 mng_info->ping_exclude_date=MagickFalse;
11189 mng_info->ping_exclude_EXIF=MagickFalse; /* hex-encoded EXIF in zTXt */
11190 mng_info->ping_exclude_gAMA=MagickFalse;
11191 mng_info->ping_exclude_iCCP=MagickFalse;
11192 /* mng_info->ping_exclude_iTXt=MagickFalse; */
11193 mng_info->ping_exclude_oFFs=MagickFalse;
11194 mng_info->ping_exclude_pHYs=MagickFalse;
11195 mng_info->ping_exclude_sRGB=MagickFalse;
11196 mng_info->ping_exclude_tEXt=MagickFalse;
11197 mng_info->ping_exclude_tRNS=MagickFalse;
11198 mng_info->ping_exclude_vpAg=MagickFalse;
11199 mng_info->ping_exclude_zCCP=MagickFalse; /* hex-encoded iCCP in zTXt */
11200 mng_info->ping_exclude_zTXt=MagickFalse;
11202 mng_info->ping_preserve_colormap=MagickFalse;
11204 value=GetImageArtifact(image,"png:preserve-colormap");
11206 value=GetImageOption(image_info,"png:preserve-colormap");
11208 mng_info->ping_preserve_colormap=MagickTrue;
11210 /* Thes compression-level, compression-strategy, and compression-filter
11211 * defines take precedence over values from the -quality option.
11213 value=GetImageArtifact(image,"png:compression-level");
11215 value=GetImageOption(image_info,"png:compression-level");
11218 /* We have to add 1 to everything because 0 is a valid input,
11219 * and we want to use 0 (the default) to mean undefined.
11221 if (LocaleCompare(value,"0") == 0)
11222 mng_info->write_png_compression_level = 1;
11224 else if (LocaleCompare(value,"1") == 0)
11225 mng_info->write_png_compression_level = 2;
11227 else if (LocaleCompare(value,"2") == 0)
11228 mng_info->write_png_compression_level = 3;
11230 else if (LocaleCompare(value,"3") == 0)
11231 mng_info->write_png_compression_level = 4;
11233 else if (LocaleCompare(value,"4") == 0)
11234 mng_info->write_png_compression_level = 5;
11236 else if (LocaleCompare(value,"5") == 0)
11237 mng_info->write_png_compression_level = 6;
11239 else if (LocaleCompare(value,"6") == 0)
11240 mng_info->write_png_compression_level = 7;
11242 else if (LocaleCompare(value,"7") == 0)
11243 mng_info->write_png_compression_level = 8;
11245 else if (LocaleCompare(value,"8") == 0)
11246 mng_info->write_png_compression_level = 9;
11248 else if (LocaleCompare(value,"9") == 0)
11249 mng_info->write_png_compression_level = 10;
11252 (void) ThrowMagickException(exception,
11253 GetMagickModule(),CoderWarning,
11254 "ignoring invalid defined png:compression-level",
11258 value=GetImageArtifact(image,"png:compression-strategy");
11260 value=GetImageOption(image_info,"png:compression-strategy");
11264 if (LocaleCompare(value,"0") == 0)
11265 mng_info->write_png_compression_strategy = Z_DEFAULT_STRATEGY+1;
11267 else if (LocaleCompare(value,"1") == 0)
11268 mng_info->write_png_compression_strategy = Z_FILTERED+1;
11270 else if (LocaleCompare(value,"2") == 0)
11271 mng_info->write_png_compression_strategy = Z_HUFFMAN_ONLY+1;
11273 else if (LocaleCompare(value,"3") == 0)
11274 #ifdef Z_RLE /* Z_RLE was added to zlib-1.2.0 */
11275 mng_info->write_png_compression_strategy = Z_RLE+1;
11277 mng_info->write_png_compression_strategy = Z_DEFAULT_STRATEGY+1;
11280 else if (LocaleCompare(value,"4") == 0)
11281 #ifdef Z_FIXED /* Z_FIXED was added to zlib-1.2.2.2 */
11282 mng_info->write_png_compression_strategy = Z_FIXED+1;
11284 mng_info->write_png_compression_strategy = Z_DEFAULT_STRATEGY+1;
11288 (void) ThrowMagickException(exception,
11289 GetMagickModule(),CoderWarning,
11290 "ignoring invalid defined png:compression-strategy",
11294 value=GetImageArtifact(image,"png:compression-filter");
11296 value=GetImageOption(image_info,"png:compression-filter");
11300 /* To do: combinations of filters allowed by libpng
11301 * masks 0x08 through 0xf8
11303 * Implement this as a comma-separated list of 0,1,2,3,4,5
11304 * where 5 is a special case meaning PNG_ALL_FILTERS.
11307 if (LocaleCompare(value,"0") == 0)
11308 mng_info->write_png_compression_filter = 1;
11310 if (LocaleCompare(value,"1") == 0)
11311 mng_info->write_png_compression_filter = 2;
11313 else if (LocaleCompare(value,"2") == 0)
11314 mng_info->write_png_compression_filter = 3;
11316 else if (LocaleCompare(value,"3") == 0)
11317 mng_info->write_png_compression_filter = 4;
11319 else if (LocaleCompare(value,"4") == 0)
11320 mng_info->write_png_compression_filter = 5;
11322 else if (LocaleCompare(value,"5") == 0)
11323 mng_info->write_png_compression_filter = 6;
11326 (void) ThrowMagickException(exception,
11327 GetMagickModule(),CoderWarning,
11328 "ignoring invalid defined png:compression-filter",
11332 excluding=MagickFalse;
11334 for (source=0; source<1; source++)
11338 value=GetImageArtifact(image,"png:exclude-chunk");
11341 value=GetImageArtifact(image,"png:exclude-chunks");
11345 value=GetImageOption(image_info,"png:exclude-chunk");
11348 value=GetImageOption(image_info,"png:exclude-chunks");
11357 excluding=MagickTrue;
11359 if (logging != MagickFalse)
11362 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11363 " png:exclude-chunk=%s found in image artifacts.\n", value);
11365 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11366 " png:exclude-chunk=%s found in image properties.\n", value);
11369 last=strlen(value);
11371 for (i=0; i<(int) last; i+=5)
11374 if (LocaleNCompare(value+i,"all",3) == 0)
11376 mng_info->ping_exclude_bKGD=MagickTrue;
11377 mng_info->ping_exclude_cHRM=MagickTrue;
11378 mng_info->ping_exclude_date=MagickTrue;
11379 mng_info->ping_exclude_EXIF=MagickTrue;
11380 mng_info->ping_exclude_gAMA=MagickTrue;
11381 mng_info->ping_exclude_iCCP=MagickTrue;
11382 /* mng_info->ping_exclude_iTXt=MagickTrue; */
11383 mng_info->ping_exclude_oFFs=MagickTrue;
11384 mng_info->ping_exclude_pHYs=MagickTrue;
11385 mng_info->ping_exclude_sRGB=MagickTrue;
11386 mng_info->ping_exclude_tEXt=MagickTrue;
11387 mng_info->ping_exclude_tRNS=MagickTrue;
11388 mng_info->ping_exclude_vpAg=MagickTrue;
11389 mng_info->ping_exclude_zCCP=MagickTrue;
11390 mng_info->ping_exclude_zTXt=MagickTrue;
11394 if (LocaleNCompare(value+i,"none",4) == 0)
11396 mng_info->ping_exclude_bKGD=MagickFalse;
11397 mng_info->ping_exclude_cHRM=MagickFalse;
11398 mng_info->ping_exclude_date=MagickFalse;
11399 mng_info->ping_exclude_EXIF=MagickFalse;
11400 mng_info->ping_exclude_gAMA=MagickFalse;
11401 mng_info->ping_exclude_iCCP=MagickFalse;
11402 /* mng_info->ping_exclude_iTXt=MagickFalse; */
11403 mng_info->ping_exclude_oFFs=MagickFalse;
11404 mng_info->ping_exclude_pHYs=MagickFalse;
11405 mng_info->ping_exclude_sRGB=MagickFalse;
11406 mng_info->ping_exclude_tEXt=MagickFalse;
11407 mng_info->ping_exclude_tRNS=MagickFalse;
11408 mng_info->ping_exclude_vpAg=MagickFalse;
11409 mng_info->ping_exclude_zCCP=MagickFalse;
11410 mng_info->ping_exclude_zTXt=MagickFalse;
11413 if (LocaleNCompare(value+i,"bkgd",4) == 0)
11414 mng_info->ping_exclude_bKGD=MagickTrue;
11416 if (LocaleNCompare(value+i,"chrm",4) == 0)
11417 mng_info->ping_exclude_cHRM=MagickTrue;
11419 if (LocaleNCompare(value+i,"date",4) == 0)
11420 mng_info->ping_exclude_date=MagickTrue;
11422 if (LocaleNCompare(value+i,"exif",4) == 0)
11423 mng_info->ping_exclude_EXIF=MagickTrue;
11425 if (LocaleNCompare(value+i,"gama",4) == 0)
11426 mng_info->ping_exclude_gAMA=MagickTrue;
11428 if (LocaleNCompare(value+i,"iccp",4) == 0)
11429 mng_info->ping_exclude_iCCP=MagickTrue;
11432 if (LocaleNCompare(value+i,"itxt",4) == 0)
11433 mng_info->ping_exclude_iTXt=MagickTrue;
11436 if (LocaleNCompare(value+i,"gama",4) == 0)
11437 mng_info->ping_exclude_gAMA=MagickTrue;
11439 if (LocaleNCompare(value+i,"offs",4) == 0)
11440 mng_info->ping_exclude_oFFs=MagickTrue;
11442 if (LocaleNCompare(value+i,"phys",4) == 0)
11443 mng_info->ping_exclude_pHYs=MagickTrue;
11445 if (LocaleNCompare(value+i,"srgb",4) == 0)
11446 mng_info->ping_exclude_sRGB=MagickTrue;
11448 if (LocaleNCompare(value+i,"text",4) == 0)
11449 mng_info->ping_exclude_tEXt=MagickTrue;
11451 if (LocaleNCompare(value+i,"trns",4) == 0)
11452 mng_info->ping_exclude_tRNS=MagickTrue;
11454 if (LocaleNCompare(value+i,"vpag",4) == 0)
11455 mng_info->ping_exclude_vpAg=MagickTrue;
11457 if (LocaleNCompare(value+i,"zccp",4) == 0)
11458 mng_info->ping_exclude_zCCP=MagickTrue;
11460 if (LocaleNCompare(value+i,"ztxt",4) == 0)
11461 mng_info->ping_exclude_zTXt=MagickTrue;
11467 for (source=0; source<1; source++)
11471 value=GetImageArtifact(image,"png:include-chunk");
11474 value=GetImageArtifact(image,"png:include-chunks");
11478 value=GetImageOption(image_info,"png:include-chunk");
11481 value=GetImageOption(image_info,"png:include-chunks");
11489 excluding=MagickTrue;
11491 if (logging != MagickFalse)
11494 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11495 " png:include-chunk=%s found in image artifacts.\n", value);
11497 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11498 " png:include-chunk=%s found in image properties.\n", value);
11501 last=strlen(value);
11503 for (i=0; i<(int) last; i+=5)
11505 if (LocaleNCompare(value+i,"all",3) == 0)
11507 mng_info->ping_exclude_bKGD=MagickFalse;
11508 mng_info->ping_exclude_cHRM=MagickFalse;
11509 mng_info->ping_exclude_date=MagickFalse;
11510 mng_info->ping_exclude_EXIF=MagickFalse;
11511 mng_info->ping_exclude_gAMA=MagickFalse;
11512 mng_info->ping_exclude_iCCP=MagickFalse;
11513 /* mng_info->ping_exclude_iTXt=MagickFalse; */
11514 mng_info->ping_exclude_oFFs=MagickFalse;
11515 mng_info->ping_exclude_pHYs=MagickFalse;
11516 mng_info->ping_exclude_sRGB=MagickFalse;
11517 mng_info->ping_exclude_tEXt=MagickFalse;
11518 mng_info->ping_exclude_tRNS=MagickFalse;
11519 mng_info->ping_exclude_vpAg=MagickFalse;
11520 mng_info->ping_exclude_zCCP=MagickFalse;
11521 mng_info->ping_exclude_zTXt=MagickFalse;
11525 if (LocaleNCompare(value+i,"none",4) == 0)
11527 mng_info->ping_exclude_bKGD=MagickTrue;
11528 mng_info->ping_exclude_cHRM=MagickTrue;
11529 mng_info->ping_exclude_date=MagickTrue;
11530 mng_info->ping_exclude_EXIF=MagickTrue;
11531 mng_info->ping_exclude_gAMA=MagickTrue;
11532 mng_info->ping_exclude_iCCP=MagickTrue;
11533 /* mng_info->ping_exclude_iTXt=MagickTrue; */
11534 mng_info->ping_exclude_oFFs=MagickTrue;
11535 mng_info->ping_exclude_pHYs=MagickTrue;
11536 mng_info->ping_exclude_sRGB=MagickTrue;
11537 mng_info->ping_exclude_tEXt=MagickTrue;
11538 mng_info->ping_exclude_tRNS=MagickTrue;
11539 mng_info->ping_exclude_vpAg=MagickTrue;
11540 mng_info->ping_exclude_zCCP=MagickTrue;
11541 mng_info->ping_exclude_zTXt=MagickTrue;
11544 if (LocaleNCompare(value+i,"bkgd",4) == 0)
11545 mng_info->ping_exclude_bKGD=MagickFalse;
11547 if (LocaleNCompare(value+i,"chrm",4) == 0)
11548 mng_info->ping_exclude_cHRM=MagickFalse;
11550 if (LocaleNCompare(value+i,"date",4) == 0)
11551 mng_info->ping_exclude_date=MagickFalse;
11553 if (LocaleNCompare(value+i,"exif",4) == 0)
11554 mng_info->ping_exclude_EXIF=MagickFalse;
11556 if (LocaleNCompare(value+i,"gama",4) == 0)
11557 mng_info->ping_exclude_gAMA=MagickFalse;
11559 if (LocaleNCompare(value+i,"iccp",4) == 0)
11560 mng_info->ping_exclude_iCCP=MagickFalse;
11563 if (LocaleNCompare(value+i,"itxt",4) == 0)
11564 mng_info->ping_exclude_iTXt=MagickFalse;
11567 if (LocaleNCompare(value+i,"gama",4) == 0)
11568 mng_info->ping_exclude_gAMA=MagickFalse;
11570 if (LocaleNCompare(value+i,"offs",4) == 0)
11571 mng_info->ping_exclude_oFFs=MagickFalse;
11573 if (LocaleNCompare(value+i,"phys",4) == 0)
11574 mng_info->ping_exclude_pHYs=MagickFalse;
11576 if (LocaleNCompare(value+i,"srgb",4) == 0)
11577 mng_info->ping_exclude_sRGB=MagickFalse;
11579 if (LocaleNCompare(value+i,"text",4) == 0)
11580 mng_info->ping_exclude_tEXt=MagickFalse;
11582 if (LocaleNCompare(value+i,"trns",4) == 0)
11583 mng_info->ping_exclude_tRNS=MagickFalse;
11585 if (LocaleNCompare(value+i,"vpag",4) == 0)
11586 mng_info->ping_exclude_vpAg=MagickFalse;
11588 if (LocaleNCompare(value+i,"zccp",4) == 0)
11589 mng_info->ping_exclude_zCCP=MagickFalse;
11591 if (LocaleNCompare(value+i,"ztxt",4) == 0)
11592 mng_info->ping_exclude_zTXt=MagickFalse;
11598 if (excluding != MagickFalse && logging != MagickFalse)
11600 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11601 " Chunks to be excluded from the output png:");
11602 if (mng_info->ping_exclude_bKGD != MagickFalse)
11603 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11605 if (mng_info->ping_exclude_cHRM != MagickFalse)
11606 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11608 if (mng_info->ping_exclude_date != MagickFalse)
11609 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11611 if (mng_info->ping_exclude_EXIF != MagickFalse)
11612 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11614 if (mng_info->ping_exclude_gAMA != MagickFalse)
11615 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11617 if (mng_info->ping_exclude_iCCP != MagickFalse)
11618 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11621 if (mng_info->ping_exclude_iTXt != MagickFalse)
11622 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11625 if (mng_info->ping_exclude_oFFs != MagickFalse)
11626 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11628 if (mng_info->ping_exclude_pHYs != MagickFalse)
11629 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11631 if (mng_info->ping_exclude_sRGB != MagickFalse)
11632 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11634 if (mng_info->ping_exclude_tEXt != MagickFalse)
11635 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11637 if (mng_info->ping_exclude_tRNS != MagickFalse)
11638 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11640 if (mng_info->ping_exclude_vpAg != MagickFalse)
11641 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11643 if (mng_info->ping_exclude_zCCP != MagickFalse)
11644 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11646 if (mng_info->ping_exclude_zTXt != MagickFalse)
11647 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11651 mng_info->need_blob = MagickTrue;
11653 status=WriteOnePNGImage(mng_info,image_info,image,exception);
11655 MngInfoFreeStruct(mng_info,&have_mng_structure);
11657 if (logging != MagickFalse)
11658 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit WritePNGImage()");
11663 #if defined(JNG_SUPPORTED)
11665 /* Write one JNG image */
11666 static MagickBooleanType WriteOneJNGImage(MngInfo *mng_info,
11667 const ImageInfo *image_info,Image *image,ExceptionInfo *exception)
11688 jng_alpha_compression_method,
11689 jng_alpha_sample_depth,
11697 logging=LogMagickEvent(CoderEvent,GetMagickModule(),
11698 " Enter WriteOneJNGImage()");
11700 blob=(unsigned char *) NULL;
11701 jpeg_image=(Image *) NULL;
11702 jpeg_image_info=(ImageInfo *) NULL;
11705 transparent=image_info->type==GrayscaleMatteType ||
11706 image_info->type==TrueColorMatteType || image->matte != MagickFalse;
11708 jng_quality=image_info->quality == 0UL ? 75UL : image_info->quality%1000;
11710 jng_alpha_compression_method=image->compression==JPEGCompression? 8 : 0;
11712 jng_alpha_quality=image_info->quality == 0UL ? 75UL :
11713 image_info->quality;
11715 if (jng_alpha_quality >= 1000)
11716 jng_alpha_quality /= 1000;
11722 /* Create JPEG blob, image, and image_info */
11723 if (logging != MagickFalse)
11724 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11725 " Creating jpeg_image_info for alpha.");
11727 jpeg_image_info=(ImageInfo *) CloneImageInfo(image_info);
11729 if (jpeg_image_info == (ImageInfo *) NULL)
11730 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
11732 if (logging != MagickFalse)
11733 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11734 " Creating jpeg_image.");
11736 jpeg_image=SeparateImage(image,AlphaChannel,exception);
11737 if (jpeg_image == (Image *) NULL)
11738 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
11739 (void) CopyMagickString(jpeg_image->magick,"JPEG",MaxTextExtent);
11740 jpeg_image->matte=MagickFalse;
11741 jpeg_image->quality=jng_alpha_quality;
11742 jpeg_image_info->type=GrayscaleType;
11743 (void) SetImageType(jpeg_image,GrayscaleType,exception);
11744 (void) AcquireUniqueFilename(jpeg_image->filename);
11745 (void) FormatLocaleString(jpeg_image_info->filename,MaxTextExtent,
11746 "%s",jpeg_image->filename);
11750 jng_alpha_compression_method=0;
11752 jng_alpha_sample_depth=0;
11755 /* To do: check bit depth of PNG alpha channel */
11757 /* Check if image is grayscale. */
11758 if (image_info->type != TrueColorMatteType && image_info->type !=
11759 TrueColorType && IsImageGray(image,exception))
11762 if (logging != MagickFalse)
11764 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11765 " JNG Quality = %d",(int) jng_quality);
11766 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11767 " JNG Color Type = %d",jng_color_type);
11770 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11771 " JNG Alpha Compression = %d",jng_alpha_compression_method);
11772 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11773 " JNG Alpha Depth = %d",jng_alpha_sample_depth);
11774 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11775 " JNG Alpha Quality = %d",(int) jng_alpha_quality);
11781 if (jng_alpha_compression_method==0)
11786 /* Encode alpha as a grayscale PNG blob */
11787 status=OpenBlob(jpeg_image_info,jpeg_image,WriteBinaryBlobMode,
11789 if (logging != MagickFalse)
11790 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11791 " Creating PNG blob.");
11794 (void) CopyMagickString(jpeg_image_info->magick,"PNG",MaxTextExtent);
11795 (void) CopyMagickString(jpeg_image->magick,"PNG",MaxTextExtent);
11796 jpeg_image_info->interlace=NoInterlace;
11798 /* Exclude all ancillary chunks */
11799 (void) SetImageArtifact(jpeg_image,"png:exclude-chunks","all");
11801 blob=ImageToBlob(jpeg_image_info,jpeg_image,&length,
11804 /* Retrieve sample depth used */
11805 value=GetImageProperty(jpeg_image,"png:bit-depth-written",exception);
11806 if (value != (char *) NULL)
11807 jng_alpha_sample_depth= (unsigned int) value[0];
11811 /* Encode alpha as a grayscale JPEG blob */
11813 status=OpenBlob(jpeg_image_info,jpeg_image,WriteBinaryBlobMode,
11816 (void) CopyMagickString(jpeg_image_info->magick,"JPEG",MaxTextExtent);
11817 (void) CopyMagickString(jpeg_image->magick,"JPEG",MaxTextExtent);
11818 jpeg_image_info->interlace=NoInterlace;
11819 if (logging != MagickFalse)
11820 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11821 " Creating blob.");
11822 blob=ImageToBlob(jpeg_image_info,jpeg_image,&length,
11824 jng_alpha_sample_depth=8;
11826 if (logging != MagickFalse)
11827 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11828 " Successfully read jpeg_image into a blob, length=%.20g.",
11832 /* Destroy JPEG image and image_info */
11833 jpeg_image=DestroyImage(jpeg_image);
11834 (void) RelinquishUniqueFileResource(jpeg_image_info->filename);
11835 jpeg_image_info=DestroyImageInfo(jpeg_image_info);
11838 /* Write JHDR chunk */
11839 (void) WriteBlobMSBULong(image,16L); /* chunk data length=16 */
11840 PNGType(chunk,mng_JHDR);
11841 LogPNGChunk(logging,mng_JHDR,16L);
11842 PNGLong(chunk+4,(png_uint_32) image->columns);
11843 PNGLong(chunk+8,(png_uint_32) image->rows);
11844 chunk[12]=jng_color_type;
11845 chunk[13]=8; /* sample depth */
11846 chunk[14]=8; /*jng_image_compression_method */
11847 chunk[15]=(unsigned char) (image_info->interlace == NoInterlace ? 0 : 8);
11848 chunk[16]=jng_alpha_sample_depth;
11849 chunk[17]=jng_alpha_compression_method;
11850 chunk[18]=0; /*jng_alpha_filter_method */
11851 chunk[19]=0; /*jng_alpha_interlace_method */
11852 (void) WriteBlob(image,20,chunk);
11853 (void) WriteBlobMSBULong(image,crc32(0,chunk,20));
11854 if (logging != MagickFalse)
11856 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11857 " JNG width:%15lu",(unsigned long) image->columns);
11859 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11860 " JNG height:%14lu",(unsigned long) image->rows);
11862 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11863 " JNG color type:%10d",jng_color_type);
11865 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11866 " JNG sample depth:%8d",8);
11868 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11869 " JNG compression:%9d",8);
11871 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11872 " JNG interlace:%11d",0);
11874 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11875 " JNG alpha depth:%9d",jng_alpha_sample_depth);
11877 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11878 " JNG alpha compression:%3d",jng_alpha_compression_method);
11880 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11881 " JNG alpha filter:%8d",0);
11883 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11884 " JNG alpha interlace:%5d",0);
11887 /* Write any JNG-chunk-b profiles */
11888 (void) Magick_png_write_chunk_from_profile(image,"JNG-chunk-b",logging);
11891 Write leading ancillary chunks
11897 Write JNG bKGD chunk
11908 if (jng_color_type == 8 || jng_color_type == 12)
11912 (void) WriteBlobMSBULong(image,(size_t) (num_bytes-4L));
11913 PNGType(chunk,mng_bKGD);
11914 LogPNGChunk(logging,mng_bKGD,(size_t) (num_bytes-4L));
11915 red=ScaleQuantumToChar(image->background_color.red);
11916 green=ScaleQuantumToChar(image->background_color.green);
11917 blue=ScaleQuantumToChar(image->background_color.blue);
11924 (void) WriteBlob(image,(size_t) num_bytes,chunk);
11925 (void) WriteBlobMSBULong(image,crc32(0,chunk,(uInt) num_bytes));
11928 if ((image->colorspace == sRGBColorspace || image->rendering_intent))
11931 Write JNG sRGB chunk
11933 (void) WriteBlobMSBULong(image,1L);
11934 PNGType(chunk,mng_sRGB);
11935 LogPNGChunk(logging,mng_sRGB,1L);
11937 if (image->rendering_intent != UndefinedIntent)
11938 chunk[4]=(unsigned char)
11939 Magick_RenderingIntent_to_PNG_RenderingIntent(
11940 (image->rendering_intent));
11943 chunk[4]=(unsigned char)
11944 Magick_RenderingIntent_to_PNG_RenderingIntent(
11945 (PerceptualIntent));
11947 (void) WriteBlob(image,5,chunk);
11948 (void) WriteBlobMSBULong(image,crc32(0,chunk,5));
11952 if (image->gamma != 0.0)
11955 Write JNG gAMA chunk
11957 (void) WriteBlobMSBULong(image,4L);
11958 PNGType(chunk,mng_gAMA);
11959 LogPNGChunk(logging,mng_gAMA,4L);
11960 PNGLong(chunk+4,(png_uint_32) (100000*image->gamma+0.5));
11961 (void) WriteBlob(image,8,chunk);
11962 (void) WriteBlobMSBULong(image,crc32(0,chunk,8));
11965 if ((mng_info->equal_chrms == MagickFalse) &&
11966 (image->chromaticity.red_primary.x != 0.0))
11972 Write JNG cHRM chunk
11974 (void) WriteBlobMSBULong(image,32L);
11975 PNGType(chunk,mng_cHRM);
11976 LogPNGChunk(logging,mng_cHRM,32L);
11977 primary=image->chromaticity.white_point;
11978 PNGLong(chunk+4,(png_uint_32) (100000*primary.x+0.5));
11979 PNGLong(chunk+8,(png_uint_32) (100000*primary.y+0.5));
11980 primary=image->chromaticity.red_primary;
11981 PNGLong(chunk+12,(png_uint_32) (100000*primary.x+0.5));
11982 PNGLong(chunk+16,(png_uint_32) (100000*primary.y+0.5));
11983 primary=image->chromaticity.green_primary;
11984 PNGLong(chunk+20,(png_uint_32) (100000*primary.x+0.5));
11985 PNGLong(chunk+24,(png_uint_32) (100000*primary.y+0.5));
11986 primary=image->chromaticity.blue_primary;
11987 PNGLong(chunk+28,(png_uint_32) (100000*primary.x+0.5));
11988 PNGLong(chunk+32,(png_uint_32) (100000*primary.y+0.5));
11989 (void) WriteBlob(image,36,chunk);
11990 (void) WriteBlobMSBULong(image,crc32(0,chunk,36));
11994 if (image->resolution.x && image->resolution.y && !mng_info->equal_physs)
11997 Write JNG pHYs chunk
11999 (void) WriteBlobMSBULong(image,9L);
12000 PNGType(chunk,mng_pHYs);
12001 LogPNGChunk(logging,mng_pHYs,9L);
12002 if (image->units == PixelsPerInchResolution)
12004 PNGLong(chunk+4,(png_uint_32)
12005 (image->resolution.x*100.0/2.54+0.5));
12007 PNGLong(chunk+8,(png_uint_32)
12008 (image->resolution.y*100.0/2.54+0.5));
12015 if (image->units == PixelsPerCentimeterResolution)
12017 PNGLong(chunk+4,(png_uint_32)
12018 (image->resolution.x*100.0+0.5));
12020 PNGLong(chunk+8,(png_uint_32)
12021 (image->resolution.y*100.0+0.5));
12028 PNGLong(chunk+4,(png_uint_32) (image->resolution.x+0.5));
12029 PNGLong(chunk+8,(png_uint_32) (image->resolution.y+0.5));
12033 (void) WriteBlob(image,13,chunk);
12034 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
12037 if (mng_info->write_mng == 0 && (image->page.x || image->page.y))
12040 Write JNG oFFs chunk
12042 (void) WriteBlobMSBULong(image,9L);
12043 PNGType(chunk,mng_oFFs);
12044 LogPNGChunk(logging,mng_oFFs,9L);
12045 PNGsLong(chunk+4,(ssize_t) (image->page.x));
12046 PNGsLong(chunk+8,(ssize_t) (image->page.y));
12048 (void) WriteBlob(image,13,chunk);
12049 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
12051 if (mng_info->write_mng == 0 && (image->page.width || image->page.height))
12053 (void) WriteBlobMSBULong(image,9L); /* data length=8 */
12054 PNGType(chunk,mng_vpAg);
12055 LogPNGChunk(logging,mng_vpAg,9L);
12056 PNGLong(chunk+4,(png_uint_32) image->page.width);
12057 PNGLong(chunk+8,(png_uint_32) image->page.height);
12058 chunk[12]=0; /* unit = pixels */
12059 (void) WriteBlob(image,13,chunk);
12060 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
12066 if (jng_alpha_compression_method==0)
12074 /* Write IDAT chunk header */
12075 if (logging != MagickFalse)
12076 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12077 " Write IDAT chunks from blob, length=%.20g.",(double)
12080 /* Copy IDAT chunks */
12083 for (i=8; i<(ssize_t) length; i+=len+12)
12085 len=(*p<<24)|((*(p+1))<<16)|((*(p+2))<<8)|(*(p+3));
12088 if (*(p)==73 && *(p+1)==68 && *(p+2)==65 && *(p+3)==84) /* IDAT */
12090 /* Found an IDAT chunk. */
12091 (void) WriteBlobMSBULong(image,(size_t) len);
12092 LogPNGChunk(logging,mng_IDAT,(size_t) len);
12093 (void) WriteBlob(image,(size_t) len+4,p);
12094 (void) WriteBlobMSBULong(image,
12095 crc32(0,p,(uInt) len+4));
12100 if (logging != MagickFalse)
12101 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12102 " Skipping %c%c%c%c chunk, length=%.20g.",
12103 *(p),*(p+1),*(p+2),*(p+3),(double) len);
12110 /* Write JDAA chunk header */
12111 if (logging != MagickFalse)
12112 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12113 " Write JDAA chunk, length=%.20g.",(double) length);
12114 (void) WriteBlobMSBULong(image,(size_t) length);
12115 PNGType(chunk,mng_JDAA);
12116 LogPNGChunk(logging,mng_JDAA,length);
12117 /* Write JDAT chunk(s) data */
12118 (void) WriteBlob(image,4,chunk);
12119 (void) WriteBlob(image,length,blob);
12120 (void) WriteBlobMSBULong(image,crc32(crc32(0,chunk,4),blob,
12123 blob=(unsigned char *) RelinquishMagickMemory(blob);
12126 /* Encode image as a JPEG blob */
12127 if (logging != MagickFalse)
12128 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12129 " Creating jpeg_image_info.");
12130 jpeg_image_info=(ImageInfo *) CloneImageInfo(image_info);
12131 if (jpeg_image_info == (ImageInfo *) NULL)
12132 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
12134 if (logging != MagickFalse)
12135 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12136 " Creating jpeg_image.");
12138 jpeg_image=CloneImage(image,0,0,MagickTrue,exception);
12139 if (jpeg_image == (Image *) NULL)
12140 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
12141 (void) CopyMagickString(jpeg_image->magick,"JPEG",MaxTextExtent);
12143 (void) AcquireUniqueFilename(jpeg_image->filename);
12144 (void) FormatLocaleString(jpeg_image_info->filename,MaxTextExtent,"%s",
12145 jpeg_image->filename);
12147 status=OpenBlob(jpeg_image_info,jpeg_image,WriteBinaryBlobMode,
12150 if (logging != MagickFalse)
12151 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12152 " Created jpeg_image, %.20g x %.20g.",(double) jpeg_image->columns,
12153 (double) jpeg_image->rows);
12155 if (jng_color_type == 8 || jng_color_type == 12)
12156 jpeg_image_info->type=GrayscaleType;
12158 jpeg_image_info->quality=jng_quality;
12159 jpeg_image->quality=jng_quality;
12160 (void) CopyMagickString(jpeg_image_info->magick,"JPEG",MaxTextExtent);
12161 (void) CopyMagickString(jpeg_image->magick,"JPEG",MaxTextExtent);
12163 if (logging != MagickFalse)
12164 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12165 " Creating blob.");
12167 blob=ImageToBlob(jpeg_image_info,jpeg_image,&length,exception);
12169 if (logging != MagickFalse)
12171 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12172 " Successfully read jpeg_image into a blob, length=%.20g.",
12175 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12176 " Write JDAT chunk, length=%.20g.",(double) length);
12179 /* Write JDAT chunk(s) */
12180 (void) WriteBlobMSBULong(image,(size_t) length);
12181 PNGType(chunk,mng_JDAT);
12182 LogPNGChunk(logging,mng_JDAT,length);
12183 (void) WriteBlob(image,4,chunk);
12184 (void) WriteBlob(image,length,blob);
12185 (void) WriteBlobMSBULong(image,crc32(crc32(0,chunk,4),blob,(uInt) length));
12187 jpeg_image=DestroyImage(jpeg_image);
12188 (void) RelinquishUniqueFileResource(jpeg_image_info->filename);
12189 jpeg_image_info=DestroyImageInfo(jpeg_image_info);
12190 blob=(unsigned char *) RelinquishMagickMemory(blob);
12192 /* Write any JNG-chunk-e profiles */
12193 (void) Magick_png_write_chunk_from_profile(image,"JNG-chunk-e",logging);
12195 /* Write IEND chunk */
12196 (void) WriteBlobMSBULong(image,0L);
12197 PNGType(chunk,mng_IEND);
12198 LogPNGChunk(logging,mng_IEND,0);
12199 (void) WriteBlob(image,4,chunk);
12200 (void) WriteBlobMSBULong(image,crc32(0,chunk,4));
12202 if (logging != MagickFalse)
12203 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12204 " exit WriteOneJNGImage()");
12211 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12215 % W r i t e J N G I m a g e %
12219 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12221 % WriteJNGImage() writes a JPEG Network Graphics (JNG) image file.
12223 % JNG support written by Glenn Randers-Pehrson, glennrp@image...
12225 % The format of the WriteJNGImage method is:
12227 % MagickBooleanType WriteJNGImage(const ImageInfo *image_info,
12228 % Image *image,ExceptionInfo *exception)
12230 % A description of each parameter follows:
12232 % o image_info: the image info.
12234 % o image: The image.
12236 % o exception: return any errors or warnings in this structure.
12238 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12240 static MagickBooleanType WriteJNGImage(const ImageInfo *image_info,Image *image,
12241 ExceptionInfo *exception)
12244 have_mng_structure,
12254 assert(image_info != (const ImageInfo *) NULL);
12255 assert(image_info->signature == MagickSignature);
12256 assert(image != (Image *) NULL);
12257 assert(image->signature == MagickSignature);
12258 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
12259 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter WriteJNGImage()");
12260 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
12261 if (status == MagickFalse)
12265 Allocate a MngInfo structure.
12267 have_mng_structure=MagickFalse;
12268 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
12269 if (mng_info == (MngInfo *) NULL)
12270 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
12272 Initialize members of the MngInfo structure.
12274 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
12275 mng_info->image=image;
12276 have_mng_structure=MagickTrue;
12278 (void) WriteBlob(image,8,(const unsigned char *) "\213JNG\r\n\032\n");
12280 status=WriteOneJNGImage(mng_info,image_info,image,exception);
12281 (void) CloseBlob(image);
12283 (void) CatchImageException(image);
12284 MngInfoFreeStruct(mng_info,&have_mng_structure);
12285 if (logging != MagickFalse)
12286 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit WriteJNGImage()");
12291 static MagickBooleanType WriteMNGImage(const ImageInfo *image_info,Image *image,
12292 ExceptionInfo *exception)
12301 have_mng_structure,
12304 volatile MagickBooleanType
12316 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
12317 defined(PNG_MNG_FEATURES_SUPPORTED)
12320 all_images_are_gray,
12330 volatile unsigned int
12341 #if (PNG_LIBPNG_VER < 10200)
12342 if (image_info->verbose)
12343 printf("Your PNG library (libpng-%s) is rather old.\n",
12344 PNG_LIBPNG_VER_STRING);
12350 assert(image_info != (const ImageInfo *) NULL);
12351 assert(image_info->signature == MagickSignature);
12352 assert(image != (Image *) NULL);
12353 assert(image->signature == MagickSignature);
12354 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
12355 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter WriteMNGImage()");
12356 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
12357 if (status == MagickFalse)
12361 Allocate a MngInfo structure.
12363 have_mng_structure=MagickFalse;
12364 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
12365 if (mng_info == (MngInfo *) NULL)
12366 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
12368 Initialize members of the MngInfo structure.
12370 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
12371 mng_info->image=image;
12372 have_mng_structure=MagickTrue;
12373 write_mng=LocaleCompare(image_info->magick,"MNG") == 0;
12376 * See if user has requested a specific PNG subformat to be used
12377 * for all of the PNGs in the MNG being written, e.g.,
12379 * convert *.png png8:animation.mng
12381 * To do: check -define png:bit_depth and png:color_type as well,
12382 * or perhaps use mng:bit_depth and mng:color_type instead for
12386 mng_info->write_png8=LocaleCompare(image_info->magick,"PNG8") == 0;
12387 mng_info->write_png24=LocaleCompare(image_info->magick,"PNG24") == 0;
12388 mng_info->write_png32=LocaleCompare(image_info->magick,"PNG32") == 0;
12390 write_jng=MagickFalse;
12391 if (image_info->compression == JPEGCompression)
12392 write_jng=MagickTrue;
12394 mng_info->adjoin=image_info->adjoin &&
12395 (GetNextImageInList(image) != (Image *) NULL) && write_mng;
12397 if (logging != MagickFalse)
12399 /* Log some info about the input */
12403 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12404 " Checking input image(s)");
12406 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12407 " Image_info depth: %.20g",(double) image_info->depth);
12409 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12410 " Type: %d",image_info->type);
12413 for (p=image; p != (Image *) NULL; p=GetNextImageInList(p))
12415 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12416 " Scene: %.20g",(double) scene++);
12418 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12419 " Image depth: %.20g",(double) p->depth);
12422 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12426 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12429 if (p->storage_class == PseudoClass)
12430 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12431 " Storage class: PseudoClass");
12434 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12435 " Storage class: DirectClass");
12438 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12439 " Number of colors: %.20g",(double) p->colors);
12442 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12443 " Number of colors: unspecified");
12445 if (mng_info->adjoin == MagickFalse)
12450 use_global_plte=MagickFalse;
12451 all_images_are_gray=MagickFalse;
12452 #ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
12453 need_local_plte=MagickTrue;
12455 need_defi=MagickFalse;
12456 need_matte=MagickFalse;
12457 mng_info->framing_mode=1;
12458 mng_info->old_framing_mode=1;
12461 if (image_info->page != (char *) NULL)
12464 Determine image bounding box.
12466 SetGeometry(image,&mng_info->page);
12467 (void) ParseMetaGeometry(image_info->page,&mng_info->page.x,
12468 &mng_info->page.y,&mng_info->page.width,&mng_info->page.height);
12480 mng_info->page=image->page;
12481 need_geom=MagickTrue;
12482 if (mng_info->page.width || mng_info->page.height)
12483 need_geom=MagickFalse;
12485 Check all the scenes.
12487 initial_delay=image->delay;
12488 need_iterations=MagickFalse;
12489 mng_info->equal_chrms=image->chromaticity.red_primary.x != 0.0;
12490 mng_info->equal_physs=MagickTrue,
12491 mng_info->equal_gammas=MagickTrue;
12492 mng_info->equal_srgbs=MagickTrue;
12493 mng_info->equal_backgrounds=MagickTrue;
12495 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
12496 defined(PNG_MNG_FEATURES_SUPPORTED)
12497 all_images_are_gray=MagickTrue;
12498 mng_info->equal_palettes=MagickFalse;
12499 need_local_plte=MagickFalse;
12501 for (next_image=image; next_image != (Image *) NULL; )
12505 if ((next_image->columns+next_image->page.x) > mng_info->page.width)
12506 mng_info->page.width=next_image->columns+next_image->page.x;
12508 if ((next_image->rows+next_image->page.y) > mng_info->page.height)
12509 mng_info->page.height=next_image->rows+next_image->page.y;
12512 if (next_image->page.x || next_image->page.y)
12513 need_defi=MagickTrue;
12515 if (next_image->matte)
12516 need_matte=MagickTrue;
12518 if ((int) next_image->dispose >= BackgroundDispose)
12519 if (next_image->matte || next_image->page.x || next_image->page.y ||
12520 ((next_image->columns < mng_info->page.width) &&
12521 (next_image->rows < mng_info->page.height)))
12522 mng_info->need_fram=MagickTrue;
12524 if (next_image->iterations)
12525 need_iterations=MagickTrue;
12527 final_delay=next_image->delay;
12529 if (final_delay != initial_delay || final_delay > 1UL*
12530 next_image->ticks_per_second)
12531 mng_info->need_fram=1;
12533 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
12534 defined(PNG_MNG_FEATURES_SUPPORTED)
12536 check for global palette possibility.
12538 if (image->matte != MagickFalse)
12539 need_local_plte=MagickTrue;
12541 if (need_local_plte == 0)
12543 if (IsImageGray(image,exception) == MagickFalse)
12544 all_images_are_gray=MagickFalse;
12545 mng_info->equal_palettes=PalettesAreEqual(image,next_image);
12546 if (use_global_plte == 0)
12547 use_global_plte=mng_info->equal_palettes;
12548 need_local_plte=!mng_info->equal_palettes;
12551 if (GetNextImageInList(next_image) != (Image *) NULL)
12553 if (next_image->background_color.red !=
12554 next_image->next->background_color.red ||
12555 next_image->background_color.green !=
12556 next_image->next->background_color.green ||
12557 next_image->background_color.blue !=
12558 next_image->next->background_color.blue)
12559 mng_info->equal_backgrounds=MagickFalse;
12561 if (next_image->gamma != next_image->next->gamma)
12562 mng_info->equal_gammas=MagickFalse;
12564 if (next_image->rendering_intent !=
12565 next_image->next->rendering_intent)
12566 mng_info->equal_srgbs=MagickFalse;
12568 if ((next_image->units != next_image->next->units) ||
12569 (next_image->resolution.x != next_image->next->resolution.x) ||
12570 (next_image->resolution.y != next_image->next->resolution.y))
12571 mng_info->equal_physs=MagickFalse;
12573 if (mng_info->equal_chrms)
12575 if (next_image->chromaticity.red_primary.x !=
12576 next_image->next->chromaticity.red_primary.x ||
12577 next_image->chromaticity.red_primary.y !=
12578 next_image->next->chromaticity.red_primary.y ||
12579 next_image->chromaticity.green_primary.x !=
12580 next_image->next->chromaticity.green_primary.x ||
12581 next_image->chromaticity.green_primary.y !=
12582 next_image->next->chromaticity.green_primary.y ||
12583 next_image->chromaticity.blue_primary.x !=
12584 next_image->next->chromaticity.blue_primary.x ||
12585 next_image->chromaticity.blue_primary.y !=
12586 next_image->next->chromaticity.blue_primary.y ||
12587 next_image->chromaticity.white_point.x !=
12588 next_image->next->chromaticity.white_point.x ||
12589 next_image->chromaticity.white_point.y !=
12590 next_image->next->chromaticity.white_point.y)
12591 mng_info->equal_chrms=MagickFalse;
12595 next_image=GetNextImageInList(next_image);
12597 if (image_count < 2)
12599 mng_info->equal_backgrounds=MagickFalse;
12600 mng_info->equal_chrms=MagickFalse;
12601 mng_info->equal_gammas=MagickFalse;
12602 mng_info->equal_srgbs=MagickFalse;
12603 mng_info->equal_physs=MagickFalse;
12604 use_global_plte=MagickFalse;
12605 #ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
12606 need_local_plte=MagickTrue;
12608 need_iterations=MagickFalse;
12611 if (mng_info->need_fram == MagickFalse)
12614 Only certain framing rates 100/n are exactly representable without
12615 the FRAM chunk but we'll allow some slop in VLC files
12617 if (final_delay == 0)
12619 if (need_iterations != MagickFalse)
12622 It's probably a GIF with loop; don't run it *too* fast.
12624 if (mng_info->adjoin)
12627 (void) ThrowMagickException(exception,GetMagickModule(),
12629 "input has zero delay between all frames; assuming",
12634 mng_info->ticks_per_second=0;
12636 if (final_delay != 0)
12637 mng_info->ticks_per_second=(png_uint_32)
12638 (image->ticks_per_second/final_delay);
12639 if (final_delay > 50)
12640 mng_info->ticks_per_second=2;
12642 if (final_delay > 75)
12643 mng_info->ticks_per_second=1;
12645 if (final_delay > 125)
12646 mng_info->need_fram=MagickTrue;
12648 if (need_defi && final_delay > 2 && (final_delay != 4) &&
12649 (final_delay != 5) && (final_delay != 10) && (final_delay != 20) &&
12650 (final_delay != 25) && (final_delay != 50) && (final_delay !=
12651 1UL*image->ticks_per_second))
12652 mng_info->need_fram=MagickTrue; /* make it exact; cannot be VLC */
12655 if (mng_info->need_fram != MagickFalse)
12656 mng_info->ticks_per_second=1UL*image->ticks_per_second;
12658 If pseudocolor, we should also check to see if all the
12659 palettes are identical and write a global PLTE if they are.
12663 Write the MNG version 1.0 signature and MHDR chunk.
12665 (void) WriteBlob(image,8,(const unsigned char *) "\212MNG\r\n\032\n");
12666 (void) WriteBlobMSBULong(image,28L); /* chunk data length=28 */
12667 PNGType(chunk,mng_MHDR);
12668 LogPNGChunk(logging,mng_MHDR,28L);
12669 PNGLong(chunk+4,(png_uint_32) mng_info->page.width);
12670 PNGLong(chunk+8,(png_uint_32) mng_info->page.height);
12671 PNGLong(chunk+12,mng_info->ticks_per_second);
12672 PNGLong(chunk+16,0L); /* layer count=unknown */
12673 PNGLong(chunk+20,0L); /* frame count=unknown */
12674 PNGLong(chunk+24,0L); /* play time=unknown */
12679 if (need_defi || mng_info->need_fram || use_global_plte)
12680 PNGLong(chunk+28,27L); /* simplicity=LC+JNG */
12683 PNGLong(chunk+28,25L); /* simplicity=VLC+JNG */
12688 if (need_defi || mng_info->need_fram || use_global_plte)
12689 PNGLong(chunk+28,19L); /* simplicity=LC+JNG, no transparency */
12692 PNGLong(chunk+28,17L); /* simplicity=VLC+JNG, no transparency */
12700 if (need_defi || mng_info->need_fram || use_global_plte)
12701 PNGLong(chunk+28,11L); /* simplicity=LC */
12704 PNGLong(chunk+28,9L); /* simplicity=VLC */
12709 if (need_defi || mng_info->need_fram || use_global_plte)
12710 PNGLong(chunk+28,3L); /* simplicity=LC, no transparency */
12713 PNGLong(chunk+28,1L); /* simplicity=VLC, no transparency */
12716 (void) WriteBlob(image,32,chunk);
12717 (void) WriteBlobMSBULong(image,crc32(0,chunk,32));
12718 option=GetImageOption(image_info,"mng:need-cacheoff");
12719 if (option != (const char *) NULL)
12725 Write "nEED CACHEOFF" to turn playback caching off for streaming MNG.
12727 PNGType(chunk,mng_nEED);
12728 length=CopyMagickString((char *) chunk+4,"CACHEOFF",20);
12729 (void) WriteBlobMSBULong(image,(size_t) length);
12730 LogPNGChunk(logging,mng_nEED,(size_t) length);
12732 (void) WriteBlob(image,length,chunk);
12733 (void) WriteBlobMSBULong(image,crc32(0,chunk,(uInt) length));
12735 if ((GetPreviousImageInList(image) == (Image *) NULL) &&
12736 (GetNextImageInList(image) != (Image *) NULL) &&
12737 (image->iterations != 1))
12740 Write MNG TERM chunk
12742 (void) WriteBlobMSBULong(image,10L); /* data length=10 */
12743 PNGType(chunk,mng_TERM);
12744 LogPNGChunk(logging,mng_TERM,10L);
12745 chunk[4]=3; /* repeat animation */
12746 chunk[5]=0; /* show last frame when done */
12747 PNGLong(chunk+6,(png_uint_32) (mng_info->ticks_per_second*
12748 final_delay/MagickMax(image->ticks_per_second,1)));
12750 if (image->iterations == 0)
12751 PNGLong(chunk+10,PNG_UINT_31_MAX);
12754 PNGLong(chunk+10,(png_uint_32) image->iterations);
12756 if (logging != MagickFalse)
12758 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12759 " TERM delay: %.20g",(double) (mng_info->ticks_per_second*
12760 final_delay/MagickMax(image->ticks_per_second,1)));
12762 if (image->iterations == 0)
12763 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12764 " TERM iterations: %.20g",(double) PNG_UINT_31_MAX);
12767 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12768 " Image iterations: %.20g",(double) image->iterations);
12770 (void) WriteBlob(image,14,chunk);
12771 (void) WriteBlobMSBULong(image,crc32(0,chunk,14));
12774 To do: check for cHRM+gAMA == sRGB, and write sRGB instead.
12776 if ((image->colorspace == sRGBColorspace || image->rendering_intent) &&
12777 mng_info->equal_srgbs)
12780 Write MNG sRGB chunk
12782 (void) WriteBlobMSBULong(image,1L);
12783 PNGType(chunk,mng_sRGB);
12784 LogPNGChunk(logging,mng_sRGB,1L);
12786 if (image->rendering_intent != UndefinedIntent)
12787 chunk[4]=(unsigned char)
12788 Magick_RenderingIntent_to_PNG_RenderingIntent(
12789 (image->rendering_intent));
12792 chunk[4]=(unsigned char)
12793 Magick_RenderingIntent_to_PNG_RenderingIntent(
12794 (PerceptualIntent));
12796 (void) WriteBlob(image,5,chunk);
12797 (void) WriteBlobMSBULong(image,crc32(0,chunk,5));
12798 mng_info->have_write_global_srgb=MagickTrue;
12803 if (image->gamma && mng_info->equal_gammas)
12806 Write MNG gAMA chunk
12808 (void) WriteBlobMSBULong(image,4L);
12809 PNGType(chunk,mng_gAMA);
12810 LogPNGChunk(logging,mng_gAMA,4L);
12811 PNGLong(chunk+4,(png_uint_32) (100000*image->gamma+0.5));
12812 (void) WriteBlob(image,8,chunk);
12813 (void) WriteBlobMSBULong(image,crc32(0,chunk,8));
12814 mng_info->have_write_global_gama=MagickTrue;
12816 if (mng_info->equal_chrms)
12822 Write MNG cHRM chunk
12824 (void) WriteBlobMSBULong(image,32L);
12825 PNGType(chunk,mng_cHRM);
12826 LogPNGChunk(logging,mng_cHRM,32L);
12827 primary=image->chromaticity.white_point;
12828 PNGLong(chunk+4,(png_uint_32) (100000*primary.x+0.5));
12829 PNGLong(chunk+8,(png_uint_32) (100000*primary.y+0.5));
12830 primary=image->chromaticity.red_primary;
12831 PNGLong(chunk+12,(png_uint_32) (100000*primary.x+0.5));
12832 PNGLong(chunk+16,(png_uint_32) (100000*primary.y+0.5));
12833 primary=image->chromaticity.green_primary;
12834 PNGLong(chunk+20,(png_uint_32) (100000*primary.x+0.5));
12835 PNGLong(chunk+24,(png_uint_32) (100000*primary.y+0.5));
12836 primary=image->chromaticity.blue_primary;
12837 PNGLong(chunk+28,(png_uint_32) (100000*primary.x+0.5));
12838 PNGLong(chunk+32,(png_uint_32) (100000*primary.y+0.5));
12839 (void) WriteBlob(image,36,chunk);
12840 (void) WriteBlobMSBULong(image,crc32(0,chunk,36));
12841 mng_info->have_write_global_chrm=MagickTrue;
12844 if (image->resolution.x && image->resolution.y && mng_info->equal_physs)
12847 Write MNG pHYs chunk
12849 (void) WriteBlobMSBULong(image,9L);
12850 PNGType(chunk,mng_pHYs);
12851 LogPNGChunk(logging,mng_pHYs,9L);
12853 if (image->units == PixelsPerInchResolution)
12855 PNGLong(chunk+4,(png_uint_32)
12856 (image->resolution.x*100.0/2.54+0.5));
12858 PNGLong(chunk+8,(png_uint_32)
12859 (image->resolution.y*100.0/2.54+0.5));
12866 if (image->units == PixelsPerCentimeterResolution)
12868 PNGLong(chunk+4,(png_uint_32)
12869 (image->resolution.x*100.0+0.5));
12871 PNGLong(chunk+8,(png_uint_32)
12872 (image->resolution.y*100.0+0.5));
12879 PNGLong(chunk+4,(png_uint_32) (image->resolution.x+0.5));
12880 PNGLong(chunk+8,(png_uint_32) (image->resolution.y+0.5));
12884 (void) WriteBlob(image,13,chunk);
12885 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
12888 Write MNG BACK chunk and global bKGD chunk, if the image is transparent
12889 or does not cover the entire frame.
12891 if (write_mng && (image->matte || image->page.x > 0 ||
12892 image->page.y > 0 || (image->page.width &&
12893 (image->page.width+image->page.x < mng_info->page.width))
12894 || (image->page.height && (image->page.height+image->page.y
12895 < mng_info->page.height))))
12897 (void) WriteBlobMSBULong(image,6L);
12898 PNGType(chunk,mng_BACK);
12899 LogPNGChunk(logging,mng_BACK,6L);
12900 red=ScaleQuantumToShort(image->background_color.red);
12901 green=ScaleQuantumToShort(image->background_color.green);
12902 blue=ScaleQuantumToShort(image->background_color.blue);
12903 PNGShort(chunk+4,red);
12904 PNGShort(chunk+6,green);
12905 PNGShort(chunk+8,blue);
12906 (void) WriteBlob(image,10,chunk);
12907 (void) WriteBlobMSBULong(image,crc32(0,chunk,10));
12908 if (mng_info->equal_backgrounds)
12910 (void) WriteBlobMSBULong(image,6L);
12911 PNGType(chunk,mng_bKGD);
12912 LogPNGChunk(logging,mng_bKGD,6L);
12913 (void) WriteBlob(image,10,chunk);
12914 (void) WriteBlobMSBULong(image,crc32(0,chunk,10));
12918 #ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
12919 if ((need_local_plte == MagickFalse) &&
12920 (image->storage_class == PseudoClass) &&
12921 (all_images_are_gray == MagickFalse))
12927 Write MNG PLTE chunk
12929 data_length=3*image->colors;
12930 (void) WriteBlobMSBULong(image,data_length);
12931 PNGType(chunk,mng_PLTE);
12932 LogPNGChunk(logging,mng_PLTE,data_length);
12934 for (i=0; i < (ssize_t) image->colors; i++)
12936 chunk[4+i*3]=(unsigned char) (ScaleQuantumToChar(
12937 image->colormap[i].red) & 0xff);
12938 chunk[5+i*3]=(unsigned char) (ScaleQuantumToChar(
12939 image->colormap[i].green) & 0xff);
12940 chunk[6+i*3]=(unsigned char) (ScaleQuantumToChar(
12941 image->colormap[i].blue) & 0xff);
12944 (void) WriteBlob(image,data_length+4,chunk);
12945 (void) WriteBlobMSBULong(image,crc32(0,chunk,(uInt) (data_length+4)));
12946 mng_info->have_write_global_plte=MagickTrue;
12952 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
12953 defined(PNG_MNG_FEATURES_SUPPORTED)
12954 mng_info->equal_palettes=MagickFalse;
12958 if (mng_info->adjoin)
12960 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
12961 defined(PNG_MNG_FEATURES_SUPPORTED)
12963 If we aren't using a global palette for the entire MNG, check to
12964 see if we can use one for two or more consecutive images.
12966 if (need_local_plte && use_global_plte && !all_images_are_gray)
12968 if (mng_info->IsPalette)
12971 When equal_palettes is true, this image has the same palette
12972 as the previous PseudoClass image
12974 mng_info->have_write_global_plte=mng_info->equal_palettes;
12975 mng_info->equal_palettes=PalettesAreEqual(image,image->next);
12976 if (mng_info->equal_palettes && !mng_info->have_write_global_plte)
12979 Write MNG PLTE chunk
12984 data_length=3*image->colors;
12985 (void) WriteBlobMSBULong(image,data_length);
12986 PNGType(chunk,mng_PLTE);
12987 LogPNGChunk(logging,mng_PLTE,data_length);
12989 for (i=0; i < (ssize_t) image->colors; i++)
12991 chunk[4+i*3]=ScaleQuantumToChar(image->colormap[i].red);
12992 chunk[5+i*3]=ScaleQuantumToChar(image->colormap[i].green);
12993 chunk[6+i*3]=ScaleQuantumToChar(image->colormap[i].blue);
12996 (void) WriteBlob(image,data_length+4,chunk);
12997 (void) WriteBlobMSBULong(image,crc32(0,chunk,
12998 (uInt) (data_length+4)));
12999 mng_info->have_write_global_plte=MagickTrue;
13003 mng_info->have_write_global_plte=MagickFalse;
13014 previous_x=mng_info->page.x;
13015 previous_y=mng_info->page.y;
13022 mng_info->page=image->page;
13023 if ((mng_info->page.x != previous_x) ||
13024 (mng_info->page.y != previous_y))
13026 (void) WriteBlobMSBULong(image,12L); /* data length=12 */
13027 PNGType(chunk,mng_DEFI);
13028 LogPNGChunk(logging,mng_DEFI,12L);
13029 chunk[4]=0; /* object 0 MSB */
13030 chunk[5]=0; /* object 0 LSB */
13031 chunk[6]=0; /* visible */
13032 chunk[7]=0; /* abstract */
13033 PNGLong(chunk+8,(png_uint_32) mng_info->page.x);
13034 PNGLong(chunk+12,(png_uint_32) mng_info->page.y);
13035 (void) WriteBlob(image,16,chunk);
13036 (void) WriteBlobMSBULong(image,crc32(0,chunk,16));
13041 mng_info->write_mng=write_mng;
13043 if ((int) image->dispose >= 3)
13044 mng_info->framing_mode=3;
13046 if (mng_info->need_fram && mng_info->adjoin &&
13047 ((image->delay != mng_info->delay) ||
13048 (mng_info->framing_mode != mng_info->old_framing_mode)))
13050 if (image->delay == mng_info->delay)
13053 Write a MNG FRAM chunk with the new framing mode.
13055 (void) WriteBlobMSBULong(image,1L); /* data length=1 */
13056 PNGType(chunk,mng_FRAM);
13057 LogPNGChunk(logging,mng_FRAM,1L);
13058 chunk[4]=(unsigned char) mng_info->framing_mode;
13059 (void) WriteBlob(image,5,chunk);
13060 (void) WriteBlobMSBULong(image,crc32(0,chunk,5));
13065 Write a MNG FRAM chunk with the delay.
13067 (void) WriteBlobMSBULong(image,10L); /* data length=10 */
13068 PNGType(chunk,mng_FRAM);
13069 LogPNGChunk(logging,mng_FRAM,10L);
13070 chunk[4]=(unsigned char) mng_info->framing_mode;
13071 chunk[5]=0; /* frame name separator (no name) */
13072 chunk[6]=2; /* flag for changing default delay */
13073 chunk[7]=0; /* flag for changing frame timeout */
13074 chunk[8]=0; /* flag for changing frame clipping */
13075 chunk[9]=0; /* flag for changing frame sync_id */
13076 PNGLong(chunk+10,(png_uint_32)
13077 ((mng_info->ticks_per_second*
13078 image->delay)/MagickMax(image->ticks_per_second,1)));
13079 (void) WriteBlob(image,14,chunk);
13080 (void) WriteBlobMSBULong(image,crc32(0,chunk,14));
13081 mng_info->delay=(png_uint_32) image->delay;
13083 mng_info->old_framing_mode=mng_info->framing_mode;
13086 #if defined(JNG_SUPPORTED)
13087 if (image_info->compression == JPEGCompression)
13092 if (logging != MagickFalse)
13093 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
13094 " Writing JNG object.");
13095 /* To do: specify the desired alpha compression method. */
13096 write_info=CloneImageInfo(image_info);
13097 write_info->compression=UndefinedCompression;
13098 status=WriteOneJNGImage(mng_info,write_info,image,exception);
13099 write_info=DestroyImageInfo(write_info);
13104 if (logging != MagickFalse)
13105 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
13106 " Writing PNG object.");
13108 mng_info->need_blob = MagickFalse;
13109 mng_info->ping_preserve_colormap = MagickFalse;
13111 /* We don't want any ancillary chunks written */
13112 mng_info->ping_exclude_bKGD=MagickTrue;
13113 mng_info->ping_exclude_cHRM=MagickTrue;
13114 mng_info->ping_exclude_date=MagickTrue;
13115 mng_info->ping_exclude_EXIF=MagickTrue;
13116 mng_info->ping_exclude_gAMA=MagickTrue;
13117 mng_info->ping_exclude_iCCP=MagickTrue;
13118 /* mng_info->ping_exclude_iTXt=MagickTrue; */
13119 mng_info->ping_exclude_oFFs=MagickTrue;
13120 mng_info->ping_exclude_pHYs=MagickTrue;
13121 mng_info->ping_exclude_sRGB=MagickTrue;
13122 mng_info->ping_exclude_tEXt=MagickTrue;
13123 mng_info->ping_exclude_tRNS=MagickTrue;
13124 mng_info->ping_exclude_vpAg=MagickTrue;
13125 mng_info->ping_exclude_zCCP=MagickTrue;
13126 mng_info->ping_exclude_zTXt=MagickTrue;
13128 status=WriteOnePNGImage(mng_info,image_info,image,exception);
13131 if (status == MagickFalse)
13133 MngInfoFreeStruct(mng_info,&have_mng_structure);
13134 (void) CloseBlob(image);
13135 return(MagickFalse);
13137 (void) CatchImageException(image);
13138 if (GetNextImageInList(image) == (Image *) NULL)
13140 image=SyncNextImageInList(image);
13141 status=SetImageProgress(image,SaveImagesTag,scene++,
13142 GetImageListLength(image));
13144 if (status == MagickFalse)
13147 } while (mng_info->adjoin);
13151 while (GetPreviousImageInList(image) != (Image *) NULL)
13152 image=GetPreviousImageInList(image);
13154 Write the MEND chunk.
13156 (void) WriteBlobMSBULong(image,0x00000000L);
13157 PNGType(chunk,mng_MEND);
13158 LogPNGChunk(logging,mng_MEND,0L);
13159 (void) WriteBlob(image,4,chunk);
13160 (void) WriteBlobMSBULong(image,crc32(0,chunk,4));
13163 Relinquish resources.
13165 (void) CloseBlob(image);
13166 MngInfoFreeStruct(mng_info,&have_mng_structure);
13168 if (logging != MagickFalse)
13169 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit WriteMNGImage()");
13171 return(MagickTrue);
13173 #else /* PNG_LIBPNG_VER > 10011 */
13175 static MagickBooleanType WritePNGImage(const ImageInfo *image_info,Image *image)
13178 printf("Your PNG library is too old: You have libpng-%s\n",
13179 PNG_LIBPNG_VER_STRING);
13181 ThrowBinaryException(CoderError,"PNG library is too old",
13182 image_info->filename);
13185 static MagickBooleanType WriteMNGImage(const ImageInfo *image_info,Image *image)
13187 return(WritePNGImage(image_info,image));
13189 #endif /* PNG_LIBPNG_VER > 10011 */