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;
1127 Magick_RenderingIntentString_from_PNG_RenderingIntent(const int ping_intent)
1129 switch (ping_intent)
1132 return "Perceptual Intent";
1135 return "Relative Intent";
1138 return "Saturation Intent";
1141 return "Absolute Intent";
1144 return "Undefined Intent";
1148 static inline ssize_t MagickMax(const ssize_t x,const ssize_t y)
1157 Magick_ColorType_from_PNG_ColorType(const int ping_colortype)
1159 switch (ping_colortype)
1177 return "UndefinedColorType";
1182 static inline ssize_t MagickMin(const ssize_t x,const ssize_t y)
1189 #endif /* PNG_LIBPNG_VER > 10011 */
1190 #endif /* MAGICKCORE_PNG_DELEGATE */
1193 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1201 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1203 % IsMNG() returns MagickTrue if the image format type, identified by the
1204 % magick string, is MNG.
1206 % The format of the IsMNG method is:
1208 % MagickBooleanType IsMNG(const unsigned char *magick,const size_t length)
1210 % A description of each parameter follows:
1212 % o magick: compare image format pattern against these bytes.
1214 % o length: Specifies the length of the magick string.
1218 static MagickBooleanType IsMNG(const unsigned char *magick,const size_t length)
1221 return(MagickFalse);
1223 if (memcmp(magick,"\212MNG\r\n\032\n",8) == 0)
1226 return(MagickFalse);
1230 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1238 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1240 % IsJNG() returns MagickTrue if the image format type, identified by the
1241 % magick string, is JNG.
1243 % The format of the IsJNG method is:
1245 % MagickBooleanType IsJNG(const unsigned char *magick,const size_t length)
1247 % A description of each parameter follows:
1249 % o magick: compare image format pattern against these bytes.
1251 % o length: Specifies the length of the magick string.
1255 static MagickBooleanType IsJNG(const unsigned char *magick,const size_t length)
1258 return(MagickFalse);
1260 if (memcmp(magick,"\213JNG\r\n\032\n",8) == 0)
1263 return(MagickFalse);
1267 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1275 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1277 % IsPNG() returns MagickTrue if the image format type, identified by the
1278 % magick string, is PNG.
1280 % The format of the IsPNG method is:
1282 % MagickBooleanType IsPNG(const unsigned char *magick,const size_t length)
1284 % A description of each parameter follows:
1286 % o magick: compare image format pattern against these bytes.
1288 % o length: Specifies the length of the magick string.
1291 static MagickBooleanType IsPNG(const unsigned char *magick,const size_t length)
1294 return(MagickFalse);
1296 if (memcmp(magick,"\211PNG\r\n\032\n",8) == 0)
1299 return(MagickFalse);
1302 #if defined(MAGICKCORE_PNG_DELEGATE)
1303 #if defined(__cplusplus) || defined(c_plusplus)
1307 #if (PNG_LIBPNG_VER > 10011)
1308 static size_t WriteBlobMSBULong(Image *image,const size_t value)
1313 assert(image != (Image *) NULL);
1314 assert(image->signature == MagickSignature);
1315 buffer[0]=(unsigned char) (value >> 24);
1316 buffer[1]=(unsigned char) (value >> 16);
1317 buffer[2]=(unsigned char) (value >> 8);
1318 buffer[3]=(unsigned char) value;
1319 return((size_t) WriteBlob(image,4,buffer));
1322 static void PNGLong(png_bytep p,png_uint_32 value)
1324 *p++=(png_byte) ((value >> 24) & 0xff);
1325 *p++=(png_byte) ((value >> 16) & 0xff);
1326 *p++=(png_byte) ((value >> 8) & 0xff);
1327 *p++=(png_byte) (value & 0xff);
1330 #if defined(JNG_SUPPORTED)
1331 static void PNGsLong(png_bytep p,png_int_32 value)
1333 *p++=(png_byte) ((value >> 24) & 0xff);
1334 *p++=(png_byte) ((value >> 16) & 0xff);
1335 *p++=(png_byte) ((value >> 8) & 0xff);
1336 *p++=(png_byte) (value & 0xff);
1340 static void PNGShort(png_bytep p,png_uint_16 value)
1342 *p++=(png_byte) ((value >> 8) & 0xff);
1343 *p++=(png_byte) (value & 0xff);
1346 static void PNGType(png_bytep p,png_bytep type)
1348 (void) CopyMagickMemory(p,type,4*sizeof(png_byte));
1351 static void LogPNGChunk(MagickBooleanType logging, png_bytep type,
1354 if (logging != MagickFalse)
1355 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1356 " Writing %c%c%c%c chunk, length: %.20g",
1357 type[0],type[1],type[2],type[3],(double) length);
1359 #endif /* PNG_LIBPNG_VER > 10011 */
1361 #if defined(__cplusplus) || defined(c_plusplus)
1365 #if PNG_LIBPNG_VER > 10011
1367 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1371 % R e a d P N G I m a g e %
1375 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1377 % ReadPNGImage() reads a Portable Network Graphics (PNG) or
1378 % Multiple-image Network Graphics (MNG) image file and returns it. It
1379 % allocates the memory necessary for the new Image structure and returns a
1380 % pointer to the new image or set of images.
1382 % MNG support written by Glenn Randers-Pehrson, glennrp@image...
1384 % The format of the ReadPNGImage method is:
1386 % Image *ReadPNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
1388 % A description of each parameter follows:
1390 % o image_info: the image info.
1392 % o exception: return any errors or warnings in this structure.
1394 % To do, more or less in chronological order (as of version 5.5.2,
1395 % November 26, 2002 -- glennrp -- see also "To do" under WriteMNGImage):
1397 % Get 16-bit cheap transparency working.
1399 % (At this point, PNG decoding is supposed to be in full MNG-LC compliance)
1401 % Preserve all unknown and not-yet-handled known chunks found in input
1402 % PNG file and copy them into output PNG files according to the PNG
1405 % (At this point, PNG encoding should be in full MNG compliance)
1407 % Provide options for choice of background to use when the MNG BACK
1408 % chunk is not present or is not mandatory (i.e., leave transparent,
1409 % user specified, MNG BACK, PNG bKGD)
1411 % Implement LOOP/ENDL [done, but could do discretionary loops more
1412 % efficiently by linking in the duplicate frames.].
1414 % Decode and act on the MHDR simplicity profile (offer option to reject
1415 % files or attempt to process them anyway when the profile isn't LC or VLC).
1417 % Upgrade to full MNG without Delta-PNG.
1419 % o BACK [done a while ago except for background image ID]
1420 % o MOVE [done 15 May 1999]
1421 % o CLIP [done 15 May 1999]
1422 % o DISC [done 19 May 1999]
1423 % o SAVE [partially done 19 May 1999 (marks objects frozen)]
1424 % o SEEK [partially done 19 May 1999 (discard function only)]
1428 % o MNG-level tEXt/iTXt/zTXt
1433 % o iTXt (wait for libpng implementation).
1435 % Use the scene signature to discover when an identical scene is
1436 % being reused, and just point to the original image->exception instead
1437 % of storing another set of pixels. This not specific to MNG
1438 % but could be applied generally.
1440 % Upgrade to full MNG with Delta-PNG.
1442 % JNG tEXt/iTXt/zTXt
1444 % We will not attempt to read files containing the CgBI chunk.
1445 % They are really Xcode files meant for display on the iPhone.
1446 % These are not valid PNG files and it is impossible to recover
1447 % the original PNG from files that have been converted to Xcode-PNG,
1448 % since irretrievable loss of color data has occurred due to the
1449 % use of premultiplied alpha.
1452 #if defined(__cplusplus) || defined(c_plusplus)
1457 This the function that does the actual reading of data. It is
1458 the same as the one supplied in libpng, except that it receives the
1459 datastream from the ReadBlob() function instead of standard input.
1461 static void png_get_data(png_structp png_ptr,png_bytep data,png_size_t length)
1466 image=(Image *) png_get_io_ptr(png_ptr);
1472 check=(png_size_t) ReadBlob(image,(size_t) length,data);
1473 if (check != length)
1478 (void) FormatLocaleString(msg,MaxTextExtent,
1479 "Expected %.20g bytes; found %.20g bytes",(double) length,
1481 png_warning(png_ptr,msg);
1482 png_error(png_ptr,"Read Exception");
1487 #if !defined(PNG_READ_EMPTY_PLTE_SUPPORTED) && \
1488 !defined(PNG_MNG_FEATURES_SUPPORTED)
1489 /* We use mng_get_data() instead of png_get_data() if we have a libpng
1490 * older than libpng-1.0.3a, which was the first to allow the empty
1491 * PLTE, or a newer libpng in which PNG_MNG_FEATURES_SUPPORTED was
1492 * ifdef'ed out. Earlier versions would crash if the bKGD chunk was
1493 * encountered after an empty PLTE, so we have to look ahead for bKGD
1494 * chunks and remove them from the datastream that is passed to libpng,
1495 * and store their contents for later use.
1497 static void mng_get_data(png_structp png_ptr,png_bytep data,png_size_t length)
1512 mng_info=(MngInfo *) png_get_io_ptr(png_ptr);
1513 image=(Image *) mng_info->image;
1514 while (mng_info->bytes_in_read_buffer && length)
1516 data[i]=mng_info->read_buffer[i];
1517 mng_info->bytes_in_read_buffer--;
1523 check=(png_size_t) ReadBlob(image,(size_t) length,(char *) data);
1525 if (check != length)
1526 png_error(png_ptr,"Read Exception");
1530 if ((data[0] == 0) && (data[1] == 0) && (data[2] == 0) &&
1533 check=(png_size_t) ReadBlob(image,(size_t) length,
1534 (char *) mng_info->read_buffer);
1535 mng_info->read_buffer[4]=0;
1536 mng_info->bytes_in_read_buffer=4;
1537 if (memcmp(mng_info->read_buffer,mng_PLTE,4) == 0)
1538 mng_info->found_empty_plte=MagickTrue;
1539 if (memcmp(mng_info->read_buffer,mng_IEND,4) == 0)
1541 mng_info->found_empty_plte=MagickFalse;
1542 mng_info->have_saved_bkgd_index=MagickFalse;
1546 if ((data[0] == 0) && (data[1] == 0) && (data[2] == 0) &&
1549 check=(png_size_t) ReadBlob(image,(size_t) length,
1550 (char *) mng_info->read_buffer);
1551 mng_info->read_buffer[4]=0;
1552 mng_info->bytes_in_read_buffer=4;
1553 if (memcmp(mng_info->read_buffer,mng_bKGD,4) == 0)
1554 if (mng_info->found_empty_plte)
1557 Skip the bKGD data byte and CRC.
1560 ReadBlob(image,5,(char *) mng_info->read_buffer);
1561 check=(png_size_t) ReadBlob(image,(size_t) length,
1562 (char *) mng_info->read_buffer);
1563 mng_info->saved_bkgd_index=mng_info->read_buffer[0];
1564 mng_info->have_saved_bkgd_index=MagickTrue;
1565 mng_info->bytes_in_read_buffer=0;
1573 static void png_put_data(png_structp png_ptr,png_bytep data,png_size_t length)
1578 image=(Image *) png_get_io_ptr(png_ptr);
1584 check=(png_size_t) WriteBlob(image,(size_t) length,data);
1586 if (check != length)
1587 png_error(png_ptr,"WriteBlob Failed");
1591 static void png_flush_data(png_structp png_ptr)
1596 #ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
1597 static int PalettesAreEqual(Image *a,Image *b)
1602 if ((a == (Image *) NULL) || (b == (Image *) NULL))
1603 return((int) MagickFalse);
1605 if (a->storage_class != PseudoClass || b->storage_class != PseudoClass)
1606 return((int) MagickFalse);
1608 if (a->colors != b->colors)
1609 return((int) MagickFalse);
1611 for (i=0; i < (ssize_t) a->colors; i++)
1613 if ((a->colormap[i].red != b->colormap[i].red) ||
1614 (a->colormap[i].green != b->colormap[i].green) ||
1615 (a->colormap[i].blue != b->colormap[i].blue))
1616 return((int) MagickFalse);
1619 return((int) MagickTrue);
1623 static void MngInfoDiscardObject(MngInfo *mng_info,int i)
1625 if (i && (i < MNG_MAX_OBJECTS) && (mng_info != (MngInfo *) NULL) &&
1626 mng_info->exists[i] && !mng_info->frozen[i])
1628 #ifdef MNG_OBJECT_BUFFERS
1629 if (mng_info->ob[i] != (MngBuffer *) NULL)
1631 if (mng_info->ob[i]->reference_count > 0)
1632 mng_info->ob[i]->reference_count--;
1634 if (mng_info->ob[i]->reference_count == 0)
1636 if (mng_info->ob[i]->image != (Image *) NULL)
1637 mng_info->ob[i]->image=DestroyImage(mng_info->ob[i]->image);
1639 mng_info->ob[i]=DestroyString(mng_info->ob[i]);
1642 mng_info->ob[i]=(MngBuffer *) NULL;
1644 mng_info->exists[i]=MagickFalse;
1645 mng_info->invisible[i]=MagickFalse;
1646 mng_info->viewable[i]=MagickFalse;
1647 mng_info->frozen[i]=MagickFalse;
1648 mng_info->x_off[i]=0;
1649 mng_info->y_off[i]=0;
1650 mng_info->object_clip[i].left=0;
1651 mng_info->object_clip[i].right=(ssize_t) PNG_UINT_31_MAX;
1652 mng_info->object_clip[i].top=0;
1653 mng_info->object_clip[i].bottom=(ssize_t) PNG_UINT_31_MAX;
1657 static void MngInfoFreeStruct(MngInfo *mng_info,
1658 MagickBooleanType *have_mng_structure)
1660 if (*have_mng_structure != MagickFalse && (mng_info != (MngInfo *) NULL))
1665 for (i=1; i < MNG_MAX_OBJECTS; i++)
1666 MngInfoDiscardObject(mng_info,i);
1668 if (mng_info->global_plte != (png_colorp) NULL)
1669 mng_info->global_plte=(png_colorp)
1670 RelinquishMagickMemory(mng_info->global_plte);
1672 mng_info=(MngInfo *) RelinquishMagickMemory(mng_info);
1673 *have_mng_structure=MagickFalse;
1677 static MngBox mng_minimum_box(MngBox box1,MngBox box2)
1683 if (box.left < box2.left)
1686 if (box.top < box2.top)
1689 if (box.right > box2.right)
1690 box.right=box2.right;
1692 if (box.bottom > box2.bottom)
1693 box.bottom=box2.bottom;
1698 static MngBox mng_read_box(MngBox previous_box,char delta_type,unsigned char *p)
1704 Read clipping boundaries from DEFI, CLIP, FRAM, or PAST chunk.
1706 box.left=(ssize_t) ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]);
1707 box.right=(ssize_t) ((p[4] << 24) | (p[5] << 16) | (p[6] << 8) | p[7]);
1708 box.top=(ssize_t) ((p[8] << 24) | (p[9] << 16) | (p[10] << 8) | p[11]);
1709 box.bottom=(ssize_t) ((p[12] << 24) | (p[13] << 16) | (p[14] << 8) | p[15]);
1710 if (delta_type != 0)
1712 box.left+=previous_box.left;
1713 box.right+=previous_box.right;
1714 box.top+=previous_box.top;
1715 box.bottom+=previous_box.bottom;
1721 static MngPair mng_read_pair(MngPair previous_pair,int delta_type,
1727 Read two ssize_ts from CLON, MOVE or PAST chunk
1729 pair.a=(long) ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]);
1730 pair.b=(long) ((p[4] << 24) | (p[5] << 16) | (p[6] << 8) | p[7]);
1732 if (delta_type != 0)
1734 pair.a+=previous_pair.a;
1735 pair.b+=previous_pair.b;
1741 static long mng_get_long(unsigned char *p)
1743 return((long) ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]));
1746 typedef struct _PNGErrorInfo
1755 static void MagickPNGErrorHandler(png_struct *ping,png_const_charp message)
1766 error_info=(PNGErrorInfo *) png_get_error_ptr(ping);
1767 image=error_info->image;
1768 exception=error_info->exception;
1770 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1771 " libpng-%s error: %s", PNG_LIBPNG_VER_STRING,message);
1773 (void) ThrowMagickException(exception,GetMagickModule(),CoderError,message,
1774 "`%s'",image->filename);
1776 #if (PNG_LIBPNG_VER < 10500)
1777 /* A warning about deprecated use of jmpbuf here is unavoidable if you
1778 * are building with libpng-1.4.x and can be ignored.
1780 longjmp(ping->jmpbuf,1);
1782 png_longjmp(ping,1);
1786 static void MagickPNGWarningHandler(png_struct *ping,png_const_charp message)
1797 if (LocaleCompare(message, "Missing PLTE before tRNS") == 0)
1798 png_error(ping, message);
1800 error_info=(PNGErrorInfo *) png_get_error_ptr(ping);
1801 image=error_info->image;
1802 exception=error_info->exception;
1803 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1804 " libpng-%s warning: %s", PNG_LIBPNG_VER_STRING,message);
1806 (void) ThrowMagickException(exception,GetMagickModule(),CoderWarning,
1807 message,"`%s'",image->filename);
1810 #ifdef PNG_USER_MEM_SUPPORTED
1811 #if PNG_LIBPNG_VER >= 14000
1812 static png_voidp Magick_png_malloc(png_structp png_ptr,png_alloc_size_t size)
1814 static png_voidp Magick_png_malloc(png_structp png_ptr,png_size_t size)
1818 return((png_voidp) AcquireMagickMemory((size_t) size));
1822 Free a pointer. It is removed from the list at the same time.
1824 static png_free_ptr Magick_png_free(png_structp png_ptr,png_voidp ptr)
1827 ptr=RelinquishMagickMemory(ptr);
1828 return((png_free_ptr) NULL);
1832 #if defined(__cplusplus) || defined(c_plusplus)
1837 Magick_png_read_raw_profile(png_struct *ping,Image *image,
1838 const ImageInfo *image_info, png_textp text,int ii,ExceptionInfo *exception)
1843 register unsigned char
1857 unhex[103]={0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,
1858 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,
1859 0,0,0,0,0,0,0,0,0,1, 2,3,4,5,6,7,8,9,0,0,
1860 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,
1861 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,10,11,12,
1865 /* look for newline */
1869 /* look for length */
1870 while (*sp == '\0' || *sp == ' ' || *sp == '\n')
1873 length=(png_uint_32) StringToLong(sp);
1875 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1876 " length: %lu",(unsigned long) length);
1878 while (*sp != ' ' && *sp != '\n')
1881 /* allocate space */
1884 png_warning(ping,"invalid profile length");
1885 return(MagickFalse);
1888 profile=BlobToStringInfo((const void *) NULL,length);
1890 if (profile == (StringInfo *) NULL)
1892 png_warning(ping, "unable to copy profile");
1893 return(MagickFalse);
1896 /* copy profile, skipping white space and column 1 "=" signs */
1897 dp=GetStringInfoDatum(profile);
1900 for (i=0; i < (ssize_t) nibbles; i++)
1902 while (*sp < '0' || (*sp > '9' && *sp < 'a') || *sp > 'f')
1906 png_warning(ping, "ran out of profile data");
1907 profile=DestroyStringInfo(profile);
1908 return(MagickFalse);
1914 *dp=(unsigned char) (16*unhex[(int) *sp++]);
1917 (*dp++)+=unhex[(int) *sp++];
1920 We have already read "Raw profile type.
1922 (void) SetImageProfile(image,&text[ii].key[17],profile,exception);
1923 profile=DestroyStringInfo(profile);
1925 if (image_info->verbose)
1926 (void) printf(" Found a generic profile, type %s\n",&text[ii].key[17]);
1931 #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
1932 static int read_vpag_chunk_callback(png_struct *ping, png_unknown_chunkp chunk)
1938 /* The unknown chunk structure contains the chunk data:
1943 Note that libpng has already taken care of the CRC handling.
1947 if (chunk->name[0] != 118 || chunk->name[1] != 112 ||
1948 chunk->name[2] != 65 ||chunk-> name[3] != 103)
1949 return(0); /* Did not recognize */
1951 /* recognized vpAg */
1953 if (chunk->size != 9)
1954 return(-1); /* Error return */
1956 if (chunk->data[8] != 0)
1957 return(0); /* ImageMagick requires pixel units */
1959 image=(Image *) png_get_user_chunk_ptr(ping);
1961 image->page.width=(size_t) ((chunk->data[0] << 24) |
1962 (chunk->data[1] << 16) | (chunk->data[2] << 8) | chunk->data[3]);
1964 image->page.height=(size_t) ((chunk->data[4] << 24) |
1965 (chunk->data[5] << 16) | (chunk->data[6] << 8) | chunk->data[7]);
1967 /* Return one of the following: */
1968 /* return(-n); chunk had an error */
1969 /* return(0); did not recognize */
1970 /* return(n); success */
1978 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1982 % R e a d O n e P N G I m a g e %
1986 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1988 % ReadOnePNGImage() reads a Portable Network Graphics (PNG) image file
1989 % (minus the 8-byte signature) and returns it. It allocates the memory
1990 % necessary for the new Image structure and returns a pointer to the new
1993 % The format of the ReadOnePNGImage method is:
1995 % Image *ReadOnePNGImage(MngInfo *mng_info, const ImageInfo *image_info,
1996 % ExceptionInfo *exception)
1998 % A description of each parameter follows:
2000 % o mng_info: Specifies a pointer to a MngInfo structure.
2002 % o image_info: the image info.
2004 % o exception: return any errors or warnings in this structure.
2007 static Image *ReadOnePNGImage(MngInfo *mng_info,
2008 const ImageInfo *image_info, ExceptionInfo *exception)
2010 /* Read one PNG image */
2012 /* To do: Read the tIME chunk into the date:modify property */
2013 /* To do: Read the tEXt/Creation Time chunk into the date:create property */
2019 intent, /* "PNG Rendering intent", which is ICC intent + 1 */
2028 ping_interlace_method,
2029 ping_compression_method,
2084 register unsigned char
2101 #ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED
2102 png_byte unused_chunks[]=
2104 104, 73, 83, 84, (png_byte) '\0', /* hIST */
2105 105, 84, 88, 116, (png_byte) '\0', /* iTXt */
2106 112, 67, 65, 76, (png_byte) '\0', /* pCAL */
2107 115, 67, 65, 76, (png_byte) '\0', /* sCAL */
2108 115, 80, 76, 84, (png_byte) '\0', /* sPLT */
2109 116, 73, 77, 69, (png_byte) '\0', /* tIME */
2110 #ifdef PNG_APNG_SUPPORTED /* libpng was built with APNG patch; */
2111 /* ignore the APNG chunks */
2112 97, 99, 84, 76, (png_byte) '\0', /* acTL */
2113 102, 99, 84, 76, (png_byte) '\0', /* fcTL */
2114 102, 100, 65, 84, (png_byte) '\0', /* fdAT */
2119 logging=LogMagickEvent(CoderEvent,GetMagickModule(),
2120 " Enter ReadOnePNGImage()");
2122 #if (PNG_LIBPNG_VER < 10200)
2123 if (image_info->verbose)
2124 printf("Your PNG library (libpng-%s) is rather old.\n",
2125 PNG_LIBPNG_VER_STRING);
2128 #if (PNG_LIBPNG_VER >= 10400)
2129 # ifndef PNG_TRANSFORM_GRAY_TO_RGB /* Added at libpng-1.4.0beta67 */
2130 if (image_info->verbose)
2132 printf("Your PNG library (libpng-%s) is an old beta version.\n",
2133 PNG_LIBPNG_VER_STRING);
2134 printf("Please update it.\n");
2140 quantum_info = (QuantumInfo *) NULL;
2141 image=mng_info->image;
2143 if (logging != MagickFalse)
2145 (void)LogMagickEvent(CoderEvent,GetMagickModule(),
2146 " image->matte=%d",(int) image->matte);
2148 (void)LogMagickEvent(CoderEvent,GetMagickModule(),
2149 " image->rendering_intent=%d",(int) image->rendering_intent);
2151 intent=Magick_RenderingIntent_to_PNG_RenderingIntent(image->rendering_intent);
2153 /* Set to an out-of-range color unless tRNS chunk is present */
2154 transparent_color.red=65537;
2155 transparent_color.green=65537;
2156 transparent_color.blue=65537;
2157 transparent_color.alpha=65537;
2162 num_raw_profiles = 0;
2164 ping_found_cHRM = MagickFalse;
2165 ping_found_gAMA = MagickFalse;
2166 ping_found_iCCP = MagickFalse;
2167 ping_found_sRGB = MagickFalse;
2170 Allocate the PNG structures
2172 #ifdef PNG_USER_MEM_SUPPORTED
2173 error_info.image=image;
2174 error_info.exception=exception;
2175 ping=png_create_read_struct_2(PNG_LIBPNG_VER_STRING,&error_info,
2176 MagickPNGErrorHandler,MagickPNGWarningHandler, NULL,
2177 (png_malloc_ptr) Magick_png_malloc,(png_free_ptr) Magick_png_free);
2179 ping=png_create_read_struct(PNG_LIBPNG_VER_STRING,&error_info,
2180 MagickPNGErrorHandler,MagickPNGWarningHandler);
2182 if (ping == (png_struct *) NULL)
2183 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2185 ping_info=png_create_info_struct(ping);
2187 if (ping_info == (png_info *) NULL)
2189 png_destroy_read_struct(&ping,(png_info **) NULL,(png_info **) NULL);
2190 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2193 end_info=png_create_info_struct(ping);
2195 if (end_info == (png_info *) NULL)
2197 png_destroy_read_struct(&ping,&ping_info,(png_info **) NULL);
2198 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2201 ping_pixels=(unsigned char *) NULL;
2203 if (setjmp(png_jmpbuf(ping)))
2206 PNG image is corrupt.
2208 png_destroy_read_struct(&ping,&ping_info,&end_info);
2210 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
2211 UnlockSemaphoreInfo(ping_semaphore);
2214 if (ping_pixels != (unsigned char *) NULL)
2215 ping_pixels=(unsigned char *) RelinquishMagickMemory(ping_pixels);
2217 if (logging != MagickFalse)
2218 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2219 " exit ReadOnePNGImage() with error.");
2221 if (image != (Image *) NULL)
2223 InheritException(exception,exception);
2227 return(GetFirstImageInList(image));
2230 /* { For navigation to end of SETJMP-protected block. Within this
2231 * block, use png_error() instead of Throwing an Exception, to ensure
2232 * that libpng is able to clean up, and that the semaphore is unlocked.
2235 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
2236 LockSemaphoreInfo(ping_semaphore);
2240 Prepare PNG for reading.
2243 mng_info->image_found++;
2244 png_set_sig_bytes(ping,8);
2246 if (LocaleCompare(image_info->magick,"MNG") == 0)
2248 #if defined(PNG_MNG_FEATURES_SUPPORTED)
2249 (void) png_permit_mng_features(ping,PNG_ALL_MNG_FEATURES);
2250 png_set_read_fn(ping,image,png_get_data);
2252 #if defined(PNG_READ_EMPTY_PLTE_SUPPORTED)
2253 png_permit_empty_plte(ping,MagickTrue);
2254 png_set_read_fn(ping,image,png_get_data);
2256 mng_info->image=image;
2257 mng_info->bytes_in_read_buffer=0;
2258 mng_info->found_empty_plte=MagickFalse;
2259 mng_info->have_saved_bkgd_index=MagickFalse;
2260 png_set_read_fn(ping,mng_info,mng_get_data);
2266 png_set_read_fn(ping,image,png_get_data);
2268 #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
2269 /* Ignore unused chunks and all unknown chunks except for vpAg */
2270 png_set_keep_unknown_chunks(ping, 1, NULL, 0);
2271 png_set_keep_unknown_chunks(ping, 2, mng_vpAg, 1);
2272 png_set_keep_unknown_chunks(ping, 1, unused_chunks,
2273 (int)sizeof(unused_chunks)/5);
2274 /* Callback for other unknown chunks */
2275 png_set_read_user_chunk_fn(ping, image, read_vpag_chunk_callback);
2278 #ifdef PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED
2279 /* Disable new libpng-1.5.10 feature */
2280 png_set_check_for_invalid_index (ping, 0);
2283 #if (PNG_LIBPNG_VER < 10400)
2284 # if defined(PNG_USE_PNGGCCRD) && defined(PNG_ASSEMBLER_CODE_SUPPORTED) && \
2285 (PNG_LIBPNG_VER >= 10200) && (PNG_LIBPNG_VER < 10220) && defined(__i386__)
2286 /* Disable thread-unsafe features of pnggccrd */
2287 if (png_access_version_number() >= 10200)
2289 png_uint_32 mmx_disable_mask=0;
2290 png_uint_32 asm_flags;
2292 mmx_disable_mask |= ( PNG_ASM_FLAG_MMX_READ_COMBINE_ROW \
2293 | PNG_ASM_FLAG_MMX_READ_FILTER_SUB \
2294 | PNG_ASM_FLAG_MMX_READ_FILTER_AVG \
2295 | PNG_ASM_FLAG_MMX_READ_FILTER_PAETH );
2296 asm_flags=png_get_asm_flags(ping);
2297 png_set_asm_flags(ping, asm_flags & ~mmx_disable_mask);
2302 png_read_info(ping,ping_info);
2304 png_get_IHDR(ping,ping_info,&ping_width,&ping_height,
2305 &ping_bit_depth,&ping_color_type,
2306 &ping_interlace_method,&ping_compression_method,
2307 &ping_filter_method);
2309 (void) png_get_tRNS(ping, ping_info, &ping_trans_alpha, &ping_num_trans,
2312 (void) png_get_bKGD(ping, ping_info, &ping_background);
2314 if (ping_bit_depth < 8)
2316 if (((int) ping_color_type == PNG_COLOR_TYPE_PALETTE))
2318 png_set_packing(ping);
2323 image->depth=ping_bit_depth;
2324 image->depth=GetImageQuantumDepth(image,MagickFalse);
2325 image->interlace=ping_interlace_method != 0 ? PNGInterlace : NoInterlace;
2327 if (((int) ping_color_type == PNG_COLOR_TYPE_GRAY) ||
2328 ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA))
2330 image->rendering_intent=UndefinedIntent;
2331 intent=Magick_RenderingIntent_to_PNG_RenderingIntent(UndefinedIntent);
2333 (void) ResetMagickMemory(&image->chromaticity,0,
2334 sizeof(image->chromaticity));
2337 if (logging != MagickFalse)
2339 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2340 " PNG width: %.20g, height: %.20g",
2341 (double) ping_width, (double) ping_height);
2343 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2344 " PNG color_type: %d, bit_depth: %d",
2345 ping_color_type, ping_bit_depth);
2347 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2348 " PNG compression_method: %d",
2349 ping_compression_method);
2351 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2352 " PNG interlace_method: %d, filter_method: %d",
2353 ping_interlace_method,ping_filter_method);
2356 if (png_get_valid(ping,ping_info,PNG_INFO_gAMA))
2358 ping_found_gAMA=MagickTrue;
2359 if (logging != MagickFalse)
2360 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2361 " Found PNG gAMA chunk.");
2364 if (png_get_valid(ping,ping_info,PNG_INFO_cHRM))
2366 ping_found_cHRM=MagickTrue;
2367 if (logging != MagickFalse)
2368 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2369 " Found PNG cHRM chunk.");
2372 if (png_get_valid(ping,ping_info,PNG_INFO_iCCP))
2374 ping_found_iCCP=MagickTrue;
2375 if (logging != MagickFalse)
2376 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2377 " Found PNG iCCP chunk.");
2380 if (png_get_valid(ping,ping_info,PNG_INFO_sRGB))
2382 ping_found_sRGB=MagickTrue;
2383 if (logging != MagickFalse)
2384 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2385 " Found PNG sRGB chunk.");
2388 #ifdef PNG_READ_iCCP_SUPPORTED
2389 if (png_get_valid(ping,ping_info,PNG_INFO_iCCP))
2394 #if (PNG_LIBPNG_VER < 10500)
2408 (void) png_get_iCCP(ping,ping_info,&name,(int *) &compression,&info,
2411 if (profile_length != 0)
2416 if (logging != MagickFalse)
2417 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2418 " Reading PNG iCCP chunk.");
2419 profile=BlobToStringInfo(info,profile_length);
2420 if (profile == (StringInfo *) NULL)
2422 png_warning(ping, "ICC profile is NULL");
2423 profile=DestroyStringInfo(profile);
2427 (void) SetImageProfile(image,"icc",profile,exception);
2428 profile=DestroyStringInfo(profile);
2433 #if defined(PNG_READ_sRGB_SUPPORTED)
2435 if (mng_info->have_global_srgb)
2437 image->rendering_intent=Magick_RenderingIntent_from_PNG_RenderingIntent
2438 (mng_info->global_srgb_intent);
2441 if (png_get_sRGB(ping,ping_info,&intent))
2443 image->rendering_intent=Magick_RenderingIntent_from_PNG_RenderingIntent
2446 if (logging != MagickFalse)
2447 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2448 " Reading PNG sRGB chunk: rendering_intent: %d",intent);
2453 if (!png_get_gAMA(ping,ping_info,&file_gamma))
2454 if (mng_info->have_global_gama)
2455 png_set_gAMA(ping,ping_info,mng_info->global_gamma);
2457 if (png_get_gAMA(ping,ping_info,&file_gamma))
2459 image->gamma=(float) file_gamma;
2460 if (logging != MagickFalse)
2461 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2462 " Reading PNG gAMA chunk: gamma: %f",file_gamma);
2466 if (!png_get_valid(ping,ping_info,PNG_INFO_cHRM))
2468 if (mng_info->have_global_chrm != MagickFalse)
2470 (void) png_set_cHRM(ping,ping_info,
2471 mng_info->global_chrm.white_point.x,
2472 mng_info->global_chrm.white_point.y,
2473 mng_info->global_chrm.red_primary.x,
2474 mng_info->global_chrm.red_primary.y,
2475 mng_info->global_chrm.green_primary.x,
2476 mng_info->global_chrm.green_primary.y,
2477 mng_info->global_chrm.blue_primary.x,
2478 mng_info->global_chrm.blue_primary.y);
2482 if (png_get_valid(ping,ping_info,PNG_INFO_cHRM))
2484 (void) png_get_cHRM(ping,ping_info,
2485 &image->chromaticity.white_point.x,
2486 &image->chromaticity.white_point.y,
2487 &image->chromaticity.red_primary.x,
2488 &image->chromaticity.red_primary.y,
2489 &image->chromaticity.green_primary.x,
2490 &image->chromaticity.green_primary.y,
2491 &image->chromaticity.blue_primary.x,
2492 &image->chromaticity.blue_primary.y);
2496 if (image->rendering_intent != UndefinedIntent)
2498 png_set_sRGB(ping,ping_info,
2499 Magick_RenderingIntent_to_PNG_RenderingIntent
2500 (image->rendering_intent));
2501 png_set_gAMA(ping,ping_info,1.000f/2.200f);
2502 png_set_cHRM(ping,ping_info,
2503 0.6400f, 0.3300f, 0.3000f, 0.6000f,
2504 0.1500f, 0.0600f, 0.3127f, 0.3290f);
2506 #if defined(PNG_oFFs_SUPPORTED)
2507 if (png_get_valid(ping,ping_info,PNG_INFO_oFFs))
2509 image->page.x=(ssize_t) png_get_x_offset_pixels(ping, ping_info);
2510 image->page.y=(ssize_t) png_get_y_offset_pixels(ping, ping_info);
2512 if (logging != MagickFalse)
2513 if (image->page.x || image->page.y)
2514 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2515 " Reading PNG oFFs chunk: x: %.20g, y: %.20g.",(double)
2516 image->page.x,(double) image->page.y);
2519 #if defined(PNG_pHYs_SUPPORTED)
2520 if (!png_get_valid(ping,ping_info,PNG_INFO_pHYs))
2522 if (mng_info->have_global_phys)
2524 png_set_pHYs(ping,ping_info,
2525 mng_info->global_x_pixels_per_unit,
2526 mng_info->global_y_pixels_per_unit,
2527 mng_info->global_phys_unit_type);
2531 if (png_get_valid(ping,ping_info,PNG_INFO_pHYs))
2534 Set image resolution.
2536 (void) png_get_pHYs(ping,ping_info,&x_resolution,&y_resolution,
2538 image->resolution.x=(double) x_resolution;
2539 image->resolution.y=(double) y_resolution;
2541 if (unit_type == PNG_RESOLUTION_METER)
2543 image->units=PixelsPerCentimeterResolution;
2544 image->resolution.x=(double) x_resolution/100.0;
2545 image->resolution.y=(double) y_resolution/100.0;
2548 if (logging != MagickFalse)
2549 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2550 " Reading PNG pHYs chunk: xres: %.20g, yres: %.20g, units: %d.",
2551 (double) x_resolution,(double) y_resolution,unit_type);
2555 if (png_get_valid(ping,ping_info,PNG_INFO_PLTE))
2560 (void) png_get_PLTE(ping,ping_info,&palette,&number_colors);
2562 if ((number_colors == 0) &&
2563 ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE))
2565 if (mng_info->global_plte_length)
2567 png_set_PLTE(ping,ping_info,mng_info->global_plte,
2568 (int) mng_info->global_plte_length);
2570 if (!png_get_valid(ping,ping_info,PNG_INFO_tRNS))
2572 if (mng_info->global_trns_length)
2575 "global tRNS has more entries than global PLTE");
2579 png_set_tRNS(ping,ping_info,mng_info->global_trns,
2580 (int) mng_info->global_trns_length,NULL);
2583 #ifdef PNG_READ_bKGD_SUPPORTED
2585 #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
2586 mng_info->have_saved_bkgd_index ||
2588 png_get_valid(ping,ping_info,PNG_INFO_bKGD))
2593 #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
2594 if (mng_info->have_saved_bkgd_index)
2595 background.index=mng_info->saved_bkgd_index;
2597 if (png_get_valid(ping, ping_info, PNG_INFO_bKGD))
2598 background.index=ping_background->index;
2600 background.red=(png_uint_16)
2601 mng_info->global_plte[background.index].red;
2603 background.green=(png_uint_16)
2604 mng_info->global_plte[background.index].green;
2606 background.blue=(png_uint_16)
2607 mng_info->global_plte[background.index].blue;
2609 background.gray=(png_uint_16)
2610 mng_info->global_plte[background.index].green;
2612 png_set_bKGD(ping,ping_info,&background);
2617 png_error(ping,"No global PLTE in file");
2621 #ifdef PNG_READ_bKGD_SUPPORTED
2622 if (mng_info->have_global_bkgd &&
2623 (!png_get_valid(ping,ping_info,PNG_INFO_bKGD)))
2624 image->background_color=mng_info->mng_global_bkgd;
2626 if (png_get_valid(ping,ping_info,PNG_INFO_bKGD))
2632 Set image background color.
2634 if (logging != MagickFalse)
2635 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2636 " Reading PNG bKGD chunk.");
2638 /* Scale background components to 16-bit, then scale
2641 if (logging != MagickFalse)
2642 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2643 " raw ping_background=(%d,%d,%d).",ping_background->red,
2644 ping_background->green,ping_background->blue);
2648 if (ping_bit_depth == 1)
2651 else if (ping_bit_depth == 2)
2654 else if (ping_bit_depth == 4)
2657 if (ping_bit_depth <= 8)
2660 ping_background->red *= bkgd_scale;
2661 ping_background->green *= bkgd_scale;
2662 ping_background->blue *= bkgd_scale;
2664 if (logging != MagickFalse)
2666 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2667 " bkgd_scale=%d.",bkgd_scale);
2669 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2670 " ping_background=(%d,%d,%d).",ping_background->red,
2671 ping_background->green,ping_background->blue);
2674 image->background_color.red=
2675 ScaleShortToQuantum(ping_background->red);
2677 image->background_color.green=
2678 ScaleShortToQuantum(ping_background->green);
2680 image->background_color.blue=
2681 ScaleShortToQuantum(ping_background->blue);
2683 image->background_color.alpha=OpaqueAlpha;
2685 if (logging != MagickFalse)
2686 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2687 " image->background_color=(%.20g,%.20g,%.20g).",
2688 (double) image->background_color.red,
2689 (double) image->background_color.green,
2690 (double) image->background_color.blue);
2692 #endif /* PNG_READ_bKGD_SUPPORTED */
2694 if (png_get_valid(ping,ping_info,PNG_INFO_tRNS))
2697 Image has a tRNS chunk.
2705 if (logging != MagickFalse)
2706 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2707 " Reading PNG tRNS chunk.");
2709 max_sample = (int) ((one << ping_bit_depth) - 1);
2711 if ((ping_color_type == PNG_COLOR_TYPE_GRAY &&
2712 (int)ping_trans_color->gray > max_sample) ||
2713 (ping_color_type == PNG_COLOR_TYPE_RGB &&
2714 ((int)ping_trans_color->red > max_sample ||
2715 (int)ping_trans_color->green > max_sample ||
2716 (int)ping_trans_color->blue > max_sample)))
2718 if (logging != MagickFalse)
2719 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2720 " Ignoring PNG tRNS chunk with out-of-range sample.");
2721 png_free_data(ping, ping_info, PNG_FREE_TRNS, 0);
2722 png_set_invalid(ping,ping_info,PNG_INFO_tRNS);
2723 image->matte=MagickFalse;
2730 scale_to_short = 65535L/((1UL << ping_bit_depth)-1);
2732 /* Scale transparent_color to short */
2733 transparent_color.red= scale_to_short*ping_trans_color->red;
2734 transparent_color.green= scale_to_short*ping_trans_color->green;
2735 transparent_color.blue= scale_to_short*ping_trans_color->blue;
2736 transparent_color.alpha= scale_to_short*ping_trans_color->gray;
2738 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
2740 if (logging != MagickFalse)
2742 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2743 " Raw tRNS graylevel is %d.",ping_trans_color->gray);
2745 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2746 " scaled graylevel is %.20g.",transparent_color.alpha);
2748 transparent_color.red=transparent_color.alpha;
2749 transparent_color.green=transparent_color.alpha;
2750 transparent_color.blue=transparent_color.alpha;
2754 #if defined(PNG_READ_sBIT_SUPPORTED)
2755 if (mng_info->have_global_sbit)
2757 if (!png_get_valid(ping,ping_info,PNG_INFO_sBIT))
2758 png_set_sBIT(ping,ping_info,&mng_info->global_sbit);
2761 num_passes=png_set_interlace_handling(ping);
2763 png_read_update_info(ping,ping_info);
2765 ping_rowbytes=png_get_rowbytes(ping,ping_info);
2768 Initialize image structure.
2770 mng_info->image_box.left=0;
2771 mng_info->image_box.right=(ssize_t) ping_width;
2772 mng_info->image_box.top=0;
2773 mng_info->image_box.bottom=(ssize_t) ping_height;
2774 if (mng_info->mng_type == 0)
2776 mng_info->mng_width=ping_width;
2777 mng_info->mng_height=ping_height;
2778 mng_info->frame=mng_info->image_box;
2779 mng_info->clip=mng_info->image_box;
2784 image->page.y=mng_info->y_off[mng_info->object_id];
2787 image->compression=ZipCompression;
2788 image->columns=ping_width;
2789 image->rows=ping_height;
2791 if (((int) ping_color_type == PNG_COLOR_TYPE_GRAY) ||
2792 ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA))
2794 if (!png_get_valid(ping,ping_info,PNG_INFO_gAMA) &&
2795 !png_get_valid(ping,ping_info,PNG_INFO_cHRM) &&
2796 !png_get_valid(ping,ping_info,PNG_INFO_sRGB))
2798 /* Set image->gamma to 1.0, image->rendering_intent to Undefined,
2799 * and reset image->chromaticity.
2801 SetImageColorspace(image,GRAYColorspace,exception);
2805 if (((int) ping_color_type == PNG_COLOR_TYPE_PALETTE) ||
2806 ((int) ping_color_type == PNG_COLOR_TYPE_GRAY))
2811 image->storage_class=PseudoClass;
2813 image->colors=one << ping_bit_depth;
2814 #if (MAGICKCORE_QUANTUM_DEPTH == 8)
2815 if (image->colors > 256)
2818 if (image->colors > 65536L)
2819 image->colors=65536L;
2821 if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
2826 (void) png_get_PLTE(ping,ping_info,&palette,&number_colors);
2827 image->colors=(size_t) number_colors;
2829 if (logging != MagickFalse)
2830 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2831 " Reading PNG PLTE chunk: number_colors: %d.",number_colors);
2835 if (image->storage_class == PseudoClass)
2838 Initialize image colormap.
2840 if (AcquireImageColormap(image,image->colors,exception) == MagickFalse)
2841 png_error(ping,"Memory allocation failed");
2843 if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
2848 (void) png_get_PLTE(ping,ping_info,&palette,&number_colors);
2850 for (i=0; i < (ssize_t) number_colors; i++)
2852 image->colormap[i].red=ScaleCharToQuantum(palette[i].red);
2853 image->colormap[i].green=ScaleCharToQuantum(palette[i].green);
2854 image->colormap[i].blue=ScaleCharToQuantum(palette[i].blue);
2857 for ( ; i < (ssize_t) image->colors; i++)
2859 image->colormap[i].red=0;
2860 image->colormap[i].green=0;
2861 image->colormap[i].blue=0;
2870 scale=(QuantumRange/((1UL << ping_bit_depth)-1));
2875 for (i=0; i < (ssize_t) image->colors; i++)
2877 image->colormap[i].red=(Quantum) (i*scale);
2878 image->colormap[i].green=(Quantum) (i*scale);
2879 image->colormap[i].blue=(Quantum) (i*scale);
2884 /* Set some properties for reporting by "identify" */
2889 /* encode ping_width, ping_height, ping_bit_depth, ping_color_type,
2890 ping_interlace_method in value */
2892 (void) FormatLocaleString(msg,MaxTextExtent,
2893 "%d, %d",(int) ping_width, (int) ping_height);
2894 (void) SetImageProperty(image,"png:IHDR.width,height ",msg,exception);
2896 (void) FormatLocaleString(msg,MaxTextExtent,"%d",(int) ping_bit_depth);
2897 (void) SetImageProperty(image,"png:IHDR.bit_depth ",msg,exception);
2899 (void) FormatLocaleString(msg,MaxTextExtent,"%d (%s)",
2900 (int) ping_color_type,
2901 Magick_ColorType_from_PNG_ColorType((int)ping_color_type));
2902 (void) SetImageProperty(image,"png:IHDR.color_type ",msg,exception);
2904 if (ping_interlace_method == 0)
2906 (void) FormatLocaleString(msg,MaxTextExtent,"%d (Not interlaced)",
2907 (int) ping_interlace_method);
2909 else if (ping_interlace_method == 1)
2911 (void) FormatLocaleString(msg,MaxTextExtent,"%d (Adam7 method)",
2912 (int) ping_interlace_method);
2916 (void) FormatLocaleString(msg,MaxTextExtent,"%d (Unknown method)",
2917 (int) ping_interlace_method);
2919 (void) SetImageProperty(image,"png:IHDR.interlace_method",msg,exception);
2921 if (number_colors != 0)
2923 (void) FormatLocaleString(msg,MaxTextExtent,"%d",
2924 (int) number_colors);
2925 (void) SetImageProperty(image,"png:PLTE.number_colors ",msg,
2931 Read image scanlines.
2933 if (image->delay != 0)
2934 mng_info->scenes_found++;
2936 if ((mng_info->mng_type == 0 && (image->ping != MagickFalse)) || (
2937 (image_info->number_scenes != 0) && (mng_info->scenes_found > (ssize_t)
2938 (image_info->first_scene+image_info->number_scenes))))
2940 /* This happens later in non-ping decodes */
2941 if (png_get_valid(ping,ping_info,PNG_INFO_tRNS))
2942 image->storage_class=DirectClass;
2944 if (logging != MagickFalse)
2945 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2946 " Skipping PNG image data for scene %.20g",(double)
2947 mng_info->scenes_found-1);
2948 png_destroy_read_struct(&ping,&ping_info,&end_info);
2950 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
2951 UnlockSemaphoreInfo(ping_semaphore);
2954 if (logging != MagickFalse)
2955 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2956 " exit ReadOnePNGImage().");
2961 if (logging != MagickFalse)
2962 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2963 " Reading PNG IDAT chunk(s)");
2966 ping_pixels=(unsigned char *) AcquireQuantumMemory(image->rows,
2967 ping_rowbytes*sizeof(*ping_pixels));
2970 ping_pixels=(unsigned char *) AcquireQuantumMemory(ping_rowbytes,
2971 sizeof(*ping_pixels));
2973 if (ping_pixels == (unsigned char *) NULL)
2974 png_error(ping,"Memory allocation failed");
2976 if (logging != MagickFalse)
2977 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2978 " Converting PNG pixels to pixel packets");
2980 Convert PNG pixels to pixel packets.
2982 quantum_info=AcquireQuantumInfo(image_info,image);
2984 if (quantum_info == (QuantumInfo *) NULL)
2985 png_error(ping,"Failed to allocate quantum_info");
2990 found_transparent_pixel;
2992 found_transparent_pixel=MagickFalse;
2994 if (image->storage_class == DirectClass)
2996 for (pass=0; pass < num_passes; pass++)
2999 Convert image to DirectClass pixel packets.
3001 #if (MAGICKCORE_QUANTUM_DEPTH == 8)
3005 depth=(ssize_t) ping_bit_depth;
3007 image->matte=(((int) ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA) ||
3008 ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) ||
3009 (png_get_valid(ping,ping_info,PNG_INFO_tRNS))) ?
3010 MagickTrue : MagickFalse;
3012 for (y=0; y < (ssize_t) image->rows; y++)
3015 row_offset=ping_rowbytes*y;
3020 png_read_row(ping,ping_pixels+row_offset,NULL);
3021 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
3023 if (q == (Quantum *) NULL)
3026 if ((int) ping_color_type == PNG_COLOR_TYPE_GRAY)
3027 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
3028 GrayQuantum,ping_pixels+row_offset,exception);
3030 else if ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
3031 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
3032 GrayAlphaQuantum,ping_pixels+row_offset,exception);
3034 else if ((int) ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA)
3035 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
3036 RGBAQuantum,ping_pixels+row_offset,exception);
3038 else if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
3039 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
3040 IndexQuantum,ping_pixels+row_offset,exception);
3042 else /* ping_color_type == PNG_COLOR_TYPE_RGB */
3043 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
3044 RGBQuantum,ping_pixels+row_offset,exception);
3046 if (found_transparent_pixel == MagickFalse)
3048 /* Is there a transparent pixel in the row? */
3049 if (y== 0 && logging != MagickFalse)
3050 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3051 " Looking for cheap transparent pixel");
3053 for (x=(ssize_t) image->columns-1; x >= 0; x--)
3055 if ((ping_color_type == PNG_COLOR_TYPE_RGBA ||
3056 ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) &&
3057 (GetPixelAlpha(image,q) != OpaqueAlpha))
3059 if (logging != MagickFalse)
3060 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3063 found_transparent_pixel = MagickTrue;
3066 if ((ping_color_type == PNG_COLOR_TYPE_RGB ||
3067 ping_color_type == PNG_COLOR_TYPE_GRAY) &&
3068 (ScaleQuantumToShort(GetPixelRed(image,q)) ==
3069 transparent_color.red &&
3070 ScaleQuantumToShort(GetPixelGreen(image,q)) ==
3071 transparent_color.green &&
3072 ScaleQuantumToShort(GetPixelBlue(image,q)) ==
3073 transparent_color.blue))
3075 if (logging != MagickFalse)
3076 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3078 found_transparent_pixel = MagickTrue;
3081 q+=GetPixelChannels(image);
3085 if ((image->previous == (Image *) NULL) && (num_passes == 1))
3087 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
3090 if (status == MagickFalse)
3093 if (SyncAuthenticPixels(image,exception) == MagickFalse)
3097 if ((image->previous == (Image *) NULL) && (num_passes != 1))
3099 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
3100 if (status == MagickFalse)
3106 else /* image->storage_class != DirectClass */
3108 for (pass=0; pass < num_passes; pass++)
3117 Convert grayscale image to PseudoClass pixel packets.
3119 if (logging != MagickFalse)
3120 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3121 " Converting grayscale pixels to pixel packets");
3123 image->matte=ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA ?
3124 MagickTrue : MagickFalse;
3126 quantum_scanline=(Quantum *) AcquireQuantumMemory(image->columns,
3127 (image->matte ? 2 : 1)*sizeof(*quantum_scanline));
3129 if (quantum_scanline == (Quantum *) NULL)
3130 png_error(ping,"Memory allocation failed");
3132 for (y=0; y < (ssize_t) image->rows; y++)
3135 row_offset=ping_rowbytes*y;
3140 png_read_row(ping,ping_pixels+row_offset,NULL);
3141 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
3143 if (q == (Quantum *) NULL)
3146 p=ping_pixels+row_offset;
3149 switch (ping_bit_depth)
3156 for (x=(ssize_t) image->columns-7; x > 0; x-=8)
3158 for (bit=7; bit >= 0; bit--)
3159 *r++=(Quantum) ((*p) & (0x01 << bit) ? 0x01 : 0x00);
3163 if ((image->columns % 8) != 0)
3165 for (bit=7; bit >= (ssize_t) (8-(image->columns % 8)); bit--)
3166 *r++=(Quantum) ((*p) & (0x01 << bit) ? 0x01 : 0x00);
3174 for (x=(ssize_t) image->columns-3; x > 0; x-=4)
3176 *r++=(*p >> 6) & 0x03;
3177 *r++=(*p >> 4) & 0x03;
3178 *r++=(*p >> 2) & 0x03;
3182 if ((image->columns % 4) != 0)
3184 for (i=3; i >= (ssize_t) (4-(image->columns % 4)); i--)
3185 *r++=(Quantum) ((*p >> (i*2)) & 0x03);
3193 for (x=(ssize_t) image->columns-1; x > 0; x-=2)
3195 *r++=(*p >> 4) & 0x0f;
3199 if ((image->columns % 2) != 0)
3200 *r++=(*p++ >> 4) & 0x0f;
3207 if (ping_color_type == 4)
3208 for (x=(ssize_t) image->columns-1; x >= 0; x--)
3211 SetPixelAlpha(image,ScaleCharToQuantum((unsigned char) *p++),q);
3212 if (GetPixelAlpha(image,q) != OpaqueAlpha)
3213 found_transparent_pixel = MagickTrue;
3214 q+=GetPixelChannels(image);
3218 for (x=(ssize_t) image->columns-1; x >= 0; x--)
3226 for (x=(ssize_t) image->columns-1; x >= 0; x--)
3228 #if (MAGICKCORE_QUANTUM_DEPTH == 16) || (MAGICKCORE_QUANTUM_DEPTH == 32)
3232 if (image->colors > 256)
3233 quantum=((*p++) << 8);
3239 *r=ScaleShortToQuantum(quantum);
3242 if (ping_color_type == 4)
3244 if (image->colors > 256)
3245 quantum=((*p++) << 8);
3250 SetPixelAlpha(image,ScaleShortToQuantum(quantum),q);
3251 if (GetPixelAlpha(image,q) != OpaqueAlpha)
3252 found_transparent_pixel = MagickTrue;
3253 q+=GetPixelChannels(image);
3256 #else /* MAGICKCORE_QUANTUM_DEPTH == 8 */
3258 p++; /* strip low byte */
3260 if (ping_color_type == 4)
3262 SetPixelAlpha(image,*p++,q);
3263 if (GetPixelAlpha(image,q) != OpaqueAlpha)
3264 found_transparent_pixel = MagickTrue;
3266 q+=GetPixelChannels(image);
3279 Transfer image scanline.
3283 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
3285 if (q == (Quantum *) NULL)
3287 for (x=0; x < (ssize_t) image->columns; x++)
3289 SetPixelIndex(image,*r++,q);
3290 q+=GetPixelChannels(image);
3293 if (SyncAuthenticPixels(image,exception) == MagickFalse)
3296 if ((image->previous == (Image *) NULL) && (num_passes == 1))
3298 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
3301 if (status == MagickFalse)
3306 if ((image->previous == (Image *) NULL) && (num_passes != 1))
3308 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
3310 if (status == MagickFalse)
3314 quantum_scanline=(Quantum *) RelinquishMagickMemory(quantum_scanline);
3317 image->matte=found_transparent_pixel;
3319 if (logging != MagickFalse)
3321 if (found_transparent_pixel != MagickFalse)
3322 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3323 " Found transparent pixel");
3326 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3327 " No transparent pixel was found");
3329 ping_color_type&=0x03;
3334 if (quantum_info != (QuantumInfo *) NULL)
3335 quantum_info=DestroyQuantumInfo(quantum_info);
3337 if (image->storage_class == PseudoClass)
3343 image->matte=MagickFalse;
3344 (void) SyncImage(image,exception);
3348 png_read_end(ping,end_info);
3350 if (image_info->number_scenes != 0 && mng_info->scenes_found-1 <
3351 (ssize_t) image_info->first_scene && image->delay != 0)
3353 png_destroy_read_struct(&ping,&ping_info,&end_info);
3354 ping_pixels=(unsigned char *) RelinquishMagickMemory(ping_pixels);
3356 (void) SetImageBackgroundColor(image,exception);
3357 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
3358 UnlockSemaphoreInfo(ping_semaphore);
3360 if (logging != MagickFalse)
3361 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3362 " exit ReadOnePNGImage() early.");
3366 if (png_get_valid(ping,ping_info,PNG_INFO_tRNS))
3372 Image has a transparent background.
3374 storage_class=image->storage_class;
3375 image->matte=MagickTrue;
3377 /* Balfour fix from imagemagick discourse server, 5 Feb 2010 */
3379 if (storage_class == PseudoClass)
3381 if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
3383 for (x=0; x < ping_num_trans; x++)
3385 image->colormap[x].matte=MagickTrue;
3386 image->colormap[x].alpha =
3387 ScaleCharToQuantum((unsigned char)ping_trans_alpha[x]);
3391 else if (ping_color_type == PNG_COLOR_TYPE_GRAY)
3393 for (x=0; x < (int) image->colors; x++)
3395 if (ScaleQuantumToShort(image->colormap[x].red) ==
3396 transparent_color.alpha)
3398 image->colormap[x].matte=MagickTrue;
3399 image->colormap[x].alpha = (Quantum) TransparentAlpha;
3403 (void) SyncImage(image,exception);
3406 #if 1 /* Should have already been done above, but glennrp problem P10
3411 for (y=0; y < (ssize_t) image->rows; y++)
3413 image->storage_class=storage_class;
3414 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
3416 if (q == (Quantum *) NULL)
3420 /* Caution: on a Q8 build, this does not distinguish between
3421 * 16-bit colors that differ only in the low byte
3423 for (x=(ssize_t) image->columns-1; x >= 0; x--)
3425 if (ScaleQuantumToShort(GetPixelRed(image,q)) ==
3426 transparent_color.red &&
3427 ScaleQuantumToShort(GetPixelGreen(image,q)) ==
3428 transparent_color.green &&
3429 ScaleQuantumToShort(GetPixelBlue(image,q)) ==
3430 transparent_color.blue)
3432 SetPixelAlpha(image,TransparentAlpha,q);
3435 #if 0 /* I have not found a case where this is needed. */
3438 SetPixelAlpha(image,q)=(Quantum) OpaqueAlpha;
3442 q+=GetPixelChannels(image);
3445 if (SyncAuthenticPixels(image,exception) == MagickFalse)
3451 image->storage_class=DirectClass;
3454 for (j = 0; j < 2; j++)
3457 status = png_get_text(ping,ping_info,&text,&num_text) != 0 ?
3458 MagickTrue : MagickFalse;
3460 status = png_get_text(ping,end_info,&text,&num_text) != 0 ?
3461 MagickTrue : MagickFalse;
3463 if (status != MagickFalse)
3464 for (i=0; i < (ssize_t) num_text; i++)
3466 /* Check for a profile */
3468 if (logging != MagickFalse)
3469 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3470 " Reading PNG text chunk");
3472 if (memcmp(text[i].key, "Raw profile type ",17) == 0)
3474 (void) Magick_png_read_raw_profile(ping,image,image_info,text,
3484 length=text[i].text_length;
3485 value=(char *) AcquireQuantumMemory(length+MaxTextExtent,
3487 if (value == (char *) NULL)
3489 png_error(ping,"Memory allocation failed");
3493 (void) ConcatenateMagickString(value,text[i].text,length+2);
3495 /* Don't save "density" or "units" property if we have a pHYs
3498 if (!png_get_valid(ping,ping_info,PNG_INFO_pHYs) ||
3499 (LocaleCompare(text[i].key,"density") != 0 &&
3500 LocaleCompare(text[i].key,"units") != 0))
3501 (void) SetImageProperty(image,text[i].key,value,exception);
3503 if (logging != MagickFalse)
3505 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3506 " length: %lu",(unsigned long) length);
3507 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3508 " Keyword: %s",text[i].key);
3511 value=DestroyString(value);
3514 num_text_total += num_text;
3517 #ifdef MNG_OBJECT_BUFFERS
3519 Store the object if necessary.
3521 if (object_id && !mng_info->frozen[object_id])
3523 if (mng_info->ob[object_id] == (MngBuffer *) NULL)
3526 create a new object buffer.
3528 mng_info->ob[object_id]=(MngBuffer *)
3529 AcquireMagickMemory(sizeof(MngBuffer));
3531 if (mng_info->ob[object_id] != (MngBuffer *) NULL)
3533 mng_info->ob[object_id]->image=(Image *) NULL;
3534 mng_info->ob[object_id]->reference_count=1;
3538 if ((mng_info->ob[object_id] == (MngBuffer *) NULL) ||
3539 mng_info->ob[object_id]->frozen)
3541 if (mng_info->ob[object_id] == (MngBuffer *) NULL)
3542 png_error(ping,"Memory allocation failed");
3544 if (mng_info->ob[object_id]->frozen)
3545 png_error(ping,"Cannot overwrite frozen MNG object buffer");
3551 if (mng_info->ob[object_id]->image != (Image *) NULL)
3552 mng_info->ob[object_id]->image=DestroyImage
3553 (mng_info->ob[object_id]->image);
3555 mng_info->ob[object_id]->image=CloneImage(image,0,0,MagickTrue,
3558 if (mng_info->ob[object_id]->image != (Image *) NULL)
3559 mng_info->ob[object_id]->image->file=(FILE *) NULL;
3562 png_error(ping, "Cloning image for object buffer failed");
3564 if (ping_width > 250000L || ping_height > 250000L)
3565 png_error(ping,"PNG Image dimensions are too large.");
3567 mng_info->ob[object_id]->width=ping_width;
3568 mng_info->ob[object_id]->height=ping_height;
3569 mng_info->ob[object_id]->color_type=ping_color_type;
3570 mng_info->ob[object_id]->sample_depth=ping_bit_depth;
3571 mng_info->ob[object_id]->interlace_method=ping_interlace_method;
3572 mng_info->ob[object_id]->compression_method=
3573 ping_compression_method;
3574 mng_info->ob[object_id]->filter_method=ping_filter_method;
3576 if (png_get_valid(ping,ping_info,PNG_INFO_PLTE))
3582 Copy the PLTE to the object buffer.
3584 png_get_PLTE(ping,ping_info,&plte,&number_colors);
3585 mng_info->ob[object_id]->plte_length=number_colors;
3587 for (i=0; i < number_colors; i++)
3589 mng_info->ob[object_id]->plte[i]=plte[i];
3594 mng_info->ob[object_id]->plte_length=0;
3599 /* Set image->matte to MagickTrue if the input colortype supports
3600 * alpha or if a valid tRNS chunk is present, no matter whether there
3601 * is actual transparency present.
3603 image->matte=(((int) ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA) ||
3604 ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) ||
3605 (png_get_valid(ping,ping_info,PNG_INFO_tRNS))) ?
3606 MagickTrue : MagickFalse;
3608 /* Set more properties for identify to retrieve */
3613 if (num_text_total != 0)
3615 /* libpng doesn't tell us whether they were tEXt, zTXt, or iTXt */
3616 (void) FormatLocaleString(msg,MaxTextExtent,
3617 "%d tEXt/zTXt/iTXt chunks were found", num_text_total);
3618 (void) SetImageProperty(image,"png:text ",msg,
3622 if (num_raw_profiles != 0)
3624 (void) FormatLocaleString(msg,MaxTextExtent,
3625 "%d were found", num_raw_profiles);
3626 (void) SetImageProperty(image,"png:text-encoded profiles",msg,
3630 if (ping_found_cHRM != MagickFalse)
3632 (void) FormatLocaleString(msg,MaxTextExtent,"%s",
3633 "chunk was found (see Chromaticity, above)");
3634 (void) SetImageProperty(image,"png:cHRM ",msg,
3638 if (png_get_valid(ping,ping_info,PNG_INFO_bKGD))
3640 (void) FormatLocaleString(msg,MaxTextExtent,"%s",
3641 "chunk was found (see Background color, above)");
3642 (void) SetImageProperty(image,"png:bKGD ",msg,
3646 (void) FormatLocaleString(msg,MaxTextExtent,"%s",
3649 #if defined(PNG_iCCP_SUPPORTED)
3650 if (ping_found_iCCP != MagickFalse)
3651 (void) SetImageProperty(image,"png:iCCP ",msg,
3655 if (png_get_valid(ping,ping_info,PNG_INFO_tRNS))
3656 (void) SetImageProperty(image,"png:tRNS ",msg,
3659 #if defined(PNG_sRGB_SUPPORTED)
3660 if (ping_found_sRGB != MagickFalse)
3662 (void) FormatLocaleString(msg,MaxTextExtent,
3665 Magick_RenderingIntentString_from_PNG_RenderingIntent(intent));
3666 (void) SetImageProperty(image,"png:sRGB ",msg,
3671 if (ping_found_gAMA != MagickFalse)
3673 (void) FormatLocaleString(msg,MaxTextExtent,
3674 "gamma=%.8g (See Gamma, above)",
3676 (void) SetImageProperty(image,"png:gAMA ",msg,
3680 #if defined(PNG_pHYs_SUPPORTED)
3681 if (png_get_valid(ping,ping_info,PNG_INFO_pHYs))
3683 (void) FormatLocaleString(msg,MaxTextExtent,
3684 "x_res=%.10g, y_res=%.10g, units=%d",
3685 (double) x_resolution,(double) y_resolution, unit_type);
3686 (void) SetImageProperty(image,"png:pHYs ",msg,
3691 #if defined(PNG_oFFs_SUPPORTED)
3692 if (png_get_valid(ping,ping_info,PNG_INFO_oFFs))
3694 (void) FormatLocaleString(msg,MaxTextExtent,"x_off=%.20g, y_off=%.20g",
3695 (double) image->page.x,(double) image->page.y);
3696 (void) SetImageProperty(image,"png:oFFs ",msg,
3701 if ((image->page.width != 0 && image->page.width != image->columns) ||
3702 (image->page.height != 0 && image->page.height != image->rows))
3704 (void) FormatLocaleString(msg,MaxTextExtent,
3705 "width=%.20g, height=%.20g",
3706 (double) image->page.width,(double) image->page.height);
3707 (void) SetImageProperty(image,"png:vpAg ",msg,
3713 Relinquish resources.
3715 png_destroy_read_struct(&ping,&ping_info,&end_info);
3717 ping_pixels=(unsigned char *) RelinquishMagickMemory(ping_pixels);
3719 if (logging != MagickFalse)
3720 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3721 " exit ReadOnePNGImage()");
3723 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
3724 UnlockSemaphoreInfo(ping_semaphore);
3727 /* } for navigation to beginning of SETJMP-protected block, revert to
3728 * Throwing an Exception when an error occurs.
3733 /* end of reading one PNG image */
3736 static Image *ReadPNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
3751 magic_number[MaxTextExtent];
3759 assert(image_info != (const ImageInfo *) NULL);
3760 assert(image_info->signature == MagickSignature);
3762 if (image_info->debug != MagickFalse)
3763 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
3764 image_info->filename);
3766 assert(exception != (ExceptionInfo *) NULL);
3767 assert(exception->signature == MagickSignature);
3768 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter ReadPNGImage()");
3769 image=AcquireImage(image_info,exception);
3770 mng_info=(MngInfo *) NULL;
3771 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
3773 if (status == MagickFalse)
3774 ThrowReaderException(FileOpenError,"UnableToOpenFile");
3777 Verify PNG signature.
3779 count=ReadBlob(image,8,(unsigned char *) magic_number);
3781 if (count < 8 || memcmp(magic_number,"\211PNG\r\n\032\n",8) != 0)
3782 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
3785 Allocate a MngInfo structure.
3787 have_mng_structure=MagickFalse;
3788 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
3790 if (mng_info == (MngInfo *) NULL)
3791 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
3794 Initialize members of the MngInfo structure.
3796 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
3797 mng_info->image=image;
3798 have_mng_structure=MagickTrue;
3801 image=ReadOnePNGImage(mng_info,image_info,exception);
3802 MngInfoFreeStruct(mng_info,&have_mng_structure);
3804 if (image == (Image *) NULL)
3806 if (previous != (Image *) NULL)
3808 if (previous->signature != MagickSignature)
3809 ThrowReaderException(CorruptImageError,"CorruptImage");
3811 (void) CloseBlob(previous);
3812 (void) DestroyImageList(previous);
3815 if (logging != MagickFalse)
3816 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3817 "exit ReadPNGImage() with error");
3819 return((Image *) NULL);
3822 (void) CloseBlob(image);
3824 if ((image->columns == 0) || (image->rows == 0))
3826 if (logging != MagickFalse)
3827 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3828 "exit ReadPNGImage() with error.");
3830 ThrowReaderException(CorruptImageError,"CorruptImage");
3833 if ((IssRGBColorspace(image->colorspace) != MagickFalse) &&
3834 (image->gamma == 1.0))
3835 SetImageColorspace(image,RGBColorspace,exception);
3837 if (LocaleCompare(image_info->magick,"PNG24") == 0)
3839 (void) SetImageType(image,TrueColorType,exception);
3840 image->matte=MagickFalse;
3843 if (LocaleCompare(image_info->magick,"PNG32") == 0)
3844 (void) SetImageType(image,TrueColorMatteType,exception);
3846 if (logging != MagickFalse)
3847 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3848 " page.w: %.20g, page.h: %.20g,page.x: %.20g, page.y: %.20g.",
3849 (double) image->page.width,(double) image->page.height,
3850 (double) image->page.x,(double) image->page.y);
3852 if (logging != MagickFalse)
3853 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit ReadPNGImage()");
3860 #if defined(JNG_SUPPORTED)
3862 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3866 % R e a d O n e J N G I m a g e %
3870 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3872 % ReadOneJNGImage() reads a JPEG Network Graphics (JNG) image file
3873 % (minus the 8-byte signature) and returns it. It allocates the memory
3874 % necessary for the new Image structure and returns a pointer to the new
3877 % JNG support written by Glenn Randers-Pehrson, glennrp@image...
3879 % The format of the ReadOneJNGImage method is:
3881 % Image *ReadOneJNGImage(MngInfo *mng_info, const ImageInfo *image_info,
3882 % ExceptionInfo *exception)
3884 % A description of each parameter follows:
3886 % o mng_info: Specifies a pointer to a MngInfo structure.
3888 % o image_info: the image info.
3890 % o exception: return any errors or warnings in this structure.
3893 static Image *ReadOneJNGImage(MngInfo *mng_info,
3894 const ImageInfo *image_info, ExceptionInfo *exception)
3921 jng_image_sample_depth,
3922 jng_image_compression_method,
3923 jng_image_interlace_method,
3924 jng_alpha_sample_depth,
3925 jng_alpha_compression_method,
3926 jng_alpha_filter_method,
3927 jng_alpha_interlace_method;
3929 register const Quantum
3939 register unsigned char
3950 jng_alpha_compression_method=0;
3951 jng_alpha_sample_depth=8;
3955 alpha_image=(Image *) NULL;
3956 color_image=(Image *) NULL;
3957 alpha_image_info=(ImageInfo *) NULL;
3958 color_image_info=(ImageInfo *) NULL;
3960 logging=LogMagickEvent(CoderEvent,GetMagickModule(),
3961 " Enter ReadOneJNGImage()");
3963 image=mng_info->image;
3965 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
3968 Allocate next image structure.
3970 if (logging != MagickFalse)
3971 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3972 " AcquireNextImage()");
3974 AcquireNextImage(image_info,image,exception);
3976 if (GetNextImageInList(image) == (Image *) NULL)
3977 return((Image *) NULL);
3979 image=SyncNextImageInList(image);
3981 mng_info->image=image;
3984 Signature bytes have already been read.
3987 read_JSEP=MagickFalse;
3988 reading_idat=MagickFalse;
3989 skip_to_iend=MagickFalse;
3993 type[MaxTextExtent];
4002 Read a new JNG chunk.
4004 status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
4005 2*GetBlobSize(image));
4007 if (status == MagickFalse)
4011 (void) ConcatenateMagickString(type,"errr",MaxTextExtent);
4012 length=ReadBlobMSBLong(image);
4013 count=(unsigned int) ReadBlob(image,4,(unsigned char *) type);
4015 if (logging != MagickFalse)
4016 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4017 " Reading JNG chunk type %c%c%c%c, length: %.20g",
4018 type[0],type[1],type[2],type[3],(double) length);
4020 if (length > PNG_UINT_31_MAX || count == 0)
4021 ThrowReaderException(CorruptImageError,"CorruptImage");
4024 chunk=(unsigned char *) NULL;
4028 chunk=(unsigned char *) AcquireQuantumMemory(length,sizeof(*chunk));
4030 if (chunk == (unsigned char *) NULL)
4031 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
4033 for (i=0; i < (ssize_t) length; i++)
4034 chunk[i]=(unsigned char) ReadBlobByte(image);
4039 (void) ReadBlobMSBLong(image); /* read crc word */
4044 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4049 if (memcmp(type,mng_JHDR,4) == 0)
4053 jng_width=(size_t) ((p[0] << 24) | (p[1] << 16) |
4054 (p[2] << 8) | p[3]);
4055 jng_height=(size_t) ((p[4] << 24) | (p[5] << 16) |
4056 (p[6] << 8) | p[7]);
4057 jng_color_type=p[8];
4058 jng_image_sample_depth=p[9];
4059 jng_image_compression_method=p[10];
4060 jng_image_interlace_method=p[11];
4062 image->interlace=jng_image_interlace_method != 0 ? PNGInterlace :
4065 jng_alpha_sample_depth=p[12];
4066 jng_alpha_compression_method=p[13];
4067 jng_alpha_filter_method=p[14];
4068 jng_alpha_interlace_method=p[15];
4070 if (logging != MagickFalse)
4072 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4073 " jng_width: %16lu",(unsigned long) jng_width);
4075 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4076 " jng_width: %16lu",(unsigned long) jng_height);
4078 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4079 " jng_color_type: %16d",jng_color_type);
4081 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4082 " jng_image_sample_depth: %3d",
4083 jng_image_sample_depth);
4085 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4086 " jng_image_compression_method:%3d",
4087 jng_image_compression_method);
4089 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4090 " jng_image_interlace_method: %3d",
4091 jng_image_interlace_method);
4093 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4094 " jng_alpha_sample_depth: %3d",
4095 jng_alpha_sample_depth);
4097 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4098 " jng_alpha_compression_method:%3d",
4099 jng_alpha_compression_method);
4101 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4102 " jng_alpha_filter_method: %3d",
4103 jng_alpha_filter_method);
4105 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4106 " jng_alpha_interlace_method: %3d",
4107 jng_alpha_interlace_method);
4112 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4118 if ((reading_idat == MagickFalse) && (read_JSEP == MagickFalse) &&
4119 ((memcmp(type,mng_JDAT,4) == 0) || (memcmp(type,mng_JdAA,4) == 0) ||
4120 (memcmp(type,mng_IDAT,4) == 0) || (memcmp(type,mng_JDAA,4) == 0)))
4123 o create color_image
4124 o open color_blob, attached to color_image
4125 o if (color type has alpha)
4126 open alpha_blob, attached to alpha_image
4129 color_image_info=(ImageInfo *)AcquireMagickMemory(sizeof(ImageInfo));
4131 if (color_image_info == (ImageInfo *) NULL)
4132 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
4134 GetImageInfo(color_image_info);
4135 color_image=AcquireImage(color_image_info,exception);
4137 if (color_image == (Image *) NULL)
4138 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
4140 if (logging != MagickFalse)
4141 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4142 " Creating color_blob.");
4144 (void) AcquireUniqueFilename(color_image->filename);
4145 status=OpenBlob(color_image_info,color_image,WriteBinaryBlobMode,
4148 if (status == MagickFalse)
4149 return((Image *) NULL);
4151 if ((image_info->ping == MagickFalse) && (jng_color_type >= 12))
4153 alpha_image_info=(ImageInfo *)
4154 AcquireMagickMemory(sizeof(ImageInfo));
4156 if (alpha_image_info == (ImageInfo *) NULL)
4157 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
4159 GetImageInfo(alpha_image_info);
4160 alpha_image=AcquireImage(alpha_image_info,exception);
4162 if (alpha_image == (Image *) NULL)
4164 alpha_image=DestroyImage(alpha_image);
4165 ThrowReaderException(ResourceLimitError,
4166 "MemoryAllocationFailed");
4169 if (logging != MagickFalse)
4170 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4171 " Creating alpha_blob.");
4173 (void) AcquireUniqueFilename(alpha_image->filename);
4174 status=OpenBlob(alpha_image_info,alpha_image,WriteBinaryBlobMode,
4177 if (status == MagickFalse)
4178 return((Image *) NULL);
4180 if (jng_alpha_compression_method == 0)
4185 if (logging != MagickFalse)
4186 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4187 " Writing IHDR chunk to alpha_blob.");
4189 (void) WriteBlob(alpha_image,8,(const unsigned char *)
4190 "\211PNG\r\n\032\n");
4192 (void) WriteBlobMSBULong(alpha_image,13L);
4193 PNGType(data,mng_IHDR);
4194 LogPNGChunk(logging,mng_IHDR,13L);
4195 PNGLong(data+4,jng_width);
4196 PNGLong(data+8,jng_height);
4197 data[12]=jng_alpha_sample_depth;
4198 data[13]=0; /* color_type gray */
4199 data[14]=0; /* compression method 0 */
4200 data[15]=0; /* filter_method 0 */
4201 data[16]=0; /* interlace_method 0 */
4202 (void) WriteBlob(alpha_image,17,data);
4203 (void) WriteBlobMSBULong(alpha_image,crc32(0,data,17));
4206 reading_idat=MagickTrue;
4209 if (memcmp(type,mng_JDAT,4) == 0)
4211 /* Copy chunk to color_image->blob */
4213 if (logging != MagickFalse)
4214 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4215 " Copying JDAT chunk data to color_blob.");
4217 (void) WriteBlob(color_image,length,chunk);
4220 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4225 if (memcmp(type,mng_IDAT,4) == 0)
4230 /* Copy IDAT header and chunk data to alpha_image->blob */
4232 if (image_info->ping == MagickFalse)
4234 if (logging != MagickFalse)
4235 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4236 " Copying IDAT chunk data to alpha_blob.");
4238 (void) WriteBlobMSBULong(alpha_image,(size_t) length);
4239 PNGType(data,mng_IDAT);
4240 LogPNGChunk(logging,mng_IDAT,length);
4241 (void) WriteBlob(alpha_image,4,data);
4242 (void) WriteBlob(alpha_image,length,chunk);
4243 (void) WriteBlobMSBULong(alpha_image,
4244 crc32(crc32(0,data,4),chunk,(uInt) length));
4248 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4253 if ((memcmp(type,mng_JDAA,4) == 0) || (memcmp(type,mng_JdAA,4) == 0))
4255 /* Copy chunk data to alpha_image->blob */
4257 if (image_info->ping == MagickFalse)
4259 if (logging != MagickFalse)
4260 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4261 " Copying JDAA chunk data to alpha_blob.");
4263 (void) WriteBlob(alpha_image,length,chunk);
4267 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4272 if (memcmp(type,mng_JSEP,4) == 0)
4274 read_JSEP=MagickTrue;
4277 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4282 if (memcmp(type,mng_bKGD,4) == 0)
4286 image->background_color.red=ScaleCharToQuantum(p[1]);
4287 image->background_color.green=image->background_color.red;
4288 image->background_color.blue=image->background_color.red;
4293 image->background_color.red=ScaleCharToQuantum(p[1]);
4294 image->background_color.green=ScaleCharToQuantum(p[3]);
4295 image->background_color.blue=ScaleCharToQuantum(p[5]);
4298 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4302 if (memcmp(type,mng_gAMA,4) == 0)
4305 image->gamma=((float) mng_get_long(p))*0.00001;
4307 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4311 if (memcmp(type,mng_cHRM,4) == 0)
4315 image->chromaticity.white_point.x=0.00001*mng_get_long(p);
4316 image->chromaticity.white_point.y=0.00001*mng_get_long(&p[4]);
4317 image->chromaticity.red_primary.x=0.00001*mng_get_long(&p[8]);
4318 image->chromaticity.red_primary.y=0.00001*mng_get_long(&p[12]);
4319 image->chromaticity.green_primary.x=0.00001*mng_get_long(&p[16]);
4320 image->chromaticity.green_primary.y=0.00001*mng_get_long(&p[20]);
4321 image->chromaticity.blue_primary.x=0.00001*mng_get_long(&p[24]);
4322 image->chromaticity.blue_primary.y=0.00001*mng_get_long(&p[28]);
4325 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4329 if (memcmp(type,mng_sRGB,4) == 0)
4333 image->rendering_intent=
4334 Magick_RenderingIntent_from_PNG_RenderingIntent(p[0]);
4335 image->gamma=1.000f/2.200f;
4336 image->chromaticity.red_primary.x=0.6400f;
4337 image->chromaticity.red_primary.y=0.3300f;
4338 image->chromaticity.green_primary.x=0.3000f;
4339 image->chromaticity.green_primary.y=0.6000f;
4340 image->chromaticity.blue_primary.x=0.1500f;
4341 image->chromaticity.blue_primary.y=0.0600f;
4342 image->chromaticity.white_point.x=0.3127f;
4343 image->chromaticity.white_point.y=0.3290f;
4346 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4350 if (memcmp(type,mng_oFFs,4) == 0)
4354 image->page.x=(ssize_t) mng_get_long(p);
4355 image->page.y=(ssize_t) mng_get_long(&p[4]);
4357 if ((int) p[8] != 0)
4359 image->page.x/=10000;
4360 image->page.y/=10000;
4365 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4370 if (memcmp(type,mng_pHYs,4) == 0)
4374 image->resolution.x=(double) mng_get_long(p);
4375 image->resolution.y=(double) mng_get_long(&p[4]);
4376 if ((int) p[8] == PNG_RESOLUTION_METER)
4378 image->units=PixelsPerCentimeterResolution;
4379 image->resolution.x=image->resolution.x/100.0f;
4380 image->resolution.y=image->resolution.y/100.0f;
4384 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4389 if (memcmp(type,mng_iCCP,4) == 0)
4393 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4400 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4402 if (memcmp(type,mng_IEND,4))
4412 Finish up reading image data:
4414 o read main image from color_blob.
4418 o if (color_type has alpha)
4419 if alpha_encoding is PNG
4420 read secondary image from alpha_blob via ReadPNG
4421 if alpha_encoding is JPEG
4422 read secondary image from alpha_blob via ReadJPEG
4426 o copy intensity of secondary image into
4427 alpha samples of main image.
4429 o destroy the secondary image.
4432 (void) CloseBlob(color_image);
4434 if (logging != MagickFalse)
4435 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4436 " Reading jng_image from color_blob.");
4438 (void) FormatLocaleString(color_image_info->filename,MaxTextExtent,"%s",
4439 color_image->filename);
4441 color_image_info->ping=MagickFalse; /* To do: avoid this */
4442 jng_image=ReadImage(color_image_info,exception);
4444 if (jng_image == (Image *) NULL)
4445 return((Image *) NULL);
4447 (void) RelinquishUniqueFileResource(color_image->filename);
4448 color_image=DestroyImage(color_image);
4449 color_image_info=DestroyImageInfo(color_image_info);
4451 if (jng_image == (Image *) NULL)
4452 return((Image *) NULL);
4454 if (logging != MagickFalse)
4455 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4456 " Copying jng_image pixels to main image.");
4458 image->rows=jng_height;
4459 image->columns=jng_width;
4461 for (y=0; y < (ssize_t) image->rows; y++)
4463 s=GetVirtualPixels(jng_image,0,y,image->columns,1,exception);
4464 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
4465 for (x=(ssize_t) image->columns; x != 0; x--)
4467 SetPixelRed(image,GetPixelRed(jng_image,s),q);
4468 SetPixelGreen(image,GetPixelGreen(jng_image,s),q);
4469 SetPixelBlue(image,GetPixelBlue(jng_image,s),q);
4470 q+=GetPixelChannels(image);
4471 s+=GetPixelChannels(jng_image);
4474 if (SyncAuthenticPixels(image,exception) == MagickFalse)
4478 jng_image=DestroyImage(jng_image);
4480 if (image_info->ping == MagickFalse)
4482 if (jng_color_type >= 12)
4484 if (jng_alpha_compression_method == 0)
4488 (void) WriteBlobMSBULong(alpha_image,0x00000000L);
4489 PNGType(data,mng_IEND);
4490 LogPNGChunk(logging,mng_IEND,0L);
4491 (void) WriteBlob(alpha_image,4,data);
4492 (void) WriteBlobMSBULong(alpha_image,crc32(0,data,4));
4495 (void) CloseBlob(alpha_image);
4497 if (logging != MagickFalse)
4498 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4499 " Reading alpha from alpha_blob.");
4501 (void) FormatLocaleString(alpha_image_info->filename,MaxTextExtent,
4502 "%s",alpha_image->filename);
4504 jng_image=ReadImage(alpha_image_info,exception);
4506 if (jng_image != (Image *) NULL)
4507 for (y=0; y < (ssize_t) image->rows; y++)
4509 s=GetVirtualPixels(jng_image,0,y,image->columns,1,
4511 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
4513 if (image->matte != MagickFalse)
4514 for (x=(ssize_t) image->columns; x != 0; x--)
4516 SetPixelAlpha(image,GetPixelRed(jng_image,s),q);
4517 q+=GetPixelChannels(image);
4518 s+=GetPixelChannels(jng_image);
4522 for (x=(ssize_t) image->columns; x != 0; x--)
4524 SetPixelAlpha(image,GetPixelRed(jng_image,s),q);
4525 if (GetPixelAlpha(image,q) != OpaqueAlpha)
4526 image->matte=MagickTrue;
4527 q+=GetPixelChannels(image);
4528 s+=GetPixelChannels(jng_image);
4531 if (SyncAuthenticPixels(image,exception) == MagickFalse)
4534 (void) RelinquishUniqueFileResource(alpha_image->filename);
4535 alpha_image=DestroyImage(alpha_image);
4536 alpha_image_info=DestroyImageInfo(alpha_image_info);
4537 if (jng_image != (Image *) NULL)
4538 jng_image=DestroyImage(jng_image);
4542 /* Read the JNG image. */
4544 if (mng_info->mng_type == 0)
4546 mng_info->mng_width=jng_width;
4547 mng_info->mng_height=jng_height;
4550 if (image->page.width == 0 && image->page.height == 0)
4552 image->page.width=jng_width;
4553 image->page.height=jng_height;
4556 if (image->page.x == 0 && image->page.y == 0)
4558 image->page.x=mng_info->x_off[mng_info->object_id];
4559 image->page.y=mng_info->y_off[mng_info->object_id];
4564 image->page.y=mng_info->y_off[mng_info->object_id];
4567 mng_info->image_found++;
4568 status=SetImageProgress(image,LoadImagesTag,2*TellBlob(image),
4569 2*GetBlobSize(image));
4571 if (logging != MagickFalse)
4572 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4573 " exit ReadOneJNGImage()");
4579 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4583 % R e a d J N G I m a g e %
4587 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4589 % ReadJNGImage() reads a JPEG Network Graphics (JNG) image file
4590 % (including the 8-byte signature) and returns it. It allocates the memory
4591 % necessary for the new Image structure and returns a pointer to the new
4594 % JNG support written by Glenn Randers-Pehrson, glennrp@image...
4596 % The format of the ReadJNGImage method is:
4598 % Image *ReadJNGImage(const ImageInfo *image_info, ExceptionInfo
4601 % A description of each parameter follows:
4603 % o image_info: the image info.
4605 % o exception: return any errors or warnings in this structure.
4609 static Image *ReadJNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
4624 magic_number[MaxTextExtent];
4632 assert(image_info != (const ImageInfo *) NULL);
4633 assert(image_info->signature == MagickSignature);
4634 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image_info->filename);
4635 assert(exception != (ExceptionInfo *) NULL);
4636 assert(exception->signature == MagickSignature);
4637 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter ReadJNGImage()");
4638 image=AcquireImage(image_info,exception);
4639 mng_info=(MngInfo *) NULL;
4640 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
4642 if (status == MagickFalse)
4643 return((Image *) NULL);
4645 if (LocaleCompare(image_info->magick,"JNG") != 0)
4646 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
4648 /* Verify JNG signature. */
4650 count=(size_t) ReadBlob(image,8,(unsigned char *) magic_number);
4652 if (count < 8 || memcmp(magic_number,"\213JNG\r\n\032\n",8) != 0)
4653 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
4655 /* Allocate a MngInfo structure. */
4657 have_mng_structure=MagickFalse;
4658 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(*mng_info));
4660 if (mng_info == (MngInfo *) NULL)
4661 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
4663 /* Initialize members of the MngInfo structure. */
4665 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
4666 have_mng_structure=MagickTrue;
4668 mng_info->image=image;
4670 image=ReadOneJNGImage(mng_info,image_info,exception);
4671 MngInfoFreeStruct(mng_info,&have_mng_structure);
4673 if (image == (Image *) NULL)
4675 if (IsImageObject(previous) != MagickFalse)
4677 (void) CloseBlob(previous);
4678 (void) DestroyImageList(previous);
4681 if (logging != MagickFalse)
4682 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4683 "exit ReadJNGImage() with error");
4685 return((Image *) NULL);
4687 (void) CloseBlob(image);
4689 if (image->columns == 0 || image->rows == 0)
4691 if (logging != MagickFalse)
4692 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4693 "exit ReadJNGImage() with error");
4695 ThrowReaderException(CorruptImageError,"CorruptImage");
4698 if (logging != MagickFalse)
4699 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit ReadJNGImage()");
4705 static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
4708 page_geometry[MaxTextExtent];
4741 #if defined(MNG_INSERT_LAYERS)
4743 mng_background_color;
4746 register unsigned char
4761 #if defined(MNG_INSERT_LAYERS)
4766 volatile unsigned int
4767 #ifdef MNG_OBJECT_BUFFERS
4768 mng_background_object=0,
4770 mng_type=0; /* 0: PNG or JNG; 1: MNG; 2: MNG-LC; 3: MNG-VLC */
4773 default_frame_timeout,
4775 #if defined(MNG_INSERT_LAYERS)
4781 /* These delays are all measured in image ticks_per_second,
4782 * not in MNG ticks_per_second
4785 default_frame_delay,
4789 #if defined(MNG_INSERT_LAYERS)
4798 previous_fb.bottom=0;
4800 previous_fb.right=0;
4802 default_fb.bottom=0;
4806 /* Open image file. */
4808 assert(image_info != (const ImageInfo *) NULL);
4809 assert(image_info->signature == MagickSignature);
4810 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image_info->filename);
4811 assert(exception != (ExceptionInfo *) NULL);
4812 assert(exception->signature == MagickSignature);
4813 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter ReadMNGImage()");
4814 image=AcquireImage(image_info,exception);
4815 mng_info=(MngInfo *) NULL;
4816 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
4818 if (status == MagickFalse)
4819 return((Image *) NULL);
4821 first_mng_object=MagickFalse;
4823 have_mng_structure=MagickFalse;
4825 /* Allocate a MngInfo structure. */
4827 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
4829 if (mng_info == (MngInfo *) NULL)
4830 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
4832 /* Initialize members of the MngInfo structure. */
4834 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
4835 mng_info->image=image;
4836 have_mng_structure=MagickTrue;
4838 if (LocaleCompare(image_info->magick,"MNG") == 0)
4841 magic_number[MaxTextExtent];
4843 /* Verify MNG signature. */
4844 count=(size_t) ReadBlob(image,8,(unsigned char *) magic_number);
4845 if (memcmp(magic_number,"\212MNG\r\n\032\n",8) != 0)
4846 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
4848 /* Initialize some nonzero members of the MngInfo structure. */
4849 for (i=0; i < MNG_MAX_OBJECTS; i++)
4851 mng_info->object_clip[i].right=(ssize_t) PNG_UINT_31_MAX;
4852 mng_info->object_clip[i].bottom=(ssize_t) PNG_UINT_31_MAX;
4854 mng_info->exists[0]=MagickTrue;
4857 first_mng_object=MagickTrue;
4859 #if defined(MNG_INSERT_LAYERS)
4860 insert_layers=MagickFalse; /* should be False when converting or mogrifying */
4862 default_frame_delay=0;
4863 default_frame_timeout=0;
4866 mng_info->ticks_per_second=1UL*image->ticks_per_second;
4868 skip_to_iend=MagickFalse;
4869 term_chunk_found=MagickFalse;
4870 mng_info->framing_mode=1;
4871 #if defined(MNG_INSERT_LAYERS)
4872 mandatory_back=MagickFalse;
4874 #if defined(MNG_INSERT_LAYERS)
4875 mng_background_color=image->background_color;
4877 default_fb=mng_info->frame;
4878 previous_fb=mng_info->frame;
4882 type[MaxTextExtent];
4884 if (LocaleCompare(image_info->magick,"MNG") == 0)
4893 (void) ConcatenateMagickString(type,"errr",MaxTextExtent);
4894 length=ReadBlobMSBLong(image);
4895 count=(size_t) ReadBlob(image,4,(unsigned char *) type);
4897 if (logging != MagickFalse)
4898 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4899 " Reading MNG chunk type %c%c%c%c, length: %.20g",
4900 type[0],type[1],type[2],type[3],(double) length);
4902 if (length > PNG_UINT_31_MAX)
4906 ThrowReaderException(CorruptImageError,"CorruptImage");
4909 chunk=(unsigned char *) NULL;
4913 chunk=(unsigned char *) AcquireQuantumMemory(length,sizeof(*chunk));
4915 if (chunk == (unsigned char *) NULL)
4916 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
4918 for (i=0; i < (ssize_t) length; i++)
4919 chunk[i]=(unsigned char) ReadBlobByte(image);
4924 (void) ReadBlobMSBLong(image); /* read crc word */
4926 #if !defined(JNG_SUPPORTED)
4927 if (memcmp(type,mng_JHDR,4) == 0)
4929 skip_to_iend=MagickTrue;
4931 if (mng_info->jhdr_warning == 0)
4932 (void) ThrowMagickException(exception,GetMagickModule(),
4933 CoderError,"JNGCompressNotSupported","`%s'",image->filename);
4935 mng_info->jhdr_warning++;
4938 if (memcmp(type,mng_DHDR,4) == 0)
4940 skip_to_iend=MagickTrue;
4942 if (mng_info->dhdr_warning == 0)
4943 (void) ThrowMagickException(exception,GetMagickModule(),
4944 CoderError,"DeltaPNGNotSupported","`%s'",image->filename);
4946 mng_info->dhdr_warning++;
4948 if (memcmp(type,mng_MEND,4) == 0)
4953 if (memcmp(type,mng_IEND,4) == 0)
4954 skip_to_iend=MagickFalse;
4957 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4959 if (logging != MagickFalse)
4960 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4966 if (memcmp(type,mng_MHDR,4) == 0)
4968 mng_info->mng_width=(size_t) ((p[0] << 24) | (p[1] << 16) |
4969 (p[2] << 8) | p[3]);
4971 mng_info->mng_height=(size_t) ((p[4] << 24) | (p[5] << 16) |
4972 (p[6] << 8) | p[7]);
4974 if (logging != MagickFalse)
4976 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4977 " MNG width: %.20g",(double) mng_info->mng_width);
4978 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4979 " MNG height: %.20g",(double) mng_info->mng_height);
4983 mng_info->ticks_per_second=(size_t) mng_get_long(p);
4985 if (mng_info->ticks_per_second == 0)
4986 default_frame_delay=0;
4989 default_frame_delay=1UL*image->ticks_per_second/
4990 mng_info->ticks_per_second;
4992 frame_delay=default_frame_delay;
4998 simplicity=(size_t) mng_get_long(p);
5001 mng_type=1; /* Full MNG */
5003 if ((simplicity != 0) && ((simplicity | 11) == 11))
5004 mng_type=2; /* LC */
5006 if ((simplicity != 0) && ((simplicity | 9) == 9))
5007 mng_type=3; /* VLC */
5009 #if defined(MNG_INSERT_LAYERS)
5011 insert_layers=MagickTrue;
5013 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
5015 /* Allocate next image structure. */
5016 AcquireNextImage(image_info,image,exception);
5018 if (GetNextImageInList(image) == (Image *) NULL)
5019 return((Image *) NULL);
5021 image=SyncNextImageInList(image);
5022 mng_info->image=image;
5025 if ((mng_info->mng_width > 65535L) ||
5026 (mng_info->mng_height > 65535L))
5027 ThrowReaderException(ImageError,"WidthOrHeightExceedsLimit");
5029 (void) FormatLocaleString(page_geometry,MaxTextExtent,
5030 "%.20gx%.20g+0+0",(double) mng_info->mng_width,(double)
5031 mng_info->mng_height);
5033 mng_info->frame.left=0;
5034 mng_info->frame.right=(ssize_t) mng_info->mng_width;
5035 mng_info->frame.top=0;
5036 mng_info->frame.bottom=(ssize_t) mng_info->mng_height;
5037 mng_info->clip=default_fb=previous_fb=mng_info->frame;
5039 for (i=0; i < MNG_MAX_OBJECTS; i++)
5040 mng_info->object_clip[i]=mng_info->frame;
5042 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5046 if (memcmp(type,mng_TERM,4) == 0)
5057 final_delay=(png_uint_32) mng_get_long(&p[2]);
5058 mng_iterations=(png_uint_32) mng_get_long(&p[6]);
5060 if (mng_iterations == PNG_UINT_31_MAX)
5063 image->iterations=mng_iterations;
5064 term_chunk_found=MagickTrue;
5067 if (logging != MagickFalse)
5069 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5070 " repeat=%d",repeat);
5072 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5073 " final_delay=%.20g",(double) final_delay);
5075 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5076 " image->iterations=%.20g",(double) image->iterations);
5079 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5082 if (memcmp(type,mng_DEFI,4) == 0)
5085 (void) ThrowMagickException(exception,GetMagickModule(),
5086 CoderError,"DEFI chunk found in MNG-VLC datastream","`%s'",
5089 object_id=(p[0] << 8) | p[1];
5091 if (mng_type == 2 && object_id != 0)
5092 (void) ThrowMagickException(exception,GetMagickModule(),
5093 CoderError,"Nonzero object_id in MNG-LC datastream","`%s'",
5096 if (object_id > MNG_MAX_OBJECTS)
5099 Instead of using a warning we should allocate a larger
5100 MngInfo structure and continue.
5102 (void) ThrowMagickException(exception,GetMagickModule(),
5103 CoderError,"object id too large","`%s'",image->filename);
5104 object_id=MNG_MAX_OBJECTS;
5107 if (mng_info->exists[object_id])
5108 if (mng_info->frozen[object_id])
5110 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5111 (void) ThrowMagickException(exception,
5112 GetMagickModule(),CoderError,
5113 "DEFI cannot redefine a frozen MNG object","`%s'",
5118 mng_info->exists[object_id]=MagickTrue;
5121 mng_info->invisible[object_id]=p[2];
5124 Extract object offset info.
5128 mng_info->x_off[object_id]=(ssize_t) ((p[4] << 24) |
5129 (p[5] << 16) | (p[6] << 8) | p[7]);
5131 mng_info->y_off[object_id]=(ssize_t) ((p[8] << 24) |
5132 (p[9] << 16) | (p[10] << 8) | p[11]);
5134 if (logging != MagickFalse)
5136 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5137 " x_off[%d]: %.20g",object_id,(double)
5138 mng_info->x_off[object_id]);
5140 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5141 " y_off[%d]: %.20g",object_id,(double)
5142 mng_info->y_off[object_id]);
5147 Extract object clipping info.
5150 mng_info->object_clip[object_id]=mng_read_box(mng_info->frame,0,
5153 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5156 if (memcmp(type,mng_bKGD,4) == 0)
5158 mng_info->have_global_bkgd=MagickFalse;
5162 mng_info->mng_global_bkgd.red=
5163 ScaleShortToQuantum((unsigned short) ((p[0] << 8) | p[1]));
5165 mng_info->mng_global_bkgd.green=
5166 ScaleShortToQuantum((unsigned short) ((p[2] << 8) | p[3]));
5168 mng_info->mng_global_bkgd.blue=
5169 ScaleShortToQuantum((unsigned short) ((p[4] << 8) | p[5]));
5171 mng_info->have_global_bkgd=MagickTrue;
5174 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5177 if (memcmp(type,mng_BACK,4) == 0)
5179 #if defined(MNG_INSERT_LAYERS)
5181 mandatory_back=p[6];
5186 if (mandatory_back && length > 5)
5188 mng_background_color.red=
5189 ScaleShortToQuantum((unsigned short) ((p[0] << 8) | p[1]));
5191 mng_background_color.green=
5192 ScaleShortToQuantum((unsigned short) ((p[2] << 8) | p[3]));
5194 mng_background_color.blue=
5195 ScaleShortToQuantum((unsigned short) ((p[4] << 8) | p[5]));
5197 mng_background_color.alpha=OpaqueAlpha;
5200 #ifdef MNG_OBJECT_BUFFERS
5202 mng_background_object=(p[7] << 8) | p[8];
5205 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5209 if (memcmp(type,mng_PLTE,4) == 0)
5211 /* Read global PLTE. */
5213 if (length && (length < 769))
5215 if (mng_info->global_plte == (png_colorp) NULL)
5216 mng_info->global_plte=(png_colorp) AcquireQuantumMemory(256,
5217 sizeof(*mng_info->global_plte));
5219 for (i=0; i < (ssize_t) (length/3); i++)
5221 mng_info->global_plte[i].red=p[3*i];
5222 mng_info->global_plte[i].green=p[3*i+1];
5223 mng_info->global_plte[i].blue=p[3*i+2];
5226 mng_info->global_plte_length=(unsigned int) (length/3);
5229 for ( ; i < 256; i++)
5231 mng_info->global_plte[i].red=i;
5232 mng_info->global_plte[i].green=i;
5233 mng_info->global_plte[i].blue=i;
5237 mng_info->global_plte_length=256;
5240 mng_info->global_plte_length=0;
5242 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5246 if (memcmp(type,mng_tRNS,4) == 0)
5248 /* read global tRNS */
5251 for (i=0; i < (ssize_t) length; i++)
5252 mng_info->global_trns[i]=p[i];
5255 for ( ; i < 256; i++)
5256 mng_info->global_trns[i]=255;
5258 mng_info->global_trns_length=(unsigned int) length;
5259 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5262 if (memcmp(type,mng_gAMA,4) == 0)
5269 igamma=mng_get_long(p);
5270 mng_info->global_gamma=((float) igamma)*0.00001;
5271 mng_info->have_global_gama=MagickTrue;
5275 mng_info->have_global_gama=MagickFalse;
5277 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5281 if (memcmp(type,mng_cHRM,4) == 0)
5283 /* Read global cHRM */
5287 mng_info->global_chrm.white_point.x=0.00001*mng_get_long(p);
5288 mng_info->global_chrm.white_point.y=0.00001*mng_get_long(&p[4]);
5289 mng_info->global_chrm.red_primary.x=0.00001*mng_get_long(&p[8]);
5290 mng_info->global_chrm.red_primary.y=0.00001*
5291 mng_get_long(&p[12]);
5292 mng_info->global_chrm.green_primary.x=0.00001*
5293 mng_get_long(&p[16]);
5294 mng_info->global_chrm.green_primary.y=0.00001*
5295 mng_get_long(&p[20]);
5296 mng_info->global_chrm.blue_primary.x=0.00001*
5297 mng_get_long(&p[24]);
5298 mng_info->global_chrm.blue_primary.y=0.00001*
5299 mng_get_long(&p[28]);
5300 mng_info->have_global_chrm=MagickTrue;
5303 mng_info->have_global_chrm=MagickFalse;
5305 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5309 if (memcmp(type,mng_sRGB,4) == 0)
5316 mng_info->global_srgb_intent=
5317 Magick_RenderingIntent_from_PNG_RenderingIntent(p[0]);
5318 mng_info->have_global_srgb=MagickTrue;
5321 mng_info->have_global_srgb=MagickFalse;
5323 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5327 if (memcmp(type,mng_iCCP,4) == 0)
5335 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5340 if (memcmp(type,mng_FRAM,4) == 0)
5343 (void) ThrowMagickException(exception,GetMagickModule(),
5344 CoderError,"FRAM chunk found in MNG-VLC datastream","`%s'",
5347 if ((mng_info->framing_mode == 2) || (mng_info->framing_mode == 4))
5348 image->delay=frame_delay;
5350 frame_delay=default_frame_delay;
5351 frame_timeout=default_frame_timeout;
5356 mng_info->framing_mode=p[0];
5358 if (logging != MagickFalse)
5359 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5360 " Framing_mode=%d",mng_info->framing_mode);
5364 /* Note the delay and frame clipping boundaries. */
5366 p++; /* framing mode */
5368 while (*p && ((p-chunk) < (ssize_t) length))
5369 p++; /* frame name */
5371 p++; /* frame name terminator */
5373 if ((p-chunk) < (ssize_t) (length-4))
5380 change_delay=(*p++);
5381 change_timeout=(*p++);
5382 change_clipping=(*p++);
5383 p++; /* change_sync */
5387 frame_delay=1UL*image->ticks_per_second*
5390 if (mng_info->ticks_per_second != 0)
5391 frame_delay/=mng_info->ticks_per_second;
5394 frame_delay=PNG_UINT_31_MAX;
5396 if (change_delay == 2)
5397 default_frame_delay=frame_delay;
5401 if (logging != MagickFalse)
5402 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5403 " Framing_delay=%.20g",(double) frame_delay);
5408 frame_timeout=1UL*image->ticks_per_second*
5411 if (mng_info->ticks_per_second != 0)
5412 frame_timeout/=mng_info->ticks_per_second;
5415 frame_timeout=PNG_UINT_31_MAX;
5417 if (change_delay == 2)
5418 default_frame_timeout=frame_timeout;
5422 if (logging != MagickFalse)
5423 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5424 " Framing_timeout=%.20g",(double) frame_timeout);
5427 if (change_clipping)
5429 fb=mng_read_box(previous_fb,(char) p[0],&p[1]);
5433 if (logging != MagickFalse)
5434 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5435 " Frame_clip: L=%.20g R=%.20g T=%.20g B=%.20g",
5436 (double) fb.left,(double) fb.right,(double) fb.top,
5437 (double) fb.bottom);
5439 if (change_clipping == 2)
5445 mng_info->clip=mng_minimum_box(fb,mng_info->frame);
5447 subframe_width=(size_t) (mng_info->clip.right
5448 -mng_info->clip.left);
5450 subframe_height=(size_t) (mng_info->clip.bottom
5451 -mng_info->clip.top);
5453 Insert a background layer behind the frame if framing_mode is 4.
5455 #if defined(MNG_INSERT_LAYERS)
5456 if (logging != MagickFalse)
5457 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5458 " subframe_width=%.20g, subframe_height=%.20g",(double)
5459 subframe_width,(double) subframe_height);
5461 if (insert_layers && (mng_info->framing_mode == 4) &&
5462 (subframe_width) && (subframe_height))
5464 /* Allocate next image structure. */
5465 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
5467 AcquireNextImage(image_info,image,exception);
5469 if (GetNextImageInList(image) == (Image *) NULL)
5471 image=DestroyImageList(image);
5472 MngInfoFreeStruct(mng_info,&have_mng_structure);
5473 return((Image *) NULL);
5476 image=SyncNextImageInList(image);
5479 mng_info->image=image;
5481 if (term_chunk_found)
5483 image->start_loop=MagickTrue;
5484 image->iterations=mng_iterations;
5485 term_chunk_found=MagickFalse;
5489 image->start_loop=MagickFalse;
5491 image->columns=subframe_width;
5492 image->rows=subframe_height;
5493 image->page.width=subframe_width;
5494 image->page.height=subframe_height;
5495 image->page.x=mng_info->clip.left;
5496 image->page.y=mng_info->clip.top;
5497 image->background_color=mng_background_color;
5498 image->matte=MagickFalse;
5500 (void) SetImageBackgroundColor(image,exception);
5502 if (logging != MagickFalse)
5503 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5504 " Insert backgd layer, L=%.20g, R=%.20g T=%.20g, B=%.20g",
5505 (double) mng_info->clip.left,(double) mng_info->clip.right,
5506 (double) mng_info->clip.top,(double) mng_info->clip.bottom);
5509 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5512 if (memcmp(type,mng_CLIP,4) == 0)
5521 first_object=(p[0] << 8) | p[1];
5522 last_object=(p[2] << 8) | p[3];
5524 for (i=(int) first_object; i <= (int) last_object; i++)
5526 if (mng_info->exists[i] && !mng_info->frozen[i])
5531 box=mng_info->object_clip[i];
5532 mng_info->object_clip[i]=mng_read_box(box,(char) p[4],&p[5]);
5536 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5539 if (memcmp(type,mng_SAVE,4) == 0)
5541 for (i=1; i < MNG_MAX_OBJECTS; i++)
5542 if (mng_info->exists[i])
5544 mng_info->frozen[i]=MagickTrue;
5545 #ifdef MNG_OBJECT_BUFFERS
5546 if (mng_info->ob[i] != (MngBuffer *) NULL)
5547 mng_info->ob[i]->frozen=MagickTrue;
5552 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5557 if ((memcmp(type,mng_DISC,4) == 0) || (memcmp(type,mng_SEEK,4) == 0))
5559 /* Read DISC or SEEK. */
5561 if ((length == 0) || !memcmp(type,mng_SEEK,4))
5563 for (i=1; i < MNG_MAX_OBJECTS; i++)
5564 MngInfoDiscardObject(mng_info,i);
5572 for (j=0; j < (ssize_t) length; j+=2)
5574 i=p[j] << 8 | p[j+1];
5575 MngInfoDiscardObject(mng_info,i);
5580 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5585 if (memcmp(type,mng_MOVE,4) == 0)
5593 first_object=(p[0] << 8) | p[1];
5594 last_object=(p[2] << 8) | p[3];
5595 for (i=(ssize_t) first_object; i <= (ssize_t) last_object; i++)
5597 if (mng_info->exists[i] && !mng_info->frozen[i])
5605 old_pair.a=mng_info->x_off[i];
5606 old_pair.b=mng_info->y_off[i];
5607 new_pair=mng_read_pair(old_pair,(int) p[4],&p[5]);
5608 mng_info->x_off[i]=new_pair.a;
5609 mng_info->y_off[i]=new_pair.b;
5613 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5617 if (memcmp(type,mng_LOOP,4) == 0)
5619 ssize_t loop_iters=1;
5620 loop_level=chunk[0];
5621 mng_info->loop_active[loop_level]=1; /* mark loop active */
5623 /* Record starting point. */
5624 loop_iters=mng_get_long(&chunk[1]);
5626 if (logging != MagickFalse)
5627 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5628 " LOOP level %.20g has %.20g iterations ",(double) loop_level,
5629 (double) loop_iters);
5631 if (loop_iters == 0)
5632 skipping_loop=loop_level;
5636 mng_info->loop_jump[loop_level]=TellBlob(image);
5637 mng_info->loop_count[loop_level]=loop_iters;
5640 mng_info->loop_iteration[loop_level]=0;
5641 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5645 if (memcmp(type,mng_ENDL,4) == 0)
5647 loop_level=chunk[0];
5649 if (skipping_loop > 0)
5651 if (skipping_loop == loop_level)
5654 Found end of zero-iteration loop.
5657 mng_info->loop_active[loop_level]=0;
5663 if (mng_info->loop_active[loop_level] == 1)
5665 mng_info->loop_count[loop_level]--;
5666 mng_info->loop_iteration[loop_level]++;
5668 if (logging != MagickFalse)
5669 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5670 " ENDL: LOOP level %.20g has %.20g remaining iters ",
5671 (double) loop_level,(double)
5672 mng_info->loop_count[loop_level]);
5674 if (mng_info->loop_count[loop_level] != 0)
5676 offset=SeekBlob(image,mng_info->loop_jump[loop_level],
5680 ThrowReaderException(CorruptImageError,
5681 "ImproperImageHeader");
5692 mng_info->loop_active[loop_level]=0;
5694 for (i=0; i < loop_level; i++)
5695 if (mng_info->loop_active[i] == 1)
5696 last_level=(short) i;
5697 loop_level=last_level;
5702 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5706 if (memcmp(type,mng_CLON,4) == 0)
5708 if (mng_info->clon_warning == 0)
5709 (void) ThrowMagickException(exception,GetMagickModule(),
5710 CoderError,"CLON is not implemented yet","`%s'",
5713 mng_info->clon_warning++;
5716 if (memcmp(type,mng_MAGN,4) == 0)
5731 magn_first=(p[0] << 8) | p[1];
5737 magn_last=(p[2] << 8) | p[3];
5740 magn_last=magn_first;
5741 #ifndef MNG_OBJECT_BUFFERS
5742 if (magn_first || magn_last)
5743 if (mng_info->magn_warning == 0)
5745 (void) ThrowMagickException(exception,
5746 GetMagickModule(),CoderError,
5747 "MAGN is not implemented yet for nonzero objects",
5748 "`%s'",image->filename);
5750 mng_info->magn_warning++;
5760 magn_mx=(p[5] << 8) | p[6];
5769 magn_my=(p[7] << 8) | p[8];
5778 magn_ml=(p[9] << 8) | p[10];
5787 magn_mr=(p[11] << 8) | p[12];
5796 magn_mt=(p[13] << 8) | p[14];
5805 magn_mb=(p[15] << 8) | p[16];
5817 magn_methy=magn_methx;
5820 if (magn_methx > 5 || magn_methy > 5)
5821 if (mng_info->magn_warning == 0)
5823 (void) ThrowMagickException(exception,
5824 GetMagickModule(),CoderError,
5825 "Unknown MAGN method in MNG datastream","`%s'",
5828 mng_info->magn_warning++;
5830 #ifdef MNG_OBJECT_BUFFERS
5831 /* Magnify existing objects in the range magn_first to magn_last */
5833 if (magn_first == 0 || magn_last == 0)
5835 /* Save the magnification factors for object 0 */
5836 mng_info->magn_mb=magn_mb;
5837 mng_info->magn_ml=magn_ml;
5838 mng_info->magn_mr=magn_mr;
5839 mng_info->magn_mt=magn_mt;
5840 mng_info->magn_mx=magn_mx;
5841 mng_info->magn_my=magn_my;
5842 mng_info->magn_methx=magn_methx;
5843 mng_info->magn_methy=magn_methy;
5847 if (memcmp(type,mng_PAST,4) == 0)
5849 if (mng_info->past_warning == 0)
5850 (void) ThrowMagickException(exception,GetMagickModule(),
5851 CoderError,"PAST is not implemented yet","`%s'",
5854 mng_info->past_warning++;
5857 if (memcmp(type,mng_SHOW,4) == 0)
5859 if (mng_info->show_warning == 0)
5860 (void) ThrowMagickException(exception,GetMagickModule(),
5861 CoderError,"SHOW is not implemented yet","`%s'",
5864 mng_info->show_warning++;
5867 if (memcmp(type,mng_sBIT,4) == 0)
5870 mng_info->have_global_sbit=MagickFalse;
5874 mng_info->global_sbit.gray=p[0];
5875 mng_info->global_sbit.red=p[0];
5876 mng_info->global_sbit.green=p[1];
5877 mng_info->global_sbit.blue=p[2];
5878 mng_info->global_sbit.alpha=p[3];
5879 mng_info->have_global_sbit=MagickTrue;
5882 if (memcmp(type,mng_pHYs,4) == 0)
5886 mng_info->global_x_pixels_per_unit=
5887 (size_t) mng_get_long(p);
5888 mng_info->global_y_pixels_per_unit=
5889 (size_t) mng_get_long(&p[4]);
5890 mng_info->global_phys_unit_type=p[8];
5891 mng_info->have_global_phys=MagickTrue;
5895 mng_info->have_global_phys=MagickFalse;
5897 if (memcmp(type,mng_pHYg,4) == 0)
5899 if (mng_info->phyg_warning == 0)
5900 (void) ThrowMagickException(exception,GetMagickModule(),
5901 CoderError,"pHYg is not implemented.","`%s'",image->filename);
5903 mng_info->phyg_warning++;
5905 if (memcmp(type,mng_BASI,4) == 0)
5907 skip_to_iend=MagickTrue;
5909 if (mng_info->basi_warning == 0)
5910 (void) ThrowMagickException(exception,GetMagickModule(),
5911 CoderError,"BASI is not implemented yet","`%s'",
5914 mng_info->basi_warning++;
5915 #ifdef MNG_BASI_SUPPORTED
5916 basi_width=(size_t) ((p[0] << 24) | (p[1] << 16) |
5917 (p[2] << 8) | p[3]);
5918 basi_height=(size_t) ((p[4] << 24) | (p[5] << 16) |
5919 (p[6] << 8) | p[7]);
5920 basi_color_type=p[8];
5921 basi_compression_method=p[9];
5922 basi_filter_type=p[10];
5923 basi_interlace_method=p[11];
5925 basi_red=(p[12] << 8) & p[13];
5931 basi_green=(p[14] << 8) & p[15];
5937 basi_blue=(p[16] << 8) & p[17];
5943 basi_alpha=(p[18] << 8) & p[19];
5947 if (basi_sample_depth == 16)
5954 basi_viewable=p[20];
5960 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5964 if (memcmp(type,mng_IHDR,4)
5965 #if defined(JNG_SUPPORTED)
5966 && memcmp(type,mng_JHDR,4)
5970 /* Not an IHDR or JHDR chunk */
5972 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5977 if (logging != MagickFalse)
5978 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5979 " Processing %c%c%c%c chunk",type[0],type[1],type[2],type[3]);
5981 mng_info->exists[object_id]=MagickTrue;
5982 mng_info->viewable[object_id]=MagickTrue;
5984 if (mng_info->invisible[object_id])
5986 if (logging != MagickFalse)
5987 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5988 " Skipping invisible object");
5990 skip_to_iend=MagickTrue;
5991 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5994 #if defined(MNG_INSERT_LAYERS)
5996 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
5998 image_width=(size_t) mng_get_long(p);
5999 image_height=(size_t) mng_get_long(&p[4]);
6001 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
6004 Insert a transparent background layer behind the entire animation
6005 if it is not full screen.
6007 #if defined(MNG_INSERT_LAYERS)
6008 if (insert_layers && mng_type && first_mng_object)
6010 if ((mng_info->clip.left > 0) || (mng_info->clip.top > 0) ||
6011 (image_width < mng_info->mng_width) ||
6012 (mng_info->clip.right < (ssize_t) mng_info->mng_width) ||
6013 (image_height < mng_info->mng_height) ||
6014 (mng_info->clip.bottom < (ssize_t) mng_info->mng_height))
6016 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
6019 Allocate next image structure.
6021 AcquireNextImage(image_info,image,exception);
6023 if (GetNextImageInList(image) == (Image *) NULL)
6025 image=DestroyImageList(image);
6026 MngInfoFreeStruct(mng_info,&have_mng_structure);
6027 return((Image *) NULL);
6030 image=SyncNextImageInList(image);
6032 mng_info->image=image;
6034 if (term_chunk_found)
6036 image->start_loop=MagickTrue;
6037 image->iterations=mng_iterations;
6038 term_chunk_found=MagickFalse;
6042 image->start_loop=MagickFalse;
6044 /* Make a background rectangle. */
6047 image->columns=mng_info->mng_width;
6048 image->rows=mng_info->mng_height;
6049 image->page.width=mng_info->mng_width;
6050 image->page.height=mng_info->mng_height;
6053 image->background_color=mng_background_color;
6054 (void) SetImageBackgroundColor(image,exception);
6055 if (logging != MagickFalse)
6056 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6057 " Inserted transparent background layer, W=%.20g, H=%.20g",
6058 (double) mng_info->mng_width,(double) mng_info->mng_height);
6062 Insert a background layer behind the upcoming image if
6063 framing_mode is 3, and we haven't already inserted one.
6065 if (insert_layers && (mng_info->framing_mode == 3) &&
6066 (subframe_width) && (subframe_height) && (simplicity == 0 ||
6067 (simplicity & 0x08)))
6069 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
6072 Allocate next image structure.
6074 AcquireNextImage(image_info,image,exception);
6076 if (GetNextImageInList(image) == (Image *) NULL)
6078 image=DestroyImageList(image);
6079 MngInfoFreeStruct(mng_info,&have_mng_structure);
6080 return((Image *) NULL);
6083 image=SyncNextImageInList(image);
6086 mng_info->image=image;
6088 if (term_chunk_found)
6090 image->start_loop=MagickTrue;
6091 image->iterations=mng_iterations;
6092 term_chunk_found=MagickFalse;
6096 image->start_loop=MagickFalse;
6099 image->columns=subframe_width;
6100 image->rows=subframe_height;
6101 image->page.width=subframe_width;
6102 image->page.height=subframe_height;
6103 image->page.x=mng_info->clip.left;
6104 image->page.y=mng_info->clip.top;
6105 image->background_color=mng_background_color;
6106 image->matte=MagickFalse;
6107 (void) SetImageBackgroundColor(image,exception);
6109 if (logging != MagickFalse)
6110 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6111 " Insert background layer, L=%.20g, R=%.20g T=%.20g, B=%.20g",
6112 (double) mng_info->clip.left,(double) mng_info->clip.right,
6113 (double) mng_info->clip.top,(double) mng_info->clip.bottom);
6115 #endif /* MNG_INSERT_LAYERS */
6116 first_mng_object=MagickFalse;
6118 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
6121 Allocate next image structure.
6123 AcquireNextImage(image_info,image,exception);
6125 if (GetNextImageInList(image) == (Image *) NULL)
6127 image=DestroyImageList(image);
6128 MngInfoFreeStruct(mng_info,&have_mng_structure);
6129 return((Image *) NULL);
6132 image=SyncNextImageInList(image);
6134 mng_info->image=image;
6135 status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
6136 GetBlobSize(image));
6138 if (status == MagickFalse)
6141 if (term_chunk_found)
6143 image->start_loop=MagickTrue;
6144 term_chunk_found=MagickFalse;
6148 image->start_loop=MagickFalse;
6150 if (mng_info->framing_mode == 1 || mng_info->framing_mode == 3)
6152 image->delay=frame_delay;
6153 frame_delay=default_frame_delay;
6159 image->page.width=mng_info->mng_width;
6160 image->page.height=mng_info->mng_height;
6161 image->page.x=mng_info->x_off[object_id];
6162 image->page.y=mng_info->y_off[object_id];
6163 image->iterations=mng_iterations;
6166 Seek back to the beginning of the IHDR or JHDR chunk's length field.
6169 if (logging != MagickFalse)
6170 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6171 " Seeking back to beginning of %c%c%c%c chunk",type[0],type[1],
6174 offset=SeekBlob(image,-((ssize_t) length+12),SEEK_CUR);
6177 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
6181 mng_info->image=image;
6182 mng_info->mng_type=mng_type;
6183 mng_info->object_id=object_id;
6185 if (memcmp(type,mng_IHDR,4) == 0)
6186 image=ReadOnePNGImage(mng_info,image_info,exception);
6188 #if defined(JNG_SUPPORTED)
6190 image=ReadOneJNGImage(mng_info,image_info,exception);
6193 if (image == (Image *) NULL)
6195 if (IsImageObject(previous) != MagickFalse)
6197 (void) DestroyImageList(previous);
6198 (void) CloseBlob(previous);
6201 MngInfoFreeStruct(mng_info,&have_mng_structure);
6202 return((Image *) NULL);
6205 if (image->columns == 0 || image->rows == 0)
6207 (void) CloseBlob(image);
6208 image=DestroyImageList(image);
6209 MngInfoFreeStruct(mng_info,&have_mng_structure);
6210 return((Image *) NULL);
6213 mng_info->image=image;
6220 if (mng_info->magn_methx || mng_info->magn_methy)
6226 if (logging != MagickFalse)
6227 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6228 " Processing MNG MAGN chunk");
6230 if (mng_info->magn_methx == 1)
6232 magnified_width=mng_info->magn_ml;
6234 if (image->columns > 1)
6235 magnified_width += mng_info->magn_mr;
6237 if (image->columns > 2)
6238 magnified_width += (png_uint_32)
6239 ((image->columns-2)*(mng_info->magn_mx));
6244 magnified_width=(png_uint_32) image->columns;
6246 if (image->columns > 1)
6247 magnified_width += mng_info->magn_ml-1;
6249 if (image->columns > 2)
6250 magnified_width += mng_info->magn_mr-1;
6252 if (image->columns > 3)
6253 magnified_width += (png_uint_32)
6254 ((image->columns-3)*(mng_info->magn_mx-1));
6257 if (mng_info->magn_methy == 1)
6259 magnified_height=mng_info->magn_mt;
6261 if (image->rows > 1)
6262 magnified_height += mng_info->magn_mb;
6264 if (image->rows > 2)
6265 magnified_height += (png_uint_32)
6266 ((image->rows-2)*(mng_info->magn_my));
6271 magnified_height=(png_uint_32) image->rows;
6273 if (image->rows > 1)
6274 magnified_height += mng_info->magn_mt-1;
6276 if (image->rows > 2)
6277 magnified_height += mng_info->magn_mb-1;
6279 if (image->rows > 3)
6280 magnified_height += (png_uint_32)
6281 ((image->rows-3)*(mng_info->magn_my-1));
6284 if (magnified_height > image->rows ||
6285 magnified_width > image->columns)
6312 /* Allocate next image structure. */
6314 if (logging != MagickFalse)
6315 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6316 " Allocate magnified image");
6318 AcquireNextImage(image_info,image,exception);
6320 if (GetNextImageInList(image) == (Image *) NULL)
6322 image=DestroyImageList(image);
6323 MngInfoFreeStruct(mng_info,&have_mng_structure);
6324 return((Image *) NULL);
6327 large_image=SyncNextImageInList(image);
6329 large_image->columns=magnified_width;
6330 large_image->rows=magnified_height;
6332 magn_methx=mng_info->magn_methx;
6333 magn_methy=mng_info->magn_methy;
6335 #if (MAGICKCORE_QUANTUM_DEPTH > 16)
6336 #define QM unsigned short
6337 if (magn_methx != 1 || magn_methy != 1)
6340 Scale pixels to unsigned shorts to prevent
6341 overflow of intermediate values of interpolations
6343 for (y=0; y < (ssize_t) image->rows; y++)
6345 q=GetAuthenticPixels(image,0,y,image->columns,1,
6348 for (x=(ssize_t) image->columns-1; x >= 0; x--)
6350 SetPixelRed(image,ScaleQuantumToShort(
6351 GetPixelRed(image,q)),q);
6352 SetPixelGreen(image,ScaleQuantumToShort(
6353 GetPixelGreen(image,q)),q);
6354 SetPixelBlue(image,ScaleQuantumToShort(
6355 GetPixelBlue(image,q)),q);
6356 SetPixelAlpha(image,ScaleQuantumToShort(
6357 GetPixelAlpha(image,q)),q);
6358 q+=GetPixelChannels(image);
6361 if (SyncAuthenticPixels(image,exception) == MagickFalse)
6369 if (image->matte != MagickFalse)
6370 (void) SetImageBackgroundColor(large_image,exception);
6374 large_image->background_color.alpha=OpaqueAlpha;
6375 (void) SetImageBackgroundColor(large_image,exception);
6377 if (magn_methx == 4)
6380 if (magn_methx == 5)
6383 if (magn_methy == 4)
6386 if (magn_methy == 5)
6390 /* magnify the rows into the right side of the large image */
6392 if (logging != MagickFalse)
6393 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6394 " Magnify the rows to %.20g",(double) large_image->rows);
6395 m=(ssize_t) mng_info->magn_mt;
6397 length=(size_t) image->columns*GetPixelChannels(image);
6398 next=(Quantum *) AcquireQuantumMemory(length,sizeof(*next));
6399 prev=(Quantum *) AcquireQuantumMemory(length,sizeof(*prev));
6401 if ((prev == (Quantum *) NULL) ||
6402 (next == (Quantum *) NULL))
6404 image=DestroyImageList(image);
6405 MngInfoFreeStruct(mng_info,&have_mng_structure);
6406 ThrowReaderException(ResourceLimitError,
6407 "MemoryAllocationFailed");
6410 n=GetAuthenticPixels(image,0,0,image->columns,1,exception);
6411 (void) CopyMagickMemory(next,n,length);
6413 for (y=0; y < (ssize_t) image->rows; y++)
6416 m=(ssize_t) mng_info->magn_mt;
6418 else if (magn_methy > 1 && y == (ssize_t) image->rows-2)
6419 m=(ssize_t) mng_info->magn_mb;
6421 else if (magn_methy <= 1 && y == (ssize_t) image->rows-1)
6422 m=(ssize_t) mng_info->magn_mb;
6424 else if (magn_methy > 1 && y == (ssize_t) image->rows-1)
6428 m=(ssize_t) mng_info->magn_my;
6434 if (y < (ssize_t) image->rows-1)
6436 n=GetAuthenticPixels(image,0,y+1,image->columns,1,
6438 (void) CopyMagickMemory(next,n,length);
6441 for (i=0; i < m; i++, yy++)
6446 assert(yy < (ssize_t) large_image->rows);
6449 q=GetAuthenticPixels(large_image,0,yy,large_image->columns,
6451 q+=(large_image->columns-image->columns)*
6452 GetPixelChannels(large_image);
6454 for (x=(ssize_t) image->columns-1; x >= 0; x--)
6456 /* To do: get color as function of indexes[x] */
6458 if (image->storage_class == PseudoClass)
6463 if (magn_methy <= 1)
6465 /* replicate previous */
6466 SetPixelRed(large_image,GetPixelRed(image,pixels),q);
6467 SetPixelGreen(large_image,GetPixelGreen(image,
6469 SetPixelBlue(large_image,GetPixelBlue(image,
6471 SetPixelAlpha(large_image,GetPixelAlpha(image,
6475 else if (magn_methy == 2 || magn_methy == 4)
6479 SetPixelRed(large_image,GetPixelRed(image,
6481 SetPixelGreen(large_image,GetPixelGreen(image,
6483 SetPixelBlue(large_image,GetPixelBlue(image,
6485 SetPixelAlpha(large_image,GetPixelAlpha(image,
6492 SetPixelRed(large_image,((QM) (((ssize_t)
6493 (2*i*(GetPixelRed(image,n)
6494 -GetPixelRed(image,pixels)+m))/
6496 +GetPixelRed(image,pixels)))),q);
6497 SetPixelGreen(large_image,((QM) (((ssize_t)
6498 (2*i*(GetPixelGreen(image,n)
6499 -GetPixelGreen(image,pixels)+m))/
6501 +GetPixelGreen(image,pixels)))),q);
6502 SetPixelBlue(large_image,((QM) (((ssize_t)
6503 (2*i*(GetPixelBlue(image,n)
6504 -GetPixelBlue(image,pixels)+m))/
6506 +GetPixelBlue(image,pixels)))),q);
6508 if (image->matte != MagickFalse)
6509 SetPixelAlpha(large_image, ((QM) (((ssize_t)
6510 (2*i*(GetPixelAlpha(image,n)
6511 -GetPixelAlpha(image,pixels)+m))
6513 GetPixelAlpha(image,pixels)))),q);
6516 if (magn_methy == 4)
6518 /* Replicate nearest */
6519 if (i <= ((m+1) << 1))
6520 SetPixelAlpha(large_image,GetPixelAlpha(image,
6523 SetPixelAlpha(large_image,GetPixelAlpha(image,
6528 else /* if (magn_methy == 3 || magn_methy == 5) */
6530 /* Replicate nearest */
6531 if (i <= ((m+1) << 1))
6533 SetPixelRed(large_image,GetPixelRed(image,
6535 SetPixelGreen(large_image,GetPixelGreen(image,
6537 SetPixelBlue(large_image,GetPixelBlue(image,
6539 SetPixelAlpha(large_image,GetPixelAlpha(image,
6545 SetPixelRed(large_image,GetPixelRed(image,n),q);
6546 SetPixelGreen(large_image,GetPixelGreen(image,n),
6548 SetPixelBlue(large_image,GetPixelBlue(image,n),
6550 SetPixelAlpha(large_image,GetPixelAlpha(image,n),
6554 if (magn_methy == 5)
6556 SetPixelAlpha(large_image,(QM) (((ssize_t) (2*i*
6557 (GetPixelAlpha(image,n)
6558 -GetPixelAlpha(image,pixels))
6559 +m))/((ssize_t) (m*2))
6560 +GetPixelAlpha(image,pixels)),q);
6563 n+=GetPixelChannels(image);
6564 q+=GetPixelChannels(large_image);
6565 pixels+=GetPixelChannels(image);
6568 if (SyncAuthenticPixels(large_image,exception) == 0)
6574 prev=(Quantum *) RelinquishMagickMemory(prev);
6575 next=(Quantum *) RelinquishMagickMemory(next);
6577 length=image->columns;
6579 if (logging != MagickFalse)
6580 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6581 " Delete original image");
6583 DeleteImageFromList(&image);
6587 mng_info->image=image;
6589 /* magnify the columns */
6590 if (logging != MagickFalse)
6591 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6592 " Magnify the columns to %.20g",(double) image->columns);
6594 for (y=0; y < (ssize_t) image->rows; y++)
6599 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
6600 pixels=q+(image->columns-length)*GetPixelChannels(image);
6601 n=pixels+GetPixelChannels(image);
6603 for (x=(ssize_t) (image->columns-length);
6604 x < (ssize_t) image->columns; x++)
6606 /* To do: Rewrite using Get/Set***PixelChannel() */
6608 if (x == (ssize_t) (image->columns-length))
6609 m=(ssize_t) mng_info->magn_ml;
6611 else if (magn_methx > 1 && x == (ssize_t) image->columns-2)
6612 m=(ssize_t) mng_info->magn_mr;
6614 else if (magn_methx <= 1 && x == (ssize_t) image->columns-1)
6615 m=(ssize_t) mng_info->magn_mr;
6617 else if (magn_methx > 1 && x == (ssize_t) image->columns-1)
6621 m=(ssize_t) mng_info->magn_mx;
6623 for (i=0; i < m; i++)
6625 if (magn_methx <= 1)
6627 /* replicate previous */
6628 SetPixelRed(image,GetPixelRed(image,pixels),q);
6629 SetPixelGreen(image,GetPixelGreen(image,pixels),q);
6630 SetPixelBlue(image,GetPixelBlue(image,pixels),q);
6631 SetPixelAlpha(image,GetPixelAlpha(image,pixels),q);
6634 else if (magn_methx == 2 || magn_methx == 4)
6638 SetPixelRed(image,GetPixelRed(image,pixels),q);
6639 SetPixelGreen(image,GetPixelGreen(image,pixels),q);
6640 SetPixelBlue(image,GetPixelBlue(image,pixels),q);
6641 SetPixelAlpha(image,GetPixelAlpha(image,pixels),q);
6644 /* To do: Rewrite using Get/Set***PixelChannel() */
6648 SetPixelRed(image,(QM) ((2*i*(
6649 GetPixelRed(image,n)
6650 -GetPixelRed(image,pixels))+m)
6652 GetPixelRed(image,pixels)),q);
6654 SetPixelGreen(image,(QM) ((2*i*(
6655 GetPixelGreen(image,n)
6656 -GetPixelGreen(image,pixels))+m)
6658 GetPixelGreen(image,pixels)),q);
6660 SetPixelBlue(image,(QM) ((2*i*(
6661 GetPixelBlue(image,n)
6662 -GetPixelBlue(image,pixels))+m)
6664 GetPixelBlue(image,pixels)),q);
6665 if (image->matte != MagickFalse)
6666 SetPixelAlpha(image,(QM) ((2*i*(
6667 GetPixelAlpha(image,n)
6668 -GetPixelAlpha(image,pixels))+m)
6670 GetPixelAlpha(image,pixels)),q);
6673 if (magn_methx == 4)
6675 /* Replicate nearest */
6676 if (i <= ((m+1) << 1))
6678 SetPixelAlpha(image,
6679 GetPixelAlpha(image,pixels)+0,q);
6683 SetPixelAlpha(image,
6684 GetPixelAlpha(image,n)+0,q);
6689 else /* if (magn_methx == 3 || magn_methx == 5) */
6691 /* Replicate nearest */
6692 if (i <= ((m+1) << 1))
6694 SetPixelRed(image,GetPixelRed(image,pixels),q);
6695 SetPixelGreen(image,GetPixelGreen(image,pixels),q);
6696 SetPixelBlue(image,GetPixelBlue(image,pixels),q);
6697 SetPixelAlpha(image,GetPixelAlpha(image,pixels),q);
6702 SetPixelRed(image,GetPixelRed(image,n),q);
6703 SetPixelGreen(image,GetPixelGreen(image,n),q);
6704 SetPixelBlue(image,GetPixelBlue(image,n),q);
6705 SetPixelAlpha(image,GetPixelAlpha(image,n),q);
6708 if (magn_methx == 5)
6711 SetPixelAlpha(image,
6712 (QM) ((2*i*( GetPixelAlpha(image,n)
6713 -GetPixelAlpha(image,pixels))+m)/
6715 +GetPixelAlpha(image,pixels)),q);
6718 q+=GetPixelChannels(image);
6720 n+=GetPixelChannels(image);
6721 p+=GetPixelChannels(image);
6724 if (SyncAuthenticPixels(image,exception) == MagickFalse)
6727 #if (MAGICKCORE_QUANTUM_DEPTH > 16)
6728 if (magn_methx != 1 || magn_methy != 1)
6731 Rescale pixels to Quantum
6733 for (y=0; y < (ssize_t) image->rows; y++)
6735 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
6737 for (x=(ssize_t) image->columns-1; x >= 0; x--)
6739 SetPixelRed(image,ScaleShortToQuantum(
6740 GetPixelRed(image,q)),q);
6741 SetPixelGreen(image,ScaleShortToQuantum(
6742 GetPixelGreen(image,q)),q);
6743 SetPixelBlue(image,ScaleShortToQuantum(
6744 GetPixelBlue(image,q)),q);
6745 SetPixelAlpha(image,ScaleShortToQuantum(
6746 GetPixelAlpha(image,q)),q);
6747 q+=GetPixelChannels(image);
6750 if (SyncAuthenticPixels(image,exception) == MagickFalse)
6755 if (logging != MagickFalse)
6756 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6757 " Finished MAGN processing");
6762 Crop_box is with respect to the upper left corner of the MNG.
6764 crop_box.left=mng_info->image_box.left+mng_info->x_off[object_id];
6765 crop_box.right=mng_info->image_box.right+mng_info->x_off[object_id];
6766 crop_box.top=mng_info->image_box.top+mng_info->y_off[object_id];
6767 crop_box.bottom=mng_info->image_box.bottom+mng_info->y_off[object_id];
6768 crop_box=mng_minimum_box(crop_box,mng_info->clip);
6769 crop_box=mng_minimum_box(crop_box,mng_info->frame);
6770 crop_box=mng_minimum_box(crop_box,mng_info->object_clip[object_id]);
6771 if ((crop_box.left != (mng_info->image_box.left
6772 +mng_info->x_off[object_id])) ||
6773 (crop_box.right != (mng_info->image_box.right
6774 +mng_info->x_off[object_id])) ||
6775 (crop_box.top != (mng_info->image_box.top
6776 +mng_info->y_off[object_id])) ||
6777 (crop_box.bottom != (mng_info->image_box.bottom
6778 +mng_info->y_off[object_id])))
6780 if (logging != MagickFalse)
6781 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6782 " Crop the PNG image");
6784 if ((crop_box.left < crop_box.right) &&
6785 (crop_box.top < crop_box.bottom))
6794 Crop_info is with respect to the upper left corner of
6797 crop_info.x=(crop_box.left-mng_info->x_off[object_id]);
6798 crop_info.y=(crop_box.top-mng_info->y_off[object_id]);
6799 crop_info.width=(size_t) (crop_box.right-crop_box.left);
6800 crop_info.height=(size_t) (crop_box.bottom-crop_box.top);
6801 image->page.width=image->columns;
6802 image->page.height=image->rows;
6805 im=CropImage(image,&crop_info,exception);
6807 if (im != (Image *) NULL)
6809 image->columns=im->columns;
6810 image->rows=im->rows;
6811 im=DestroyImage(im);
6812 image->page.width=image->columns;
6813 image->page.height=image->rows;
6814 image->page.x=crop_box.left;
6815 image->page.y=crop_box.top;
6822 No pixels in crop area. The MNG spec still requires
6823 a layer, though, so make a single transparent pixel in
6824 the top left corner.
6829 (void) SetImageBackgroundColor(image,exception);
6830 image->page.width=1;
6831 image->page.height=1;
6836 #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
6837 image=mng_info->image;
6841 #if (MAGICKCORE_QUANTUM_DEPTH > 16)
6842 /* PNG does not handle depths greater than 16 so reduce it even
6845 if (image->depth > 16)
6849 #if (MAGICKCORE_QUANTUM_DEPTH > 8)
6850 if (image->depth > 8)
6852 /* To do: fill low byte properly */
6856 if (LosslessReduceDepthOK(image,exception) != MagickFalse)
6860 if (image_info->number_scenes != 0)
6862 if (mng_info->scenes_found >
6863 (ssize_t) (image_info->first_scene+image_info->number_scenes))
6867 if (logging != MagickFalse)
6868 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6869 " Finished reading image datastream.");
6871 } while (LocaleCompare(image_info->magick,"MNG") == 0);
6873 (void) CloseBlob(image);
6875 if (logging != MagickFalse)
6876 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6877 " Finished reading all image datastreams.");
6879 #if defined(MNG_INSERT_LAYERS)
6880 if (insert_layers && !mng_info->image_found && (mng_info->mng_width) &&
6881 (mng_info->mng_height))
6884 Insert a background layer if nothing else was found.
6886 if (logging != MagickFalse)
6887 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6888 " No images found. Inserting a background layer.");
6890 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
6893 Allocate next image structure.
6895 AcquireNextImage(image_info,image,exception);
6896 if (GetNextImageInList(image) == (Image *) NULL)
6898 image=DestroyImageList(image);
6899 MngInfoFreeStruct(mng_info,&have_mng_structure);
6901 if (logging != MagickFalse)
6902 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6903 " Allocation failed, returning NULL.");
6905 return((Image *) NULL);
6907 image=SyncNextImageInList(image);
6909 image->columns=mng_info->mng_width;
6910 image->rows=mng_info->mng_height;
6911 image->page.width=mng_info->mng_width;
6912 image->page.height=mng_info->mng_height;
6915 image->background_color=mng_background_color;
6916 image->matte=MagickFalse;
6918 if (image_info->ping == MagickFalse)
6919 (void) SetImageBackgroundColor(image,exception);
6921 mng_info->image_found++;
6924 image->iterations=mng_iterations;
6926 if (mng_iterations == 1)
6927 image->start_loop=MagickTrue;
6929 while (GetPreviousImageInList(image) != (Image *) NULL)
6932 if (image_count > 10*mng_info->image_found)
6934 if (logging != MagickFalse)
6935 (void) LogMagickEvent(CoderEvent,GetMagickModule()," No beginning");
6937 (void) ThrowMagickException(exception,GetMagickModule(),
6938 CoderError,"Linked list is corrupted, beginning of list not found",
6939 "`%s'",image_info->filename);
6941 return((Image *) NULL);
6944 image=GetPreviousImageInList(image);
6946 if (GetNextImageInList(image) == (Image *) NULL)
6948 if (logging != MagickFalse)
6949 (void) LogMagickEvent(CoderEvent,GetMagickModule()," Corrupt list");
6951 (void) ThrowMagickException(exception,GetMagickModule(),
6952 CoderError,"Linked list is corrupted; next_image is NULL","`%s'",
6953 image_info->filename);
6957 if (mng_info->ticks_per_second && mng_info->image_found > 1 &&
6958 GetNextImageInList(image) ==
6961 if (logging != MagickFalse)
6962 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6963 " First image null");
6965 (void) ThrowMagickException(exception,GetMagickModule(),
6966 CoderError,"image->next for first image is NULL but shouldn't be.",
6967 "`%s'",image_info->filename);
6970 if (mng_info->image_found == 0)
6972 if (logging != MagickFalse)
6973 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6974 " No visible images found.");
6976 (void) ThrowMagickException(exception,GetMagickModule(),
6977 CoderError,"No visible images in file","`%s'",image_info->filename);
6979 if (image != (Image *) NULL)
6980 image=DestroyImageList(image);
6982 MngInfoFreeStruct(mng_info,&have_mng_structure);
6983 return((Image *) NULL);
6986 if (mng_info->ticks_per_second)
6987 final_delay=1UL*MagickMax(image->ticks_per_second,1L)*
6988 final_delay/mng_info->ticks_per_second;
6991 image->start_loop=MagickTrue;
6993 /* Find final nonzero image delay */
6994 final_image_delay=0;
6996 while (GetNextImageInList(image) != (Image *) NULL)
6999 final_image_delay=image->delay;
7001 image=GetNextImageInList(image);
7004 if (final_delay < final_image_delay)
7005 final_delay=final_image_delay;
7007 image->delay=final_delay;
7009 if (logging != MagickFalse)
7010 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7011 " image->delay=%.20g, final_delay=%.20g",(double) image->delay,
7012 (double) final_delay);
7014 if (logging != MagickFalse)
7020 image=GetFirstImageInList(image);
7022 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7023 " Before coalesce:");
7025 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7026 " scene 0 delay=%.20g",(double) image->delay);
7028 while (GetNextImageInList(image) != (Image *) NULL)
7030 image=GetNextImageInList(image);
7031 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7032 " scene %.20g delay=%.20g",(double) scene++,(double) image->delay);
7036 image=GetFirstImageInList(image);
7037 #ifdef MNG_COALESCE_LAYERS
7047 if (logging != MagickFalse)
7048 (void) LogMagickEvent(CoderEvent,GetMagickModule()," Coalesce Images");
7051 next_image=CoalesceImages(image,exception);
7053 if (next_image == (Image *) NULL)
7054 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
7056 image=DestroyImageList(image);
7059 for (next=image; next != (Image *) NULL; next=next_image)
7061 next->page.width=mng_info->mng_width;
7062 next->page.height=mng_info->mng_height;
7065 next->scene=scene++;
7066 next_image=GetNextImageInList(next);
7068 if (next_image == (Image *) NULL)
7071 if (next->delay == 0)
7074 next_image->previous=GetPreviousImageInList(next);
7075 if (GetPreviousImageInList(next) == (Image *) NULL)
7078 next->previous->next=next_image;
7079 next=DestroyImage(next);
7085 while (GetNextImageInList(image) != (Image *) NULL)
7086 image=GetNextImageInList(image);
7088 image->dispose=BackgroundDispose;
7090 if (logging != MagickFalse)
7096 image=GetFirstImageInList(image);
7098 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7099 " After coalesce:");
7101 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7102 " scene 0 delay=%.20g dispose=%.20g",(double) image->delay,
7103 (double) image->dispose);
7105 while (GetNextImageInList(image) != (Image *) NULL)
7107 image=GetNextImageInList(image);
7109 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7110 " scene %.20g delay=%.20g dispose=%.20g",(double) scene++,
7111 (double) image->delay,(double) image->dispose);
7115 image=GetFirstImageInList(image);
7116 MngInfoFreeStruct(mng_info,&have_mng_structure);
7117 have_mng_structure=MagickFalse;
7119 if (logging != MagickFalse)
7120 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit ReadMNGImage()");
7122 return(GetFirstImageInList(image));
7124 #else /* PNG_LIBPNG_VER > 10011 */
7125 static Image *ReadPNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
7127 printf("Your PNG library is too old: You have libpng-%s\n",
7128 PNG_LIBPNG_VER_STRING);
7130 (void) ThrowMagickException(exception,GetMagickModule(),CoderError,
7131 "PNG library is too old","`%s'",image_info->filename);
7133 return(Image *) NULL;
7136 static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
7138 return(ReadPNGImage(image_info,exception));
7140 #endif /* PNG_LIBPNG_VER > 10011 */
7144 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7148 % R e g i s t e r P N G I m a g e %
7152 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7154 % RegisterPNGImage() adds properties for the PNG image format to
7155 % the list of supported formats. The properties include the image format
7156 % tag, a method to read and/or write the format, whether the format
7157 % supports the saving of more than one frame to the same file or blob,
7158 % whether the format supports native in-memory I/O, and a brief
7159 % description of the format.
7161 % The format of the RegisterPNGImage method is:
7163 % size_t RegisterPNGImage(void)
7166 ModuleExport size_t RegisterPNGImage(void)
7169 version[MaxTextExtent];
7177 "See http://www.libpng.org/ for details about the PNG format."
7182 "See http://www.libpng.org/pub/mng/ for details about the JNG\n"
7188 "See http://www.libpng.org/pub/mng/ for details about the MNG\n"
7194 #if defined(PNG_LIBPNG_VER_STRING)
7195 (void) ConcatenateMagickString(version,"libpng ",MaxTextExtent);
7196 (void) ConcatenateMagickString(version,PNG_LIBPNG_VER_STRING,MaxTextExtent);
7198 if (LocaleCompare(PNG_LIBPNG_VER_STRING,png_get_header_ver(NULL)) != 0)
7200 (void) ConcatenateMagickString(version,",",MaxTextExtent);
7201 (void) ConcatenateMagickString(version,png_get_libpng_ver(NULL),
7206 entry=SetMagickInfo("MNG");
7207 entry->seekable_stream=MagickTrue; /* To do: eliminate this. */
7209 #if defined(MAGICKCORE_PNG_DELEGATE)
7210 entry->decoder=(DecodeImageHandler *) ReadMNGImage;
7211 entry->encoder=(EncodeImageHandler *) WriteMNGImage;
7214 entry->magick=(IsImageFormatHandler *) IsMNG;
7215 entry->description=ConstantString("Multiple-image Network Graphics");
7217 if (*version != '\0')
7218 entry->version=ConstantString(version);
7220 entry->module=ConstantString("PNG");
7221 entry->note=ConstantString(MNGNote);
7222 (void) RegisterMagickInfo(entry);
7224 entry=SetMagickInfo("PNG");
7226 #if defined(MAGICKCORE_PNG_DELEGATE)
7227 entry->decoder=(DecodeImageHandler *) ReadPNGImage;
7228 entry->encoder=(EncodeImageHandler *) WritePNGImage;
7231 entry->magick=(IsImageFormatHandler *) IsPNG;
7232 entry->adjoin=MagickFalse;
7233 entry->description=ConstantString("Portable Network Graphics");
7234 entry->module=ConstantString("PNG");
7236 if (*version != '\0')
7237 entry->version=ConstantString(version);
7239 entry->note=ConstantString(PNGNote);
7240 (void) RegisterMagickInfo(entry);
7242 entry=SetMagickInfo("PNG8");
7244 #if defined(MAGICKCORE_PNG_DELEGATE)
7245 entry->decoder=(DecodeImageHandler *) ReadPNGImage;
7246 entry->encoder=(EncodeImageHandler *) WritePNGImage;
7249 entry->magick=(IsImageFormatHandler *) IsPNG;
7250 entry->adjoin=MagickFalse;
7251 entry->description=ConstantString(
7252 "8-bit indexed with optional binary transparency");
7253 entry->module=ConstantString("PNG");
7254 (void) RegisterMagickInfo(entry);
7256 entry=SetMagickInfo("PNG24");
7259 #if defined(ZLIB_VERSION)
7260 (void) ConcatenateMagickString(version,"zlib ",MaxTextExtent);
7261 (void) ConcatenateMagickString(version,ZLIB_VERSION,MaxTextExtent);
7263 if (LocaleCompare(ZLIB_VERSION,zlib_version) != 0)
7265 (void) ConcatenateMagickString(version,",",MaxTextExtent);
7266 (void) ConcatenateMagickString(version,zlib_version,MaxTextExtent);
7270 if (*version != '\0')
7271 entry->version=ConstantString(version);
7273 #if defined(MAGICKCORE_PNG_DELEGATE)
7274 entry->decoder=(DecodeImageHandler *) ReadPNGImage;
7275 entry->encoder=(EncodeImageHandler *) WritePNGImage;
7278 entry->magick=(IsImageFormatHandler *) IsPNG;
7279 entry->adjoin=MagickFalse;
7280 entry->description=ConstantString("opaque 24-bit RGB");
7281 entry->module=ConstantString("PNG");
7282 (void) RegisterMagickInfo(entry);
7284 entry=SetMagickInfo("PNG32");
7286 #if defined(MAGICKCORE_PNG_DELEGATE)
7287 entry->decoder=(DecodeImageHandler *) ReadPNGImage;
7288 entry->encoder=(EncodeImageHandler *) WritePNGImage;
7291 entry->magick=(IsImageFormatHandler *) IsPNG;
7292 entry->adjoin=MagickFalse;
7293 entry->description=ConstantString("opaque or transparent 32-bit RGBA");
7294 entry->module=ConstantString("PNG");
7295 (void) RegisterMagickInfo(entry);
7297 entry=SetMagickInfo("JNG");
7299 #if defined(JNG_SUPPORTED)
7300 #if defined(MAGICKCORE_PNG_DELEGATE)
7301 entry->decoder=(DecodeImageHandler *) ReadJNGImage;
7302 entry->encoder=(EncodeImageHandler *) WriteJNGImage;
7306 entry->magick=(IsImageFormatHandler *) IsJNG;
7307 entry->adjoin=MagickFalse;
7308 entry->description=ConstantString("JPEG Network Graphics");
7309 entry->module=ConstantString("PNG");
7310 entry->note=ConstantString(JNGNote);
7311 (void) RegisterMagickInfo(entry);
7313 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
7314 ping_semaphore=AllocateSemaphoreInfo();
7317 return(MagickImageCoderSignature);
7321 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7325 % U n r e g i s t e r P N G I m a g e %
7329 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7331 % UnregisterPNGImage() removes format registrations made by the
7332 % PNG module from the list of supported formats.
7334 % The format of the UnregisterPNGImage method is:
7336 % UnregisterPNGImage(void)
7339 ModuleExport void UnregisterPNGImage(void)
7341 (void) UnregisterMagickInfo("MNG");
7342 (void) UnregisterMagickInfo("PNG");
7343 (void) UnregisterMagickInfo("PNG8");
7344 (void) UnregisterMagickInfo("PNG24");
7345 (void) UnregisterMagickInfo("PNG32");
7346 (void) UnregisterMagickInfo("JNG");
7348 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
7349 if (ping_semaphore != (SemaphoreInfo *) NULL)
7350 DestroySemaphoreInfo(&ping_semaphore);
7354 #if defined(MAGICKCORE_PNG_DELEGATE)
7355 #if PNG_LIBPNG_VER > 10011
7357 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7361 % W r i t e M N G I m a g e %
7365 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7367 % WriteMNGImage() writes an image in the Portable Network Graphics
7368 % Group's "Multiple-image Network Graphics" encoded image format.
7370 % MNG support written by Glenn Randers-Pehrson, glennrp@image...
7372 % The format of the WriteMNGImage method is:
7374 % MagickBooleanType WriteMNGImage(const ImageInfo *image_info,
7375 % Image *image,ExceptionInfo *exception)
7377 % A description of each parameter follows.
7379 % o image_info: the image info.
7381 % o image: The image.
7383 % o exception: return any errors or warnings in this structure.
7385 % To do (as of version 5.5.2, November 26, 2002 -- glennrp -- see also
7386 % "To do" under ReadPNGImage):
7388 % Preserve all unknown and not-yet-handled known chunks found in input
7389 % PNG file and copy them into output PNG files according to the PNG
7392 % Write the iCCP chunk at MNG level when (icc profile length > 0)
7394 % Improve selection of color type (use indexed-colour or indexed-colour
7395 % with tRNS when 256 or fewer unique RGBA values are present).
7397 % Figure out what to do with "dispose=<restore-to-previous>" (dispose == 3)
7398 % This will be complicated if we limit ourselves to generating MNG-LC
7399 % files. For now we ignore disposal method 3 and simply overlay the next
7402 % Check for identical PLTE's or PLTE/tRNS combinations and use a
7403 % global MNG PLTE or PLTE/tRNS combination when appropriate.
7404 % [mostly done 15 June 1999 but still need to take care of tRNS]
7406 % Check for identical sRGB and replace with a global sRGB (and remove
7407 % gAMA/cHRM if sRGB is found; check for identical gAMA/cHRM and
7408 % replace with global gAMA/cHRM (or with sRGB if appropriate; replace
7409 % local gAMA/cHRM with local sRGB if appropriate).
7411 % Check for identical sBIT chunks and write global ones.
7413 % Provide option to skip writing the signature tEXt chunks.
7415 % Use signatures to detect identical objects and reuse the first
7416 % instance of such objects instead of writing duplicate objects.
7418 % Use a smaller-than-32k value of compression window size when
7421 % Encode JNG datastreams. Mostly done as of 5.5.2; need to write
7422 % ancillary text chunks and save profiles.
7424 % Provide an option to force LC files (to ensure exact framing rate)
7427 % Provide an option to force VLC files instead of LC, even when offsets
7428 % are present. This will involve expanding the embedded images with a
7429 % transparent region at the top and/or left.
7433 Magick_png_write_raw_profile(const ImageInfo *image_info,png_struct *ping,
7434 png_info *ping_info, unsigned char *profile_type, unsigned char
7435 *profile_description, unsigned char *profile_data, png_uint_32 length)
7454 hex[16]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
7456 if (LocaleNCompare((char *) profile_type+1, "ng-chunk-",9) == 0)
7459 if (image_info->verbose)
7461 (void) printf("writing raw profile: type=%s, length=%.20g\n",
7462 (char *) profile_type, (double) length);
7465 #if PNG_LIBPNG_VER >= 14000
7466 text=(png_textp) png_malloc(ping,(png_alloc_size_t) sizeof(png_text));
7468 text=(png_textp) png_malloc(ping,(png_size_t) sizeof(png_text));
7470 description_length=(png_uint_32) strlen((const char *) profile_description);
7471 allocated_length=(png_uint_32) (length*2 + (length >> 5) + 20
7472 + description_length);
7473 #if PNG_LIBPNG_VER >= 14000
7474 text[0].text=(png_charp) png_malloc(ping,
7475 (png_alloc_size_t) allocated_length);
7476 text[0].key=(png_charp) png_malloc(ping, (png_alloc_size_t) 80);
7478 text[0].text=(png_charp) png_malloc(ping, (png_size_t) allocated_length);
7479 text[0].key=(png_charp) png_malloc(ping, (png_size_t) 80);
7481 text[0].key[0]='\0';
7482 (void) ConcatenateMagickString(text[0].key,
7483 "Raw profile type ",MaxTextExtent);
7484 (void) ConcatenateMagickString(text[0].key,(const char *) profile_type,62);
7488 (void) CopyMagickString(dp,(const char *) profile_description,
7490 dp+=description_length;
7492 (void) FormatLocaleString(dp,allocated_length-
7493 (png_size_t) (dp-text[0].text),"%8lu ",(unsigned long) length);
7496 for (i=0; i < (ssize_t) length; i++)
7500 *(dp++)=(char) hex[((*sp >> 4) & 0x0f)];
7501 *(dp++)=(char) hex[((*sp++ ) & 0x0f)];
7506 text[0].text_length=(png_size_t) (dp-text[0].text);
7507 text[0].compression=image_info->compression == NoCompression ||
7508 (image_info->compression == UndefinedCompression &&
7509 text[0].text_length < 128) ? -1 : 0;
7511 if (text[0].text_length <= allocated_length)
7512 png_set_text(ping,ping_info,text,1);
7514 png_free(ping,text[0].text);
7515 png_free(ping,text[0].key);
7516 png_free(ping,text);
7519 static MagickBooleanType Magick_png_write_chunk_from_profile(Image *image,
7520 const char *string, MagickBooleanType logging)
7533 ResetImageProfileIterator(image);
7535 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
7537 profile=GetImageProfile(image,name);
7539 if (profile != (const StringInfo *) NULL)
7544 if (LocaleNCompare(name,string,11) == 0)
7546 if (logging != MagickFalse)
7547 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7548 " Found %s profile",name);
7550 ping_profile=CloneStringInfo(profile);
7551 data=GetStringInfoDatum(ping_profile),
7552 length=(png_uint_32) GetStringInfoLength(ping_profile);
7557 (void) WriteBlobMSBULong(image,length-5); /* data length */
7558 (void) WriteBlob(image,length-1,data+1);
7559 (void) WriteBlobMSBULong(image,crc32(0,data+1,(uInt) length-1));
7560 ping_profile=DestroyStringInfo(ping_profile);
7564 name=GetNextImageProfile(image);
7571 /* Write one PNG image */
7572 static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
7573 const ImageInfo *IMimage_info,Image *IMimage,ExceptionInfo *exception)
7597 ping_trans_alpha[256];
7625 ping_have_cheap_transparency,
7636 /* ping_exclude_EXIF, */
7639 /* ping_exclude_iTXt, */
7644 /* ping_exclude_tRNS, */
7646 ping_exclude_zCCP, /* hex-encoded iCCP */
7649 ping_preserve_colormap,
7650 ping_need_colortype_warning,
7674 ping_interlace_method,
7675 ping_compression_method,
7692 number_semitransparent,
7694 ping_pHYs_unit_type;
7697 ping_pHYs_x_resolution,
7698 ping_pHYs_y_resolution;
7700 logging=LogMagickEvent(CoderEvent,GetMagickModule(),
7701 " Enter WriteOnePNGImage()");
7703 image = CloneImage(IMimage,0,0,MagickFalse,exception);
7704 image_info=(ImageInfo *) CloneImageInfo(IMimage_info);
7705 if (image_info == (ImageInfo *) NULL)
7706 ThrowWriterException(ResourceLimitError, "MemoryAllocationFailed");
7708 /* Initialize some stuff */
7711 ping_interlace_method=0,
7712 ping_compression_method=0,
7713 ping_filter_method=0,
7716 ping_background.red = 0;
7717 ping_background.green = 0;
7718 ping_background.blue = 0;
7719 ping_background.gray = 0;
7720 ping_background.index = 0;
7722 ping_trans_color.red=0;
7723 ping_trans_color.green=0;
7724 ping_trans_color.blue=0;
7725 ping_trans_color.gray=0;
7727 ping_pHYs_unit_type = 0;
7728 ping_pHYs_x_resolution = 0;
7729 ping_pHYs_y_resolution = 0;
7731 ping_have_blob=MagickFalse;
7732 ping_have_color=MagickTrue;
7733 ping_have_non_bw=MagickTrue;
7734 ping_have_PLTE=MagickFalse;
7735 ping_have_bKGD=MagickFalse;
7736 ping_have_pHYs=MagickFalse;
7737 ping_have_tRNS=MagickFalse;
7739 ping_exclude_bKGD=mng_info->ping_exclude_bKGD;
7740 ping_exclude_cHRM=mng_info->ping_exclude_cHRM;
7741 ping_exclude_date=mng_info->ping_exclude_date;
7742 /* ping_exclude_EXIF=mng_info->ping_exclude_EXIF; */
7743 ping_exclude_gAMA=mng_info->ping_exclude_gAMA;
7744 ping_exclude_iCCP=mng_info->ping_exclude_iCCP;
7745 /* ping_exclude_iTXt=mng_info->ping_exclude_iTXt; */
7746 ping_exclude_oFFs=mng_info->ping_exclude_oFFs;
7747 ping_exclude_pHYs=mng_info->ping_exclude_pHYs;
7748 ping_exclude_sRGB=mng_info->ping_exclude_sRGB;
7749 ping_exclude_tEXt=mng_info->ping_exclude_tEXt;
7750 /* ping_exclude_tRNS=mng_info->ping_exclude_tRNS; */
7751 ping_exclude_vpAg=mng_info->ping_exclude_vpAg;
7752 ping_exclude_zCCP=mng_info->ping_exclude_zCCP; /* hex-encoded iCCP in zTXt */
7753 ping_exclude_zTXt=mng_info->ping_exclude_zTXt;
7755 ping_preserve_colormap = mng_info->ping_preserve_colormap;
7756 ping_need_colortype_warning = MagickFalse;
7758 /* Recognize the ICC sRGB profile and convert it to the sRGB chunk,
7759 * i.e., eliminate the ICC profile and set image->rendering_intent.
7760 * Note that this will not involve any changes to the actual pixels
7761 * but merely passes information to applications that read the resulting
7764 if (ping_exclude_sRGB == MagickFalse)
7772 ResetImageProfileIterator(image);
7773 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
7775 profile=GetImageProfile(image,name);
7777 if (profile != (StringInfo *) NULL)
7779 if ((LocaleCompare(name,"ICC") == 0) ||
7780 (LocaleCompare(name,"ICM") == 0))
7785 /* 0: not a known sRGB profile
7786 * 1: HP-Microsoft sRGB v2
7787 * 2: ICC sRGB v4 perceptual
7788 * 3: ICC sRGB v2 perceptual no black-compensation
7791 check_crc[4] = {0, 0xf29e526dUL, 0xbbef7812UL, 0x427ebb21UL},
7792 check_len[4] = {0, 3144, 60960, 3052};
7801 length=(png_uint_32) GetStringInfoLength(profile);
7803 for (icheck=3; icheck > 0; icheck--)
7805 if (length == check_len[icheck])
7807 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7808 " Got a %lu-byte ICC profile (potentially sRGB)",
7809 (unsigned long) length);
7811 data=GetStringInfoDatum(profile);
7812 profile_crc=crc32(0,data,length);
7814 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7815 " with crc=%8x",(unsigned int) profile_crc);
7817 if (profile_crc == check_crc[icheck])
7819 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7821 if (image->rendering_intent==UndefinedIntent)
7822 image->rendering_intent=PerceptualIntent;
7828 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7829 " Got a %lu-byte ICC profile",
7830 (unsigned long) length);
7833 name=GetNextImageProfile(image);
7838 number_semitransparent = 0;
7839 number_transparent = 0;
7841 if (logging != MagickFalse)
7843 if (image->storage_class == UndefinedClass)
7844 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7845 " storage_class=UndefinedClass");
7846 if (image->storage_class == DirectClass)
7847 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7848 " storage_class=DirectClass");
7849 if (image->storage_class == PseudoClass)
7850 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7851 " storage_class=PseudoClass");
7854 if (image->storage_class == PseudoClass &&
7855 (mng_info->write_png8 || mng_info->write_png24 || mng_info->write_png32 ||
7856 (mng_info->write_png_colortype != 0 &&
7857 mng_info->write_png_colortype != 4)))
7859 (void) SyncImage(image,exception);
7860 image->storage_class = DirectClass;
7863 if (ping_preserve_colormap == MagickFalse)
7865 if (image->storage_class != PseudoClass && image->colormap != NULL)
7867 /* Free the bogus colormap; it can cause trouble later */
7868 if (logging != MagickFalse)
7869 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7870 " Freeing bogus colormap");
7871 (void) RelinquishMagickMemory(image->colormap);
7872 image->colormap=NULL;
7876 if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
7877 (void) TransformImageColorspace(image,sRGBColorspace,exception);
7880 Sometimes we get PseudoClass images whose RGB values don't match
7881 the colors in the colormap. This code syncs the RGB values.
7883 if (image->depth <= 8 && image->taint && image->storage_class == PseudoClass)
7884 (void) SyncImage(image,exception);
7886 #if (MAGICKCORE_QUANTUM_DEPTH == 8)
7887 if (image->depth > 8)
7889 if (logging != MagickFalse)
7890 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7891 " Reducing PNG bit depth to 8 since this is a Q8 build.");
7897 /* Respect the -depth option */
7898 if (image->depth < MAGICKCORE_QUANTUM_DEPTH)
7903 if (image->depth > 8)
7905 #if MAGICKCORE_QUANTUM_DEPTH > 16
7906 /* Scale to 16-bit */
7907 LBR16PacketRGBO(image->background_color);
7909 for (y=0; y < (ssize_t) image->rows; y++)
7911 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
7913 if (r == (Quantum *) NULL)
7916 for (x=0; x < (ssize_t) image->columns; x++)
7919 r+=GetPixelChannels(image);
7922 if (SyncAuthenticPixels(image,exception) == MagickFalse)
7926 if (image->storage_class == PseudoClass && image->colormap != NULL)
7928 for (i=0; i < (ssize_t) image->colors; i++)
7930 LBR16PacketRGBO(image->colormap[i]);
7933 #endif /* MAGICKCORE_QUANTUM_DEPTH > 16 */
7936 else if (image->depth > 4)
7938 #if MAGICKCORE_QUANTUM_DEPTH > 8
7939 /* Scale to 8-bit */
7940 LBR08PacketRGBO(image->background_color);
7942 for (y=0; y < (ssize_t) image->rows; y++)
7944 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
7946 if (r == (Quantum *) NULL)
7949 for (x=0; x < (ssize_t) image->columns; x++)
7952 r+=GetPixelChannels(image);
7955 if (SyncAuthenticPixels(image,exception) == MagickFalse)
7959 if (image->storage_class == PseudoClass && image->colormap != NULL)
7961 for (i=0; i < (ssize_t) image->colors; i++)
7963 LBR08PacketRGBO(image->colormap[i]);
7966 #endif /* MAGICKCORE_QUANTUM_DEPTH > 8 */
7969 if (image->depth > 2)
7971 /* Scale to 4-bit */
7972 LBR04PacketRGBO(image->background_color);
7974 for (y=0; y < (ssize_t) image->rows; y++)
7976 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
7978 if (r == (Quantum *) NULL)
7981 for (x=0; x < (ssize_t) image->columns; x++)
7984 r+=GetPixelChannels(image);
7987 if (SyncAuthenticPixels(image,exception) == MagickFalse)
7991 if (image->storage_class == PseudoClass && image->colormap != NULL)
7993 for (i=0; i < (ssize_t) image->colors; i++)
7995 LBR04PacketRGBO(image->colormap[i]);
8000 else if (image->depth > 1)
8002 /* Scale to 2-bit */
8003 LBR02PacketRGBO(image->background_color);
8005 for (y=0; y < (ssize_t) image->rows; y++)
8007 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8009 if (r == (Quantum *) NULL)
8012 for (x=0; x < (ssize_t) image->columns; x++)
8015 r+=GetPixelChannels(image);
8018 if (SyncAuthenticPixels(image,exception) == MagickFalse)
8022 if (image->storage_class == PseudoClass && image->colormap != NULL)
8024 for (i=0; i < (ssize_t) image->colors; i++)
8026 LBR02PacketRGBO(image->colormap[i]);
8032 /* Scale to 1-bit */
8033 LBR01PacketRGBO(image->background_color);
8035 for (y=0; y < (ssize_t) image->rows; y++)
8037 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8039 if (r == (Quantum *) NULL)
8042 for (x=0; x < (ssize_t) image->columns; x++)
8045 r+=GetPixelChannels(image);
8048 if (SyncAuthenticPixels(image,exception) == MagickFalse)
8052 if (image->storage_class == PseudoClass && image->colormap != NULL)
8054 for (i=0; i < (ssize_t) image->colors; i++)
8056 LBR01PacketRGBO(image->colormap[i]);
8062 /* To do: set to next higher multiple of 8 */
8063 if (image->depth < 8)
8066 #if (MAGICKCORE_QUANTUM_DEPTH > 16)
8067 /* PNG does not handle depths greater than 16 so reduce it even
8070 if (image->depth > 8)
8074 #if (MAGICKCORE_QUANTUM_DEPTH > 8)
8075 if (image->depth > 8)
8077 /* To do: fill low byte properly */
8081 if (image->depth == 16 && mng_info->write_png_depth != 16)
8082 if (mng_info->write_png8 || LosslessReduceDepthOK(image,exception) != MagickFalse)
8086 /* Normally we run this just once, but in the case of writing PNG8
8087 * we reduce the transparency to binary and run again, then if there
8088 * are still too many colors we reduce to a simple 4-4-4-1, then 3-3-3-1
8089 * RGBA palette and run again, and then to a simple 3-3-2-1 RGBA
8090 * palette. Then (To do) we take care of a final reduction that is only
8091 * needed if there are still 256 colors present and one of them has both
8092 * transparent and opaque instances.
8095 tried_332 = MagickFalse;
8096 tried_333 = MagickFalse;
8097 tried_444 = MagickFalse;
8103 * Sometimes we get DirectClass images that have 256 colors or fewer.
8104 * This code will build a colormap.
8106 * Also, sometimes we get PseudoClass images with an out-of-date
8107 * colormap. This code will replace the colormap with a new one.
8108 * Sometimes we get PseudoClass images that have more than 256 colors.
8109 * This code will delete the colormap and change the image to
8112 * If image->matte is MagickFalse, we ignore the alpha channel
8113 * even though it sometimes contains left-over non-opaque values.
8115 * Also we gather some information (number of opaque, transparent,
8116 * and semitransparent pixels, and whether the image has any non-gray
8117 * pixels or only black-and-white pixels) that we might need later.
8119 * Even if the user wants to force GrayAlpha or RGBA (colortype 4 or 6)
8120 * we need to check for bogus non-opaque values, at least.
8128 semitransparent[260],
8131 register const Quantum
8138 if (logging != MagickFalse)
8139 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8140 " Enter BUILD_PALETTE:");
8142 if (logging != MagickFalse)
8144 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8145 " image->columns=%.20g",(double) image->columns);
8146 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8147 " image->rows=%.20g",(double) image->rows);
8148 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8149 " image->matte=%.20g",(double) image->matte);
8150 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8151 " image->depth=%.20g",(double) image->depth);
8153 if (image->storage_class == PseudoClass && image->colormap != NULL)
8155 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8156 " Original colormap:");
8157 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8158 " i (red,green,blue,alpha)");
8160 for (i=0; i < 256; i++)
8162 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8163 " %d (%d,%d,%d,%d)",
8165 (int) image->colormap[i].red,
8166 (int) image->colormap[i].green,
8167 (int) image->colormap[i].blue,
8168 (int) image->colormap[i].alpha);
8171 for (i=image->colors - 10; i < (ssize_t) image->colors; i++)
8175 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8176 " %d (%d,%d,%d,%d)",
8178 (int) image->colormap[i].red,
8179 (int) image->colormap[i].green,
8180 (int) image->colormap[i].blue,
8181 (int) image->colormap[i].alpha);
8186 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8187 " image->colors=%d",(int) image->colors);
8189 if (image->colors == 0)
8190 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8191 " (zero means unknown)");
8193 if (ping_preserve_colormap == MagickFalse)
8194 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8195 " Regenerate the colormap");
8200 number_semitransparent = 0;
8201 number_transparent = 0;
8203 for (y=0; y < (ssize_t) image->rows; y++)
8205 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8207 if (q == (Quantum *) NULL)
8210 for (x=0; x < (ssize_t) image->columns; x++)
8212 if (image->matte == MagickFalse ||
8213 GetPixelAlpha(image,q) == OpaqueAlpha)
8215 if (number_opaque < 259)
8217 if (number_opaque == 0)
8219 GetPixelInfoPixel(image, q, opaque);
8220 opaque[0].alpha=OpaqueAlpha;
8224 for (i=0; i< (ssize_t) number_opaque; i++)
8226 if (IsPixelEquivalent(image,q, opaque+i))
8230 if (i == (ssize_t) number_opaque && number_opaque < 259)
8233 GetPixelInfoPixel(image, q, opaque+i);
8234 opaque[i].alpha=OpaqueAlpha;
8238 else if (GetPixelAlpha(image,q) == TransparentAlpha)
8240 if (number_transparent < 259)
8242 if (number_transparent == 0)
8244 GetPixelInfoPixel(image, q, transparent);
8245 ping_trans_color.red=(unsigned short)
8246 GetPixelRed(image,q);
8247 ping_trans_color.green=(unsigned short)
8248 GetPixelGreen(image,q);
8249 ping_trans_color.blue=(unsigned short)
8250 GetPixelBlue(image,q);
8251 ping_trans_color.gray=(unsigned short)
8252 GetPixelGray(image,q);
8253 number_transparent = 1;
8256 for (i=0; i< (ssize_t) number_transparent; i++)
8258 if (IsPixelEquivalent(image,q, transparent+i))
8262 if (i == (ssize_t) number_transparent &&
8263 number_transparent < 259)
8265 number_transparent++;
8266 GetPixelInfoPixel(image,q,transparent+i);
8272 if (number_semitransparent < 259)
8274 if (number_semitransparent == 0)
8276 GetPixelInfoPixel(image,q,semitransparent);
8277 number_semitransparent = 1;
8280 for (i=0; i< (ssize_t) number_semitransparent; i++)
8282 if (IsPixelEquivalent(image,q, semitransparent+i)
8283 && GetPixelAlpha(image,q) ==
8284 semitransparent[i].alpha)
8288 if (i == (ssize_t) number_semitransparent &&
8289 number_semitransparent < 259)
8291 number_semitransparent++;
8292 GetPixelInfoPixel(image, q, semitransparent+i);
8296 q+=GetPixelChannels(image);
8300 if (mng_info->write_png8 == MagickFalse &&
8301 ping_exclude_bKGD == MagickFalse)
8303 /* Add the background color to the palette, if it
8304 * isn't already there.
8306 if (logging != MagickFalse)
8308 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8309 " Check colormap for background (%d,%d,%d)",
8310 (int) image->background_color.red,
8311 (int) image->background_color.green,
8312 (int) image->background_color.blue);
8314 for (i=0; i<number_opaque; i++)
8316 if (opaque[i].red == image->background_color.red &&
8317 opaque[i].green == image->background_color.green &&
8318 opaque[i].blue == image->background_color.blue)
8321 if (number_opaque < 259 && i == number_opaque)
8323 opaque[i] = image->background_color;
8324 ping_background.index = i;
8326 if (logging != MagickFalse)
8328 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8329 " background_color index is %d",(int) i);
8333 else if (logging != MagickFalse)
8334 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8335 " No room in the colormap to add background color");
8338 image_colors=number_opaque+number_transparent+number_semitransparent;
8340 if (mng_info->write_png8 != MagickFalse && image_colors > 256)
8342 /* No room for the background color; remove it. */
8347 if (logging != MagickFalse)
8349 if (image_colors > 256)
8350 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8351 " image has more than 256 colors");
8354 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8355 " image has %d colors",image_colors);
8358 if (ping_preserve_colormap != MagickFalse)
8361 if (mng_info->write_png_colortype != 7) /* We won't need this info */
8363 ping_have_color=MagickFalse;
8364 ping_have_non_bw=MagickFalse;
8366 if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
8368 ping_have_color=MagickTrue;
8369 ping_have_non_bw=MagickFalse;
8372 if (IssRGBColorspace(image->colorspace) != MagickFalse)
8374 ping_have_color=MagickTrue;
8375 ping_have_non_bw=MagickTrue;
8378 if(image_colors > 256)
8380 for (y=0; y < (ssize_t) image->rows; y++)
8382 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8384 if (q == (Quantum *) NULL)
8388 for (x=0; x < (ssize_t) image->columns; x++)
8390 if (GetPixelRed(image,s) != GetPixelGreen(image,s) ||
8391 GetPixelRed(image,s) != GetPixelBlue(image,s))
8393 ping_have_color=MagickTrue;
8394 ping_have_non_bw=MagickTrue;
8397 s+=GetPixelChannels(image);
8400 if (ping_have_color != MagickFalse)
8403 /* Worst case is black-and-white; we are looking at every
8407 if (ping_have_non_bw == MagickFalse)
8410 for (x=0; x < (ssize_t) image->columns; x++)
8412 if (GetPixelRed(image,s) != 0 &&
8413 GetPixelRed(image,s) != QuantumRange)
8415 ping_have_non_bw=MagickTrue;
8418 s+=GetPixelChannels(image);
8425 if (image_colors < 257)
8431 * Initialize image colormap.
8434 if (logging != MagickFalse)
8435 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8436 " Sort the new colormap");
8438 /* Sort palette, transparent first */;
8442 for (i=0; i<number_transparent; i++)
8443 colormap[n++] = transparent[i];
8445 for (i=0; i<number_semitransparent; i++)
8446 colormap[n++] = semitransparent[i];
8448 for (i=0; i<number_opaque; i++)
8449 colormap[n++] = opaque[i];
8451 ping_background.index +=
8452 (number_transparent + number_semitransparent);
8454 /* image_colors < 257; search the colormap instead of the pixels
8455 * to get ping_have_color and ping_have_non_bw
8459 if (ping_have_color == MagickFalse)
8461 if (colormap[i].red != colormap[i].green ||
8462 colormap[i].red != colormap[i].blue)
8464 ping_have_color=MagickTrue;
8465 ping_have_non_bw=MagickTrue;
8470 if (ping_have_non_bw == MagickFalse)
8472 if (colormap[i].red != 0 && colormap[i].red != QuantumRange)
8473 ping_have_non_bw=MagickTrue;
8477 if ((mng_info->ping_exclude_tRNS == MagickFalse ||
8478 (number_transparent == 0 && number_semitransparent == 0)) &&
8479 (((mng_info->write_png_colortype-1) ==
8480 PNG_COLOR_TYPE_PALETTE) ||
8481 (mng_info->write_png_colortype == 0)))
8483 if (logging != MagickFalse)
8485 if (n != (ssize_t) image_colors)
8486 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8487 " image_colors (%d) and n (%d) don't match",
8490 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8491 " AcquireImageColormap");
8494 image->colors = image_colors;
8496 if (AcquireImageColormap(image,image_colors,exception) ==
8498 ThrowWriterException(ResourceLimitError,
8499 "MemoryAllocationFailed");
8501 for (i=0; i< (ssize_t) image_colors; i++)
8502 image->colormap[i] = colormap[i];
8504 if (logging != MagickFalse)
8506 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8507 " image->colors=%d (%d)",
8508 (int) image->colors, image_colors);
8510 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8511 " Update the pixel indexes");
8514 /* Sync the pixel indices with the new colormap */
8516 for (y=0; y < (ssize_t) image->rows; y++)
8518 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8520 if (q == (Quantum *) NULL)
8523 for (x=0; x < (ssize_t) image->columns; x++)
8525 for (i=0; i< (ssize_t) image_colors; i++)
8527 if ((image->matte == MagickFalse ||
8528 image->colormap[i].alpha == GetPixelAlpha(image,q)) &&
8529 image->colormap[i].red == GetPixelRed(image,q) &&
8530 image->colormap[i].green == GetPixelGreen(image,q) &&
8531 image->colormap[i].blue == GetPixelBlue(image,q))
8533 SetPixelIndex(image,i,q);
8537 q+=GetPixelChannels(image);
8540 if (SyncAuthenticPixels(image,exception) == MagickFalse)
8546 if (logging != MagickFalse)
8548 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8549 " image->colors=%d", (int) image->colors);
8551 if (image->colormap != NULL)
8553 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8554 " i (red,green,blue,alpha)");
8556 for (i=0; i < (ssize_t) image->colors; i++)
8558 if (i < 300 || i >= (ssize_t) image->colors - 10)
8560 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8561 " %d (%d,%d,%d,%d)",
8563 (int) image->colormap[i].red,
8564 (int) image->colormap[i].green,
8565 (int) image->colormap[i].blue,
8566 (int) image->colormap[i].alpha);
8571 if (number_transparent < 257)
8572 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8573 " number_transparent = %d",
8574 number_transparent);
8577 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8578 " number_transparent > 256");
8580 if (number_opaque < 257)
8581 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8582 " number_opaque = %d",
8586 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8587 " number_opaque > 256");
8589 if (number_semitransparent < 257)
8590 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8591 " number_semitransparent = %d",
8592 number_semitransparent);
8595 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8596 " number_semitransparent > 256");
8598 if (ping_have_non_bw == MagickFalse)
8599 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8600 " All pixels and the background are black or white");
8602 else if (ping_have_color == MagickFalse)
8603 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8604 " All pixels and the background are gray");
8607 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8608 " At least one pixel or the background is non-gray");
8610 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8611 " Exit BUILD_PALETTE:");
8614 if (mng_info->write_png8 == MagickFalse)
8617 /* Make any reductions necessary for the PNG8 format */
8618 if (image_colors <= 256 &&
8619 image_colors != 0 && image->colormap != NULL &&
8620 number_semitransparent == 0 &&
8621 number_transparent <= 1)
8624 /* PNG8 can't have semitransparent colors so we threshold the
8625 * opacity to 0 or OpaqueOpacity, and PNG8 can only have one
8626 * transparent color so if more than one is transparent we merge
8627 * them into image->background_color.
8629 if (number_semitransparent != 0 || number_transparent > 1)
8631 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8632 " Thresholding the alpha channel to binary");
8634 for (y=0; y < (ssize_t) image->rows; y++)
8636 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8638 if (r == (Quantum *) NULL)
8641 for (x=0; x < (ssize_t) image->columns; x++)
8643 if (GetPixelAlpha(image,r) < OpaqueAlpha/2)
8645 SetPixelInfoPixel(image,&image->background_color,r);
8646 SetPixelAlpha(image,TransparentAlpha,r);
8649 SetPixelAlpha(image,OpaqueAlpha,r);
8650 r+=GetPixelChannels(image);
8653 if (SyncAuthenticPixels(image,exception) == MagickFalse)
8656 if (image_colors != 0 && image_colors <= 256 &&
8657 image->colormap != NULL)
8658 for (i=0; i<image_colors; i++)
8659 image->colormap[i].alpha =
8660 (image->colormap[i].alpha > TransparentAlpha/2 ?
8661 TransparentAlpha : OpaqueAlpha);
8666 /* PNG8 can't have more than 256 colors so we quantize the pixels and
8667 * background color to the 4-4-4-1, 3-3-3-1 or 3-3-2-1 palette. If the
8668 * image is mostly gray, the 4-4-4-1 palette is likely to end up with 256
8671 if (tried_444 == MagickFalse && (image_colors == 0 || image_colors > 256))
8673 if (logging != MagickFalse)
8674 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8675 " Quantizing the background color to 4-4-4");
8677 tried_444 = MagickTrue;
8679 LBR04PacketRGB(image->background_color);
8681 if (logging != MagickFalse)
8682 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8683 " Quantizing the pixel colors to 4-4-4");
8685 if (image->colormap == NULL)
8687 for (y=0; y < (ssize_t) image->rows; y++)
8689 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8691 if (r == (Quantum *) NULL)
8694 for (x=0; x < (ssize_t) image->columns; x++)
8696 if (GetPixelAlpha(image,r) == OpaqueAlpha)
8698 r+=GetPixelChannels(image);
8701 if (SyncAuthenticPixels(image,exception) == MagickFalse)
8706 else /* Should not reach this; colormap already exists and
8709 if (logging != MagickFalse)
8710 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8711 " Quantizing the colormap to 4-4-4");
8713 for (i=0; i<image_colors; i++)
8715 LBR04PacketRGB(image->colormap[i]);
8721 if (tried_333 == MagickFalse && (image_colors == 0 || image_colors > 256))
8723 if (logging != MagickFalse)
8724 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8725 " Quantizing the background color to 3-3-3");
8727 tried_333 = MagickTrue;
8729 LBR03PacketRGB(image->background_color);
8731 if (logging != MagickFalse)
8732 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8733 " Quantizing the pixel colors to 3-3-3-1");
8735 if (image->colormap == NULL)
8737 for (y=0; y < (ssize_t) image->rows; y++)
8739 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8741 if (r == (Quantum *) NULL)
8744 for (x=0; x < (ssize_t) image->columns; x++)
8746 if (GetPixelAlpha(image,r) == OpaqueAlpha)
8748 r+=GetPixelChannels(image);
8751 if (SyncAuthenticPixels(image,exception) == MagickFalse)
8756 else /* Should not reach this; colormap already exists and
8759 if (logging != MagickFalse)
8760 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8761 " Quantizing the colormap to 3-3-3-1");
8762 for (i=0; i<image_colors; i++)
8764 LBR03PacketRGB(image->colormap[i]);
8770 if (tried_332 == MagickFalse && (image_colors == 0 || image_colors > 256))
8772 if (logging != MagickFalse)
8773 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8774 " Quantizing the background color to 3-3-2");
8776 tried_332 = MagickTrue;
8778 /* Red and green were already done so we only quantize the blue
8782 LBR02PacketBlue(image->background_color);
8784 if (logging != MagickFalse)
8785 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8786 " Quantizing the pixel colors to 3-3-2-1");
8788 if (image->colormap == NULL)
8790 for (y=0; y < (ssize_t) image->rows; y++)
8792 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8794 if (r == (Quantum *) NULL)
8797 for (x=0; x < (ssize_t) image->columns; x++)
8799 if (GetPixelAlpha(image,r) == OpaqueAlpha)
8801 r+=GetPixelChannels(image);
8804 if (SyncAuthenticPixels(image,exception) == MagickFalse)
8809 else /* Should not reach this; colormap already exists and
8812 if (logging != MagickFalse)
8813 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8814 " Quantizing the colormap to 3-3-2-1");
8815 for (i=0; i<image_colors; i++)
8817 LBR02PacketBlue(image->colormap[i]);
8824 if (image_colors == 0 || image_colors > 256)
8826 /* Take care of special case with 256 colors + 1 transparent
8827 * color. We don't need to quantize to 2-3-2-1; we only need to
8828 * eliminate one color, so we'll merge the two darkest red
8829 * colors (0x49, 0, 0) -> (0x24, 0, 0).
8831 if (ScaleQuantumToChar(image->background_color.red) == 0x49 &&
8832 ScaleQuantumToChar(image->background_color.green) == 0x00 &&
8833 ScaleQuantumToChar(image->background_color.blue) == 0x00)
8835 image->background_color.red=ScaleCharToQuantum(0x24);
8838 if (image->colormap == NULL)
8840 for (y=0; y < (ssize_t) image->rows; y++)
8842 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8844 if (r == (Quantum *) NULL)
8847 for (x=0; x < (ssize_t) image->columns; x++)
8849 if (ScaleQuantumToChar(GetPixelRed(image,r)) == 0x49 &&
8850 ScaleQuantumToChar(GetPixelGreen(image,r)) == 0x00 &&
8851 ScaleQuantumToChar(GetPixelBlue(image,r)) == 0x00 &&
8852 GetPixelAlpha(image,r) == OpaqueAlpha)
8854 SetPixelRed(image,ScaleCharToQuantum(0x24),r);
8856 r+=GetPixelChannels(image);
8859 if (SyncAuthenticPixels(image,exception) == MagickFalse)
8867 for (i=0; i<image_colors; i++)
8869 if (ScaleQuantumToChar(image->colormap[i].red) == 0x49 &&
8870 ScaleQuantumToChar(image->colormap[i].green) == 0x00 &&
8871 ScaleQuantumToChar(image->colormap[i].blue) == 0x00)
8873 image->colormap[i].red=ScaleCharToQuantum(0x24);
8879 /* END OF BUILD_PALETTE */
8881 /* If we are excluding the tRNS chunk and there is transparency,
8882 * then we must write a Gray-Alpha (color-type 4) or RGBA (color-type 6)
8885 if (mng_info->ping_exclude_tRNS != MagickFalse &&
8886 (number_transparent != 0 || number_semitransparent != 0))
8888 unsigned int colortype=mng_info->write_png_colortype;
8890 if (ping_have_color == MagickFalse)
8891 mng_info->write_png_colortype = 5;
8894 mng_info->write_png_colortype = 7;
8896 if (colortype != 0 &&
8897 mng_info->write_png_colortype != colortype)
8898 ping_need_colortype_warning=MagickTrue;
8902 /* See if cheap transparency is possible. It is only possible
8903 * when there is a single transparent color, no semitransparent
8904 * color, and no opaque color that has the same RGB components
8905 * as the transparent color. We only need this information if
8906 * we are writing a PNG with colortype 0 or 2, and we have not
8907 * excluded the tRNS chunk.
8909 if (number_transparent == 1 &&
8910 mng_info->write_png_colortype < 4)
8912 ping_have_cheap_transparency = MagickTrue;
8914 if (number_semitransparent != 0)
8915 ping_have_cheap_transparency = MagickFalse;
8917 else if (image_colors == 0 || image_colors > 256 ||
8918 image->colormap == NULL)
8920 register const Quantum
8923 for (y=0; y < (ssize_t) image->rows; y++)
8925 q=GetVirtualPixels(image,0,y,image->columns,1, exception);
8927 if (q == (Quantum *) NULL)
8930 for (x=0; x < (ssize_t) image->columns; x++)
8932 if (GetPixelAlpha(image,q) != TransparentAlpha &&
8933 (unsigned short) GetPixelRed(image,q) ==
8934 ping_trans_color.red &&
8935 (unsigned short) GetPixelGreen(image,q) ==
8936 ping_trans_color.green &&
8937 (unsigned short) GetPixelBlue(image,q) ==
8938 ping_trans_color.blue)
8940 ping_have_cheap_transparency = MagickFalse;
8944 q+=GetPixelChannels(image);
8947 if (ping_have_cheap_transparency == MagickFalse)
8953 /* Assuming that image->colormap[0] is the one transparent color
8954 * and that all others are opaque.
8956 if (image_colors > 1)
8957 for (i=1; i<image_colors; i++)
8958 if (image->colormap[i].red == image->colormap[0].red &&
8959 image->colormap[i].green == image->colormap[0].green &&
8960 image->colormap[i].blue == image->colormap[0].blue)
8962 ping_have_cheap_transparency = MagickFalse;
8967 if (logging != MagickFalse)
8969 if (ping_have_cheap_transparency == MagickFalse)
8970 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8971 " Cheap transparency is not possible.");
8974 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8975 " Cheap transparency is possible.");
8979 ping_have_cheap_transparency = MagickFalse;
8981 image_depth=image->depth;
8983 quantum_info = (QuantumInfo *) NULL;
8985 image_colors=(int) image->colors;
8986 image_matte=image->matte;
8988 mng_info->IsPalette=image->storage_class == PseudoClass &&
8989 image_colors <= 256 && image->colormap != NULL;
8991 if ((mng_info->write_png_colortype == 4 || mng_info->write_png8) &&
8992 (image->colors == 0 || image->colormap == NULL))
8994 image_info=DestroyImageInfo(image_info);
8995 image=DestroyImage(image);
8996 (void) ThrowMagickException(exception,GetMagickModule(),CoderError,
8997 "Cannot write PNG8 or color-type 3; colormap is NULL",
8998 "`%s'",IMimage->filename);
8999 return(MagickFalse);
9003 Allocate the PNG structures
9005 #ifdef PNG_USER_MEM_SUPPORTED
9006 error_info.image=image;
9007 error_info.exception=exception;
9008 ping=png_create_write_struct_2(PNG_LIBPNG_VER_STRING,&error_info,
9009 MagickPNGErrorHandler,MagickPNGWarningHandler,(void *) NULL,
9010 (png_malloc_ptr) Magick_png_malloc,(png_free_ptr) Magick_png_free);
9013 ping=png_create_write_struct(PNG_LIBPNG_VER_STRING,&error_info,
9014 MagickPNGErrorHandler,MagickPNGWarningHandler);
9017 if (ping == (png_struct *) NULL)
9018 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
9020 ping_info=png_create_info_struct(ping);
9022 if (ping_info == (png_info *) NULL)
9024 png_destroy_write_struct(&ping,(png_info **) NULL);
9025 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
9028 png_set_write_fn(ping,image,png_put_data,png_flush_data);
9029 ping_pixels=(unsigned char *) NULL;
9031 if (setjmp(png_jmpbuf(ping)))
9037 if (image_info->verbose)
9038 (void) printf("PNG write has failed.\n");
9040 png_destroy_write_struct(&ping,&ping_info);
9041 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
9042 UnlockSemaphoreInfo(ping_semaphore);
9045 if (ping_pixels != (unsigned char *) NULL)
9046 ping_pixels=(unsigned char *) RelinquishMagickMemory(ping_pixels);
9048 if (quantum_info != (QuantumInfo *) NULL)
9049 quantum_info=DestroyQuantumInfo(quantum_info);
9051 if (ping_have_blob != MagickFalse)
9052 (void) CloseBlob(image);
9053 image_info=DestroyImageInfo(image_info);
9054 image=DestroyImage(image);
9055 return(MagickFalse);
9058 /* { For navigation to end of SETJMP-protected block. Within this
9059 * block, use png_error() instead of Throwing an Exception, to ensure
9060 * that libpng is able to clean up, and that the semaphore is unlocked.
9063 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
9064 LockSemaphoreInfo(ping_semaphore);
9068 Prepare PNG for writing.
9071 #if defined(PNG_MNG_FEATURES_SUPPORTED)
9072 if (mng_info->write_mng)
9074 (void) png_permit_mng_features(ping,PNG_ALL_MNG_FEATURES);
9075 # ifdef PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED
9076 /* Disable new libpng-1.5.10 feature when writing a MNG because
9077 * zero-length PLTE is OK
9079 png_set_check_for_invalid_index (ping, 0);
9084 # ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
9085 if (mng_info->write_mng)
9086 png_permit_empty_plte(ping,MagickTrue);
9093 ping_width=(png_uint_32) image->columns;
9094 ping_height=(png_uint_32) image->rows;
9096 if (mng_info->write_png8 || mng_info->write_png24 || mng_info->write_png32)
9099 if (mng_info->write_png_depth != 0)
9100 image_depth=mng_info->write_png_depth;
9102 /* Adjust requested depth to next higher valid depth if necessary */
9103 if (image_depth > 8)
9106 if ((image_depth > 4) && (image_depth < 8))
9109 if (image_depth == 3)
9112 if (logging != MagickFalse)
9114 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9115 " width=%.20g",(double) ping_width);
9116 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9117 " height=%.20g",(double) ping_height);
9118 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9119 " image_matte=%.20g",(double) image->matte);
9120 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9121 " image->depth=%.20g",(double) image->depth);
9122 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9123 " Tentative ping_bit_depth=%.20g",(double) image_depth);
9126 save_image_depth=image_depth;
9127 ping_bit_depth=(png_byte) save_image_depth;
9130 #if defined(PNG_pHYs_SUPPORTED)
9131 if (ping_exclude_pHYs == MagickFalse)
9133 if ((image->resolution.x != 0) && (image->resolution.y != 0) &&
9134 (!mng_info->write_mng || !mng_info->equal_physs))
9136 if (logging != MagickFalse)
9137 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9138 " Setting up pHYs chunk");
9140 if (image->units == PixelsPerInchResolution)
9142 ping_pHYs_unit_type=PNG_RESOLUTION_METER;
9143 ping_pHYs_x_resolution=
9144 (png_uint_32) ((100.0*image->resolution.x+0.5)/2.54);
9145 ping_pHYs_y_resolution=
9146 (png_uint_32) ((100.0*image->resolution.y+0.5)/2.54);
9149 else if (image->units == PixelsPerCentimeterResolution)
9151 ping_pHYs_unit_type=PNG_RESOLUTION_METER;
9152 ping_pHYs_x_resolution=(png_uint_32) (100.0*image->resolution.x+0.5);
9153 ping_pHYs_y_resolution=(png_uint_32) (100.0*image->resolution.y+0.5);
9158 ping_pHYs_unit_type=PNG_RESOLUTION_UNKNOWN;
9159 ping_pHYs_x_resolution=(png_uint_32) image->resolution.x;
9160 ping_pHYs_y_resolution=(png_uint_32) image->resolution.y;
9163 if (logging != MagickFalse)
9164 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9165 " Set up PNG pHYs chunk: xres: %.20g, yres: %.20g, units: %d.",
9166 (double) ping_pHYs_x_resolution,(double) ping_pHYs_y_resolution,
9167 (int) ping_pHYs_unit_type);
9168 ping_have_pHYs = MagickTrue;
9173 if (ping_exclude_bKGD == MagickFalse)
9175 if ((!mng_info->adjoin || !mng_info->equal_backgrounds))
9181 if (ping_bit_depth == 8)
9184 if (ping_bit_depth == 4)
9187 if (ping_bit_depth == 2)
9190 if (ping_bit_depth == 1)
9193 ping_background.red=(png_uint_16)
9194 (ScaleQuantumToShort(image->background_color.red) & mask);
9196 ping_background.green=(png_uint_16)
9197 (ScaleQuantumToShort(image->background_color.green) & mask);
9199 ping_background.blue=(png_uint_16)
9200 (ScaleQuantumToShort(image->background_color.blue) & mask);
9202 ping_background.gray=(png_uint_16) ping_background.green;
9205 if (logging != MagickFalse)
9207 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9208 " Setting up bKGD chunk (1)");
9209 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9210 " background_color index is %d",
9211 (int) ping_background.index);
9213 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9214 " ping_bit_depth=%d",ping_bit_depth);
9217 ping_have_bKGD = MagickTrue;
9221 Select the color type.
9226 if (mng_info->IsPalette && mng_info->write_png8)
9229 /* To do: make this a function cause it's used twice, except
9230 for reducing the sample depth from 8. */
9232 number_colors=image_colors;
9234 ping_have_tRNS=MagickFalse;
9239 ping_color_type=(png_byte) PNG_COLOR_TYPE_PALETTE;
9241 if (logging != MagickFalse)
9242 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9243 " Setting up PLTE chunk with %d colors (%d)",
9244 number_colors, image_colors);
9246 for (i=0; i < (ssize_t) number_colors; i++)
9248 palette[i].red=ScaleQuantumToChar(image->colormap[i].red);
9249 palette[i].green=ScaleQuantumToChar(image->colormap[i].green);
9250 palette[i].blue=ScaleQuantumToChar(image->colormap[i].blue);
9251 if (logging != MagickFalse)
9252 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9253 #if MAGICKCORE_QUANTUM_DEPTH == 8
9254 " %3ld (%3d,%3d,%3d)",
9256 " %5ld (%5d,%5d,%5d)",
9258 (long) i,palette[i].red,palette[i].green,palette[i].blue);
9262 ping_have_PLTE=MagickTrue;
9263 image_depth=ping_bit_depth;
9266 if (matte != MagickFalse)
9269 Identify which colormap entry is transparent.
9271 assert(number_colors <= 256);
9272 assert(image->colormap != NULL);
9274 for (i=0; i < (ssize_t) number_transparent; i++)
9275 ping_trans_alpha[i]=0;
9278 ping_num_trans=(unsigned short) (number_transparent +
9279 number_semitransparent);
9281 if (ping_num_trans == 0)
9282 ping_have_tRNS=MagickFalse;
9285 ping_have_tRNS=MagickTrue;
9288 if (ping_exclude_bKGD == MagickFalse)
9291 * Identify which colormap entry is the background color.
9294 for (i=0; i < (ssize_t) MagickMax(1L*number_colors-1L,1L); i++)
9295 if (IsPNGColorEqual(ping_background,image->colormap[i]))
9298 ping_background.index=(png_byte) i;
9300 if (logging != MagickFalse)
9302 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9303 " background_color index is %d",
9304 (int) ping_background.index);
9307 } /* end of write_png8 */
9309 else if (mng_info->write_png24 || mng_info->write_png_colortype == 3)
9311 image_matte=MagickFalse;
9312 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB;
9315 else if (mng_info->write_png32 || mng_info->write_png_colortype == 7)
9317 image_matte=MagickTrue;
9318 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB_ALPHA;
9321 else /* mng_info->write_pngNN not specified */
9323 image_depth=ping_bit_depth;
9325 if (mng_info->write_png_colortype != 0)
9327 ping_color_type=(png_byte) mng_info->write_png_colortype-1;
9329 if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA ||
9330 ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA)
9331 image_matte=MagickTrue;
9334 image_matte=MagickFalse;
9336 if (logging != MagickFalse)
9337 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9338 " PNG colortype %d was specified:",(int) ping_color_type);
9341 else /* write_png_colortype not specified */
9343 if (logging != MagickFalse)
9344 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9345 " Selecting PNG colortype:");
9347 ping_color_type=(png_byte) ((matte != MagickFalse)?
9348 PNG_COLOR_TYPE_RGB_ALPHA:PNG_COLOR_TYPE_RGB);
9350 if (image_info->type == TrueColorType)
9352 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB;
9353 image_matte=MagickFalse;
9356 if (image_info->type == TrueColorMatteType)
9358 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB_ALPHA;
9359 image_matte=MagickTrue;
9362 if (image_info->type == PaletteType ||
9363 image_info->type == PaletteMatteType)
9364 ping_color_type=(png_byte) PNG_COLOR_TYPE_PALETTE;
9366 if (mng_info->write_png_colortype == 0 &&
9367 (image_info->type == UndefinedType ||
9368 image_info->type == OptimizeType))
9370 if (ping_have_color == MagickFalse)
9372 if (image_matte == MagickFalse)
9374 ping_color_type=(png_byte) PNG_COLOR_TYPE_GRAY;
9375 image_matte=MagickFalse;
9380 ping_color_type=(png_byte) PNG_COLOR_TYPE_GRAY_ALPHA;
9381 image_matte=MagickTrue;
9386 if (image_matte == MagickFalse)
9388 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB;
9389 image_matte=MagickFalse;
9394 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGBA;
9395 image_matte=MagickTrue;
9402 if (logging != MagickFalse)
9403 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9404 " Selected PNG colortype=%d",ping_color_type);
9406 if (ping_bit_depth < 8)
9408 if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA ||
9409 ping_color_type == PNG_COLOR_TYPE_RGB ||
9410 ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA)
9414 old_bit_depth=ping_bit_depth;
9416 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
9418 if (image->matte == MagickFalse && ping_have_non_bw == MagickFalse)
9422 if (ping_color_type == PNG_COLOR_TYPE_PALETTE)
9427 if (image->colors == 0)
9430 png_error(ping,"image has 0 colors");
9433 while ((int) (one << ping_bit_depth) < (ssize_t) image_colors)
9434 ping_bit_depth <<= 1;
9437 if (logging != MagickFalse)
9439 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9440 " Number of colors: %.20g",(double) image_colors);
9442 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9443 " Tentative PNG bit depth: %d",ping_bit_depth);
9446 if (ping_bit_depth < (int) mng_info->write_png_depth)
9447 ping_bit_depth = mng_info->write_png_depth;
9450 image_depth=ping_bit_depth;
9452 if (logging != MagickFalse)
9454 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9455 " Tentative PNG color type: %s (%.20g)",
9456 PngColorTypeToString(ping_color_type),
9457 (double) ping_color_type);
9459 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9460 " image_info->type: %.20g",(double) image_info->type);
9462 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9463 " image_depth: %.20g",(double) image_depth);
9465 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9467 " image->depth: %.20g",(double) image->depth);
9469 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9470 " ping_bit_depth: %.20g",(double) ping_bit_depth);
9473 if (matte != MagickFalse)
9475 if (mng_info->IsPalette)
9477 if (mng_info->write_png_colortype == 0)
9479 ping_color_type=PNG_COLOR_TYPE_GRAY_ALPHA;
9481 if (ping_have_color != MagickFalse)
9482 ping_color_type=PNG_COLOR_TYPE_RGBA;
9486 * Determine if there is any transparent color.
9488 if (number_transparent + number_semitransparent == 0)
9491 No transparent pixels are present. Change 4 or 6 to 0 or 2.
9494 image_matte=MagickFalse;
9496 if (mng_info->write_png_colortype == 0)
9497 ping_color_type&=0x03;
9507 if (ping_bit_depth == 8)
9510 if (ping_bit_depth == 4)
9513 if (ping_bit_depth == 2)
9516 if (ping_bit_depth == 1)
9519 ping_trans_color.red=(png_uint_16)
9520 (ScaleQuantumToShort(image->colormap[0].red) & mask);
9522 ping_trans_color.green=(png_uint_16)
9523 (ScaleQuantumToShort(image->colormap[0].green) & mask);
9525 ping_trans_color.blue=(png_uint_16)
9526 (ScaleQuantumToShort(image->colormap[0].blue) & mask);
9528 ping_trans_color.gray=(png_uint_16)
9529 (ScaleQuantumToShort(GetPixelInfoIntensity(
9530 image->colormap)) & mask);
9532 ping_trans_color.index=(png_byte) 0;
9534 ping_have_tRNS=MagickTrue;
9537 if (ping_have_tRNS != MagickFalse)
9540 * Determine if there is one and only one transparent color
9541 * and if so if it is fully transparent.
9543 if (ping_have_cheap_transparency == MagickFalse)
9544 ping_have_tRNS=MagickFalse;
9547 if (ping_have_tRNS != MagickFalse)
9549 if (mng_info->write_png_colortype == 0)
9550 ping_color_type &= 0x03; /* changes 4 or 6 to 0 or 2 */
9552 if (image_depth == 8)
9554 ping_trans_color.red&=0xff;
9555 ping_trans_color.green&=0xff;
9556 ping_trans_color.blue&=0xff;
9557 ping_trans_color.gray&=0xff;
9563 if (image_depth == 8)
9565 ping_trans_color.red&=0xff;
9566 ping_trans_color.green&=0xff;
9567 ping_trans_color.blue&=0xff;
9568 ping_trans_color.gray&=0xff;
9575 if (ping_have_tRNS != MagickFalse)
9576 image_matte=MagickFalse;
9578 if ((mng_info->IsPalette) &&
9579 mng_info->write_png_colortype-1 != PNG_COLOR_TYPE_PALETTE &&
9580 ping_have_color == MagickFalse &&
9581 (image_matte == MagickFalse || image_depth >= 8))
9585 if (image_matte != MagickFalse)
9586 ping_color_type=PNG_COLOR_TYPE_GRAY_ALPHA;
9588 else if (mng_info->write_png_colortype-1 != PNG_COLOR_TYPE_GRAY_ALPHA)
9590 ping_color_type=PNG_COLOR_TYPE_GRAY;
9592 if (save_image_depth == 16 && image_depth == 8)
9594 if (logging != MagickFalse)
9596 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9597 " Scaling ping_trans_color (0)");
9599 ping_trans_color.gray*=0x0101;
9603 if (image_depth > MAGICKCORE_QUANTUM_DEPTH)
9604 image_depth=MAGICKCORE_QUANTUM_DEPTH;
9606 if ((image_colors == 0) ||
9607 ((ssize_t) (image_colors-1) > (ssize_t) MaxColormapSize))
9608 image_colors=(int) (one << image_depth);
9610 if (image_depth > 8)
9616 if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
9618 if(!mng_info->write_png_depth)
9622 while ((int) (one << ping_bit_depth)
9623 < (ssize_t) image_colors)
9624 ping_bit_depth <<= 1;
9628 else if (ping_color_type ==
9629 PNG_COLOR_TYPE_GRAY && image_colors < 17 &&
9630 mng_info->IsPalette)
9632 /* Check if grayscale is reducible */
9635 depth_4_ok=MagickTrue,
9636 depth_2_ok=MagickTrue,
9637 depth_1_ok=MagickTrue;
9639 for (i=0; i < (ssize_t) image_colors; i++)
9644 intensity=ScaleQuantumToChar(image->colormap[i].red);
9646 if ((intensity & 0x0f) != ((intensity & 0xf0) >> 4))
9647 depth_4_ok=depth_2_ok=depth_1_ok=MagickFalse;
9648 else if ((intensity & 0x03) != ((intensity & 0x0c) >> 2))
9649 depth_2_ok=depth_1_ok=MagickFalse;
9650 else if ((intensity & 0x01) != ((intensity & 0x02) >> 1))
9651 depth_1_ok=MagickFalse;
9654 if (depth_1_ok && mng_info->write_png_depth <= 1)
9657 else if (depth_2_ok && mng_info->write_png_depth <= 2)
9660 else if (depth_4_ok && mng_info->write_png_depth <= 4)
9665 image_depth=ping_bit_depth;
9670 if (mng_info->IsPalette)
9672 number_colors=image_colors;
9674 if (image_depth <= 8)
9679 ping_color_type=(png_byte) PNG_COLOR_TYPE_PALETTE;
9681 if (mng_info->have_write_global_plte && matte == MagickFalse)
9683 png_set_PLTE(ping,ping_info,NULL,0);
9685 if (logging != MagickFalse)
9686 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9687 " Setting up empty PLTE chunk");
9692 for (i=0; i < (ssize_t) number_colors; i++)
9694 palette[i].red=ScaleQuantumToChar(image->colormap[i].red);
9695 palette[i].green=ScaleQuantumToChar(image->colormap[i].green);
9696 palette[i].blue=ScaleQuantumToChar(image->colormap[i].blue);
9699 if (logging != MagickFalse)
9700 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9701 " Setting up PLTE chunk with %d colors",
9704 ping_have_PLTE=MagickTrue;
9707 /* color_type is PNG_COLOR_TYPE_PALETTE */
9708 if (mng_info->write_png_depth == 0)
9716 while ((one << ping_bit_depth) < (size_t) number_colors)
9717 ping_bit_depth <<= 1;
9722 if (matte != MagickFalse)
9725 * Set up trans_colors array.
9727 assert(number_colors <= 256);
9729 ping_num_trans=(unsigned short) (number_transparent +
9730 number_semitransparent);
9732 if (ping_num_trans == 0)
9733 ping_have_tRNS=MagickFalse;
9737 if (logging != MagickFalse)
9739 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9740 " Scaling ping_trans_color (1)");
9742 ping_have_tRNS=MagickTrue;
9744 for (i=0; i < ping_num_trans; i++)
9746 ping_trans_alpha[i]= (png_byte)
9747 ScaleQuantumToChar(image->colormap[i].alpha);
9757 if (image_depth < 8)
9760 if ((save_image_depth == 16) && (image_depth == 8))
9762 if (logging != MagickFalse)
9764 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9765 " Scaling ping_trans_color from (%d,%d,%d)",
9766 (int) ping_trans_color.red,
9767 (int) ping_trans_color.green,
9768 (int) ping_trans_color.blue);
9771 ping_trans_color.red*=0x0101;
9772 ping_trans_color.green*=0x0101;
9773 ping_trans_color.blue*=0x0101;
9774 ping_trans_color.gray*=0x0101;
9776 if (logging != MagickFalse)
9778 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9780 (int) ping_trans_color.red,
9781 (int) ping_trans_color.green,
9782 (int) ping_trans_color.blue);
9787 if (ping_bit_depth < (ssize_t) mng_info->write_png_depth)
9788 ping_bit_depth = (ssize_t) mng_info->write_png_depth;
9791 Adjust background and transparency samples in sub-8-bit grayscale files.
9793 if (ping_bit_depth < 8 && ping_color_type ==
9794 PNG_COLOR_TYPE_GRAY)
9802 maxval=(png_uint_16) ((one << ping_bit_depth)-1);
9804 if (ping_exclude_bKGD == MagickFalse)
9807 ping_background.gray=(png_uint_16) ((maxval/65535.)*
9808 (ScaleQuantumToShort(((GetPixelInfoIntensity(
9809 &image->background_color))) +.5)));
9811 if (logging != MagickFalse)
9812 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9813 " Setting up bKGD chunk (2)");
9814 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9815 " background_color index is %d",
9816 (int) ping_background.index);
9818 ping_have_bKGD = MagickTrue;
9821 if (logging != MagickFalse)
9822 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9823 " Scaling ping_trans_color.gray from %d",
9824 (int)ping_trans_color.gray);
9826 ping_trans_color.gray=(png_uint_16) ((maxval/255.)*(
9827 ping_trans_color.gray)+.5);
9829 if (logging != MagickFalse)
9830 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9831 " to %d", (int)ping_trans_color.gray);
9834 if (ping_exclude_bKGD == MagickFalse)
9836 if (mng_info->IsPalette && (int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
9839 Identify which colormap entry is the background color.
9842 number_colors=image_colors;
9844 for (i=0; i < (ssize_t) MagickMax(1L*number_colors,1L); i++)
9845 if (IsPNGColorEqual(image->background_color,image->colormap[i]))
9848 ping_background.index=(png_byte) i;
9850 if (logging != MagickFalse)
9852 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9853 " Setting up bKGD chunk with index=%d",(int) i);
9856 if (i < (ssize_t) number_colors)
9858 ping_have_bKGD = MagickTrue;
9860 if (logging != MagickFalse)
9862 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9863 " background =(%d,%d,%d)",
9864 (int) ping_background.red,
9865 (int) ping_background.green,
9866 (int) ping_background.blue);
9870 else /* Can't happen */
9872 if (logging != MagickFalse)
9873 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9874 " No room in PLTE to add bKGD color");
9875 ping_have_bKGD = MagickFalse;
9880 if (logging != MagickFalse)
9881 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9882 " PNG color type: %s (%d)", PngColorTypeToString(ping_color_type),
9885 Initialize compression level and filtering.
9887 if (logging != MagickFalse)
9889 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9890 " Setting up deflate compression");
9892 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9893 " Compression buffer size: 32768");
9896 png_set_compression_buffer_size(ping,32768L);
9898 if (logging != MagickFalse)
9899 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9900 " Compression mem level: 9");
9902 png_set_compression_mem_level(ping, 9);
9904 /* Untangle the "-quality" setting:
9906 Undefined is 0; the default is used.
9911 0: Use Z_HUFFMAN_ONLY strategy with the
9912 zlib default compression level
9914 1-9: the zlib compression level
9918 0-4: the PNG filter method
9920 5: libpng adaptive filtering if compression level > 5
9921 libpng filter type "none" if compression level <= 5
9922 or if image is grayscale or palette
9924 6: libpng adaptive filtering
9926 7: "LOCO" filtering (intrapixel differing) if writing
9927 a MNG, othewise "none". Did not work in IM-6.7.0-9
9928 and earlier because of a missing "else".
9930 8: Z_RLE strategy, all filters
9931 Unused prior to IM-6.7.0-10, was same as 6
9933 9: Z_RLE strategy, no PNG filters
9934 Unused prior to IM-6.7.0-10, was same as 6
9936 Note that using the -quality option, not all combinations of
9937 PNG filter type, zlib compression level, and zlib compression
9938 strategy are possible. This will be addressed soon in a
9939 release that accomodates "-define png:compression-strategy", etc.
9943 quality=image->quality == UndefinedCompressionQuality ? 75UL :
9948 if (mng_info->write_png_compression_strategy == 0)
9949 mng_info->write_png_compression_strategy = Z_HUFFMAN_ONLY+1;
9952 else if (mng_info->write_png_compression_level == 0)
9957 level=(int) MagickMin((ssize_t) quality/10,9);
9959 mng_info->write_png_compression_level = level+1;
9962 if (mng_info->write_png_compression_strategy == 0)
9964 if ((quality %10) == 8 || (quality %10) == 9)
9965 #ifdef Z_RLE /* Z_RLE was added to zlib-1.2.0 */
9966 mng_info->write_png_compression_strategy=Z_RLE+1;
9968 mng_info->write_png_compression_strategy = Z_DEFAULT_STRATEGY+1;
9972 if (mng_info->write_png_compression_filter == 0)
9973 mng_info->write_png_compression_filter=((int) quality % 10) + 1;
9975 if (logging != MagickFalse)
9977 if (mng_info->write_png_compression_level)
9978 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9979 " Compression level: %d",
9980 (int) mng_info->write_png_compression_level-1);
9982 if (mng_info->write_png_compression_strategy)
9983 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9984 " Compression strategy: %d",
9985 (int) mng_info->write_png_compression_strategy-1);
9987 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9988 " Setting up filtering");
9990 if (mng_info->write_png_compression_filter == 6)
9991 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9992 " Base filter method: ADAPTIVE");
9993 else if (mng_info->write_png_compression_filter == 0 ||
9994 mng_info->write_png_compression_filter == 1)
9995 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9996 " Base filter method: NONE");
9998 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9999 " Base filter method: %d",
10000 (int) mng_info->write_png_compression_filter-1);
10003 if (mng_info->write_png_compression_level != 0)
10004 png_set_compression_level(ping,mng_info->write_png_compression_level-1);
10006 if (mng_info->write_png_compression_filter == 6)
10008 if (((int) ping_color_type == PNG_COLOR_TYPE_GRAY) ||
10009 ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE) ||
10011 png_set_filter(ping,PNG_FILTER_TYPE_BASE,PNG_NO_FILTERS);
10013 png_set_filter(ping,PNG_FILTER_TYPE_BASE,PNG_ALL_FILTERS);
10015 else if (mng_info->write_png_compression_filter == 7 ||
10016 mng_info->write_png_compression_filter == 10)
10017 png_set_filter(ping,PNG_FILTER_TYPE_BASE,PNG_ALL_FILTERS);
10019 else if (mng_info->write_png_compression_filter == 8)
10021 #if defined(PNG_MNG_FEATURES_SUPPORTED) && defined(PNG_INTRAPIXEL_DIFFERENCING)
10022 if (mng_info->write_mng)
10024 if (((int) ping_color_type == PNG_COLOR_TYPE_RGB) ||
10025 ((int) ping_color_type == PNG_COLOR_TYPE_RGBA))
10026 ping_filter_method=PNG_INTRAPIXEL_DIFFERENCING;
10029 png_set_filter(ping,PNG_FILTER_TYPE_BASE,PNG_NO_FILTERS);
10032 else if (mng_info->write_png_compression_filter == 9)
10033 png_set_filter(ping,PNG_FILTER_TYPE_BASE,PNG_NO_FILTERS);
10035 else if (mng_info->write_png_compression_filter != 0)
10036 png_set_filter(ping,PNG_FILTER_TYPE_BASE,
10037 mng_info->write_png_compression_filter-1);
10039 if (mng_info->write_png_compression_strategy != 0)
10040 png_set_compression_strategy(ping,
10041 mng_info->write_png_compression_strategy-1);
10043 /* Only write the iCCP chunk if we are not writing the sRGB chunk. */
10044 if (ping_exclude_sRGB != MagickFalse ||
10045 (image->rendering_intent == UndefinedIntent))
10047 if ((ping_exclude_tEXt == MagickFalse ||
10048 ping_exclude_zTXt == MagickFalse) &&
10049 (ping_exclude_iCCP == MagickFalse || ping_exclude_zCCP == MagickFalse))
10051 ResetImageProfileIterator(image);
10052 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
10054 profile=GetImageProfile(image,name);
10056 if (profile != (StringInfo *) NULL)
10058 #ifdef PNG_WRITE_iCCP_SUPPORTED
10059 if ((LocaleCompare(name,"ICC") == 0) ||
10060 (LocaleCompare(name,"ICM") == 0))
10063 if (ping_exclude_iCCP == MagickFalse)
10065 png_set_iCCP(ping,ping_info,(png_charp) name,0,
10066 #if (PNG_LIBPNG_VER < 10500)
10067 (png_charp) GetStringInfoDatum(profile),
10069 (png_const_bytep) GetStringInfoDatum(profile),
10071 (png_uint_32) GetStringInfoLength(profile));
10077 if (ping_exclude_zCCP == MagickFalse)
10079 Magick_png_write_raw_profile(image_info,ping,ping_info,
10080 (unsigned char *) name,(unsigned char *) name,
10081 GetStringInfoDatum(profile),
10082 (png_uint_32) GetStringInfoLength(profile));
10086 if (logging != MagickFalse)
10087 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10088 " Setting up text chunk with %s profile",name);
10090 name=GetNextImageProfile(image);
10095 #if defined(PNG_WRITE_sRGB_SUPPORTED)
10096 if ((mng_info->have_write_global_srgb == 0) &&
10097 (image->rendering_intent != UndefinedIntent))
10099 if (ping_exclude_sRGB == MagickFalse)
10102 Note image rendering intent.
10104 if (logging != MagickFalse)
10105 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10106 " Setting up sRGB chunk");
10108 (void) png_set_sRGB(ping,ping_info,(
10109 Magick_RenderingIntent_to_PNG_RenderingIntent(
10110 image->rendering_intent)));
10114 if ((!mng_info->write_mng) || (!png_get_valid(ping,ping_info,PNG_INFO_sRGB)))
10117 if (ping_exclude_gAMA == MagickFalse &&
10118 (ping_exclude_sRGB == MagickFalse ||
10119 (image->gamma < .45 || image->gamma > .46)))
10121 if ((mng_info->have_write_global_gama == 0) && (image->gamma != 0.0))
10125 To do: check for cHRM+gAMA == sRGB, and write sRGB instead.
10127 if (logging != MagickFalse)
10128 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10129 " Setting up gAMA chunk");
10131 png_set_gAMA(ping,ping_info,image->gamma);
10135 if (ping_exclude_cHRM == MagickFalse)
10137 if ((mng_info->have_write_global_chrm == 0) &&
10138 (image->chromaticity.red_primary.x != 0.0))
10141 Note image chromaticity.
10142 To do: check for cHRM+gAMA == sRGB, and write sRGB instead.
10150 wp=image->chromaticity.white_point;
10151 rp=image->chromaticity.red_primary;
10152 gp=image->chromaticity.green_primary;
10153 bp=image->chromaticity.blue_primary;
10155 if (logging != MagickFalse)
10156 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10157 " Setting up cHRM chunk");
10159 png_set_cHRM(ping,ping_info,wp.x,wp.y,rp.x,rp.y,gp.x,gp.y,
10165 ping_interlace_method=image_info->interlace != NoInterlace;
10167 if (mng_info->write_mng)
10168 png_set_sig_bytes(ping,8);
10170 /* Bail out if cannot meet defined png:bit-depth or png:color-type */
10172 if (mng_info->write_png_colortype != 0)
10174 if (mng_info->write_png_colortype-1 == PNG_COLOR_TYPE_GRAY)
10175 if (ping_have_color != MagickFalse)
10177 ping_color_type = PNG_COLOR_TYPE_RGB;
10179 if (ping_bit_depth < 8)
10183 if (mng_info->write_png_colortype-1 == PNG_COLOR_TYPE_GRAY_ALPHA)
10184 if (ping_have_color != MagickFalse)
10185 ping_color_type = PNG_COLOR_TYPE_RGB_ALPHA;
10188 if (ping_need_colortype_warning != MagickFalse ||
10189 ((mng_info->write_png_depth &&
10190 (int) mng_info->write_png_depth != ping_bit_depth) ||
10191 (mng_info->write_png_colortype &&
10192 ((int) mng_info->write_png_colortype-1 != ping_color_type &&
10193 mng_info->write_png_colortype != 7 &&
10194 !(mng_info->write_png_colortype == 5 && ping_color_type == 0)))))
10196 if (logging != MagickFalse)
10198 if (ping_need_colortype_warning != MagickFalse)
10200 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10201 " Image has transparency but tRNS chunk was excluded");
10204 if (mng_info->write_png_depth)
10206 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10207 " Defined png:bit-depth=%u, Computed depth=%u",
10208 mng_info->write_png_depth,
10212 if (mng_info->write_png_colortype)
10214 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10215 " Defined png:color-type=%u, Computed color type=%u",
10216 mng_info->write_png_colortype-1,
10222 "Cannot write image with defined png:bit-depth or png:color-type.");
10225 if (image_matte != MagickFalse && image->matte == MagickFalse)
10227 /* Add an opaque matte channel */
10228 image->matte = MagickTrue;
10229 (void) SetImageAlpha(image,OpaqueAlpha,exception);
10231 if (logging != MagickFalse)
10232 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10233 " Added an opaque matte channel");
10236 if (number_transparent != 0 || number_semitransparent != 0)
10238 if (ping_color_type < 4)
10240 ping_have_tRNS=MagickTrue;
10241 if (logging != MagickFalse)
10242 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10243 " Setting ping_have_tRNS=MagickTrue.");
10247 if (logging != MagickFalse)
10248 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10249 " Writing PNG header chunks");
10251 png_set_IHDR(ping,ping_info,ping_width,ping_height,
10252 ping_bit_depth,ping_color_type,
10253 ping_interlace_method,ping_compression_method,
10254 ping_filter_method);
10256 if (ping_color_type == 3 && ping_have_PLTE != MagickFalse)
10258 png_set_PLTE(ping,ping_info,palette,number_colors);
10260 if (logging != MagickFalse)
10262 for (i=0; i< (ssize_t) number_colors; i++)
10264 if (i < ping_num_trans)
10265 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10266 " PLTE[%d] = (%d,%d,%d), tRNS[%d] = (%d)",
10268 (int) palette[i].red,
10269 (int) palette[i].green,
10270 (int) palette[i].blue,
10272 (int) ping_trans_alpha[i]);
10274 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10275 " PLTE[%d] = (%d,%d,%d)",
10277 (int) palette[i].red,
10278 (int) palette[i].green,
10279 (int) palette[i].blue);
10284 if (ping_exclude_bKGD == MagickFalse)
10286 if (ping_have_bKGD != MagickFalse)
10288 png_set_bKGD(ping,ping_info,&ping_background);
10291 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10292 " Setting up bKGD chunk");
10293 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10294 " background color = (%d,%d,%d)",
10295 (int) ping_background.red,
10296 (int) ping_background.green,
10297 (int) ping_background.blue);
10298 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10299 " index = %d, gray=%d",
10300 (int) ping_background.index,
10301 (int) ping_background.gray);
10306 if (ping_exclude_pHYs == MagickFalse)
10308 if (ping_have_pHYs != MagickFalse)
10310 png_set_pHYs(ping,ping_info,
10311 ping_pHYs_x_resolution,
10312 ping_pHYs_y_resolution,
10313 ping_pHYs_unit_type);
10317 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10318 " Setting up pHYs chunk");
10319 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10320 " x_resolution=%lu",
10321 (unsigned long) ping_pHYs_x_resolution);
10322 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10323 " y_resolution=%lu",
10324 (unsigned long) ping_pHYs_y_resolution);
10325 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10327 (unsigned long) ping_pHYs_unit_type);
10332 #if defined(PNG_oFFs_SUPPORTED)
10333 if (ping_exclude_oFFs == MagickFalse)
10335 if (image->page.x || image->page.y)
10337 png_set_oFFs(ping,ping_info,(png_int_32) image->page.x,
10338 (png_int_32) image->page.y, 0);
10340 if (logging != MagickFalse)
10341 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10342 " Setting up oFFs chunk with x=%d, y=%d, units=0",
10343 (int) image->page.x, (int) image->page.y);
10348 if (mng_info->need_blob != MagickFalse)
10350 if (OpenBlob(image_info,image,WriteBinaryBlobMode,exception) ==
10352 png_error(ping,"WriteBlob Failed");
10354 ping_have_blob=MagickTrue;
10357 png_write_info_before_PLTE(ping, ping_info);
10359 if (ping_have_tRNS != MagickFalse && ping_color_type < 4)
10361 if (logging != MagickFalse)
10363 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10364 " Calling png_set_tRNS with num_trans=%d",ping_num_trans);
10367 if (ping_color_type == 3)
10368 (void) png_set_tRNS(ping, ping_info,
10375 (void) png_set_tRNS(ping, ping_info,
10378 &ping_trans_color);
10380 if (logging != MagickFalse)
10382 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10383 " tRNS color =(%d,%d,%d)",
10384 (int) ping_trans_color.red,
10385 (int) ping_trans_color.green,
10386 (int) ping_trans_color.blue);
10391 /* write any png-chunk-b profiles */
10392 (void) Magick_png_write_chunk_from_profile(image,"PNG-chunk-b",logging);
10394 png_write_info(ping,ping_info);
10396 /* write any PNG-chunk-m profiles */
10397 (void) Magick_png_write_chunk_from_profile(image,"PNG-chunk-m",logging);
10399 if (ping_exclude_vpAg == MagickFalse)
10401 if ((image->page.width != 0 && image->page.width != image->columns) ||
10402 (image->page.height != 0 && image->page.height != image->rows))
10407 (void) WriteBlobMSBULong(image,9L); /* data length=8 */
10408 PNGType(chunk,mng_vpAg);
10409 LogPNGChunk(logging,mng_vpAg,9L);
10410 PNGLong(chunk+4,(png_uint_32) image->page.width);
10411 PNGLong(chunk+8,(png_uint_32) image->page.height);
10412 chunk[12]=0; /* unit = pixels */
10413 (void) WriteBlob(image,13,chunk);
10414 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
10418 #if (PNG_LIBPNG_VER == 10206)
10419 /* avoid libpng-1.2.6 bug by setting PNG_HAVE_IDAT flag */
10420 #define PNG_HAVE_IDAT 0x04
10421 ping->mode |= PNG_HAVE_IDAT;
10422 #undef PNG_HAVE_IDAT
10425 png_set_packing(ping);
10429 rowbytes=image->columns;
10430 if (image_depth > 8)
10432 switch (ping_color_type)
10434 case PNG_COLOR_TYPE_RGB:
10438 case PNG_COLOR_TYPE_GRAY_ALPHA:
10442 case PNG_COLOR_TYPE_RGBA:
10450 if (logging != MagickFalse)
10452 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10453 " Writing PNG image data");
10455 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10456 " Allocating %.20g bytes of memory for pixels",(double) rowbytes);
10458 ping_pixels=(unsigned char *) AcquireQuantumMemory(rowbytes,
10459 sizeof(*ping_pixels));
10461 if (ping_pixels == (unsigned char *) NULL)
10462 png_error(ping,"Allocation of memory for pixels failed");
10465 Initialize image scanlines.
10467 quantum_info=AcquireQuantumInfo(image_info,image);
10468 if (quantum_info == (QuantumInfo *) NULL)
10469 png_error(ping,"Memory allocation for quantum_info failed");
10470 quantum_info->format=UndefinedQuantumFormat;
10471 quantum_info->depth=image_depth;
10472 num_passes=png_set_interlace_handling(ping);
10474 if ((!mng_info->write_png8 && !mng_info->write_png24 &&
10475 !mng_info->write_png32) &&
10476 (mng_info->IsPalette ||
10477 (image_info->type == BilevelType)) &&
10478 image_matte == MagickFalse &&
10479 ping_have_non_bw == MagickFalse)
10481 /* Palette, Bilevel, or Opaque Monochrome */
10482 register const Quantum
10485 quantum_info->depth=8;
10486 for (pass=0; pass < num_passes; pass++)
10489 Convert PseudoClass image to a PNG monochrome image.
10491 for (y=0; y < (ssize_t) image->rows; y++)
10493 if (logging != MagickFalse && y == 0)
10494 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10495 " Writing row of pixels (0)");
10497 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
10499 if (p == (const Quantum *) NULL)
10502 if (mng_info->IsPalette)
10504 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10505 quantum_info,GrayQuantum,ping_pixels,exception);
10506 if (mng_info->write_png_colortype-1 == PNG_COLOR_TYPE_PALETTE &&
10507 mng_info->write_png_depth &&
10508 mng_info->write_png_depth != old_bit_depth)
10510 /* Undo pixel scaling */
10511 for (i=0; i < (ssize_t) image->columns; i++)
10512 *(ping_pixels+i)=(unsigned char) (*(ping_pixels+i)
10513 >> (8-old_bit_depth));
10519 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10520 quantum_info,RedQuantum,ping_pixels,exception);
10523 if (mng_info->write_png_colortype-1 != PNG_COLOR_TYPE_PALETTE)
10524 for (i=0; i < (ssize_t) image->columns; i++)
10525 *(ping_pixels+i)=(unsigned char) ((*(ping_pixels+i) > 127) ?
10528 if (logging != MagickFalse && y == 0)
10529 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10530 " Writing row of pixels (1)");
10532 png_write_row(ping,ping_pixels);
10534 if (image->previous == (Image *) NULL)
10536 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
10537 if (status == MagickFalse)
10543 else /* Not Palette, Bilevel, or Opaque Monochrome */
10545 if ((!mng_info->write_png8 && !mng_info->write_png24 &&
10546 !mng_info->write_png32) &&
10547 (image_matte != MagickFalse ||
10548 (ping_bit_depth >= MAGICKCORE_QUANTUM_DEPTH)) &&
10549 (mng_info->IsPalette) && ping_have_color == MagickFalse)
10551 register const Quantum
10554 for (pass=0; pass < num_passes; pass++)
10557 for (y=0; y < (ssize_t) image->rows; y++)
10559 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
10561 if (p == (const Quantum *) NULL)
10564 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
10566 if (mng_info->IsPalette)
10567 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10568 quantum_info,GrayQuantum,ping_pixels,exception);
10571 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10572 quantum_info,RedQuantum,ping_pixels,exception);
10574 if (logging != MagickFalse && y == 0)
10575 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10576 " Writing GRAY PNG pixels (2)");
10579 else /* PNG_COLOR_TYPE_GRAY_ALPHA */
10581 if (logging != MagickFalse && y == 0)
10582 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10583 " Writing GRAY_ALPHA PNG pixels (2)");
10585 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10586 quantum_info,GrayAlphaQuantum,ping_pixels,exception);
10589 if (logging != MagickFalse && y == 0)
10590 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10591 " Writing row of pixels (2)");
10593 png_write_row(ping,ping_pixels);
10596 if (image->previous == (Image *) NULL)
10598 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
10599 if (status == MagickFalse)
10607 register const Quantum
10610 for (pass=0; pass < num_passes; pass++)
10612 if ((image_depth > 8) || (mng_info->write_png24 ||
10613 mng_info->write_png32 ||
10614 (!mng_info->write_png8 && !mng_info->IsPalette)))
10616 for (y=0; y < (ssize_t) image->rows; y++)
10618 p=GetVirtualPixels(image,0,y,image->columns,1, exception);
10620 if (p == (const Quantum *) NULL)
10623 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
10625 if (image->storage_class == DirectClass)
10626 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10627 quantum_info,RedQuantum,ping_pixels,exception);
10630 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10631 quantum_info,GrayQuantum,ping_pixels,exception);
10634 else if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
10636 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10637 quantum_info,GrayAlphaQuantum,ping_pixels,
10640 if (logging != MagickFalse && y == 0)
10641 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10642 " Writing GRAY_ALPHA PNG pixels (3)");
10645 else if (image_matte != MagickFalse)
10646 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10647 quantum_info,RGBAQuantum,ping_pixels,exception);
10650 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10651 quantum_info,RGBQuantum,ping_pixels,exception);
10653 if (logging != MagickFalse && y == 0)
10654 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10655 " Writing row of pixels (3)");
10657 png_write_row(ping,ping_pixels);
10662 /* not ((image_depth > 8) || (mng_info->write_png24 ||
10663 mng_info->write_png32 ||
10664 (!mng_info->write_png8 && !mng_info->IsPalette))) */
10666 if ((ping_color_type != PNG_COLOR_TYPE_GRAY) &&
10667 (ping_color_type != PNG_COLOR_TYPE_GRAY_ALPHA))
10669 if (logging != MagickFalse)
10670 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10671 " pass %d, Image Is not GRAY or GRAY_ALPHA",pass);
10673 quantum_info->depth=8;
10677 for (y=0; y < (ssize_t) image->rows; y++)
10679 if (logging != MagickFalse && y == 0)
10680 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10681 " pass %d, Image Is RGB, 16-bit GRAY, or GRAY_ALPHA",pass);
10683 p=GetVirtualPixels(image,0,y,image->columns,1, exception);
10685 if (p == (const Quantum *) NULL)
10688 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
10690 quantum_info->depth=image->depth;
10692 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10693 quantum_info,GrayQuantum,ping_pixels,exception);
10696 else if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
10698 if (logging != MagickFalse && y == 0)
10699 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10700 " Writing GRAY_ALPHA PNG pixels (4)");
10702 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10703 quantum_info,GrayAlphaQuantum,ping_pixels,
10709 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10710 quantum_info,IndexQuantum,ping_pixels,exception);
10712 if (logging != MagickFalse && y <= 2)
10714 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10715 " Writing row of non-gray pixels (4)");
10717 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10718 " ping_pixels[0]=%d,ping_pixels[1]=%d",
10719 (int)ping_pixels[0],(int)ping_pixels[1]);
10722 png_write_row(ping,ping_pixels);
10726 if (image->previous == (Image *) NULL)
10728 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
10729 if (status == MagickFalse)
10736 if (quantum_info != (QuantumInfo *) NULL)
10737 quantum_info=DestroyQuantumInfo(quantum_info);
10739 if (logging != MagickFalse)
10741 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10742 " Wrote PNG image data");
10744 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10745 " Width: %.20g",(double) ping_width);
10747 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10748 " Height: %.20g",(double) ping_height);
10750 if (mng_info->write_png_depth)
10752 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10753 " Defined png:bit-depth: %d",mng_info->write_png_depth);
10756 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10757 " PNG bit-depth written: %d",ping_bit_depth);
10759 if (mng_info->write_png_colortype)
10761 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10762 " Defined png:color-type: %d",mng_info->write_png_colortype-1);
10765 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10766 " PNG color-type written: %d",ping_color_type);
10768 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10769 " PNG Interlace method: %d",ping_interlace_method);
10772 Generate text chunks after IDAT.
10774 if (ping_exclude_tEXt == MagickFalse || ping_exclude_zTXt == MagickFalse)
10776 ResetImagePropertyIterator(image);
10777 property=GetNextImageProperty(image);
10778 while (property != (const char *) NULL)
10783 value=GetImageProperty(image,property,exception);
10785 /* Don't write any "png:" properties; those are just for "identify" */
10786 if (LocaleNCompare(property,"png:",4) != 0 &&
10788 /* Suppress density and units if we wrote a pHYs chunk */
10789 (ping_exclude_pHYs != MagickFalse ||
10790 LocaleCompare(property,"density") != 0 ||
10791 LocaleCompare(property,"units") != 0) &&
10793 /* Suppress the IM-generated Date:create and Date:modify */
10794 (ping_exclude_date == MagickFalse ||
10795 LocaleNCompare(property, "Date:",5) != 0))
10797 if (value != (const char *) NULL)
10800 #if PNG_LIBPNG_VER >= 14000
10801 text=(png_textp) png_malloc(ping,
10802 (png_alloc_size_t) sizeof(png_text));
10804 text=(png_textp) png_malloc(ping,(png_size_t) sizeof(png_text));
10806 text[0].key=(char *) property;
10807 text[0].text=(char *) value;
10808 text[0].text_length=strlen(value);
10810 if (ping_exclude_tEXt != MagickFalse)
10811 text[0].compression=PNG_TEXT_COMPRESSION_zTXt;
10813 else if (ping_exclude_zTXt != MagickFalse)
10814 text[0].compression=PNG_TEXT_COMPRESSION_NONE;
10818 text[0].compression=image_info->compression == NoCompression ||
10819 (image_info->compression == UndefinedCompression &&
10820 text[0].text_length < 128) ? PNG_TEXT_COMPRESSION_NONE :
10821 PNG_TEXT_COMPRESSION_zTXt ;
10824 if (logging != MagickFalse)
10826 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10827 " Setting up text chunk");
10829 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10830 " keyword: %s",text[0].key);
10833 png_set_text(ping,ping_info,text,1);
10834 png_free(ping,text);
10837 property=GetNextImageProperty(image);
10841 /* write any PNG-chunk-e profiles */
10842 (void) Magick_png_write_chunk_from_profile(image,"PNG-chunk-e",logging);
10844 if (logging != MagickFalse)
10845 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10846 " Writing PNG end info");
10848 png_write_end(ping,ping_info);
10850 if (mng_info->need_fram && (int) image->dispose == BackgroundDispose)
10852 if (mng_info->page.x || mng_info->page.y ||
10853 (ping_width != mng_info->page.width) ||
10854 (ping_height != mng_info->page.height))
10860 Write FRAM 4 with clipping boundaries followed by FRAM 1.
10862 (void) WriteBlobMSBULong(image,27L); /* data length=27 */
10863 PNGType(chunk,mng_FRAM);
10864 LogPNGChunk(logging,mng_FRAM,27L);
10866 chunk[5]=0; /* frame name separator (no name) */
10867 chunk[6]=1; /* flag for changing delay, for next frame only */
10868 chunk[7]=0; /* flag for changing frame timeout */
10869 chunk[8]=1; /* flag for changing frame clipping for next frame */
10870 chunk[9]=0; /* flag for changing frame sync_id */
10871 PNGLong(chunk+10,(png_uint_32) (0L)); /* temporary 0 delay */
10872 chunk[14]=0; /* clipping boundaries delta type */
10873 PNGLong(chunk+15,(png_uint_32) (mng_info->page.x)); /* left cb */
10875 (png_uint_32) (mng_info->page.x + ping_width));
10876 PNGLong(chunk+23,(png_uint_32) (mng_info->page.y)); /* top cb */
10878 (png_uint_32) (mng_info->page.y + ping_height));
10879 (void) WriteBlob(image,31,chunk);
10880 (void) WriteBlobMSBULong(image,crc32(0,chunk,31));
10881 mng_info->old_framing_mode=4;
10882 mng_info->framing_mode=1;
10886 mng_info->framing_mode=3;
10888 if (mng_info->write_mng && !mng_info->need_fram &&
10889 ((int) image->dispose == 3))
10890 png_error(ping, "Cannot convert GIF with disposal method 3 to MNG-LC");
10893 Free PNG resources.
10896 png_destroy_write_struct(&ping,&ping_info);
10898 ping_pixels=(unsigned char *) RelinquishMagickMemory(ping_pixels);
10900 if (ping_have_blob != MagickFalse)
10901 (void) CloseBlob(image);
10903 image_info=DestroyImageInfo(image_info);
10904 image=DestroyImage(image);
10906 /* Store bit depth actually written */
10907 s[0]=(char) ping_bit_depth;
10910 (void) SetImageProperty(IMimage,"png:bit-depth-written",s,exception);
10912 if (logging != MagickFalse)
10913 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10914 " exit WriteOnePNGImage()");
10916 #ifdef PNG_SETJMP_NOT_THREAD_SAFE
10917 UnlockSemaphoreInfo(ping_semaphore);
10920 /* } for navigation to beginning of SETJMP-protected block. Revert to
10921 * Throwing an Exception when an error occurs.
10924 return(MagickTrue);
10925 /* End write one PNG image */
10930 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10934 % W r i t e P N G I m a g e %
10938 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10940 % WritePNGImage() writes a Portable Network Graphics (PNG) or
10941 % Multiple-image Network Graphics (MNG) image file.
10943 % MNG support written by Glenn Randers-Pehrson, glennrp@image...
10945 % The format of the WritePNGImage method is:
10947 % MagickBooleanType WritePNGImage(const ImageInfo *image_info,
10948 % Image *image,ExceptionInfo *exception)
10950 % A description of each parameter follows:
10952 % o image_info: the image info.
10954 % o image: The image.
10956 % o exception: return any errors or warnings in this structure.
10958 % Returns MagickTrue on success, MagickFalse on failure.
10960 % Communicating with the PNG encoder:
10962 % While the datastream written is always in PNG format and normally would
10963 % be given the "png" file extension, this method also writes the following
10964 % pseudo-formats which are subsets of png:
10966 % o PNG8: An 8-bit indexed PNG datastream is written. If the image has
10967 % a depth greater than 8, the depth is reduced. If transparency
10968 % is present, the tRNS chunk must only have values 0 and 255
10969 % (i.e., transparency is binary: fully opaque or fully
10970 % transparent). If other values are present they will be
10971 % 50%-thresholded to binary transparency. If more than 256
10972 % colors are present, they will be quantized to the 4-4-4-1,
10973 % 3-3-3-1, or 3-3-2-1 palette. The underlying RGB color
10974 % of any resulting fully-transparent pixels is changed to
10975 % the image's background color.
10977 % If you want better quantization or dithering of the colors
10978 % or alpha than that, you need to do it before calling the
10979 % PNG encoder. The pixels contain 8-bit indices even if
10980 % they could be represented with 1, 2, or 4 bits. Grayscale
10981 % images will be written as indexed PNG files even though the
10982 % PNG grayscale type might be slightly more efficient. Please
10983 % note that writing to the PNG8 format may result in loss
10984 % of color and alpha data.
10986 % o PNG24: An 8-bit per sample RGB PNG datastream is written. The tRNS
10987 % chunk can be present to convey binary transparency by naming
10988 % one of the colors as transparent. The only loss incurred
10989 % is reduction of sample depth to 8. If the image has more
10990 % than one transparent color, has semitransparent pixels, or
10991 % has an opaque pixel with the same RGB components as the
10992 % transparent color, an image is not written.
10994 % o PNG32: An 8-bit per sample RGBA PNG is written. Partial
10995 % transparency is permitted, i.e., the alpha sample for
10996 % each pixel can have any value from 0 to 255. The alpha
10997 % channel is present even if the image is fully opaque.
10998 % The only loss in data is the reduction of the sample depth
11001 % o -define: For more precise control of the PNG output, you can use the
11002 % Image options "png:bit-depth" and "png:color-type". These
11003 % can be set from the commandline with "-define" and also
11004 % from the application programming interfaces. The options
11005 % are case-independent and are converted to lowercase before
11006 % being passed to this encoder.
11008 % png:color-type can be 0, 2, 3, 4, or 6.
11010 % When png:color-type is 0 (Grayscale), png:bit-depth can
11011 % be 1, 2, 4, 8, or 16.
11013 % When png:color-type is 2 (RGB), png:bit-depth can
11016 % When png:color-type is 3 (Indexed), png:bit-depth can
11017 % be 1, 2, 4, or 8. This refers to the number of bits
11018 % used to store the index. The color samples always have
11019 % bit-depth 8 in indexed PNG files.
11021 % When png:color-type is 4 (Gray-Matte) or 6 (RGB-Matte),
11022 % png:bit-depth can be 8 or 16.
11024 % If the image cannot be written without loss with the requested bit-depth
11025 % and color-type, a PNG file will not be written, and the encoder will
11026 % return MagickFalse.
11028 % Since image encoders should not be responsible for the "heavy lifting",
11029 % the user should make sure that ImageMagick has already reduced the
11030 % image depth and number of colors and limit transparency to binary
11031 % transparency prior to attempting to write the image with depth, color,
11032 % or transparency limitations.
11034 % Note that another definition, "png:bit-depth-written" exists, but it
11035 % is not intended for external use. It is only used internally by the
11036 % PNG encoder to inform the JNG encoder of the depth of the alpha channel.
11038 % It is possible to request that the PNG encoder write previously-formatted
11039 % ancillary chunks in the output PNG file, using the "-profile" commandline
11040 % option as shown below or by setting the profile via a programming
11043 % -profile PNG-chunk-x:<file>
11045 % where x is a location flag and <file> is a file containing the chunk
11046 % name in the first 4 bytes, then a colon (":"), followed by the chunk data.
11047 % This encoder will compute the chunk length and CRC, so those must not
11048 % be included in the file.
11050 % "x" can be "b" (before PLTE), "m" (middle, i.e., between PLTE and IDAT),
11051 % or "e" (end, i.e., after IDAT). If you want to write multiple chunks
11052 % of the same type, then add a short unique string after the "x" to prevent
11053 % subsequent profiles from overwriting the preceding ones, e.g.,
11055 % -profile PNG-chunk-b01:file01 -profile PNG-chunk-b02:file02
11057 % As of version 6.6.6 the following optimizations are always done:
11059 % o 32-bit depth is reduced to 16.
11060 % o 16-bit depth is reduced to 8 if all pixels contain samples whose
11061 % high byte and low byte are identical.
11062 % o Palette is sorted to remove unused entries and to put a
11063 % transparent color first, if BUILD_PNG_PALETTE is defined.
11064 % o Opaque matte channel is removed when writing an indexed PNG.
11065 % o Grayscale images are reduced to 1, 2, or 4 bit depth if
11066 % this can be done without loss and a larger bit depth N was not
11067 % requested via the "-define png:bit-depth=N" option.
11068 % o If matte channel is present but only one transparent color is
11069 % present, RGB+tRNS is written instead of RGBA
11070 % o Opaque matte channel is removed (or added, if color-type 4 or 6
11071 % was requested when converting an opaque image).
11073 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11075 static MagickBooleanType WritePNGImage(const ImageInfo *image_info,
11076 Image *image,ExceptionInfo *exception)
11081 have_mng_structure,
11097 assert(image_info != (const ImageInfo *) NULL);
11098 assert(image_info->signature == MagickSignature);
11099 assert(image != (Image *) NULL);
11100 assert(image->signature == MagickSignature);
11101 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
11102 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter WritePNGImage()");
11104 Allocate a MngInfo structure.
11106 have_mng_structure=MagickFalse;
11107 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
11109 if (mng_info == (MngInfo *) NULL)
11110 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
11113 Initialize members of the MngInfo structure.
11115 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
11116 mng_info->image=image;
11117 mng_info->equal_backgrounds=MagickTrue;
11118 have_mng_structure=MagickTrue;
11120 /* See if user has requested a specific PNG subformat */
11122 mng_info->write_png8=LocaleCompare(image_info->magick,"PNG8") == 0;
11123 mng_info->write_png24=LocaleCompare(image_info->magick,"PNG24") == 0;
11124 mng_info->write_png32=LocaleCompare(image_info->magick,"PNG32") == 0;
11126 value=GetImageOption(image_info,"png:format");
11128 if (value != (char *) NULL)
11130 if (LocaleCompare(value,"png8") == 0)
11132 mng_info->write_png8 = MagickTrue;
11133 mng_info->write_png24 = MagickFalse;
11134 mng_info->write_png32 = MagickFalse;
11137 else if (LocaleCompare(value,"png24") == 0)
11139 mng_info->write_png8 = MagickFalse;
11140 mng_info->write_png24 = MagickTrue;
11141 mng_info->write_png32 = MagickFalse;
11144 else if (LocaleCompare(value,"png32") == 0)
11146 mng_info->write_png8 = MagickFalse;
11147 mng_info->write_png24 = MagickFalse;
11148 mng_info->write_png32 = MagickTrue;
11151 if (mng_info->write_png8)
11153 mng_info->write_png_colortype = /* 3 */ 4;
11154 mng_info->write_png_depth = 8;
11158 if (mng_info->write_png24)
11160 mng_info->write_png_colortype = /* 2 */ 3;
11161 mng_info->write_png_depth = 8;
11164 if (image->matte == MagickTrue)
11165 (void) SetImageType(image,TrueColorMatteType,exception);
11168 (void) SetImageType(image,TrueColorType,exception);
11170 (void) SyncImage(image,exception);
11173 if (mng_info->write_png32)
11175 mng_info->write_png_colortype = /* 6 */ 7;
11176 mng_info->write_png_depth = 8;
11179 if (image->matte == MagickTrue)
11180 (void) SetImageType(image,TrueColorMatteType,exception);
11183 (void) SetImageType(image,TrueColorType,exception);
11185 (void) SyncImage(image,exception);
11188 value=GetImageOption(image_info,"png:bit-depth");
11190 if (value != (char *) NULL)
11192 if (LocaleCompare(value,"1") == 0)
11193 mng_info->write_png_depth = 1;
11195 else if (LocaleCompare(value,"2") == 0)
11196 mng_info->write_png_depth = 2;
11198 else if (LocaleCompare(value,"4") == 0)
11199 mng_info->write_png_depth = 4;
11201 else if (LocaleCompare(value,"8") == 0)
11202 mng_info->write_png_depth = 8;
11204 else if (LocaleCompare(value,"16") == 0)
11205 mng_info->write_png_depth = 16;
11208 (void) ThrowMagickException(exception,
11209 GetMagickModule(),CoderWarning,
11210 "ignoring invalid defined png:bit-depth",
11213 if (logging != MagickFalse)
11214 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11215 " png:bit-depth=%d was defined.\n",mng_info->write_png_depth);
11218 value=GetImageOption(image_info,"png:color-type");
11220 if (value != (char *) NULL)
11222 /* We must store colortype+1 because 0 is a valid colortype */
11223 if (LocaleCompare(value,"0") == 0)
11224 mng_info->write_png_colortype = 1;
11226 else if (LocaleCompare(value,"1") == 0)
11227 mng_info->write_png_colortype = 2;
11229 else if (LocaleCompare(value,"2") == 0)
11230 mng_info->write_png_colortype = 3;
11232 else if (LocaleCompare(value,"3") == 0)
11233 mng_info->write_png_colortype = 4;
11235 else if (LocaleCompare(value,"4") == 0)
11236 mng_info->write_png_colortype = 5;
11238 else if (LocaleCompare(value,"6") == 0)
11239 mng_info->write_png_colortype = 7;
11242 (void) ThrowMagickException(exception,
11243 GetMagickModule(),CoderWarning,
11244 "ignoring invalid defined png:color-type",
11247 if (logging != MagickFalse)
11248 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11249 " png:color-type=%d was defined.\n",mng_info->write_png_colortype-1);
11252 /* Check for chunks to be excluded:
11254 * The default is to not exclude any known chunks except for any
11255 * listed in the "unused_chunks" array, above.
11257 * Chunks can be listed for exclusion via a "png:exclude-chunk"
11258 * define (in the image properties or in the image artifacts)
11259 * or via a mng_info member. For convenience, in addition
11260 * to or instead of a comma-separated list of chunks, the
11261 * "exclude-chunk" string can be simply "all" or "none".
11263 * The exclude-chunk define takes priority over the mng_info.
11265 * A "png:include-chunk" define takes priority over both the
11266 * mng_info and the "png:exclude-chunk" define. Like the
11267 * "exclude-chunk" string, it can define "all" or "none" as
11268 * well as a comma-separated list. Chunks that are unknown to
11269 * ImageMagick are always excluded, regardless of their "copy-safe"
11270 * status according to the PNG specification, and even if they
11271 * appear in the "include-chunk" list. Such defines appearing among
11272 * the image options take priority over those found among the image
11275 * Finally, all chunks listed in the "unused_chunks" array are
11276 * automatically excluded, regardless of the other instructions
11279 * if you exclude sRGB but not gAMA (recommended), then sRGB chunk
11280 * will not be written and the gAMA chunk will only be written if it
11281 * is not between .45 and .46, or approximately (1.0/2.2).
11283 * If you exclude tRNS and the image has transparency, the colortype
11284 * is forced to be 4 or 6 (GRAY_ALPHA or RGB_ALPHA).
11286 * The -strip option causes StripImage() to set the png:include-chunk
11287 * artifact to "none,trns,gama".
11290 mng_info->ping_exclude_bKGD=MagickFalse;
11291 mng_info->ping_exclude_cHRM=MagickFalse;
11292 mng_info->ping_exclude_date=MagickFalse;
11293 mng_info->ping_exclude_EXIF=MagickFalse; /* hex-encoded EXIF in zTXt */
11294 mng_info->ping_exclude_gAMA=MagickFalse;
11295 mng_info->ping_exclude_iCCP=MagickFalse;
11296 /* mng_info->ping_exclude_iTXt=MagickFalse; */
11297 mng_info->ping_exclude_oFFs=MagickFalse;
11298 mng_info->ping_exclude_pHYs=MagickFalse;
11299 mng_info->ping_exclude_sRGB=MagickFalse;
11300 mng_info->ping_exclude_tEXt=MagickFalse;
11301 mng_info->ping_exclude_tRNS=MagickFalse;
11302 mng_info->ping_exclude_vpAg=MagickFalse;
11303 mng_info->ping_exclude_zCCP=MagickFalse; /* hex-encoded iCCP in zTXt */
11304 mng_info->ping_exclude_zTXt=MagickFalse;
11306 mng_info->ping_preserve_colormap=MagickFalse;
11308 value=GetImageArtifact(image,"png:preserve-colormap");
11310 value=GetImageOption(image_info,"png:preserve-colormap");
11312 mng_info->ping_preserve_colormap=MagickTrue;
11314 /* Thes compression-level, compression-strategy, and compression-filter
11315 * defines take precedence over values from the -quality option.
11317 value=GetImageArtifact(image,"png:compression-level");
11319 value=GetImageOption(image_info,"png:compression-level");
11322 /* We have to add 1 to everything because 0 is a valid input,
11323 * and we want to use 0 (the default) to mean undefined.
11325 if (LocaleCompare(value,"0") == 0)
11326 mng_info->write_png_compression_level = 1;
11328 else if (LocaleCompare(value,"1") == 0)
11329 mng_info->write_png_compression_level = 2;
11331 else if (LocaleCompare(value,"2") == 0)
11332 mng_info->write_png_compression_level = 3;
11334 else if (LocaleCompare(value,"3") == 0)
11335 mng_info->write_png_compression_level = 4;
11337 else if (LocaleCompare(value,"4") == 0)
11338 mng_info->write_png_compression_level = 5;
11340 else if (LocaleCompare(value,"5") == 0)
11341 mng_info->write_png_compression_level = 6;
11343 else if (LocaleCompare(value,"6") == 0)
11344 mng_info->write_png_compression_level = 7;
11346 else if (LocaleCompare(value,"7") == 0)
11347 mng_info->write_png_compression_level = 8;
11349 else if (LocaleCompare(value,"8") == 0)
11350 mng_info->write_png_compression_level = 9;
11352 else if (LocaleCompare(value,"9") == 0)
11353 mng_info->write_png_compression_level = 10;
11356 (void) ThrowMagickException(exception,
11357 GetMagickModule(),CoderWarning,
11358 "ignoring invalid defined png:compression-level",
11362 value=GetImageArtifact(image,"png:compression-strategy");
11364 value=GetImageOption(image_info,"png:compression-strategy");
11368 if (LocaleCompare(value,"0") == 0)
11369 mng_info->write_png_compression_strategy = Z_DEFAULT_STRATEGY+1;
11371 else if (LocaleCompare(value,"1") == 0)
11372 mng_info->write_png_compression_strategy = Z_FILTERED+1;
11374 else if (LocaleCompare(value,"2") == 0)
11375 mng_info->write_png_compression_strategy = Z_HUFFMAN_ONLY+1;
11377 else if (LocaleCompare(value,"3") == 0)
11378 #ifdef Z_RLE /* Z_RLE was added to zlib-1.2.0 */
11379 mng_info->write_png_compression_strategy = Z_RLE+1;
11381 mng_info->write_png_compression_strategy = Z_DEFAULT_STRATEGY+1;
11384 else if (LocaleCompare(value,"4") == 0)
11385 #ifdef Z_FIXED /* Z_FIXED was added to zlib-1.2.2.2 */
11386 mng_info->write_png_compression_strategy = Z_FIXED+1;
11388 mng_info->write_png_compression_strategy = Z_DEFAULT_STRATEGY+1;
11392 (void) ThrowMagickException(exception,
11393 GetMagickModule(),CoderWarning,
11394 "ignoring invalid defined png:compression-strategy",
11398 value=GetImageArtifact(image,"png:compression-filter");
11400 value=GetImageOption(image_info,"png:compression-filter");
11404 /* To do: combinations of filters allowed by libpng
11405 * masks 0x08 through 0xf8
11407 * Implement this as a comma-separated list of 0,1,2,3,4,5
11408 * where 5 is a special case meaning PNG_ALL_FILTERS.
11411 if (LocaleCompare(value,"0") == 0)
11412 mng_info->write_png_compression_filter = 1;
11414 if (LocaleCompare(value,"1") == 0)
11415 mng_info->write_png_compression_filter = 2;
11417 else if (LocaleCompare(value,"2") == 0)
11418 mng_info->write_png_compression_filter = 3;
11420 else if (LocaleCompare(value,"3") == 0)
11421 mng_info->write_png_compression_filter = 4;
11423 else if (LocaleCompare(value,"4") == 0)
11424 mng_info->write_png_compression_filter = 5;
11426 else if (LocaleCompare(value,"5") == 0)
11427 mng_info->write_png_compression_filter = 6;
11430 (void) ThrowMagickException(exception,
11431 GetMagickModule(),CoderWarning,
11432 "ignoring invalid defined png:compression-filter",
11436 excluding=MagickFalse;
11438 for (source=0; source<1; source++)
11442 value=GetImageArtifact(image,"png:exclude-chunk");
11445 value=GetImageArtifact(image,"png:exclude-chunks");
11449 value=GetImageOption(image_info,"png:exclude-chunk");
11452 value=GetImageOption(image_info,"png:exclude-chunks");
11461 excluding=MagickTrue;
11463 if (logging != MagickFalse)
11466 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11467 " png:exclude-chunk=%s found in image artifacts.\n", value);
11469 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11470 " png:exclude-chunk=%s found in image properties.\n", value);
11473 last=strlen(value);
11475 for (i=0; i<(int) last; i+=5)
11478 if (LocaleNCompare(value+i,"all",3) == 0)
11480 mng_info->ping_exclude_bKGD=MagickTrue;
11481 mng_info->ping_exclude_cHRM=MagickTrue;
11482 mng_info->ping_exclude_date=MagickTrue;
11483 mng_info->ping_exclude_EXIF=MagickTrue;
11484 mng_info->ping_exclude_gAMA=MagickTrue;
11485 mng_info->ping_exclude_iCCP=MagickTrue;
11486 /* mng_info->ping_exclude_iTXt=MagickTrue; */
11487 mng_info->ping_exclude_oFFs=MagickTrue;
11488 mng_info->ping_exclude_pHYs=MagickTrue;
11489 mng_info->ping_exclude_sRGB=MagickTrue;
11490 mng_info->ping_exclude_tEXt=MagickTrue;
11491 mng_info->ping_exclude_tRNS=MagickTrue;
11492 mng_info->ping_exclude_vpAg=MagickTrue;
11493 mng_info->ping_exclude_zCCP=MagickTrue;
11494 mng_info->ping_exclude_zTXt=MagickTrue;
11498 if (LocaleNCompare(value+i,"none",4) == 0)
11500 mng_info->ping_exclude_bKGD=MagickFalse;
11501 mng_info->ping_exclude_cHRM=MagickFalse;
11502 mng_info->ping_exclude_date=MagickFalse;
11503 mng_info->ping_exclude_EXIF=MagickFalse;
11504 mng_info->ping_exclude_gAMA=MagickFalse;
11505 mng_info->ping_exclude_iCCP=MagickFalse;
11506 /* mng_info->ping_exclude_iTXt=MagickFalse; */
11507 mng_info->ping_exclude_oFFs=MagickFalse;
11508 mng_info->ping_exclude_pHYs=MagickFalse;
11509 mng_info->ping_exclude_sRGB=MagickFalse;
11510 mng_info->ping_exclude_tEXt=MagickFalse;
11511 mng_info->ping_exclude_tRNS=MagickFalse;
11512 mng_info->ping_exclude_vpAg=MagickFalse;
11513 mng_info->ping_exclude_zCCP=MagickFalse;
11514 mng_info->ping_exclude_zTXt=MagickFalse;
11517 if (LocaleNCompare(value+i,"bkgd",4) == 0)
11518 mng_info->ping_exclude_bKGD=MagickTrue;
11520 if (LocaleNCompare(value+i,"chrm",4) == 0)
11521 mng_info->ping_exclude_cHRM=MagickTrue;
11523 if (LocaleNCompare(value+i,"date",4) == 0)
11524 mng_info->ping_exclude_date=MagickTrue;
11526 if (LocaleNCompare(value+i,"exif",4) == 0)
11527 mng_info->ping_exclude_EXIF=MagickTrue;
11529 if (LocaleNCompare(value+i,"gama",4) == 0)
11530 mng_info->ping_exclude_gAMA=MagickTrue;
11532 if (LocaleNCompare(value+i,"iccp",4) == 0)
11533 mng_info->ping_exclude_iCCP=MagickTrue;
11536 if (LocaleNCompare(value+i,"itxt",4) == 0)
11537 mng_info->ping_exclude_iTXt=MagickTrue;
11540 if (LocaleNCompare(value+i,"gama",4) == 0)
11541 mng_info->ping_exclude_gAMA=MagickTrue;
11543 if (LocaleNCompare(value+i,"offs",4) == 0)
11544 mng_info->ping_exclude_oFFs=MagickTrue;
11546 if (LocaleNCompare(value+i,"phys",4) == 0)
11547 mng_info->ping_exclude_pHYs=MagickTrue;
11549 if (LocaleNCompare(value+i,"srgb",4) == 0)
11550 mng_info->ping_exclude_sRGB=MagickTrue;
11552 if (LocaleNCompare(value+i,"text",4) == 0)
11553 mng_info->ping_exclude_tEXt=MagickTrue;
11555 if (LocaleNCompare(value+i,"trns",4) == 0)
11556 mng_info->ping_exclude_tRNS=MagickTrue;
11558 if (LocaleNCompare(value+i,"vpag",4) == 0)
11559 mng_info->ping_exclude_vpAg=MagickTrue;
11561 if (LocaleNCompare(value+i,"zccp",4) == 0)
11562 mng_info->ping_exclude_zCCP=MagickTrue;
11564 if (LocaleNCompare(value+i,"ztxt",4) == 0)
11565 mng_info->ping_exclude_zTXt=MagickTrue;
11571 for (source=0; source<1; source++)
11575 value=GetImageArtifact(image,"png:include-chunk");
11578 value=GetImageArtifact(image,"png:include-chunks");
11582 value=GetImageOption(image_info,"png:include-chunk");
11585 value=GetImageOption(image_info,"png:include-chunks");
11593 excluding=MagickTrue;
11595 if (logging != MagickFalse)
11598 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11599 " png:include-chunk=%s found in image artifacts.\n", value);
11601 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11602 " png:include-chunk=%s found in image properties.\n", value);
11605 last=strlen(value);
11607 for (i=0; i<(int) last; i+=5)
11609 if (LocaleNCompare(value+i,"all",3) == 0)
11611 mng_info->ping_exclude_bKGD=MagickFalse;
11612 mng_info->ping_exclude_cHRM=MagickFalse;
11613 mng_info->ping_exclude_date=MagickFalse;
11614 mng_info->ping_exclude_EXIF=MagickFalse;
11615 mng_info->ping_exclude_gAMA=MagickFalse;
11616 mng_info->ping_exclude_iCCP=MagickFalse;
11617 /* mng_info->ping_exclude_iTXt=MagickFalse; */
11618 mng_info->ping_exclude_oFFs=MagickFalse;
11619 mng_info->ping_exclude_pHYs=MagickFalse;
11620 mng_info->ping_exclude_sRGB=MagickFalse;
11621 mng_info->ping_exclude_tEXt=MagickFalse;
11622 mng_info->ping_exclude_tRNS=MagickFalse;
11623 mng_info->ping_exclude_vpAg=MagickFalse;
11624 mng_info->ping_exclude_zCCP=MagickFalse;
11625 mng_info->ping_exclude_zTXt=MagickFalse;
11629 if (LocaleNCompare(value+i,"none",4) == 0)
11631 mng_info->ping_exclude_bKGD=MagickTrue;
11632 mng_info->ping_exclude_cHRM=MagickTrue;
11633 mng_info->ping_exclude_date=MagickTrue;
11634 mng_info->ping_exclude_EXIF=MagickTrue;
11635 mng_info->ping_exclude_gAMA=MagickTrue;
11636 mng_info->ping_exclude_iCCP=MagickTrue;
11637 /* mng_info->ping_exclude_iTXt=MagickTrue; */
11638 mng_info->ping_exclude_oFFs=MagickTrue;
11639 mng_info->ping_exclude_pHYs=MagickTrue;
11640 mng_info->ping_exclude_sRGB=MagickTrue;
11641 mng_info->ping_exclude_tEXt=MagickTrue;
11642 mng_info->ping_exclude_tRNS=MagickTrue;
11643 mng_info->ping_exclude_vpAg=MagickTrue;
11644 mng_info->ping_exclude_zCCP=MagickTrue;
11645 mng_info->ping_exclude_zTXt=MagickTrue;
11648 if (LocaleNCompare(value+i,"bkgd",4) == 0)
11649 mng_info->ping_exclude_bKGD=MagickFalse;
11651 if (LocaleNCompare(value+i,"chrm",4) == 0)
11652 mng_info->ping_exclude_cHRM=MagickFalse;
11654 if (LocaleNCompare(value+i,"date",4) == 0)
11655 mng_info->ping_exclude_date=MagickFalse;
11657 if (LocaleNCompare(value+i,"exif",4) == 0)
11658 mng_info->ping_exclude_EXIF=MagickFalse;
11660 if (LocaleNCompare(value+i,"gama",4) == 0)
11661 mng_info->ping_exclude_gAMA=MagickFalse;
11663 if (LocaleNCompare(value+i,"iccp",4) == 0)
11664 mng_info->ping_exclude_iCCP=MagickFalse;
11667 if (LocaleNCompare(value+i,"itxt",4) == 0)
11668 mng_info->ping_exclude_iTXt=MagickFalse;
11671 if (LocaleNCompare(value+i,"gama",4) == 0)
11672 mng_info->ping_exclude_gAMA=MagickFalse;
11674 if (LocaleNCompare(value+i,"offs",4) == 0)
11675 mng_info->ping_exclude_oFFs=MagickFalse;
11677 if (LocaleNCompare(value+i,"phys",4) == 0)
11678 mng_info->ping_exclude_pHYs=MagickFalse;
11680 if (LocaleNCompare(value+i,"srgb",4) == 0)
11681 mng_info->ping_exclude_sRGB=MagickFalse;
11683 if (LocaleNCompare(value+i,"text",4) == 0)
11684 mng_info->ping_exclude_tEXt=MagickFalse;
11686 if (LocaleNCompare(value+i,"trns",4) == 0)
11687 mng_info->ping_exclude_tRNS=MagickFalse;
11689 if (LocaleNCompare(value+i,"vpag",4) == 0)
11690 mng_info->ping_exclude_vpAg=MagickFalse;
11692 if (LocaleNCompare(value+i,"zccp",4) == 0)
11693 mng_info->ping_exclude_zCCP=MagickFalse;
11695 if (LocaleNCompare(value+i,"ztxt",4) == 0)
11696 mng_info->ping_exclude_zTXt=MagickFalse;
11702 if (excluding != MagickFalse && logging != MagickFalse)
11704 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11705 " Chunks to be excluded from the output png:");
11706 if (mng_info->ping_exclude_bKGD != MagickFalse)
11707 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11709 if (mng_info->ping_exclude_cHRM != MagickFalse)
11710 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11712 if (mng_info->ping_exclude_date != MagickFalse)
11713 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11715 if (mng_info->ping_exclude_EXIF != MagickFalse)
11716 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11718 if (mng_info->ping_exclude_gAMA != MagickFalse)
11719 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11721 if (mng_info->ping_exclude_iCCP != MagickFalse)
11722 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11725 if (mng_info->ping_exclude_iTXt != MagickFalse)
11726 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11729 if (mng_info->ping_exclude_oFFs != MagickFalse)
11730 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11732 if (mng_info->ping_exclude_pHYs != MagickFalse)
11733 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11735 if (mng_info->ping_exclude_sRGB != MagickFalse)
11736 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11738 if (mng_info->ping_exclude_tEXt != MagickFalse)
11739 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11741 if (mng_info->ping_exclude_tRNS != MagickFalse)
11742 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11744 if (mng_info->ping_exclude_vpAg != MagickFalse)
11745 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11747 if (mng_info->ping_exclude_zCCP != MagickFalse)
11748 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11750 if (mng_info->ping_exclude_zTXt != MagickFalse)
11751 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11755 mng_info->need_blob = MagickTrue;
11757 status=WriteOnePNGImage(mng_info,image_info,image,exception);
11759 MngInfoFreeStruct(mng_info,&have_mng_structure);
11761 if (logging != MagickFalse)
11762 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit WritePNGImage()");
11767 #if defined(JNG_SUPPORTED)
11769 /* Write one JNG image */
11770 static MagickBooleanType WriteOneJNGImage(MngInfo *mng_info,
11771 const ImageInfo *image_info,Image *image,ExceptionInfo *exception)
11792 jng_alpha_compression_method,
11793 jng_alpha_sample_depth,
11801 logging=LogMagickEvent(CoderEvent,GetMagickModule(),
11802 " Enter WriteOneJNGImage()");
11804 blob=(unsigned char *) NULL;
11805 jpeg_image=(Image *) NULL;
11806 jpeg_image_info=(ImageInfo *) NULL;
11809 transparent=image_info->type==GrayscaleMatteType ||
11810 image_info->type==TrueColorMatteType || image->matte != MagickFalse;
11812 jng_quality=image_info->quality == 0UL ? 75UL : image_info->quality%1000;
11814 jng_alpha_compression_method=image->compression==JPEGCompression? 8 : 0;
11816 jng_alpha_quality=image_info->quality == 0UL ? 75UL :
11817 image_info->quality;
11819 if (jng_alpha_quality >= 1000)
11820 jng_alpha_quality /= 1000;
11826 /* Create JPEG blob, image, and image_info */
11827 if (logging != MagickFalse)
11828 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11829 " Creating jpeg_image_info for alpha.");
11831 jpeg_image_info=(ImageInfo *) CloneImageInfo(image_info);
11833 if (jpeg_image_info == (ImageInfo *) NULL)
11834 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
11836 if (logging != MagickFalse)
11837 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11838 " Creating jpeg_image.");
11840 jpeg_image=SeparateImage(image,AlphaChannel,exception);
11841 if (jpeg_image == (Image *) NULL)
11842 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
11843 (void) CopyMagickString(jpeg_image->magick,"JPEG",MaxTextExtent);
11844 jpeg_image->matte=MagickFalse;
11845 jpeg_image->quality=jng_alpha_quality;
11846 jpeg_image_info->type=GrayscaleType;
11847 (void) SetImageType(jpeg_image,GrayscaleType,exception);
11848 (void) AcquireUniqueFilename(jpeg_image->filename);
11849 (void) FormatLocaleString(jpeg_image_info->filename,MaxTextExtent,
11850 "%s",jpeg_image->filename);
11854 jng_alpha_compression_method=0;
11856 jng_alpha_sample_depth=0;
11859 /* To do: check bit depth of PNG alpha channel */
11861 /* Check if image is grayscale. */
11862 if (image_info->type != TrueColorMatteType && image_info->type !=
11863 TrueColorType && IsImageGray(image,exception))
11866 if (logging != MagickFalse)
11868 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11869 " JNG Quality = %d",(int) jng_quality);
11870 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11871 " JNG Color Type = %d",jng_color_type);
11874 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11875 " JNG Alpha Compression = %d",jng_alpha_compression_method);
11876 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11877 " JNG Alpha Depth = %d",jng_alpha_sample_depth);
11878 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11879 " JNG Alpha Quality = %d",(int) jng_alpha_quality);
11885 if (jng_alpha_compression_method==0)
11890 /* Encode alpha as a grayscale PNG blob */
11891 status=OpenBlob(jpeg_image_info,jpeg_image,WriteBinaryBlobMode,
11893 if (logging != MagickFalse)
11894 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11895 " Creating PNG blob.");
11898 (void) CopyMagickString(jpeg_image_info->magick,"PNG",MaxTextExtent);
11899 (void) CopyMagickString(jpeg_image->magick,"PNG",MaxTextExtent);
11900 jpeg_image_info->interlace=NoInterlace;
11902 /* Exclude all ancillary chunks */
11903 (void) SetImageArtifact(jpeg_image,"png:exclude-chunks","all");
11905 blob=ImageToBlob(jpeg_image_info,jpeg_image,&length,
11908 /* Retrieve sample depth used */
11909 value=GetImageProperty(jpeg_image,"png:bit-depth-written",exception);
11910 if (value != (char *) NULL)
11911 jng_alpha_sample_depth= (unsigned int) value[0];
11915 /* Encode alpha as a grayscale JPEG blob */
11917 status=OpenBlob(jpeg_image_info,jpeg_image,WriteBinaryBlobMode,
11920 (void) CopyMagickString(jpeg_image_info->magick,"JPEG",MaxTextExtent);
11921 (void) CopyMagickString(jpeg_image->magick,"JPEG",MaxTextExtent);
11922 jpeg_image_info->interlace=NoInterlace;
11923 if (logging != MagickFalse)
11924 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11925 " Creating blob.");
11926 blob=ImageToBlob(jpeg_image_info,jpeg_image,&length,
11928 jng_alpha_sample_depth=8;
11930 if (logging != MagickFalse)
11931 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11932 " Successfully read jpeg_image into a blob, length=%.20g.",
11936 /* Destroy JPEG image and image_info */
11937 jpeg_image=DestroyImage(jpeg_image);
11938 (void) RelinquishUniqueFileResource(jpeg_image_info->filename);
11939 jpeg_image_info=DestroyImageInfo(jpeg_image_info);
11942 /* Write JHDR chunk */
11943 (void) WriteBlobMSBULong(image,16L); /* chunk data length=16 */
11944 PNGType(chunk,mng_JHDR);
11945 LogPNGChunk(logging,mng_JHDR,16L);
11946 PNGLong(chunk+4,(png_uint_32) image->columns);
11947 PNGLong(chunk+8,(png_uint_32) image->rows);
11948 chunk[12]=jng_color_type;
11949 chunk[13]=8; /* sample depth */
11950 chunk[14]=8; /*jng_image_compression_method */
11951 chunk[15]=(unsigned char) (image_info->interlace == NoInterlace ? 0 : 8);
11952 chunk[16]=jng_alpha_sample_depth;
11953 chunk[17]=jng_alpha_compression_method;
11954 chunk[18]=0; /*jng_alpha_filter_method */
11955 chunk[19]=0; /*jng_alpha_interlace_method */
11956 (void) WriteBlob(image,20,chunk);
11957 (void) WriteBlobMSBULong(image,crc32(0,chunk,20));
11958 if (logging != MagickFalse)
11960 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11961 " JNG width:%15lu",(unsigned long) image->columns);
11963 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11964 " JNG height:%14lu",(unsigned long) image->rows);
11966 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11967 " JNG color type:%10d",jng_color_type);
11969 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11970 " JNG sample depth:%8d",8);
11972 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11973 " JNG compression:%9d",8);
11975 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11976 " JNG interlace:%11d",0);
11978 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11979 " JNG alpha depth:%9d",jng_alpha_sample_depth);
11981 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11982 " JNG alpha compression:%3d",jng_alpha_compression_method);
11984 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11985 " JNG alpha filter:%8d",0);
11987 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11988 " JNG alpha interlace:%5d",0);
11991 /* Write any JNG-chunk-b profiles */
11992 (void) Magick_png_write_chunk_from_profile(image,"JNG-chunk-b",logging);
11995 Write leading ancillary chunks
12001 Write JNG bKGD chunk
12012 if (jng_color_type == 8 || jng_color_type == 12)
12016 (void) WriteBlobMSBULong(image,(size_t) (num_bytes-4L));
12017 PNGType(chunk,mng_bKGD);
12018 LogPNGChunk(logging,mng_bKGD,(size_t) (num_bytes-4L));
12019 red=ScaleQuantumToChar(image->background_color.red);
12020 green=ScaleQuantumToChar(image->background_color.green);
12021 blue=ScaleQuantumToChar(image->background_color.blue);
12028 (void) WriteBlob(image,(size_t) num_bytes,chunk);
12029 (void) WriteBlobMSBULong(image,crc32(0,chunk,(uInt) num_bytes));
12032 if ((image->colorspace == sRGBColorspace || image->rendering_intent))
12035 Write JNG sRGB chunk
12037 (void) WriteBlobMSBULong(image,1L);
12038 PNGType(chunk,mng_sRGB);
12039 LogPNGChunk(logging,mng_sRGB,1L);
12041 if (image->rendering_intent != UndefinedIntent)
12042 chunk[4]=(unsigned char)
12043 Magick_RenderingIntent_to_PNG_RenderingIntent(
12044 (image->rendering_intent));
12047 chunk[4]=(unsigned char)
12048 Magick_RenderingIntent_to_PNG_RenderingIntent(
12049 (PerceptualIntent));
12051 (void) WriteBlob(image,5,chunk);
12052 (void) WriteBlobMSBULong(image,crc32(0,chunk,5));
12056 if (image->gamma != 0.0)
12059 Write JNG gAMA chunk
12061 (void) WriteBlobMSBULong(image,4L);
12062 PNGType(chunk,mng_gAMA);
12063 LogPNGChunk(logging,mng_gAMA,4L);
12064 PNGLong(chunk+4,(png_uint_32) (100000*image->gamma+0.5));
12065 (void) WriteBlob(image,8,chunk);
12066 (void) WriteBlobMSBULong(image,crc32(0,chunk,8));
12069 if ((mng_info->equal_chrms == MagickFalse) &&
12070 (image->chromaticity.red_primary.x != 0.0))
12076 Write JNG cHRM chunk
12078 (void) WriteBlobMSBULong(image,32L);
12079 PNGType(chunk,mng_cHRM);
12080 LogPNGChunk(logging,mng_cHRM,32L);
12081 primary=image->chromaticity.white_point;
12082 PNGLong(chunk+4,(png_uint_32) (100000*primary.x+0.5));
12083 PNGLong(chunk+8,(png_uint_32) (100000*primary.y+0.5));
12084 primary=image->chromaticity.red_primary;
12085 PNGLong(chunk+12,(png_uint_32) (100000*primary.x+0.5));
12086 PNGLong(chunk+16,(png_uint_32) (100000*primary.y+0.5));
12087 primary=image->chromaticity.green_primary;
12088 PNGLong(chunk+20,(png_uint_32) (100000*primary.x+0.5));
12089 PNGLong(chunk+24,(png_uint_32) (100000*primary.y+0.5));
12090 primary=image->chromaticity.blue_primary;
12091 PNGLong(chunk+28,(png_uint_32) (100000*primary.x+0.5));
12092 PNGLong(chunk+32,(png_uint_32) (100000*primary.y+0.5));
12093 (void) WriteBlob(image,36,chunk);
12094 (void) WriteBlobMSBULong(image,crc32(0,chunk,36));
12098 if (image->resolution.x && image->resolution.y && !mng_info->equal_physs)
12101 Write JNG pHYs chunk
12103 (void) WriteBlobMSBULong(image,9L);
12104 PNGType(chunk,mng_pHYs);
12105 LogPNGChunk(logging,mng_pHYs,9L);
12106 if (image->units == PixelsPerInchResolution)
12108 PNGLong(chunk+4,(png_uint_32)
12109 (image->resolution.x*100.0/2.54+0.5));
12111 PNGLong(chunk+8,(png_uint_32)
12112 (image->resolution.y*100.0/2.54+0.5));
12119 if (image->units == PixelsPerCentimeterResolution)
12121 PNGLong(chunk+4,(png_uint_32)
12122 (image->resolution.x*100.0+0.5));
12124 PNGLong(chunk+8,(png_uint_32)
12125 (image->resolution.y*100.0+0.5));
12132 PNGLong(chunk+4,(png_uint_32) (image->resolution.x+0.5));
12133 PNGLong(chunk+8,(png_uint_32) (image->resolution.y+0.5));
12137 (void) WriteBlob(image,13,chunk);
12138 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
12141 if (mng_info->write_mng == 0 && (image->page.x || image->page.y))
12144 Write JNG oFFs chunk
12146 (void) WriteBlobMSBULong(image,9L);
12147 PNGType(chunk,mng_oFFs);
12148 LogPNGChunk(logging,mng_oFFs,9L);
12149 PNGsLong(chunk+4,(ssize_t) (image->page.x));
12150 PNGsLong(chunk+8,(ssize_t) (image->page.y));
12152 (void) WriteBlob(image,13,chunk);
12153 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
12155 if (mng_info->write_mng == 0 && (image->page.width || image->page.height))
12157 (void) WriteBlobMSBULong(image,9L); /* data length=8 */
12158 PNGType(chunk,mng_vpAg);
12159 LogPNGChunk(logging,mng_vpAg,9L);
12160 PNGLong(chunk+4,(png_uint_32) image->page.width);
12161 PNGLong(chunk+8,(png_uint_32) image->page.height);
12162 chunk[12]=0; /* unit = pixels */
12163 (void) WriteBlob(image,13,chunk);
12164 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
12170 if (jng_alpha_compression_method==0)
12178 /* Write IDAT chunk header */
12179 if (logging != MagickFalse)
12180 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12181 " Write IDAT chunks from blob, length=%.20g.",(double)
12184 /* Copy IDAT chunks */
12187 for (i=8; i<(ssize_t) length; i+=len+12)
12189 len=(*p<<24)|((*(p+1))<<16)|((*(p+2))<<8)|(*(p+3));
12192 if (*(p)==73 && *(p+1)==68 && *(p+2)==65 && *(p+3)==84) /* IDAT */
12194 /* Found an IDAT chunk. */
12195 (void) WriteBlobMSBULong(image,(size_t) len);
12196 LogPNGChunk(logging,mng_IDAT,(size_t) len);
12197 (void) WriteBlob(image,(size_t) len+4,p);
12198 (void) WriteBlobMSBULong(image,
12199 crc32(0,p,(uInt) len+4));
12204 if (logging != MagickFalse)
12205 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12206 " Skipping %c%c%c%c chunk, length=%.20g.",
12207 *(p),*(p+1),*(p+2),*(p+3),(double) len);
12214 /* Write JDAA chunk header */
12215 if (logging != MagickFalse)
12216 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12217 " Write JDAA chunk, length=%.20g.",(double) length);
12218 (void) WriteBlobMSBULong(image,(size_t) length);
12219 PNGType(chunk,mng_JDAA);
12220 LogPNGChunk(logging,mng_JDAA,length);
12221 /* Write JDAT chunk(s) data */
12222 (void) WriteBlob(image,4,chunk);
12223 (void) WriteBlob(image,length,blob);
12224 (void) WriteBlobMSBULong(image,crc32(crc32(0,chunk,4),blob,
12227 blob=(unsigned char *) RelinquishMagickMemory(blob);
12230 /* Encode image as a JPEG blob */
12231 if (logging != MagickFalse)
12232 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12233 " Creating jpeg_image_info.");
12234 jpeg_image_info=(ImageInfo *) CloneImageInfo(image_info);
12235 if (jpeg_image_info == (ImageInfo *) NULL)
12236 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
12238 if (logging != MagickFalse)
12239 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12240 " Creating jpeg_image.");
12242 jpeg_image=CloneImage(image,0,0,MagickTrue,exception);
12243 if (jpeg_image == (Image *) NULL)
12244 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
12245 (void) CopyMagickString(jpeg_image->magick,"JPEG",MaxTextExtent);
12247 (void) AcquireUniqueFilename(jpeg_image->filename);
12248 (void) FormatLocaleString(jpeg_image_info->filename,MaxTextExtent,"%s",
12249 jpeg_image->filename);
12251 status=OpenBlob(jpeg_image_info,jpeg_image,WriteBinaryBlobMode,
12254 if (logging != MagickFalse)
12255 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12256 " Created jpeg_image, %.20g x %.20g.",(double) jpeg_image->columns,
12257 (double) jpeg_image->rows);
12259 if (jng_color_type == 8 || jng_color_type == 12)
12260 jpeg_image_info->type=GrayscaleType;
12262 jpeg_image_info->quality=jng_quality;
12263 jpeg_image->quality=jng_quality;
12264 (void) CopyMagickString(jpeg_image_info->magick,"JPEG",MaxTextExtent);
12265 (void) CopyMagickString(jpeg_image->magick,"JPEG",MaxTextExtent);
12267 if (logging != MagickFalse)
12268 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12269 " Creating blob.");
12271 blob=ImageToBlob(jpeg_image_info,jpeg_image,&length,exception);
12273 if (logging != MagickFalse)
12275 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12276 " Successfully read jpeg_image into a blob, length=%.20g.",
12279 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12280 " Write JDAT chunk, length=%.20g.",(double) length);
12283 /* Write JDAT chunk(s) */
12284 (void) WriteBlobMSBULong(image,(size_t) length);
12285 PNGType(chunk,mng_JDAT);
12286 LogPNGChunk(logging,mng_JDAT,length);
12287 (void) WriteBlob(image,4,chunk);
12288 (void) WriteBlob(image,length,blob);
12289 (void) WriteBlobMSBULong(image,crc32(crc32(0,chunk,4),blob,(uInt) length));
12291 jpeg_image=DestroyImage(jpeg_image);
12292 (void) RelinquishUniqueFileResource(jpeg_image_info->filename);
12293 jpeg_image_info=DestroyImageInfo(jpeg_image_info);
12294 blob=(unsigned char *) RelinquishMagickMemory(blob);
12296 /* Write any JNG-chunk-e profiles */
12297 (void) Magick_png_write_chunk_from_profile(image,"JNG-chunk-e",logging);
12299 /* Write IEND chunk */
12300 (void) WriteBlobMSBULong(image,0L);
12301 PNGType(chunk,mng_IEND);
12302 LogPNGChunk(logging,mng_IEND,0);
12303 (void) WriteBlob(image,4,chunk);
12304 (void) WriteBlobMSBULong(image,crc32(0,chunk,4));
12306 if (logging != MagickFalse)
12307 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12308 " exit WriteOneJNGImage()");
12315 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12319 % W r i t e J N G I m a g e %
12323 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12325 % WriteJNGImage() writes a JPEG Network Graphics (JNG) image file.
12327 % JNG support written by Glenn Randers-Pehrson, glennrp@image...
12329 % The format of the WriteJNGImage method is:
12331 % MagickBooleanType WriteJNGImage(const ImageInfo *image_info,
12332 % Image *image,ExceptionInfo *exception)
12334 % A description of each parameter follows:
12336 % o image_info: the image info.
12338 % o image: The image.
12340 % o exception: return any errors or warnings in this structure.
12342 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12344 static MagickBooleanType WriteJNGImage(const ImageInfo *image_info,Image *image,
12345 ExceptionInfo *exception)
12348 have_mng_structure,
12358 assert(image_info != (const ImageInfo *) NULL);
12359 assert(image_info->signature == MagickSignature);
12360 assert(image != (Image *) NULL);
12361 assert(image->signature == MagickSignature);
12362 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
12363 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter WriteJNGImage()");
12364 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
12365 if (status == MagickFalse)
12369 Allocate a MngInfo structure.
12371 have_mng_structure=MagickFalse;
12372 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
12373 if (mng_info == (MngInfo *) NULL)
12374 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
12376 Initialize members of the MngInfo structure.
12378 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
12379 mng_info->image=image;
12380 have_mng_structure=MagickTrue;
12382 (void) WriteBlob(image,8,(const unsigned char *) "\213JNG\r\n\032\n");
12384 status=WriteOneJNGImage(mng_info,image_info,image,exception);
12385 (void) CloseBlob(image);
12387 (void) CatchImageException(image);
12388 MngInfoFreeStruct(mng_info,&have_mng_structure);
12389 if (logging != MagickFalse)
12390 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit WriteJNGImage()");
12395 static MagickBooleanType WriteMNGImage(const ImageInfo *image_info,Image *image,
12396 ExceptionInfo *exception)
12405 have_mng_structure,
12408 volatile MagickBooleanType
12420 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
12421 defined(PNG_MNG_FEATURES_SUPPORTED)
12424 all_images_are_gray,
12434 volatile unsigned int
12445 #if (PNG_LIBPNG_VER < 10200)
12446 if (image_info->verbose)
12447 printf("Your PNG library (libpng-%s) is rather old.\n",
12448 PNG_LIBPNG_VER_STRING);
12454 assert(image_info != (const ImageInfo *) NULL);
12455 assert(image_info->signature == MagickSignature);
12456 assert(image != (Image *) NULL);
12457 assert(image->signature == MagickSignature);
12458 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
12459 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter WriteMNGImage()");
12460 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
12461 if (status == MagickFalse)
12465 Allocate a MngInfo structure.
12467 have_mng_structure=MagickFalse;
12468 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
12469 if (mng_info == (MngInfo *) NULL)
12470 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
12472 Initialize members of the MngInfo structure.
12474 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
12475 mng_info->image=image;
12476 have_mng_structure=MagickTrue;
12477 write_mng=LocaleCompare(image_info->magick,"MNG") == 0;
12480 * See if user has requested a specific PNG subformat to be used
12481 * for all of the PNGs in the MNG being written, e.g.,
12483 * convert *.png png8:animation.mng
12485 * To do: check -define png:bit_depth and png:color_type as well,
12486 * or perhaps use mng:bit_depth and mng:color_type instead for
12490 mng_info->write_png8=LocaleCompare(image_info->magick,"PNG8") == 0;
12491 mng_info->write_png24=LocaleCompare(image_info->magick,"PNG24") == 0;
12492 mng_info->write_png32=LocaleCompare(image_info->magick,"PNG32") == 0;
12494 write_jng=MagickFalse;
12495 if (image_info->compression == JPEGCompression)
12496 write_jng=MagickTrue;
12498 mng_info->adjoin=image_info->adjoin &&
12499 (GetNextImageInList(image) != (Image *) NULL) && write_mng;
12501 if (logging != MagickFalse)
12503 /* Log some info about the input */
12507 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12508 " Checking input image(s)");
12510 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12511 " Image_info depth: %.20g",(double) image_info->depth);
12513 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12514 " Type: %d",image_info->type);
12517 for (p=image; p != (Image *) NULL; p=GetNextImageInList(p))
12519 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12520 " Scene: %.20g",(double) scene++);
12522 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12523 " Image depth: %.20g",(double) p->depth);
12526 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12530 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12533 if (p->storage_class == PseudoClass)
12534 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12535 " Storage class: PseudoClass");
12538 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12539 " Storage class: DirectClass");
12542 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12543 " Number of colors: %.20g",(double) p->colors);
12546 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12547 " Number of colors: unspecified");
12549 if (mng_info->adjoin == MagickFalse)
12554 use_global_plte=MagickFalse;
12555 all_images_are_gray=MagickFalse;
12556 #ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
12557 need_local_plte=MagickTrue;
12559 need_defi=MagickFalse;
12560 need_matte=MagickFalse;
12561 mng_info->framing_mode=1;
12562 mng_info->old_framing_mode=1;
12565 if (image_info->page != (char *) NULL)
12568 Determine image bounding box.
12570 SetGeometry(image,&mng_info->page);
12571 (void) ParseMetaGeometry(image_info->page,&mng_info->page.x,
12572 &mng_info->page.y,&mng_info->page.width,&mng_info->page.height);
12584 mng_info->page=image->page;
12585 need_geom=MagickTrue;
12586 if (mng_info->page.width || mng_info->page.height)
12587 need_geom=MagickFalse;
12589 Check all the scenes.
12591 initial_delay=image->delay;
12592 need_iterations=MagickFalse;
12593 mng_info->equal_chrms=image->chromaticity.red_primary.x != 0.0;
12594 mng_info->equal_physs=MagickTrue,
12595 mng_info->equal_gammas=MagickTrue;
12596 mng_info->equal_srgbs=MagickTrue;
12597 mng_info->equal_backgrounds=MagickTrue;
12599 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
12600 defined(PNG_MNG_FEATURES_SUPPORTED)
12601 all_images_are_gray=MagickTrue;
12602 mng_info->equal_palettes=MagickFalse;
12603 need_local_plte=MagickFalse;
12605 for (next_image=image; next_image != (Image *) NULL; )
12609 if ((next_image->columns+next_image->page.x) > mng_info->page.width)
12610 mng_info->page.width=next_image->columns+next_image->page.x;
12612 if ((next_image->rows+next_image->page.y) > mng_info->page.height)
12613 mng_info->page.height=next_image->rows+next_image->page.y;
12616 if (next_image->page.x || next_image->page.y)
12617 need_defi=MagickTrue;
12619 if (next_image->matte)
12620 need_matte=MagickTrue;
12622 if ((int) next_image->dispose >= BackgroundDispose)
12623 if (next_image->matte || next_image->page.x || next_image->page.y ||
12624 ((next_image->columns < mng_info->page.width) &&
12625 (next_image->rows < mng_info->page.height)))
12626 mng_info->need_fram=MagickTrue;
12628 if (next_image->iterations)
12629 need_iterations=MagickTrue;
12631 final_delay=next_image->delay;
12633 if (final_delay != initial_delay || final_delay > 1UL*
12634 next_image->ticks_per_second)
12635 mng_info->need_fram=1;
12637 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
12638 defined(PNG_MNG_FEATURES_SUPPORTED)
12640 check for global palette possibility.
12642 if (image->matte != MagickFalse)
12643 need_local_plte=MagickTrue;
12645 if (need_local_plte == 0)
12647 if (IsImageGray(image,exception) == MagickFalse)
12648 all_images_are_gray=MagickFalse;
12649 mng_info->equal_palettes=PalettesAreEqual(image,next_image);
12650 if (use_global_plte == 0)
12651 use_global_plte=mng_info->equal_palettes;
12652 need_local_plte=!mng_info->equal_palettes;
12655 if (GetNextImageInList(next_image) != (Image *) NULL)
12657 if (next_image->background_color.red !=
12658 next_image->next->background_color.red ||
12659 next_image->background_color.green !=
12660 next_image->next->background_color.green ||
12661 next_image->background_color.blue !=
12662 next_image->next->background_color.blue)
12663 mng_info->equal_backgrounds=MagickFalse;
12665 if (next_image->gamma != next_image->next->gamma)
12666 mng_info->equal_gammas=MagickFalse;
12668 if (next_image->rendering_intent !=
12669 next_image->next->rendering_intent)
12670 mng_info->equal_srgbs=MagickFalse;
12672 if ((next_image->units != next_image->next->units) ||
12673 (next_image->resolution.x != next_image->next->resolution.x) ||
12674 (next_image->resolution.y != next_image->next->resolution.y))
12675 mng_info->equal_physs=MagickFalse;
12677 if (mng_info->equal_chrms)
12679 if (next_image->chromaticity.red_primary.x !=
12680 next_image->next->chromaticity.red_primary.x ||
12681 next_image->chromaticity.red_primary.y !=
12682 next_image->next->chromaticity.red_primary.y ||
12683 next_image->chromaticity.green_primary.x !=
12684 next_image->next->chromaticity.green_primary.x ||
12685 next_image->chromaticity.green_primary.y !=
12686 next_image->next->chromaticity.green_primary.y ||
12687 next_image->chromaticity.blue_primary.x !=
12688 next_image->next->chromaticity.blue_primary.x ||
12689 next_image->chromaticity.blue_primary.y !=
12690 next_image->next->chromaticity.blue_primary.y ||
12691 next_image->chromaticity.white_point.x !=
12692 next_image->next->chromaticity.white_point.x ||
12693 next_image->chromaticity.white_point.y !=
12694 next_image->next->chromaticity.white_point.y)
12695 mng_info->equal_chrms=MagickFalse;
12699 next_image=GetNextImageInList(next_image);
12701 if (image_count < 2)
12703 mng_info->equal_backgrounds=MagickFalse;
12704 mng_info->equal_chrms=MagickFalse;
12705 mng_info->equal_gammas=MagickFalse;
12706 mng_info->equal_srgbs=MagickFalse;
12707 mng_info->equal_physs=MagickFalse;
12708 use_global_plte=MagickFalse;
12709 #ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
12710 need_local_plte=MagickTrue;
12712 need_iterations=MagickFalse;
12715 if (mng_info->need_fram == MagickFalse)
12718 Only certain framing rates 100/n are exactly representable without
12719 the FRAM chunk but we'll allow some slop in VLC files
12721 if (final_delay == 0)
12723 if (need_iterations != MagickFalse)
12726 It's probably a GIF with loop; don't run it *too* fast.
12728 if (mng_info->adjoin)
12731 (void) ThrowMagickException(exception,GetMagickModule(),
12733 "input has zero delay between all frames; assuming",
12738 mng_info->ticks_per_second=0;
12740 if (final_delay != 0)
12741 mng_info->ticks_per_second=(png_uint_32)
12742 (image->ticks_per_second/final_delay);
12743 if (final_delay > 50)
12744 mng_info->ticks_per_second=2;
12746 if (final_delay > 75)
12747 mng_info->ticks_per_second=1;
12749 if (final_delay > 125)
12750 mng_info->need_fram=MagickTrue;
12752 if (need_defi && final_delay > 2 && (final_delay != 4) &&
12753 (final_delay != 5) && (final_delay != 10) && (final_delay != 20) &&
12754 (final_delay != 25) && (final_delay != 50) && (final_delay !=
12755 1UL*image->ticks_per_second))
12756 mng_info->need_fram=MagickTrue; /* make it exact; cannot be VLC */
12759 if (mng_info->need_fram != MagickFalse)
12760 mng_info->ticks_per_second=1UL*image->ticks_per_second;
12762 If pseudocolor, we should also check to see if all the
12763 palettes are identical and write a global PLTE if they are.
12767 Write the MNG version 1.0 signature and MHDR chunk.
12769 (void) WriteBlob(image,8,(const unsigned char *) "\212MNG\r\n\032\n");
12770 (void) WriteBlobMSBULong(image,28L); /* chunk data length=28 */
12771 PNGType(chunk,mng_MHDR);
12772 LogPNGChunk(logging,mng_MHDR,28L);
12773 PNGLong(chunk+4,(png_uint_32) mng_info->page.width);
12774 PNGLong(chunk+8,(png_uint_32) mng_info->page.height);
12775 PNGLong(chunk+12,mng_info->ticks_per_second);
12776 PNGLong(chunk+16,0L); /* layer count=unknown */
12777 PNGLong(chunk+20,0L); /* frame count=unknown */
12778 PNGLong(chunk+24,0L); /* play time=unknown */
12783 if (need_defi || mng_info->need_fram || use_global_plte)
12784 PNGLong(chunk+28,27L); /* simplicity=LC+JNG */
12787 PNGLong(chunk+28,25L); /* simplicity=VLC+JNG */
12792 if (need_defi || mng_info->need_fram || use_global_plte)
12793 PNGLong(chunk+28,19L); /* simplicity=LC+JNG, no transparency */
12796 PNGLong(chunk+28,17L); /* simplicity=VLC+JNG, no transparency */
12804 if (need_defi || mng_info->need_fram || use_global_plte)
12805 PNGLong(chunk+28,11L); /* simplicity=LC */
12808 PNGLong(chunk+28,9L); /* simplicity=VLC */
12813 if (need_defi || mng_info->need_fram || use_global_plte)
12814 PNGLong(chunk+28,3L); /* simplicity=LC, no transparency */
12817 PNGLong(chunk+28,1L); /* simplicity=VLC, no transparency */
12820 (void) WriteBlob(image,32,chunk);
12821 (void) WriteBlobMSBULong(image,crc32(0,chunk,32));
12822 option=GetImageOption(image_info,"mng:need-cacheoff");
12823 if (option != (const char *) NULL)
12829 Write "nEED CACHEOFF" to turn playback caching off for streaming MNG.
12831 PNGType(chunk,mng_nEED);
12832 length=CopyMagickString((char *) chunk+4,"CACHEOFF",20);
12833 (void) WriteBlobMSBULong(image,(size_t) length);
12834 LogPNGChunk(logging,mng_nEED,(size_t) length);
12836 (void) WriteBlob(image,length,chunk);
12837 (void) WriteBlobMSBULong(image,crc32(0,chunk,(uInt) length));
12839 if ((GetPreviousImageInList(image) == (Image *) NULL) &&
12840 (GetNextImageInList(image) != (Image *) NULL) &&
12841 (image->iterations != 1))
12844 Write MNG TERM chunk
12846 (void) WriteBlobMSBULong(image,10L); /* data length=10 */
12847 PNGType(chunk,mng_TERM);
12848 LogPNGChunk(logging,mng_TERM,10L);
12849 chunk[4]=3; /* repeat animation */
12850 chunk[5]=0; /* show last frame when done */
12851 PNGLong(chunk+6,(png_uint_32) (mng_info->ticks_per_second*
12852 final_delay/MagickMax(image->ticks_per_second,1)));
12854 if (image->iterations == 0)
12855 PNGLong(chunk+10,PNG_UINT_31_MAX);
12858 PNGLong(chunk+10,(png_uint_32) image->iterations);
12860 if (logging != MagickFalse)
12862 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12863 " TERM delay: %.20g",(double) (mng_info->ticks_per_second*
12864 final_delay/MagickMax(image->ticks_per_second,1)));
12866 if (image->iterations == 0)
12867 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12868 " TERM iterations: %.20g",(double) PNG_UINT_31_MAX);
12871 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12872 " Image iterations: %.20g",(double) image->iterations);
12874 (void) WriteBlob(image,14,chunk);
12875 (void) WriteBlobMSBULong(image,crc32(0,chunk,14));
12878 To do: check for cHRM+gAMA == sRGB, and write sRGB instead.
12880 if ((image->colorspace == sRGBColorspace || image->rendering_intent) &&
12881 mng_info->equal_srgbs)
12884 Write MNG sRGB chunk
12886 (void) WriteBlobMSBULong(image,1L);
12887 PNGType(chunk,mng_sRGB);
12888 LogPNGChunk(logging,mng_sRGB,1L);
12890 if (image->rendering_intent != UndefinedIntent)
12891 chunk[4]=(unsigned char)
12892 Magick_RenderingIntent_to_PNG_RenderingIntent(
12893 (image->rendering_intent));
12896 chunk[4]=(unsigned char)
12897 Magick_RenderingIntent_to_PNG_RenderingIntent(
12898 (PerceptualIntent));
12900 (void) WriteBlob(image,5,chunk);
12901 (void) WriteBlobMSBULong(image,crc32(0,chunk,5));
12902 mng_info->have_write_global_srgb=MagickTrue;
12907 if (image->gamma && mng_info->equal_gammas)
12910 Write MNG gAMA chunk
12912 (void) WriteBlobMSBULong(image,4L);
12913 PNGType(chunk,mng_gAMA);
12914 LogPNGChunk(logging,mng_gAMA,4L);
12915 PNGLong(chunk+4,(png_uint_32) (100000*image->gamma+0.5));
12916 (void) WriteBlob(image,8,chunk);
12917 (void) WriteBlobMSBULong(image,crc32(0,chunk,8));
12918 mng_info->have_write_global_gama=MagickTrue;
12920 if (mng_info->equal_chrms)
12926 Write MNG cHRM chunk
12928 (void) WriteBlobMSBULong(image,32L);
12929 PNGType(chunk,mng_cHRM);
12930 LogPNGChunk(logging,mng_cHRM,32L);
12931 primary=image->chromaticity.white_point;
12932 PNGLong(chunk+4,(png_uint_32) (100000*primary.x+0.5));
12933 PNGLong(chunk+8,(png_uint_32) (100000*primary.y+0.5));
12934 primary=image->chromaticity.red_primary;
12935 PNGLong(chunk+12,(png_uint_32) (100000*primary.x+0.5));
12936 PNGLong(chunk+16,(png_uint_32) (100000*primary.y+0.5));
12937 primary=image->chromaticity.green_primary;
12938 PNGLong(chunk+20,(png_uint_32) (100000*primary.x+0.5));
12939 PNGLong(chunk+24,(png_uint_32) (100000*primary.y+0.5));
12940 primary=image->chromaticity.blue_primary;
12941 PNGLong(chunk+28,(png_uint_32) (100000*primary.x+0.5));
12942 PNGLong(chunk+32,(png_uint_32) (100000*primary.y+0.5));
12943 (void) WriteBlob(image,36,chunk);
12944 (void) WriteBlobMSBULong(image,crc32(0,chunk,36));
12945 mng_info->have_write_global_chrm=MagickTrue;
12948 if (image->resolution.x && image->resolution.y && mng_info->equal_physs)
12951 Write MNG pHYs chunk
12953 (void) WriteBlobMSBULong(image,9L);
12954 PNGType(chunk,mng_pHYs);
12955 LogPNGChunk(logging,mng_pHYs,9L);
12957 if (image->units == PixelsPerInchResolution)
12959 PNGLong(chunk+4,(png_uint_32)
12960 (image->resolution.x*100.0/2.54+0.5));
12962 PNGLong(chunk+8,(png_uint_32)
12963 (image->resolution.y*100.0/2.54+0.5));
12970 if (image->units == PixelsPerCentimeterResolution)
12972 PNGLong(chunk+4,(png_uint_32)
12973 (image->resolution.x*100.0+0.5));
12975 PNGLong(chunk+8,(png_uint_32)
12976 (image->resolution.y*100.0+0.5));
12983 PNGLong(chunk+4,(png_uint_32) (image->resolution.x+0.5));
12984 PNGLong(chunk+8,(png_uint_32) (image->resolution.y+0.5));
12988 (void) WriteBlob(image,13,chunk);
12989 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
12992 Write MNG BACK chunk and global bKGD chunk, if the image is transparent
12993 or does not cover the entire frame.
12995 if (write_mng && (image->matte || image->page.x > 0 ||
12996 image->page.y > 0 || (image->page.width &&
12997 (image->page.width+image->page.x < mng_info->page.width))
12998 || (image->page.height && (image->page.height+image->page.y
12999 < mng_info->page.height))))
13001 (void) WriteBlobMSBULong(image,6L);
13002 PNGType(chunk,mng_BACK);
13003 LogPNGChunk(logging,mng_BACK,6L);
13004 red=ScaleQuantumToShort(image->background_color.red);
13005 green=ScaleQuantumToShort(image->background_color.green);
13006 blue=ScaleQuantumToShort(image->background_color.blue);
13007 PNGShort(chunk+4,red);
13008 PNGShort(chunk+6,green);
13009 PNGShort(chunk+8,blue);
13010 (void) WriteBlob(image,10,chunk);
13011 (void) WriteBlobMSBULong(image,crc32(0,chunk,10));
13012 if (mng_info->equal_backgrounds)
13014 (void) WriteBlobMSBULong(image,6L);
13015 PNGType(chunk,mng_bKGD);
13016 LogPNGChunk(logging,mng_bKGD,6L);
13017 (void) WriteBlob(image,10,chunk);
13018 (void) WriteBlobMSBULong(image,crc32(0,chunk,10));
13022 #ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
13023 if ((need_local_plte == MagickFalse) &&
13024 (image->storage_class == PseudoClass) &&
13025 (all_images_are_gray == MagickFalse))
13031 Write MNG PLTE chunk
13033 data_length=3*image->colors;
13034 (void) WriteBlobMSBULong(image,data_length);
13035 PNGType(chunk,mng_PLTE);
13036 LogPNGChunk(logging,mng_PLTE,data_length);
13038 for (i=0; i < (ssize_t) image->colors; i++)
13040 chunk[4+i*3]=(unsigned char) (ScaleQuantumToChar(
13041 image->colormap[i].red) & 0xff);
13042 chunk[5+i*3]=(unsigned char) (ScaleQuantumToChar(
13043 image->colormap[i].green) & 0xff);
13044 chunk[6+i*3]=(unsigned char) (ScaleQuantumToChar(
13045 image->colormap[i].blue) & 0xff);
13048 (void) WriteBlob(image,data_length+4,chunk);
13049 (void) WriteBlobMSBULong(image,crc32(0,chunk,(uInt) (data_length+4)));
13050 mng_info->have_write_global_plte=MagickTrue;
13056 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
13057 defined(PNG_MNG_FEATURES_SUPPORTED)
13058 mng_info->equal_palettes=MagickFalse;
13062 if (mng_info->adjoin)
13064 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
13065 defined(PNG_MNG_FEATURES_SUPPORTED)
13067 If we aren't using a global palette for the entire MNG, check to
13068 see if we can use one for two or more consecutive images.
13070 if (need_local_plte && use_global_plte && !all_images_are_gray)
13072 if (mng_info->IsPalette)
13075 When equal_palettes is true, this image has the same palette
13076 as the previous PseudoClass image
13078 mng_info->have_write_global_plte=mng_info->equal_palettes;
13079 mng_info->equal_palettes=PalettesAreEqual(image,image->next);
13080 if (mng_info->equal_palettes && !mng_info->have_write_global_plte)
13083 Write MNG PLTE chunk
13088 data_length=3*image->colors;
13089 (void) WriteBlobMSBULong(image,data_length);
13090 PNGType(chunk,mng_PLTE);
13091 LogPNGChunk(logging,mng_PLTE,data_length);
13093 for (i=0; i < (ssize_t) image->colors; i++)
13095 chunk[4+i*3]=ScaleQuantumToChar(image->colormap[i].red);
13096 chunk[5+i*3]=ScaleQuantumToChar(image->colormap[i].green);
13097 chunk[6+i*3]=ScaleQuantumToChar(image->colormap[i].blue);
13100 (void) WriteBlob(image,data_length+4,chunk);
13101 (void) WriteBlobMSBULong(image,crc32(0,chunk,
13102 (uInt) (data_length+4)));
13103 mng_info->have_write_global_plte=MagickTrue;
13107 mng_info->have_write_global_plte=MagickFalse;
13118 previous_x=mng_info->page.x;
13119 previous_y=mng_info->page.y;
13126 mng_info->page=image->page;
13127 if ((mng_info->page.x != previous_x) ||
13128 (mng_info->page.y != previous_y))
13130 (void) WriteBlobMSBULong(image,12L); /* data length=12 */
13131 PNGType(chunk,mng_DEFI);
13132 LogPNGChunk(logging,mng_DEFI,12L);
13133 chunk[4]=0; /* object 0 MSB */
13134 chunk[5]=0; /* object 0 LSB */
13135 chunk[6]=0; /* visible */
13136 chunk[7]=0; /* abstract */
13137 PNGLong(chunk+8,(png_uint_32) mng_info->page.x);
13138 PNGLong(chunk+12,(png_uint_32) mng_info->page.y);
13139 (void) WriteBlob(image,16,chunk);
13140 (void) WriteBlobMSBULong(image,crc32(0,chunk,16));
13145 mng_info->write_mng=write_mng;
13147 if ((int) image->dispose >= 3)
13148 mng_info->framing_mode=3;
13150 if (mng_info->need_fram && mng_info->adjoin &&
13151 ((image->delay != mng_info->delay) ||
13152 (mng_info->framing_mode != mng_info->old_framing_mode)))
13154 if (image->delay == mng_info->delay)
13157 Write a MNG FRAM chunk with the new framing mode.
13159 (void) WriteBlobMSBULong(image,1L); /* data length=1 */
13160 PNGType(chunk,mng_FRAM);
13161 LogPNGChunk(logging,mng_FRAM,1L);
13162 chunk[4]=(unsigned char) mng_info->framing_mode;
13163 (void) WriteBlob(image,5,chunk);
13164 (void) WriteBlobMSBULong(image,crc32(0,chunk,5));
13169 Write a MNG FRAM chunk with the delay.
13171 (void) WriteBlobMSBULong(image,10L); /* data length=10 */
13172 PNGType(chunk,mng_FRAM);
13173 LogPNGChunk(logging,mng_FRAM,10L);
13174 chunk[4]=(unsigned char) mng_info->framing_mode;
13175 chunk[5]=0; /* frame name separator (no name) */
13176 chunk[6]=2; /* flag for changing default delay */
13177 chunk[7]=0; /* flag for changing frame timeout */
13178 chunk[8]=0; /* flag for changing frame clipping */
13179 chunk[9]=0; /* flag for changing frame sync_id */
13180 PNGLong(chunk+10,(png_uint_32)
13181 ((mng_info->ticks_per_second*
13182 image->delay)/MagickMax(image->ticks_per_second,1)));
13183 (void) WriteBlob(image,14,chunk);
13184 (void) WriteBlobMSBULong(image,crc32(0,chunk,14));
13185 mng_info->delay=(png_uint_32) image->delay;
13187 mng_info->old_framing_mode=mng_info->framing_mode;
13190 #if defined(JNG_SUPPORTED)
13191 if (image_info->compression == JPEGCompression)
13196 if (logging != MagickFalse)
13197 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
13198 " Writing JNG object.");
13199 /* To do: specify the desired alpha compression method. */
13200 write_info=CloneImageInfo(image_info);
13201 write_info->compression=UndefinedCompression;
13202 status=WriteOneJNGImage(mng_info,write_info,image,exception);
13203 write_info=DestroyImageInfo(write_info);
13208 if (logging != MagickFalse)
13209 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
13210 " Writing PNG object.");
13212 mng_info->need_blob = MagickFalse;
13213 mng_info->ping_preserve_colormap = MagickFalse;
13215 /* We don't want any ancillary chunks written */
13216 mng_info->ping_exclude_bKGD=MagickTrue;
13217 mng_info->ping_exclude_cHRM=MagickTrue;
13218 mng_info->ping_exclude_date=MagickTrue;
13219 mng_info->ping_exclude_EXIF=MagickTrue;
13220 mng_info->ping_exclude_gAMA=MagickTrue;
13221 mng_info->ping_exclude_iCCP=MagickTrue;
13222 /* mng_info->ping_exclude_iTXt=MagickTrue; */
13223 mng_info->ping_exclude_oFFs=MagickTrue;
13224 mng_info->ping_exclude_pHYs=MagickTrue;
13225 mng_info->ping_exclude_sRGB=MagickTrue;
13226 mng_info->ping_exclude_tEXt=MagickTrue;
13227 mng_info->ping_exclude_tRNS=MagickTrue;
13228 mng_info->ping_exclude_vpAg=MagickTrue;
13229 mng_info->ping_exclude_zCCP=MagickTrue;
13230 mng_info->ping_exclude_zTXt=MagickTrue;
13232 status=WriteOnePNGImage(mng_info,image_info,image,exception);
13235 if (status == MagickFalse)
13237 MngInfoFreeStruct(mng_info,&have_mng_structure);
13238 (void) CloseBlob(image);
13239 return(MagickFalse);
13241 (void) CatchImageException(image);
13242 if (GetNextImageInList(image) == (Image *) NULL)
13244 image=SyncNextImageInList(image);
13245 status=SetImageProgress(image,SaveImagesTag,scene++,
13246 GetImageListLength(image));
13248 if (status == MagickFalse)
13251 } while (mng_info->adjoin);
13255 while (GetPreviousImageInList(image) != (Image *) NULL)
13256 image=GetPreviousImageInList(image);
13258 Write the MEND chunk.
13260 (void) WriteBlobMSBULong(image,0x00000000L);
13261 PNGType(chunk,mng_MEND);
13262 LogPNGChunk(logging,mng_MEND,0L);
13263 (void) WriteBlob(image,4,chunk);
13264 (void) WriteBlobMSBULong(image,crc32(0,chunk,4));
13267 Relinquish resources.
13269 (void) CloseBlob(image);
13270 MngInfoFreeStruct(mng_info,&have_mng_structure);
13272 if (logging != MagickFalse)
13273 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit WriteMNGImage()");
13275 return(MagickTrue);
13277 #else /* PNG_LIBPNG_VER > 10011 */
13279 static MagickBooleanType WritePNGImage(const ImageInfo *image_info,Image *image)
13282 printf("Your PNG library is too old: You have libpng-%s\n",
13283 PNG_LIBPNG_VER_STRING);
13285 ThrowBinaryException(CoderError,"PNG library is too old",
13286 image_info->filename);
13289 static MagickBooleanType WriteMNGImage(const ImageInfo *image_info,Image *image)
13291 return(WritePNGImage(image_info,image));
13293 #endif /* PNG_LIBPNG_VER > 10011 */