2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13 % Read/Write Portable Network Graphics Image Format %
17 % Glenn Randers-Pehrson %
21 % Copyright 1999-2011 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/color.h"
51 #include "MagickCore/color-private.h"
52 #include "MagickCore/colormap.h"
53 #include "MagickCore/colorspace.h"
54 #include "MagickCore/colorspace-private.h"
55 #include "MagickCore/constitute.h"
56 #include "MagickCore/enhance.h"
57 #include "MagickCore/exception.h"
58 #include "MagickCore/exception-private.h"
59 #include "MagickCore/geometry.h"
60 #include "MagickCore/histogram.h"
61 #include "MagickCore/image.h"
62 #include "MagickCore/image-private.h"
63 #include "MagickCore/layer.h"
64 #include "MagickCore/list.h"
65 #include "MagickCore/log.h"
66 #include "MagickCore/MagickCore.h"
67 #include "MagickCore/memory_.h"
68 #include "MagickCore/module.h"
69 #include "MagickCore/monitor.h"
70 #include "MagickCore/monitor-private.h"
71 #include "MagickCore/option.h"
72 #include "MagickCore/pixel.h"
73 #include "MagickCore/pixel-accessor.h"
74 #include "MagickCore/profile.h"
75 #include "MagickCore/property.h"
76 #include "MagickCore/quantum-private.h"
77 #include "MagickCore/resource_.h"
78 #include "MagickCore/semaphore.h"
79 #include "MagickCore/quantum-private.h"
80 #include "MagickCore/static.h"
81 #include "MagickCore/statistic.h"
82 #include "MagickCore/string_.h"
83 #include "MagickCore/string-private.h"
84 #include "MagickCore/transform.h"
85 #include "MagickCore/utility.h"
86 #if defined(MAGICKCORE_PNG_DELEGATE)
88 /* Suppress libpng pedantic warnings that were added in
89 * libpng-1.2.41 and libpng-1.4.0. If you are working on
90 * migration to libpng-1.5, remove these defines and then
91 * fix any code that generates warnings.
93 /* #define PNG_DEPRECATED Use of this function is deprecated */
94 /* #define PNG_USE_RESULT The result of this function must be checked */
95 /* #define PNG_NORETURN This function does not return */
96 /* #define PNG_ALLOCATED The result of the function is new memory */
97 /* #define PNG_DEPSTRUCT Access to this struct member is deprecated */
99 /* PNG_PTR_NORETURN does not work on some platforms, in libpng-1.5.x */
100 #define PNG_PTR_NORETURN
105 /* ImageMagick differences */
106 #define first_scene scene
108 #if PNG_LIBPNG_VER > 10011
110 Optional declarations. Define or undefine them as you like.
112 /* #define PNG_DEBUG -- turning this on breaks VisualC compiling */
115 Features under construction. Define these to work on them.
117 #undef MNG_OBJECT_BUFFERS
118 #undef MNG_BASI_SUPPORTED
119 #define MNG_COALESCE_LAYERS /* In 5.4.4, this interfered with MMAP'ed files. */
120 #define MNG_INSERT_LAYERS /* Troublesome, but seem to work as of 5.4.4 */
121 #if defined(MAGICKCORE_JPEG_DELEGATE)
122 # define JNG_SUPPORTED /* Not finished as of 5.5.2. See "To do" comments. */
124 #if !defined(RGBColorMatchExact)
125 #define IsPNGColorEqual(color,target) \
126 (((color).red == (target).red) && \
127 ((color).green == (target).green) && \
128 ((color).blue == (target).blue))
131 /* Macros for left-bit-replication to ensure that pixels
132 * and PixelInfos all have the same image->depth, and for use
133 * in PNG8 quantization.
137 /* LBR01: Replicate top bit */
139 #define LBR01PacketRed(pixelpacket) \
140 (pixelpacket).red=(ScaleQuantumToChar((pixelpacket).red) < 0x10 ? \
143 #define LBR01PacketGreen(pixelpacket) \
144 (pixelpacket).green=(ScaleQuantumToChar((pixelpacket).green) < 0x10 ? \
147 #define LBR01PacketBlue(pixelpacket) \
148 (pixelpacket).blue=(ScaleQuantumToChar((pixelpacket).blue) < 0x10 ? \
151 #define LBR01PacketAlpha(pixelpacket) \
152 (pixelpacket).alpha=(ScaleQuantumToChar((pixelpacket).alpha) < 0x10 ? \
155 #define LBR01PacketRGB(pixelpacket) \
157 LBR01PacketRed((pixelpacket)); \
158 LBR01PacketGreen((pixelpacket)); \
159 LBR01PacketBlue((pixelpacket)); \
162 #define LBR01PacketRGBO(pixelpacket) \
164 LBR01PacketRGB((pixelpacket)); \
165 LBR01PacketAlpha((pixelpacket)); \
168 #define LBR01PixelRed(pixel) \
169 (ScaleQuantumToChar(GetPixelRed(image,(pixel))) < 0x10 ? \
172 #define LBR01PixelGreen(pixel) \
173 (ScaleQuantumToChar(GetPixelGreen(image,(pixel))) < 0x10 ? \
176 #define LBR01PixelBlue(pixel) \
177 (ScaleQuantumToChar(GetPixelBlue(image,(pixel))) < 0x10 ? \
180 #define LBR01PixelAlpha(pixel) \
181 (ScaleQuantumToChar(GetPixelAlpha(image,(pixel))) < 0x10 ? \
184 #define LBR01PixelRGB(pixel) \
186 LBR01PixelRed((pixel)); \
187 LBR01PixelGreen((pixel)); \
188 LBR01PixelBlue((pixel)); \
191 #define LBR01PixelRGBA(pixel) \
193 LBR01PixelRGB((pixel)); \
194 LBR01PixelAlpha((pixel)); \
197 /* LBR02: Replicate top 2 bits */
199 #define LBR02PacketRed(pixelpacket) \
201 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).red) & 0xc0; \
202 (pixelpacket).red=ScaleCharToQuantum( \
203 (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))); \
205 #define LBR02PacketGreen(pixelpacket) \
207 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).green) & 0xc0; \
208 (pixelpacket).green=ScaleCharToQuantum( \
209 (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))); \
211 #define LBR02PacketBlue(pixelpacket) \
213 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).blue) & 0xc0; \
214 (pixelpacket).blue=ScaleCharToQuantum( \
215 (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))); \
217 #define LBR02PacketAlpha(pixelpacket) \
219 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).alpha) & 0xc0; \
220 (pixelpacket).alpha=ScaleCharToQuantum( \
221 (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))); \
224 #define LBR02PacketRGB(pixelpacket) \
226 LBR02PacketRed((pixelpacket)); \
227 LBR02PacketGreen((pixelpacket)); \
228 LBR02PacketBlue((pixelpacket)); \
231 #define LBR02PacketRGBO(pixelpacket) \
233 LBR02PacketRGB((pixelpacket)); \
234 LBR02PacketAlpha((pixelpacket)); \
237 #define LBR02PixelRed(pixel) \
239 unsigned char lbr_bits=ScaleQuantumToChar(GetPixelRed(image,(pixel))) \
241 SetPixelRed(image, ScaleCharToQuantum( \
242 (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))), \
245 #define LBR02PixelGreen(pixel) \
247 unsigned char lbr_bits=ScaleQuantumToChar(GetPixelGreen(image,(pixel)))\
249 SetPixelGreen(image, ScaleCharToQuantum( \
250 (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))), \
253 #define LBR02PixelBlue(pixel) \
255 unsigned char lbr_bits= \
256 ScaleQuantumToChar(GetPixelBlue(image,(pixel))) & 0xc0; \
257 SetPixelBlue(image, ScaleCharToQuantum( \
258 (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))), \
261 #define LBR02PixelAlpha(pixel) \
263 unsigned char lbr_bits= \
264 ScaleQuantumToChar(GetPixelAlpha(image,(pixel))) & 0xc0; \
265 SetPixelAlpha(image, ScaleCharToQuantum( \
266 (lbr_bits | (lbr_bits >> 2) | (lbr_bits >> 4) | (lbr_bits >> 6))), \
270 #define LBR02PixelRGB(pixel) \
272 LBR02PixelRed((pixel)); \
273 LBR02PixelGreen((pixel)); \
274 LBR02PixelBlue((pixel)); \
277 #define LBR02PixelRGBA(pixel) \
279 LBR02PixelRGB((pixel)); \
280 LBR02PixelAlpha((pixel)); \
283 /* LBR03: Replicate top 3 bits (only used with opaque pixels during
284 PNG8 quantization) */
286 #define LBR03PacketRed(pixelpacket) \
288 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).red) & 0xe0; \
289 (pixelpacket).red=ScaleCharToQuantum( \
290 (lbr_bits | (lbr_bits >> 3) | (lbr_bits >> 6))); \
292 #define LBR03PacketGreen(pixelpacket) \
294 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).green) & 0xe0; \
295 (pixelpacket).green=ScaleCharToQuantum( \
296 (lbr_bits | (lbr_bits >> 3) | (lbr_bits >> 6))); \
298 #define LBR03PacketBlue(pixelpacket) \
300 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).blue) & 0xe0; \
301 (pixelpacket).blue=ScaleCharToQuantum( \
302 (lbr_bits | (lbr_bits >> 3) | (lbr_bits >> 6))); \
305 #define LBR03PacketRGB(pixelpacket) \
307 LBR03PacketRed((pixelpacket)); \
308 LBR03PacketGreen((pixelpacket)); \
309 LBR03PacketBlue((pixelpacket)); \
312 #define LBR03PixelRed(pixel) \
314 unsigned char lbr_bits=ScaleQuantumToChar(GetPixelRed(image,(pixel))) \
316 SetPixelRed(image, ScaleCharToQuantum( \
317 (lbr_bits | (lbr_bits >> 3) | (lbr_bits >> 6))), (pixel)); \
319 #define LBR03Green(pixel) \
321 unsigned char lbr_bits=ScaleQuantumToChar(GetPixelGreen(image,(pixel)))\
323 SetPixelGreen(image, ScaleCharToQuantum( \
324 (lbr_bits | (lbr_bits >> 3) | (lbr_bits >> 6))), (pixel)); \
326 #define LBR03Blue(pixel) \
328 unsigned char lbr_bits=ScaleQuantumToChar(GetPixelBlue(image,(pixel))) \
330 SetPixelBlue(image, ScaleCharToQuantum( \
331 (lbr_bits | (lbr_bits >> 3) | (lbr_bits >> 6))), (pixel)); \
334 #define LBR03RGB(pixel) \
336 LBR03PixelRed((pixel)); \
337 LBR03Green((pixel)); \
338 LBR03Blue((pixel)); \
341 /* LBR04: Replicate top 4 bits */
343 #define LBR04PacketRed(pixelpacket) \
345 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).red) & 0xf0; \
346 (pixelpacket).red=ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))); \
348 #define LBR04PacketGreen(pixelpacket) \
350 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).green) & 0xf0; \
351 (pixelpacket).green=ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))); \
353 #define LBR04PacketBlue(pixelpacket) \
355 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).blue) & 0xf0; \
356 (pixelpacket).blue=ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))); \
358 #define LBR04PacketAlpha(pixelpacket) \
360 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).alpha) & 0xf0; \
361 (pixelpacket).alpha=ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))); \
364 #define LBR04PacketRGB(pixelpacket) \
366 LBR04PacketRed((pixelpacket)); \
367 LBR04PacketGreen((pixelpacket)); \
368 LBR04PacketBlue((pixelpacket)); \
371 #define LBR04PacketRGBO(pixelpacket) \
373 LBR04PacketRGB((pixelpacket)); \
374 LBR04PacketAlpha((pixelpacket)); \
377 #define LBR04PixelRed(pixel) \
379 unsigned char lbr_bits=ScaleQuantumToChar(GetPixelRed(image,(pixel))) \
382 ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))), (pixel)); \
384 #define LBR04PixelGreen(pixel) \
386 unsigned char lbr_bits=ScaleQuantumToChar(GetPixelGreen(image,(pixel)))\
388 SetPixelGreen(image,\
389 ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))), (pixel)); \
391 #define LBR04PixelBlue(pixel) \
393 unsigned char lbr_bits= \
394 ScaleQuantumToChar(GetPixelBlue(image,(pixel))) & 0xf0; \
396 ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))), (pixel)); \
398 #define LBR04PixelAlpha(pixel) \
400 unsigned char lbr_bits= \
401 ScaleQuantumToChar(GetPixelAlpha(image,(pixel))) & 0xf0; \
402 SetPixelAlpha(image,\
403 ScaleCharToQuantum((lbr_bits | (lbr_bits >> 4))), (pixel)); \
406 #define LBR04PixelRGB(pixel) \
408 LBR04PixelRed((pixel)); \
409 LBR04PixelGreen((pixel)); \
410 LBR04PixelBlue((pixel)); \
413 #define LBR04PixelRGBA(pixel) \
415 LBR04PixelRGB((pixel)); \
416 LBR04PixelAlpha((pixel)); \
420 /* LBR08: Replicate top 8 bits */
422 #define LBR08PacketRed(pixelpacket) \
424 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).red); \
425 (pixelpacket).red=ScaleCharToQuantum((lbr_bits)); \
427 #define LBR08PacketGreen(pixelpacket) \
429 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).green); \
430 (pixelpacket).green=ScaleCharToQuantum((lbr_bits)); \
432 #define LBR08PacketBlue(pixelpacket) \
434 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).blue); \
435 (pixelpacket).blue=ScaleCharToQuantum((lbr_bits)); \
437 #define LBR08PacketAlpha(pixelpacket) \
439 unsigned char lbr_bits=ScaleQuantumToChar((pixelpacket).alpha); \
440 (pixelpacket).alpha=ScaleCharToQuantum((lbr_bits)); \
443 #define LBR08PacketRGB(pixelpacket) \
445 LBR08PacketRed((pixelpacket)); \
446 LBR08PacketGreen((pixelpacket)); \
447 LBR08PacketBlue((pixelpacket)); \
450 #define LBR08PacketRGBO(pixelpacket) \
452 LBR08PacketRGB((pixelpacket)); \
453 LBR08PacketAlpha((pixelpacket)); \
456 #define LBR08PixelRed(pixel) \
458 unsigned char lbr_bits= \
459 ScaleQuantumToChar(GetPixelRed(image,(pixel))); \
461 ScaleCharToQuantum((lbr_bits)), (pixel)); \
463 #define LBR08PixelGreen(pixel) \
465 unsigned char lbr_bits= \
466 ScaleQuantumToChar(GetPixelGreen(image,(pixel))); \
467 SetPixelGreen(image,\
468 ScaleCharToQuantum((lbr_bits)), (pixel)); \
470 #define LBR08PixelBlue(pixel) \
472 unsigned char lbr_bits= \
473 ScaleQuantumToChar(GetPixelBlue(image,(pixel))); \
475 ScaleCharToQuantum((lbr_bits)), (pixel)); \
477 #define LBR08PixelAlpha(pixel) \
479 unsigned char lbr_bits= \
480 ScaleQuantumToChar(GetPixelAlpha(image,(pixel))); \
481 SetPixelAlpha(image,\
482 ScaleCharToQuantum((lbr_bits)), (pixel)); \
485 #define LBR08PixelRGB(pixel) \
487 LBR08PixelRed((pixel)); \
488 LBR08PixelGreen((pixel)); \
489 LBR08PixelBlue((pixel)); \
492 #define LBR08PixelRGBA(pixel) \
494 LBR08PixelRGB((pixel)); \
495 LBR08PixelAlpha((pixel)); \
499 /* LBR16: Replicate top 16 bits */
501 #define LBR16PacketRed(pixelpacket) \
503 unsigned short lbr_bits=ScaleQuantumToShort((pixelpacket).red); \
504 (pixelpacket).red=ScaleShortToQuantum((lbr_bits)); \
506 #define LBR16PacketGreen(pixelpacket) \
508 unsigned short lbr_bits=ScaleQuantumToShort((pixelpacket).green); \
509 (pixelpacket).green=ScaleShortToQuantum((lbr_bits)); \
511 #define LBR16PacketBlue(pixelpacket) \
513 unsigned short lbr_bits=ScaleQuantumToShort((pixelpacket).blue); \
514 (pixelpacket).blue=ScaleShortToQuantum((lbr_bits)); \
516 #define LBR16PacketAlpha(pixelpacket) \
518 unsigned short lbr_bits=ScaleQuantumToShort((pixelpacket).alpha); \
519 (pixelpacket).alpha=ScaleShortToQuantum((lbr_bits)); \
522 #define LBR16PacketRGB(pixelpacket) \
524 LBR16PacketRed((pixelpacket)); \
525 LBR16PacketGreen((pixelpacket)); \
526 LBR16PacketBlue((pixelpacket)); \
529 #define LBR16PacketRGBO(pixelpacket) \
531 LBR16PacketRGB((pixelpacket)); \
532 LBR16PacketAlpha((pixelpacket)); \
535 #define LBR16PixelRed(pixel) \
537 unsigned short lbr_bits= \
538 ScaleQuantumToShort(GetPixelRed(image,(pixel))); \
540 ScaleShortToQuantum((lbr_bits)),(pixel)); \
542 #define LBR16PixelGreen(pixel) \
544 unsigned short lbr_bits= \
545 ScaleQuantumToShort(GetPixelGreen(image,(pixel))); \
546 SetPixelGreen(image,\
547 ScaleShortToQuantum((lbr_bits)),(pixel)); \
549 #define LBR16PixelBlue(pixel) \
551 unsigned short lbr_bits= \
552 ScaleQuantumToShort(GetPixelBlue(image,(pixel))); \
554 ScaleShortToQuantum((lbr_bits)),(pixel)); \
556 #define LBR16PixelAlpha(pixel) \
558 unsigned short lbr_bits= \
559 ScaleQuantumToShort(GetPixelAlpha(image,(pixel))); \
560 SetPixelAlpha(image,\
561 ScaleShortToQuantum((lbr_bits)),(pixel)); \
564 #define LBR16PixelRGB(pixel) \
566 LBR16PixelRed((pixel)); \
567 LBR16PixelGreen((pixel)); \
568 LBR16PixelBlue((pixel)); \
571 #define LBR16PixelRGBA(pixel) \
573 LBR16PixelRGB((pixel)); \
574 LBR16PixelAlpha((pixel)); \
578 Establish thread safety.
579 setjmp/longjmp is claimed to be safe on these platforms:
580 setjmp/longjmp is alleged to be unsafe on these platforms:
582 #ifndef SETJMP_IS_THREAD_SAFE
583 #define PNG_SETJMP_NOT_THREAD_SAFE
586 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
588 *ping_semaphore = (SemaphoreInfo *) NULL;
592 This temporary until I set up malloc'ed object attributes array.
593 Recompile with MNG_MAX_OBJECTS=65536L to avoid this limit but
596 #define MNG_MAX_OBJECTS 256
599 If this not defined, spec is interpreted strictly. If it is
600 defined, an attempt will be made to recover from some errors,
602 o global PLTE too short
607 Don't try to define PNG_MNG_FEATURES_SUPPORTED here. Make sure
608 it's defined in libpng/pngconf.h, version 1.0.9 or later. It won't work
609 with earlier versions of libpng. From libpng-1.0.3a to libpng-1.0.8,
610 PNG_READ|WRITE_EMPTY_PLTE were used but those have been deprecated in
611 libpng in favor of PNG_MNG_FEATURES_SUPPORTED, so we set them here.
612 PNG_MNG_FEATURES_SUPPORTED is disabled by default in libpng-1.0.9 and
613 will be enabled by default in libpng-1.2.0.
615 #ifdef PNG_MNG_FEATURES_SUPPORTED
616 # ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
617 # define PNG_READ_EMPTY_PLTE_SUPPORTED
619 # ifndef PNG_WRITE_EMPTY_PLTE_SUPPORTED
620 # define PNG_WRITE_EMPTY_PLTE_SUPPORTED
625 Maximum valid size_t in PNG/MNG chunks is (2^31)-1
626 This macro is only defined in libpng-1.0.3 and later.
627 Previously it was PNG_MAX_UINT but that was deprecated in libpng-1.2.6
629 #ifndef PNG_UINT_31_MAX
630 #define PNG_UINT_31_MAX (png_uint_32) 0x7fffffffL
634 Constant strings for known chunk types. If you need to add a chunk,
635 add a string holding the name here. To make the code more
636 portable, we use ASCII numbers like this, not characters.
639 static png_byte FARDATA mng_MHDR[5]={ 77, 72, 68, 82, (png_byte) '\0'};
640 static png_byte FARDATA mng_BACK[5]={ 66, 65, 67, 75, (png_byte) '\0'};
641 static png_byte FARDATA mng_BASI[5]={ 66, 65, 83, 73, (png_byte) '\0'};
642 static png_byte FARDATA mng_CLIP[5]={ 67, 76, 73, 80, (png_byte) '\0'};
643 static png_byte FARDATA mng_CLON[5]={ 67, 76, 79, 78, (png_byte) '\0'};
644 static png_byte FARDATA mng_DEFI[5]={ 68, 69, 70, 73, (png_byte) '\0'};
645 static png_byte FARDATA mng_DHDR[5]={ 68, 72, 68, 82, (png_byte) '\0'};
646 static png_byte FARDATA mng_DISC[5]={ 68, 73, 83, 67, (png_byte) '\0'};
647 static png_byte FARDATA mng_ENDL[5]={ 69, 78, 68, 76, (png_byte) '\0'};
648 static png_byte FARDATA mng_FRAM[5]={ 70, 82, 65, 77, (png_byte) '\0'};
649 static png_byte FARDATA mng_IEND[5]={ 73, 69, 78, 68, (png_byte) '\0'};
650 static png_byte FARDATA mng_IHDR[5]={ 73, 72, 68, 82, (png_byte) '\0'};
651 static png_byte FARDATA mng_JHDR[5]={ 74, 72, 68, 82, (png_byte) '\0'};
652 static png_byte FARDATA mng_LOOP[5]={ 76, 79, 79, 80, (png_byte) '\0'};
653 static png_byte FARDATA mng_MAGN[5]={ 77, 65, 71, 78, (png_byte) '\0'};
654 static png_byte FARDATA mng_MEND[5]={ 77, 69, 78, 68, (png_byte) '\0'};
655 static png_byte FARDATA mng_MOVE[5]={ 77, 79, 86, 69, (png_byte) '\0'};
656 static png_byte FARDATA mng_PAST[5]={ 80, 65, 83, 84, (png_byte) '\0'};
657 static png_byte FARDATA mng_PLTE[5]={ 80, 76, 84, 69, (png_byte) '\0'};
658 static png_byte FARDATA mng_SAVE[5]={ 83, 65, 86, 69, (png_byte) '\0'};
659 static png_byte FARDATA mng_SEEK[5]={ 83, 69, 69, 75, (png_byte) '\0'};
660 static png_byte FARDATA mng_SHOW[5]={ 83, 72, 79, 87, (png_byte) '\0'};
661 static png_byte FARDATA mng_TERM[5]={ 84, 69, 82, 77, (png_byte) '\0'};
662 static png_byte FARDATA mng_bKGD[5]={ 98, 75, 71, 68, (png_byte) '\0'};
663 static png_byte FARDATA mng_cHRM[5]={ 99, 72, 82, 77, (png_byte) '\0'};
664 static png_byte FARDATA mng_gAMA[5]={103, 65, 77, 65, (png_byte) '\0'};
665 static png_byte FARDATA mng_iCCP[5]={105, 67, 67, 80, (png_byte) '\0'};
666 static png_byte FARDATA mng_nEED[5]={110, 69, 69, 68, (png_byte) '\0'};
667 static png_byte FARDATA mng_pHYg[5]={112, 72, 89, 103, (png_byte) '\0'};
668 static png_byte FARDATA mng_vpAg[5]={118, 112, 65, 103, (png_byte) '\0'};
669 static png_byte FARDATA mng_pHYs[5]={112, 72, 89, 115, (png_byte) '\0'};
670 static png_byte FARDATA mng_sBIT[5]={115, 66, 73, 84, (png_byte) '\0'};
671 static png_byte FARDATA mng_sRGB[5]={115, 82, 71, 66, (png_byte) '\0'};
672 static png_byte FARDATA mng_tRNS[5]={116, 82, 78, 83, (png_byte) '\0'};
674 #if defined(JNG_SUPPORTED)
675 static png_byte FARDATA mng_IDAT[5]={ 73, 68, 65, 84, (png_byte) '\0'};
676 static png_byte FARDATA mng_JDAT[5]={ 74, 68, 65, 84, (png_byte) '\0'};
677 static png_byte FARDATA mng_JDAA[5]={ 74, 68, 65, 65, (png_byte) '\0'};
678 static png_byte FARDATA mng_JdAA[5]={ 74, 100, 65, 65, (png_byte) '\0'};
679 static png_byte FARDATA mng_JSEP[5]={ 74, 83, 69, 80, (png_byte) '\0'};
680 static png_byte FARDATA mng_oFFs[5]={111, 70, 70, 115, (png_byte) '\0'};
684 Other known chunks that are not yet supported by ImageMagick:
685 static png_byte FARDATA mng_hIST[5]={104, 73, 83, 84, (png_byte) '\0'};
686 static png_byte FARDATA mng_iCCP[5]={105, 67, 67, 80, (png_byte) '\0'};
687 static png_byte FARDATA mng_iTXt[5]={105, 84, 88, 116, (png_byte) '\0'};
688 static png_byte FARDATA mng_sPLT[5]={115, 80, 76, 84, (png_byte) '\0'};
689 static png_byte FARDATA mng_sTER[5]={115, 84, 69, 82, (png_byte) '\0'};
690 static png_byte FARDATA mng_tEXt[5]={116, 69, 88, 116, (png_byte) '\0'};
691 static png_byte FARDATA mng_tIME[5]={116, 73, 77, 69, (png_byte) '\0'};
692 static png_byte FARDATA mng_zTXt[5]={122, 84, 88, 116, (png_byte) '\0'};
695 typedef struct _MngBox
704 typedef struct _MngPair
711 #ifdef MNG_OBJECT_BUFFERS
712 typedef struct _MngBuffer
744 typedef struct _MngInfo
747 #ifdef MNG_OBJECT_BUFFERS
749 *ob[MNG_MAX_OBJECTS];
760 #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
761 bytes_in_read_buffer,
767 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
768 defined(PNG_MNG_FEATURES_SUPPORTED)
780 have_saved_bkgd_index,
781 have_write_global_chrm,
782 have_write_global_gama,
783 have_write_global_plte,
784 have_write_global_srgb,
798 x_off[MNG_MAX_OBJECTS],
799 y_off[MNG_MAX_OBJECTS];
805 object_clip[MNG_MAX_OBJECTS];
808 /* These flags could be combined into one byte */
809 exists[MNG_MAX_OBJECTS],
810 frozen[MNG_MAX_OBJECTS],
812 invisible[MNG_MAX_OBJECTS],
813 viewable[MNG_MAX_OBJECTS];
825 #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
843 global_x_pixels_per_unit,
844 global_y_pixels_per_unit,
854 global_phys_unit_type,
869 write_png_compression_level,
870 write_png_compression_strategy,
871 write_png_compression_filter,
876 #ifdef MNG_BASI_SUPPORTED
884 basi_compression_method,
886 basi_interlace_method,
909 /* Added at version 6.6.6-7 */
917 /* ping_exclude_iTXt, */
924 ping_exclude_zCCP, /* hex-encoded iCCP */
926 ping_preserve_colormap;
932 Forward declarations.
934 static MagickBooleanType
935 WritePNGImage(const ImageInfo *,Image *,ExceptionInfo *);
937 static MagickBooleanType
938 WriteMNGImage(const ImageInfo *,Image *,ExceptionInfo *);
940 #if defined(JNG_SUPPORTED)
941 static MagickBooleanType
942 WriteJNGImage(const ImageInfo *,Image *,ExceptionInfo *);
945 #if PNG_LIBPNG_VER > 10011
948 #if (MAGICKCORE_QUANTUM_DEPTH >= 16)
949 static MagickBooleanType
950 LosslessReduceDepthOK(Image *image,ExceptionInfo *exception)
952 /* Reduce bit depth if it can be reduced losslessly from 16+ to 8.
954 * This is true if the high byte and the next highest byte of
955 * each sample of the image, the colormap, and the background color
956 * are equal to each other. We check this by seeing if the samples
957 * are unchanged when we scale them down to 8 and back up to Quantum.
959 * We don't use the method GetImageDepth() because it doesn't check
960 * background and doesn't handle PseudoClass specially.
963 #define QuantumToCharToQuantumEqQuantum(quantum) \
964 ((ScaleCharToQuantum((unsigned char) ScaleQuantumToChar(quantum))) == quantum)
967 ok_to_reduce=MagickFalse;
969 if (image->depth >= 16)
976 QuantumToCharToQuantumEqQuantum(image->background_color.red) &&
977 QuantumToCharToQuantumEqQuantum(image->background_color.green) &&
978 QuantumToCharToQuantumEqQuantum(image->background_color.blue) ?
979 MagickTrue : MagickFalse;
981 if (ok_to_reduce != MagickFalse && image->storage_class == PseudoClass)
985 for (indx=0; indx < (ssize_t) image->colors; indx++)
988 QuantumToCharToQuantumEqQuantum(
989 image->colormap[indx].red) &&
990 QuantumToCharToQuantumEqQuantum(
991 image->colormap[indx].green) &&
992 QuantumToCharToQuantumEqQuantum(
993 image->colormap[indx].blue)) ?
994 MagickTrue : MagickFalse;
996 if (ok_to_reduce == MagickFalse)
1001 if ((ok_to_reduce != MagickFalse) &&
1002 (image->storage_class != PseudoClass))
1010 for (y=0; y < (ssize_t) image->rows; y++)
1012 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1014 if (p == (const Quantum *) NULL)
1016 ok_to_reduce = MagickFalse;
1020 for (x=(ssize_t) image->columns-1; x >= 0; x--)
1023 QuantumToCharToQuantumEqQuantum(GetPixelRed(image,p)) &&
1024 QuantumToCharToQuantumEqQuantum(GetPixelGreen(image,p)) &&
1025 QuantumToCharToQuantumEqQuantum(GetPixelBlue(image,p)) ?
1026 MagickTrue : MagickFalse;
1028 if (ok_to_reduce == MagickFalse)
1031 p+=GetPixelChannels(image);
1038 if (ok_to_reduce != MagickFalse)
1040 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1041 " OK to reduce PNG bit depth to 8 without loss of info");
1045 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1046 " Not OK to reduce PNG bit depth to 8 without loss of info");
1050 return ok_to_reduce;
1052 #endif /* MAGICKCORE_QUANTUM_DEPTH >= 16 */
1055 Magick_RenderingIntent_to_PNG_RenderingIntent(const RenderingIntent intent)
1059 case PerceptualIntent:
1062 case RelativeIntent:
1065 case SaturationIntent:
1068 case AbsoluteIntent:
1076 static RenderingIntent
1077 Magick_RenderingIntent_from_PNG_RenderingIntent(const int ping_intent)
1079 switch (ping_intent)
1082 return PerceptualIntent;
1085 return RelativeIntent;
1088 return SaturationIntent;
1091 return AbsoluteIntent;
1094 return UndefinedIntent;
1098 static inline ssize_t MagickMax(const ssize_t x,const ssize_t y)
1106 static inline ssize_t MagickMin(const ssize_t x,const ssize_t y)
1116 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1120 % I m a g e I s G r a y %
1124 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1126 % Like IsImageGray except does not change DirectClass to PseudoClass %
1128 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1130 static MagickBooleanType ImageIsGray(Image *image,ExceptionInfo *exception)
1132 register const Quantum
1140 assert(image != (Image *) NULL);
1141 assert(image->signature == MagickSignature);
1142 if (image->debug != MagickFalse)
1143 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1145 if (image->storage_class == PseudoClass)
1147 for (i=0; i < (ssize_t) image->colors; i++)
1148 if (IsPixelInfoGray(image->colormap+i) == MagickFalse)
1149 return(MagickFalse);
1152 for (y=0; y < (ssize_t) image->rows; y++)
1154 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1155 if (p == (const Quantum *) NULL)
1156 return(MagickFalse);
1157 for (x=(ssize_t) image->columns-1; x >= 0; x--)
1159 if (IsPixelGray(image,p) == MagickFalse)
1160 return(MagickFalse);
1161 p+=GetPixelChannels(image);
1166 #endif /* PNG_LIBPNG_VER > 10011 */
1167 #endif /* MAGICKCORE_PNG_DELEGATE */
1170 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1178 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1180 % IsMNG() returns MagickTrue if the image format type, identified by the
1181 % magick string, is MNG.
1183 % The format of the IsMNG method is:
1185 % MagickBooleanType IsMNG(const unsigned char *magick,const size_t length)
1187 % A description of each parameter follows:
1189 % o magick: compare image format pattern against these bytes.
1191 % o length: Specifies the length of the magick string.
1195 static MagickBooleanType IsMNG(const unsigned char *magick,const size_t length)
1198 return(MagickFalse);
1200 if (memcmp(magick,"\212MNG\r\n\032\n",8) == 0)
1203 return(MagickFalse);
1207 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1215 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1217 % IsJNG() returns MagickTrue if the image format type, identified by the
1218 % magick string, is JNG.
1220 % The format of the IsJNG method is:
1222 % MagickBooleanType IsJNG(const unsigned char *magick,const size_t length)
1224 % A description of each parameter follows:
1226 % o magick: compare image format pattern against these bytes.
1228 % o length: Specifies the length of the magick string.
1232 static MagickBooleanType IsJNG(const unsigned char *magick,const size_t length)
1235 return(MagickFalse);
1237 if (memcmp(magick,"\213JNG\r\n\032\n",8) == 0)
1240 return(MagickFalse);
1244 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1252 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1254 % IsPNG() returns MagickTrue if the image format type, identified by the
1255 % magick string, is PNG.
1257 % The format of the IsPNG method is:
1259 % MagickBooleanType IsPNG(const unsigned char *magick,const size_t length)
1261 % A description of each parameter follows:
1263 % o magick: compare image format pattern against these bytes.
1265 % o length: Specifies the length of the magick string.
1268 static MagickBooleanType IsPNG(const unsigned char *magick,const size_t length)
1271 return(MagickFalse);
1273 if (memcmp(magick,"\211PNG\r\n\032\n",8) == 0)
1276 return(MagickFalse);
1279 #if defined(MAGICKCORE_PNG_DELEGATE)
1280 #if defined(__cplusplus) || defined(c_plusplus)
1284 #if (PNG_LIBPNG_VER > 10011)
1285 static size_t WriteBlobMSBULong(Image *image,const size_t value)
1290 assert(image != (Image *) NULL);
1291 assert(image->signature == MagickSignature);
1292 buffer[0]=(unsigned char) (value >> 24);
1293 buffer[1]=(unsigned char) (value >> 16);
1294 buffer[2]=(unsigned char) (value >> 8);
1295 buffer[3]=(unsigned char) value;
1296 return((size_t) WriteBlob(image,4,buffer));
1299 static void PNGLong(png_bytep p,png_uint_32 value)
1301 *p++=(png_byte) ((value >> 24) & 0xff);
1302 *p++=(png_byte) ((value >> 16) & 0xff);
1303 *p++=(png_byte) ((value >> 8) & 0xff);
1304 *p++=(png_byte) (value & 0xff);
1307 #if defined(JNG_SUPPORTED)
1308 static void PNGsLong(png_bytep p,png_int_32 value)
1310 *p++=(png_byte) ((value >> 24) & 0xff);
1311 *p++=(png_byte) ((value >> 16) & 0xff);
1312 *p++=(png_byte) ((value >> 8) & 0xff);
1313 *p++=(png_byte) (value & 0xff);
1317 static void PNGShort(png_bytep p,png_uint_16 value)
1319 *p++=(png_byte) ((value >> 8) & 0xff);
1320 *p++=(png_byte) (value & 0xff);
1323 static void PNGType(png_bytep p,png_bytep type)
1325 (void) CopyMagickMemory(p,type,4*sizeof(png_byte));
1328 static void LogPNGChunk(MagickBooleanType logging, png_bytep type,
1331 if (logging != MagickFalse)
1332 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1333 " Writing %c%c%c%c chunk, length: %.20g",
1334 type[0],type[1],type[2],type[3],(double) length);
1336 #endif /* PNG_LIBPNG_VER > 10011 */
1338 #if defined(__cplusplus) || defined(c_plusplus)
1342 #if PNG_LIBPNG_VER > 10011
1344 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1348 % R e a d P N G I m a g e %
1352 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1354 % ReadPNGImage() reads a Portable Network Graphics (PNG) or
1355 % Multiple-image Network Graphics (MNG) image file and returns it. It
1356 % allocates the memory necessary for the new Image structure and returns a
1357 % pointer to the new image or set of images.
1359 % MNG support written by Glenn Randers-Pehrson, glennrp@image...
1361 % The format of the ReadPNGImage method is:
1363 % Image *ReadPNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
1365 % A description of each parameter follows:
1367 % o image_info: the image info.
1369 % o exception: return any errors or warnings in this structure.
1371 % To do, more or less in chronological order (as of version 5.5.2,
1372 % November 26, 2002 -- glennrp -- see also "To do" under WriteMNGImage):
1374 % Get 16-bit cheap transparency working.
1376 % (At this point, PNG decoding is supposed to be in full MNG-LC compliance)
1378 % Preserve all unknown and not-yet-handled known chunks found in input
1379 % PNG file and copy them into output PNG files according to the PNG
1382 % (At this point, PNG encoding should be in full MNG compliance)
1384 % Provide options for choice of background to use when the MNG BACK
1385 % chunk is not present or is not mandatory (i.e., leave transparent,
1386 % user specified, MNG BACK, PNG bKGD)
1388 % Implement LOOP/ENDL [done, but could do discretionary loops more
1389 % efficiently by linking in the duplicate frames.].
1391 % Decode and act on the MHDR simplicity profile (offer option to reject
1392 % files or attempt to process them anyway when the profile isn't LC or VLC).
1394 % Upgrade to full MNG without Delta-PNG.
1396 % o BACK [done a while ago except for background image ID]
1397 % o MOVE [done 15 May 1999]
1398 % o CLIP [done 15 May 1999]
1399 % o DISC [done 19 May 1999]
1400 % o SAVE [partially done 19 May 1999 (marks objects frozen)]
1401 % o SEEK [partially done 19 May 1999 (discard function only)]
1405 % o MNG-level tEXt/iTXt/zTXt
1410 % o iTXt (wait for libpng implementation).
1412 % Use the scene signature to discover when an identical scene is
1413 % being reused, and just point to the original image->exception instead
1414 % of storing another set of pixels. This not specific to MNG
1415 % but could be applied generally.
1417 % Upgrade to full MNG with Delta-PNG.
1419 % JNG tEXt/iTXt/zTXt
1421 % We will not attempt to read files containing the CgBI chunk.
1422 % They are really Xcode files meant for display on the iPhone.
1423 % These are not valid PNG files and it is impossible to recover
1424 % the original PNG from files that have been converted to Xcode-PNG,
1425 % since irretrievable loss of color data has occurred due to the
1426 % use of premultiplied alpha.
1429 #if defined(__cplusplus) || defined(c_plusplus)
1434 This the function that does the actual reading of data. It is
1435 the same as the one supplied in libpng, except that it receives the
1436 datastream from the ReadBlob() function instead of standard input.
1438 static void png_get_data(png_structp png_ptr,png_bytep data,png_size_t length)
1443 image=(Image *) png_get_io_ptr(png_ptr);
1449 check=(png_size_t) ReadBlob(image,(size_t) length,data);
1450 if (check != length)
1455 (void) FormatLocaleString(msg,MaxTextExtent,
1456 "Expected %.20g bytes; found %.20g bytes",(double) length,
1458 png_warning(png_ptr,msg);
1459 png_error(png_ptr,"Read Exception");
1464 #if !defined(PNG_READ_EMPTY_PLTE_SUPPORTED) && \
1465 !defined(PNG_MNG_FEATURES_SUPPORTED)
1466 /* We use mng_get_data() instead of png_get_data() if we have a libpng
1467 * older than libpng-1.0.3a, which was the first to allow the empty
1468 * PLTE, or a newer libpng in which PNG_MNG_FEATURES_SUPPORTED was
1469 * ifdef'ed out. Earlier versions would crash if the bKGD chunk was
1470 * encountered after an empty PLTE, so we have to look ahead for bKGD
1471 * chunks and remove them from the datastream that is passed to libpng,
1472 * and store their contents for later use.
1474 static void mng_get_data(png_structp png_ptr,png_bytep data,png_size_t length)
1489 mng_info=(MngInfo *) png_get_io_ptr(png_ptr);
1490 image=(Image *) mng_info->image;
1491 while (mng_info->bytes_in_read_buffer && length)
1493 data[i]=mng_info->read_buffer[i];
1494 mng_info->bytes_in_read_buffer--;
1500 check=(png_size_t) ReadBlob(image,(size_t) length,(char *) data);
1502 if (check != length)
1503 png_error(png_ptr,"Read Exception");
1507 if ((data[0] == 0) && (data[1] == 0) && (data[2] == 0) &&
1510 check=(png_size_t) ReadBlob(image,(size_t) length,
1511 (char *) mng_info->read_buffer);
1512 mng_info->read_buffer[4]=0;
1513 mng_info->bytes_in_read_buffer=4;
1514 if (memcmp(mng_info->read_buffer,mng_PLTE,4) == 0)
1515 mng_info->found_empty_plte=MagickTrue;
1516 if (memcmp(mng_info->read_buffer,mng_IEND,4) == 0)
1518 mng_info->found_empty_plte=MagickFalse;
1519 mng_info->have_saved_bkgd_index=MagickFalse;
1523 if ((data[0] == 0) && (data[1] == 0) && (data[2] == 0) &&
1526 check=(png_size_t) ReadBlob(image,(size_t) length,
1527 (char *) mng_info->read_buffer);
1528 mng_info->read_buffer[4]=0;
1529 mng_info->bytes_in_read_buffer=4;
1530 if (memcmp(mng_info->read_buffer,mng_bKGD,4) == 0)
1531 if (mng_info->found_empty_plte)
1534 Skip the bKGD data byte and CRC.
1537 ReadBlob(image,5,(char *) mng_info->read_buffer);
1538 check=(png_size_t) ReadBlob(image,(size_t) length,
1539 (char *) mng_info->read_buffer);
1540 mng_info->saved_bkgd_index=mng_info->read_buffer[0];
1541 mng_info->have_saved_bkgd_index=MagickTrue;
1542 mng_info->bytes_in_read_buffer=0;
1550 static void png_put_data(png_structp png_ptr,png_bytep data,png_size_t length)
1555 image=(Image *) png_get_io_ptr(png_ptr);
1561 check=(png_size_t) WriteBlob(image,(size_t) length,data);
1563 if (check != length)
1564 png_error(png_ptr,"WriteBlob Failed");
1568 static void png_flush_data(png_structp png_ptr)
1573 #ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
1574 static int PalettesAreEqual(Image *a,Image *b)
1579 if ((a == (Image *) NULL) || (b == (Image *) NULL))
1580 return((int) MagickFalse);
1582 if (a->storage_class != PseudoClass || b->storage_class != PseudoClass)
1583 return((int) MagickFalse);
1585 if (a->colors != b->colors)
1586 return((int) MagickFalse);
1588 for (i=0; i < (ssize_t) a->colors; i++)
1590 if ((a->colormap[i].red != b->colormap[i].red) ||
1591 (a->colormap[i].green != b->colormap[i].green) ||
1592 (a->colormap[i].blue != b->colormap[i].blue))
1593 return((int) MagickFalse);
1596 return((int) MagickTrue);
1600 static void MngInfoDiscardObject(MngInfo *mng_info,int i)
1602 if (i && (i < MNG_MAX_OBJECTS) && (mng_info != (MngInfo *) NULL) &&
1603 mng_info->exists[i] && !mng_info->frozen[i])
1605 #ifdef MNG_OBJECT_BUFFERS
1606 if (mng_info->ob[i] != (MngBuffer *) NULL)
1608 if (mng_info->ob[i]->reference_count > 0)
1609 mng_info->ob[i]->reference_count--;
1611 if (mng_info->ob[i]->reference_count == 0)
1613 if (mng_info->ob[i]->image != (Image *) NULL)
1614 mng_info->ob[i]->image=DestroyImage(mng_info->ob[i]->image);
1616 mng_info->ob[i]=DestroyString(mng_info->ob[i]);
1619 mng_info->ob[i]=(MngBuffer *) NULL;
1621 mng_info->exists[i]=MagickFalse;
1622 mng_info->invisible[i]=MagickFalse;
1623 mng_info->viewable[i]=MagickFalse;
1624 mng_info->frozen[i]=MagickFalse;
1625 mng_info->x_off[i]=0;
1626 mng_info->y_off[i]=0;
1627 mng_info->object_clip[i].left=0;
1628 mng_info->object_clip[i].right=(ssize_t) PNG_UINT_31_MAX;
1629 mng_info->object_clip[i].top=0;
1630 mng_info->object_clip[i].bottom=(ssize_t) PNG_UINT_31_MAX;
1634 static void MngInfoFreeStruct(MngInfo *mng_info,
1635 MagickBooleanType *have_mng_structure)
1637 if (*have_mng_structure != MagickFalse && (mng_info != (MngInfo *) NULL))
1642 for (i=1; i < MNG_MAX_OBJECTS; i++)
1643 MngInfoDiscardObject(mng_info,i);
1645 if (mng_info->global_plte != (png_colorp) NULL)
1646 mng_info->global_plte=(png_colorp)
1647 RelinquishMagickMemory(mng_info->global_plte);
1649 mng_info=(MngInfo *) RelinquishMagickMemory(mng_info);
1650 *have_mng_structure=MagickFalse;
1654 static MngBox mng_minimum_box(MngBox box1,MngBox box2)
1660 if (box.left < box2.left)
1663 if (box.top < box2.top)
1666 if (box.right > box2.right)
1667 box.right=box2.right;
1669 if (box.bottom > box2.bottom)
1670 box.bottom=box2.bottom;
1675 static MngBox mng_read_box(MngBox previous_box,char delta_type,unsigned char *p)
1681 Read clipping boundaries from DEFI, CLIP, FRAM, or PAST chunk.
1683 box.left=(ssize_t) ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]);
1684 box.right=(ssize_t) ((p[4] << 24) | (p[5] << 16) | (p[6] << 8) | p[7]);
1685 box.top=(ssize_t) ((p[8] << 24) | (p[9] << 16) | (p[10] << 8) | p[11]);
1686 box.bottom=(ssize_t) ((p[12] << 24) | (p[13] << 16) | (p[14] << 8) | p[15]);
1687 if (delta_type != 0)
1689 box.left+=previous_box.left;
1690 box.right+=previous_box.right;
1691 box.top+=previous_box.top;
1692 box.bottom+=previous_box.bottom;
1698 static MngPair mng_read_pair(MngPair previous_pair,int delta_type,
1704 Read two ssize_ts from CLON, MOVE or PAST chunk
1706 pair.a=(long) ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]);
1707 pair.b=(long) ((p[4] << 24) | (p[5] << 16) | (p[6] << 8) | p[7]);
1709 if (delta_type != 0)
1711 pair.a+=previous_pair.a;
1712 pair.b+=previous_pair.b;
1718 static long mng_get_long(unsigned char *p)
1720 return((long) ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]));
1723 typedef struct _PNGErrorInfo
1732 static void MagickPNGErrorHandler(png_struct *ping,png_const_charp message)
1743 error_info=(PNGErrorInfo *) png_get_error_ptr(ping);
1744 image=error_info->image;
1745 exception=error_info->exception;
1747 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1748 " libpng-%s error: %s", PNG_LIBPNG_VER_STRING,message);
1750 (void) ThrowMagickException(exception,GetMagickModule(),CoderError,message,
1751 "`%s'",image->filename);
1753 #if (PNG_LIBPNG_VER < 10500)
1754 /* A warning about deprecated use of jmpbuf here is unavoidable if you
1755 * are building with libpng-1.4.x and can be ignored.
1757 longjmp(ping->jmpbuf,1);
1759 png_longjmp(ping,1);
1763 static void MagickPNGWarningHandler(png_struct *ping,png_const_charp message)
1774 if (LocaleCompare(message, "Missing PLTE before tRNS") == 0)
1775 png_error(ping, message);
1777 error_info=(PNGErrorInfo *) png_get_error_ptr(ping);
1778 image=error_info->image;
1779 exception=error_info->exception;
1780 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1781 " libpng-%s warning: %s", PNG_LIBPNG_VER_STRING,message);
1783 (void) ThrowMagickException(exception,GetMagickModule(),CoderWarning,
1784 message,"`%s'",image->filename);
1787 #ifdef PNG_USER_MEM_SUPPORTED
1788 static png_voidp Magick_png_malloc(png_structp png_ptr,png_uint_32 size)
1790 #if (PNG_LIBPNG_VER < 10011)
1795 ret=((png_voidp) AcquireMagickMemory((size_t) size));
1798 png_error("Insufficient memory.");
1803 return((png_voidp) AcquireMagickMemory((size_t) size));
1808 Free a pointer. It is removed from the list at the same time.
1810 static png_free_ptr Magick_png_free(png_structp png_ptr,png_voidp ptr)
1813 ptr=RelinquishMagickMemory(ptr);
1814 return((png_free_ptr) NULL);
1818 #if defined(__cplusplus) || defined(c_plusplus)
1823 Magick_png_read_raw_profile(Image *image, const ImageInfo *image_info,
1824 png_textp text,int ii,ExceptionInfo *exception)
1829 register unsigned char
1843 unhex[103]={0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,
1844 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,
1845 0,0,0,0,0,0,0,0,0,1, 2,3,4,5,6,7,8,9,0,0,
1846 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,
1847 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,10,11,12,
1851 /* look for newline */
1855 /* look for length */
1856 while (*sp == '\0' || *sp == ' ' || *sp == '\n')
1859 length=(png_uint_32) StringToLong(sp);
1861 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1862 " length: %lu",(unsigned long) length);
1864 while (*sp != ' ' && *sp != '\n')
1867 /* allocate space */
1870 (void) ThrowMagickException(exception,GetMagickModule(),
1871 CoderWarning,"UnableToCopyProfile","`%s'","invalid profile length");
1872 return(MagickFalse);
1875 profile=BlobToStringInfo((const void *) NULL,length);
1877 if (profile == (StringInfo *) NULL)
1879 (void) ThrowMagickException(exception,GetMagickModule(),
1880 ResourceLimitError,"MemoryAllocationFailed","`%s'",
1881 "unable to copy profile");
1882 return(MagickFalse);
1885 /* copy profile, skipping white space and column 1 "=" signs */
1886 dp=GetStringInfoDatum(profile);
1889 for (i=0; i < (ssize_t) nibbles; i++)
1891 while (*sp < '0' || (*sp > '9' && *sp < 'a') || *sp > 'f')
1895 (void) ThrowMagickException(exception,GetMagickModule(),
1896 CoderWarning,"UnableToCopyProfile","`%s'","ran out of data");
1897 profile=DestroyStringInfo(profile);
1898 return(MagickFalse);
1904 *dp=(unsigned char) (16*unhex[(int) *sp++]);
1907 (*dp++)+=unhex[(int) *sp++];
1910 We have already read "Raw profile type.
1912 (void) SetImageProfile(image,&text[ii].key[17],profile,exception);
1913 profile=DestroyStringInfo(profile);
1915 if (image_info->verbose)
1916 (void) printf(" Found a generic profile, type %s\n",&text[ii].key[17]);
1921 #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
1922 static int read_vpag_chunk_callback(png_struct *ping, png_unknown_chunkp chunk)
1928 /* The unknown chunk structure contains the chunk data:
1933 Note that libpng has already taken care of the CRC handling.
1937 if (chunk->name[0] != 118 || chunk->name[1] != 112 ||
1938 chunk->name[2] != 65 ||chunk-> name[3] != 103)
1939 return(0); /* Did not recognize */
1941 /* recognized vpAg */
1943 if (chunk->size != 9)
1944 return(-1); /* Error return */
1946 if (chunk->data[8] != 0)
1947 return(0); /* ImageMagick requires pixel units */
1949 image=(Image *) png_get_user_chunk_ptr(ping);
1951 image->page.width=(size_t) ((chunk->data[0] << 24) |
1952 (chunk->data[1] << 16) | (chunk->data[2] << 8) | chunk->data[3]);
1954 image->page.height=(size_t) ((chunk->data[4] << 24) |
1955 (chunk->data[5] << 16) | (chunk->data[6] << 8) | chunk->data[7]);
1957 /* Return one of the following: */
1958 /* return(-n); chunk had an error */
1959 /* return(0); did not recognize */
1960 /* return(n); success */
1968 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1972 % R e a d O n e P N G I m a g e %
1976 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1978 % ReadOnePNGImage() reads a Portable Network Graphics (PNG) image file
1979 % (minus the 8-byte signature) and returns it. It allocates the memory
1980 % necessary for the new Image structure and returns a pointer to the new
1983 % The format of the ReadOnePNGImage method is:
1985 % Image *ReadOnePNGImage(MngInfo *mng_info, const ImageInfo *image_info,
1986 % ExceptionInfo *exception)
1988 % A description of each parameter follows:
1990 % o mng_info: Specifies a pointer to a MngInfo structure.
1992 % o image_info: the image info.
1994 % o exception: return any errors or warnings in this structure.
1997 static Image *ReadOnePNGImage(MngInfo *mng_info,
1998 const ImageInfo *image_info, ExceptionInfo *exception)
2000 /* Read one PNG image */
2002 /* To do: Read the tIME chunk into the date:modify property */
2003 /* To do: Read the tEXt/Creation Time chunk into the date:create property */
2017 ping_interlace_method,
2018 ping_compression_method,
2069 register unsigned char
2086 #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
2087 png_byte unused_chunks[]=
2089 104, 73, 83, 84, (png_byte) '\0', /* hIST */
2090 105, 84, 88, 116, (png_byte) '\0', /* iTXt */
2091 112, 67, 65, 76, (png_byte) '\0', /* pCAL */
2092 115, 67, 65, 76, (png_byte) '\0', /* sCAL */
2093 115, 80, 76, 84, (png_byte) '\0', /* sPLT */
2094 116, 73, 77, 69, (png_byte) '\0', /* tIME */
2098 logging=LogMagickEvent(CoderEvent,GetMagickModule(),
2099 " Enter ReadOnePNGImage()");
2101 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
2102 LockSemaphoreInfo(ping_semaphore);
2105 #if (PNG_LIBPNG_VER < 10200)
2106 if (image_info->verbose)
2107 printf("Your PNG library (libpng-%s) is rather old.\n",
2108 PNG_LIBPNG_VER_STRING);
2111 #if (PNG_LIBPNG_VER >= 10400)
2112 # ifndef PNG_TRANSFORM_GRAY_TO_RGB /* Added at libpng-1.4.0beta67 */
2113 if (image_info->verbose)
2115 printf("Your PNG library (libpng-%s) is an old beta version.\n",
2116 PNG_LIBPNG_VER_STRING);
2117 printf("Please update it.\n");
2123 quantum_info = (QuantumInfo *) NULL;
2124 image=mng_info->image;
2126 if (logging != MagickFalse)
2127 (void)LogMagickEvent(CoderEvent,GetMagickModule(),
2128 " image->matte=%d",(int) image->matte);
2130 /* Set to an out-of-range color unless tRNS chunk is present */
2131 transparent_color.red=65537;
2132 transparent_color.green=65537;
2133 transparent_color.blue=65537;
2134 transparent_color.alpha=65537;
2138 num_raw_profiles = 0;
2141 Allocate the PNG structures
2143 #ifdef PNG_USER_MEM_SUPPORTED
2144 error_info.image=image;
2145 error_info.exception=exception;
2146 ping=png_create_read_struct_2(PNG_LIBPNG_VER_STRING,&error_info,
2147 MagickPNGErrorHandler,MagickPNGWarningHandler, NULL,
2148 (png_malloc_ptr) Magick_png_malloc,(png_free_ptr) Magick_png_free);
2150 ping=png_create_read_struct(PNG_LIBPNG_VER_STRING,&error_info,
2151 MagickPNGErrorHandler,MagickPNGWarningHandler);
2153 if (ping == (png_struct *) NULL)
2154 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2156 ping_info=png_create_info_struct(ping);
2158 if (ping_info == (png_info *) NULL)
2160 png_destroy_read_struct(&ping,(png_info **) NULL,(png_info **) NULL);
2161 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2164 end_info=png_create_info_struct(ping);
2166 if (end_info == (png_info *) NULL)
2168 png_destroy_read_struct(&ping,&ping_info,(png_info **) NULL);
2169 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2172 ping_pixels=(unsigned char *) NULL;
2174 if (setjmp(png_jmpbuf(ping)))
2177 PNG image is corrupt.
2179 png_destroy_read_struct(&ping,&ping_info,&end_info);
2180 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
2181 UnlockSemaphoreInfo(ping_semaphore);
2183 if (logging != MagickFalse)
2184 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2185 " exit ReadOnePNGImage() with error.");
2187 if (image != (Image *) NULL)
2189 InheritException(exception,exception);
2193 return(GetFirstImageInList(image));
2196 Prepare PNG for reading.
2199 mng_info->image_found++;
2200 png_set_sig_bytes(ping,8);
2202 if (LocaleCompare(image_info->magick,"MNG") == 0)
2204 #if defined(PNG_MNG_FEATURES_SUPPORTED)
2205 (void) png_permit_mng_features(ping,PNG_ALL_MNG_FEATURES);
2206 png_set_read_fn(ping,image,png_get_data);
2208 #if defined(PNG_READ_EMPTY_PLTE_SUPPORTED)
2209 png_permit_empty_plte(ping,MagickTrue);
2210 png_set_read_fn(ping,image,png_get_data);
2212 mng_info->image=image;
2213 mng_info->bytes_in_read_buffer=0;
2214 mng_info->found_empty_plte=MagickFalse;
2215 mng_info->have_saved_bkgd_index=MagickFalse;
2216 png_set_read_fn(ping,mng_info,mng_get_data);
2222 png_set_read_fn(ping,image,png_get_data);
2224 #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
2225 /* Ignore unused chunks and all unknown chunks except for vpAg */
2226 png_set_keep_unknown_chunks(ping, 1, NULL, 0);
2227 png_set_keep_unknown_chunks(ping, 2, mng_vpAg, 1);
2228 png_set_keep_unknown_chunks(ping, 1, unused_chunks,
2229 (int)sizeof(unused_chunks)/5);
2230 /* Callback for other unknown chunks */
2231 png_set_read_user_chunk_fn(ping, image, read_vpag_chunk_callback);
2234 #if (PNG_LIBPNG_VER < 10400)
2235 # if defined(PNG_USE_PNGGCCRD) && defined(PNG_ASSEMBLER_CODE_SUPPORTED) && \
2236 (PNG_LIBPNG_VER >= 10200) && (PNG_LIBPNG_VER < 10220) && defined(__i386__)
2237 /* Disable thread-unsafe features of pnggccrd */
2238 if (png_access_version_number() >= 10200)
2240 png_uint_32 mmx_disable_mask=0;
2241 png_uint_32 asm_flags;
2243 mmx_disable_mask |= ( PNG_ASM_FLAG_MMX_READ_COMBINE_ROW \
2244 | PNG_ASM_FLAG_MMX_READ_FILTER_SUB \
2245 | PNG_ASM_FLAG_MMX_READ_FILTER_AVG \
2246 | PNG_ASM_FLAG_MMX_READ_FILTER_PAETH );
2247 asm_flags=png_get_asm_flags(ping);
2248 png_set_asm_flags(ping, asm_flags & ~mmx_disable_mask);
2253 png_read_info(ping,ping_info);
2255 png_get_IHDR(ping,ping_info,&ping_width,&ping_height,
2256 &ping_bit_depth,&ping_color_type,
2257 &ping_interlace_method,&ping_compression_method,
2258 &ping_filter_method);
2260 (void) png_get_tRNS(ping, ping_info, &ping_trans_alpha, &ping_num_trans,
2263 (void) png_get_bKGD(ping, ping_info, &ping_background);
2265 if (ping_bit_depth < 8)
2267 if (((int) ping_color_type == PNG_COLOR_TYPE_PALETTE))
2269 png_set_packing(ping);
2274 image->depth=ping_bit_depth;
2275 image->depth=GetImageQuantumDepth(image,MagickFalse);
2276 image->interlace=ping_interlace_method != 0 ? PNGInterlace : NoInterlace;
2277 if (logging != MagickFalse)
2279 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2280 " PNG width: %.20g, height: %.20g",
2281 (double) ping_width, (double) ping_height);
2283 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2284 " PNG color_type: %d, bit_depth: %d",
2285 ping_color_type, ping_bit_depth);
2287 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2288 " PNG compression_method: %d",
2289 ping_compression_method);
2291 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2292 " PNG interlace_method: %d, filter_method: %d",
2293 ping_interlace_method,ping_filter_method);
2296 #ifdef PNG_READ_iCCP_SUPPORTED
2297 if (png_get_valid(ping,ping_info,PNG_INFO_iCCP))
2302 #if (PNG_LIBPNG_VER < 10500)
2316 (void) png_get_iCCP(ping,ping_info,&name,(int *) &compression,&info,
2319 if (profile_length != 0)
2324 if (logging != MagickFalse)
2325 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2326 " Reading PNG iCCP chunk.");
2327 profile=BlobToStringInfo(info,profile_length);
2328 if (profile == (StringInfo *) NULL)
2330 (void) ThrowMagickException(exception,GetMagickModule(),
2331 ResourceLimitError,"MemoryAllocationFailed","`%s'",
2332 "unable to copy profile");
2333 return((Image *) NULL);
2335 SetStringInfoDatum(profile,(const unsigned char *) info);
2336 (void) SetImageProfile(image,"icc",profile,exception);
2337 profile=DestroyStringInfo(profile);
2341 #if defined(PNG_READ_sRGB_SUPPORTED)
2343 if (mng_info->have_global_srgb)
2344 image->rendering_intent=Magick_RenderingIntent_from_PNG_RenderingIntent
2345 (mng_info->global_srgb_intent);
2347 if (png_get_sRGB(ping,ping_info,&intent))
2349 image->rendering_intent=Magick_RenderingIntent_from_PNG_RenderingIntent
2352 if (logging != MagickFalse)
2353 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2354 " Reading PNG sRGB chunk: rendering_intent: %d",intent);
2359 if (!png_get_gAMA(ping,ping_info,&file_gamma))
2360 if (mng_info->have_global_gama)
2361 png_set_gAMA(ping,ping_info,mng_info->global_gamma);
2363 if (png_get_gAMA(ping,ping_info,&file_gamma))
2365 image->gamma=(float) file_gamma;
2366 if (logging != MagickFalse)
2367 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2368 " Reading PNG gAMA chunk: gamma: %f",file_gamma);
2371 if (!png_get_valid(ping,ping_info,PNG_INFO_cHRM))
2373 if (mng_info->have_global_chrm != MagickFalse)
2375 (void) png_set_cHRM(ping,ping_info,
2376 mng_info->global_chrm.white_point.x,
2377 mng_info->global_chrm.white_point.y,
2378 mng_info->global_chrm.red_primary.x,
2379 mng_info->global_chrm.red_primary.y,
2380 mng_info->global_chrm.green_primary.x,
2381 mng_info->global_chrm.green_primary.y,
2382 mng_info->global_chrm.blue_primary.x,
2383 mng_info->global_chrm.blue_primary.y);
2387 if (png_get_valid(ping,ping_info,PNG_INFO_cHRM))
2389 (void) png_get_cHRM(ping,ping_info,
2390 &image->chromaticity.white_point.x,
2391 &image->chromaticity.white_point.y,
2392 &image->chromaticity.red_primary.x,
2393 &image->chromaticity.red_primary.y,
2394 &image->chromaticity.green_primary.x,
2395 &image->chromaticity.green_primary.y,
2396 &image->chromaticity.blue_primary.x,
2397 &image->chromaticity.blue_primary.y);
2399 if (logging != MagickFalse)
2400 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2401 " Reading PNG cHRM chunk.");
2404 if (image->rendering_intent != UndefinedIntent)
2406 png_set_sRGB(ping,ping_info,
2407 Magick_RenderingIntent_to_PNG_RenderingIntent
2408 (image->rendering_intent));
2409 png_set_gAMA(ping,ping_info,0.45455f);
2410 png_set_cHRM(ping,ping_info,
2411 0.6400f, 0.3300f, 0.3000f, 0.6000f,
2412 0.1500f, 0.0600f, 0.3127f, 0.3290f);
2414 #if defined(PNG_oFFs_SUPPORTED)
2415 if (png_get_valid(ping,ping_info,PNG_INFO_oFFs))
2417 image->page.x=(ssize_t) png_get_x_offset_pixels(ping, ping_info);
2418 image->page.y=(ssize_t) png_get_y_offset_pixels(ping, ping_info);
2420 if (logging != MagickFalse)
2421 if (image->page.x || image->page.y)
2422 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2423 " Reading PNG oFFs chunk: x: %.20g, y: %.20g.",(double)
2424 image->page.x,(double) image->page.y);
2427 #if defined(PNG_pHYs_SUPPORTED)
2428 if (!png_get_valid(ping,ping_info,PNG_INFO_pHYs))
2430 if (mng_info->have_global_phys)
2432 png_set_pHYs(ping,ping_info,
2433 mng_info->global_x_pixels_per_unit,
2434 mng_info->global_y_pixels_per_unit,
2435 mng_info->global_phys_unit_type);
2439 if (png_get_valid(ping,ping_info,PNG_INFO_pHYs))
2442 Set image resolution.
2444 (void) png_get_pHYs(ping,ping_info,&x_resolution,&y_resolution,
2446 image->x_resolution=(double) x_resolution;
2447 image->y_resolution=(double) y_resolution;
2449 if (unit_type == PNG_RESOLUTION_METER)
2451 image->units=PixelsPerCentimeterResolution;
2452 image->x_resolution=(double) x_resolution/100.0;
2453 image->y_resolution=(double) y_resolution/100.0;
2456 if (logging != MagickFalse)
2457 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2458 " Reading PNG pHYs chunk: xres: %.20g, yres: %.20g, units: %d.",
2459 (double) x_resolution,(double) y_resolution,unit_type);
2463 if (png_get_valid(ping,ping_info,PNG_INFO_PLTE))
2471 (void) png_get_PLTE(ping,ping_info,&palette,&number_colors);
2473 if ((number_colors == 0) &&
2474 ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE))
2476 if (mng_info->global_plte_length)
2478 png_set_PLTE(ping,ping_info,mng_info->global_plte,
2479 (int) mng_info->global_plte_length);
2481 if (!png_get_valid(ping,ping_info,PNG_INFO_tRNS))
2482 if (mng_info->global_trns_length)
2484 if (mng_info->global_trns_length >
2485 mng_info->global_plte_length)
2486 (void) ThrowMagickException(exception,
2487 GetMagickModule(),CoderError,
2488 "global tRNS has more entries than global PLTE",
2489 "`%s'",image_info->filename);
2490 png_set_tRNS(ping,ping_info,mng_info->global_trns,
2491 (int) mng_info->global_trns_length,NULL);
2493 #ifdef PNG_READ_bKGD_SUPPORTED
2495 #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
2496 mng_info->have_saved_bkgd_index ||
2498 png_get_valid(ping,ping_info,PNG_INFO_bKGD))
2503 #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
2504 if (mng_info->have_saved_bkgd_index)
2505 background.index=mng_info->saved_bkgd_index;
2507 if (png_get_valid(ping, ping_info, PNG_INFO_bKGD))
2508 background.index=ping_background->index;
2510 background.red=(png_uint_16)
2511 mng_info->global_plte[background.index].red;
2513 background.green=(png_uint_16)
2514 mng_info->global_plte[background.index].green;
2516 background.blue=(png_uint_16)
2517 mng_info->global_plte[background.index].blue;
2519 background.gray=(png_uint_16)
2520 mng_info->global_plte[background.index].green;
2522 png_set_bKGD(ping,ping_info,&background);
2527 (void) ThrowMagickException(exception,GetMagickModule(),
2528 CoderError,"No global PLTE in file","`%s'",
2529 image_info->filename);
2533 #ifdef PNG_READ_bKGD_SUPPORTED
2534 if (mng_info->have_global_bkgd &&
2535 (!png_get_valid(ping,ping_info,PNG_INFO_bKGD)))
2536 image->background_color=mng_info->mng_global_bkgd;
2538 if (png_get_valid(ping,ping_info,PNG_INFO_bKGD))
2544 Set image background color.
2546 if (logging != MagickFalse)
2547 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2548 " Reading PNG bKGD chunk.");
2550 /* Scale background components to 16-bit, then scale
2553 if (logging != MagickFalse)
2554 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2555 " raw ping_background=(%d,%d,%d).",ping_background->red,
2556 ping_background->green,ping_background->blue);
2560 if (ping_bit_depth == 1)
2563 else if (ping_bit_depth == 2)
2566 else if (ping_bit_depth == 4)
2569 if (ping_bit_depth <= 8)
2572 ping_background->red *= bkgd_scale;
2573 ping_background->green *= bkgd_scale;
2574 ping_background->blue *= bkgd_scale;
2576 if (logging != MagickFalse)
2578 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2579 " bkgd_scale=%d.",bkgd_scale);
2581 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2582 " ping_background=(%d,%d,%d).",ping_background->red,
2583 ping_background->green,ping_background->blue);
2586 image->background_color.red=
2587 ScaleShortToQuantum(ping_background->red);
2589 image->background_color.green=
2590 ScaleShortToQuantum(ping_background->green);
2592 image->background_color.blue=
2593 ScaleShortToQuantum(ping_background->blue);
2595 image->background_color.alpha=OpaqueAlpha;
2597 if (logging != MagickFalse)
2598 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2599 " image->background_color=(%.20g,%.20g,%.20g).",
2600 (double) image->background_color.red,
2601 (double) image->background_color.green,
2602 (double) image->background_color.blue);
2604 #endif /* PNG_READ_bKGD_SUPPORTED */
2606 if (png_get_valid(ping,ping_info,PNG_INFO_tRNS))
2609 Image has a tRNS chunk.
2617 if (logging != MagickFalse)
2618 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2619 " Reading PNG tRNS chunk.");
2621 max_sample = (int) ((one << ping_bit_depth) - 1);
2623 if ((ping_color_type == PNG_COLOR_TYPE_GRAY &&
2624 (int)ping_trans_color->gray > max_sample) ||
2625 (ping_color_type == PNG_COLOR_TYPE_RGB &&
2626 ((int)ping_trans_color->red > max_sample ||
2627 (int)ping_trans_color->green > max_sample ||
2628 (int)ping_trans_color->blue > max_sample)))
2630 if (logging != MagickFalse)
2631 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2632 " Ignoring PNG tRNS chunk with out-of-range sample.");
2633 png_free_data(ping, ping_info, PNG_FREE_TRNS, 0);
2634 png_set_invalid(ping,ping_info,PNG_INFO_tRNS);
2635 image->matte=MagickFalse;
2642 scale_to_short = 65535L/((1UL << ping_bit_depth)-1);
2644 /* Scale transparent_color to short */
2645 transparent_color.red= scale_to_short*ping_trans_color->red;
2646 transparent_color.green= scale_to_short*ping_trans_color->green;
2647 transparent_color.blue= scale_to_short*ping_trans_color->blue;
2648 transparent_color.alpha= scale_to_short*ping_trans_color->gray;
2650 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
2652 if (logging != MagickFalse)
2654 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2655 " Raw tRNS graylevel is %d.",ping_trans_color->gray);
2657 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2658 " scaled graylevel is %.20g.",transparent_color.alpha);
2660 transparent_color.red=transparent_color.alpha;
2661 transparent_color.green=transparent_color.alpha;
2662 transparent_color.blue=transparent_color.alpha;
2666 #if defined(PNG_READ_sBIT_SUPPORTED)
2667 if (mng_info->have_global_sbit)
2669 if (!png_get_valid(ping,ping_info,PNG_INFO_sBIT))
2670 png_set_sBIT(ping,ping_info,&mng_info->global_sbit);
2673 num_passes=png_set_interlace_handling(ping);
2675 png_read_update_info(ping,ping_info);
2677 ping_rowbytes=png_get_rowbytes(ping,ping_info);
2680 Initialize image structure.
2682 mng_info->image_box.left=0;
2683 mng_info->image_box.right=(ssize_t) ping_width;
2684 mng_info->image_box.top=0;
2685 mng_info->image_box.bottom=(ssize_t) ping_height;
2686 if (mng_info->mng_type == 0)
2688 mng_info->mng_width=ping_width;
2689 mng_info->mng_height=ping_height;
2690 mng_info->frame=mng_info->image_box;
2691 mng_info->clip=mng_info->image_box;
2696 image->page.y=mng_info->y_off[mng_info->object_id];
2699 image->compression=ZipCompression;
2700 image->columns=ping_width;
2701 image->rows=ping_height;
2702 if (((int) ping_color_type == PNG_COLOR_TYPE_PALETTE) ||
2703 ((int) ping_color_type == PNG_COLOR_TYPE_GRAY))
2708 image->storage_class=PseudoClass;
2710 image->colors=one << ping_bit_depth;
2711 #if (MAGICKCORE_QUANTUM_DEPTH == 8)
2712 if (image->colors > 256)
2715 if (image->colors > 65536L)
2716 image->colors=65536L;
2718 if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
2726 (void) png_get_PLTE(ping,ping_info,&palette,&number_colors);
2727 image->colors=(size_t) number_colors;
2729 if (logging != MagickFalse)
2730 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2731 " Reading PNG PLTE chunk: number_colors: %d.",number_colors);
2735 if (image->storage_class == PseudoClass)
2738 Initialize image colormap.
2740 if (AcquireImageColormap(image,image->colors,exception) == MagickFalse)
2741 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2743 if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
2751 (void) png_get_PLTE(ping,ping_info,&palette,&number_colors);
2753 for (i=0; i < (ssize_t) number_colors; i++)
2755 image->colormap[i].red=ScaleCharToQuantum(palette[i].red);
2756 image->colormap[i].green=ScaleCharToQuantum(palette[i].green);
2757 image->colormap[i].blue=ScaleCharToQuantum(palette[i].blue);
2760 for ( ; i < (ssize_t) image->colors; i++)
2762 image->colormap[i].red=0;
2763 image->colormap[i].green=0;
2764 image->colormap[i].blue=0;
2773 scale=(QuantumRange/((1UL << ping_bit_depth)-1));
2778 for (i=0; i < (ssize_t) image->colors; i++)
2780 image->colormap[i].red=(Quantum) (i*scale);
2781 image->colormap[i].green=(Quantum) (i*scale);
2782 image->colormap[i].blue=(Quantum) (i*scale);
2787 /* Set some properties for reporting by "identify" */
2792 /* encode ping_width, ping_height, ping_bit_depth, ping_color_type,
2793 ping_interlace_method in value */
2795 (void) FormatLocaleString(msg,MaxTextExtent,
2796 "%d, %d",(int) ping_width, (int) ping_height);
2797 (void) SetImageProperty(image,"PNG:IHDR.width,height ",msg,exception);
2799 (void) FormatLocaleString(msg,MaxTextExtent,"%d",(int) ping_bit_depth);
2800 (void) SetImageProperty(image,"PNG:IHDR.bit_depth ",msg,exception);
2802 (void) FormatLocaleString(msg,MaxTextExtent,"%d",(int) ping_color_type);
2803 (void) SetImageProperty(image,"PNG:IHDR.color_type ",msg,exception);
2805 (void) FormatLocaleString(msg,MaxTextExtent,"%d",
2806 (int) ping_interlace_method);
2807 (void) SetImageProperty(image,"PNG:IHDR.interlace_method",msg,exception);
2811 Read image scanlines.
2813 if (image->delay != 0)
2814 mng_info->scenes_found++;
2816 if ((mng_info->mng_type == 0 && (image->ping != MagickFalse)) || (
2817 (image_info->number_scenes != 0) && (mng_info->scenes_found > (ssize_t)
2818 (image_info->first_scene+image_info->number_scenes))))
2820 if (logging != MagickFalse)
2821 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2822 " Skipping PNG image data for scene %.20g",(double)
2823 mng_info->scenes_found-1);
2824 png_destroy_read_struct(&ping,&ping_info,&end_info);
2825 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
2826 UnlockSemaphoreInfo(ping_semaphore);
2828 if (logging != MagickFalse)
2829 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2830 " exit ReadOnePNGImage().");
2835 if (logging != MagickFalse)
2836 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2837 " Reading PNG IDAT chunk(s)");
2840 ping_pixels=(unsigned char *) AcquireQuantumMemory(image->rows,
2841 ping_rowbytes*sizeof(*ping_pixels));
2844 ping_pixels=(unsigned char *) AcquireQuantumMemory(ping_rowbytes,
2845 sizeof(*ping_pixels));
2847 if (ping_pixels == (unsigned char *) NULL)
2848 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2850 if (logging != MagickFalse)
2851 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2852 " Converting PNG pixels to pixel packets");
2854 Convert PNG pixels to pixel packets.
2856 if (setjmp(png_jmpbuf(ping)))
2859 PNG image is corrupt.
2861 png_destroy_read_struct(&ping,&ping_info,&end_info);
2862 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
2863 UnlockSemaphoreInfo(ping_semaphore);
2865 if (quantum_info != (QuantumInfo *) NULL)
2866 quantum_info = DestroyQuantumInfo(quantum_info);
2868 if (ping_pixels != (unsigned char *) NULL)
2869 ping_pixels=(unsigned char *) RelinquishMagickMemory(ping_pixels);
2871 if (logging != MagickFalse)
2872 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2873 " exit ReadOnePNGImage() with error.");
2875 if (image != (Image *) NULL)
2877 InheritException(exception,exception);
2881 return(GetFirstImageInList(image));
2884 quantum_info=AcquireQuantumInfo(image_info,image);
2886 if (quantum_info == (QuantumInfo *) NULL)
2887 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2892 found_transparent_pixel;
2894 found_transparent_pixel=MagickFalse;
2896 if (image->storage_class == DirectClass)
2898 for (pass=0; pass < num_passes; pass++)
2901 Convert image to DirectClass pixel packets.
2903 #if (MAGICKCORE_QUANTUM_DEPTH == 8)
2907 depth=(ssize_t) ping_bit_depth;
2909 image->matte=(((int) ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA) ||
2910 ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) ||
2911 (png_get_valid(ping,ping_info,PNG_INFO_tRNS))) ?
2912 MagickTrue : MagickFalse;
2914 for (y=0; y < (ssize_t) image->rows; y++)
2917 row_offset=ping_rowbytes*y;
2922 png_read_row(ping,ping_pixels+row_offset,NULL);
2923 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
2925 if (q == (Quantum *) NULL)
2928 if ((int) ping_color_type == PNG_COLOR_TYPE_GRAY)
2929 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
2930 GrayQuantum,ping_pixels+row_offset,exception);
2932 else if ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
2933 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
2934 GrayAlphaQuantum,ping_pixels+row_offset,exception);
2936 else if ((int) ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA)
2937 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
2938 RGBAQuantum,ping_pixels+row_offset,exception);
2940 else if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
2941 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
2942 IndexQuantum,ping_pixels+row_offset,exception);
2944 else /* ping_color_type == PNG_COLOR_TYPE_RGB */
2945 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
2946 RGBQuantum,ping_pixels+row_offset,exception);
2948 if (found_transparent_pixel == MagickFalse)
2950 /* Is there a transparent pixel in the row? */
2951 if (y== 0 && logging != MagickFalse)
2952 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2953 " Looking for cheap transparent pixel");
2955 for (x=(ssize_t) image->columns-1; x >= 0; x--)
2957 if ((ping_color_type == PNG_COLOR_TYPE_RGBA ||
2958 ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) &&
2959 (GetPixelAlpha(image,q) != OpaqueAlpha))
2961 if (logging != MagickFalse)
2962 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2965 found_transparent_pixel = MagickTrue;
2968 if ((ping_color_type == PNG_COLOR_TYPE_RGB ||
2969 ping_color_type == PNG_COLOR_TYPE_GRAY) &&
2970 (ScaleQuantumToShort(GetPixelRed(image,q)) ==
2971 transparent_color.red &&
2972 ScaleQuantumToShort(GetPixelGreen(image,q)) ==
2973 transparent_color.green &&
2974 ScaleQuantumToShort(GetPixelBlue(image,q)) ==
2975 transparent_color.blue))
2977 if (logging != MagickFalse)
2978 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2980 found_transparent_pixel = MagickTrue;
2983 q+=GetPixelChannels(image);
2987 if ((image->previous == (Image *) NULL) && (num_passes == 1))
2989 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
2992 if (status == MagickFalse)
2995 if (SyncAuthenticPixels(image,exception) == MagickFalse)
2999 if ((image->previous == (Image *) NULL) && (num_passes != 1))
3001 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
3002 if (status == MagickFalse)
3008 else /* image->storage_class != DirectClass */
3010 for (pass=0; pass < num_passes; pass++)
3019 Convert grayscale image to PseudoClass pixel packets.
3021 if (logging != MagickFalse)
3022 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3023 " Converting grayscale pixels to pixel packets");
3025 image->matte=ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA ?
3026 MagickTrue : MagickFalse;
3028 quantum_scanline=(Quantum *) AcquireQuantumMemory(image->columns,
3029 (image->matte ? 2 : 1)*sizeof(*quantum_scanline));
3031 if (quantum_scanline == (Quantum *) NULL)
3032 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
3034 for (y=0; y < (ssize_t) image->rows; y++)
3037 row_offset=ping_rowbytes*y;
3042 png_read_row(ping,ping_pixels+row_offset,NULL);
3043 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
3045 if (q == (Quantum *) NULL)
3048 p=ping_pixels+row_offset;
3051 switch (ping_bit_depth)
3058 for (x=(ssize_t) image->columns-7; x > 0; x-=8)
3060 for (bit=7; bit >= 0; bit--)
3061 *r++=(Quantum) ((*p) & (0x01 << bit) ? 0x01 : 0x00);
3065 if ((image->columns % 8) != 0)
3067 for (bit=7; bit >= (ssize_t) (8-(image->columns % 8)); bit--)
3068 *r++=(Quantum) ((*p) & (0x01 << bit) ? 0x01 : 0x00);
3076 for (x=(ssize_t) image->columns-3; x > 0; x-=4)
3078 *r++=(*p >> 6) & 0x03;
3079 *r++=(*p >> 4) & 0x03;
3080 *r++=(*p >> 2) & 0x03;
3084 if ((image->columns % 4) != 0)
3086 for (i=3; i >= (ssize_t) (4-(image->columns % 4)); i--)
3087 *r++=(Quantum) ((*p >> (i*2)) & 0x03);
3095 for (x=(ssize_t) image->columns-1; x > 0; x-=2)
3097 *r++=(*p >> 4) & 0x0f;
3101 if ((image->columns % 2) != 0)
3102 *r++=(*p++ >> 4) & 0x0f;
3109 if (ping_color_type == 4)
3110 for (x=(ssize_t) image->columns-1; x >= 0; x--)
3113 SetPixelAlpha(image,ScaleCharToQuantum((unsigned char) *p++),q);
3114 if (GetPixelAlpha(image,q) != OpaqueAlpha)
3115 found_transparent_pixel = MagickTrue;
3116 q+=GetPixelChannels(image);
3120 for (x=(ssize_t) image->columns-1; x >= 0; x--)
3128 for (x=(ssize_t) image->columns-1; x >= 0; x--)
3130 #if (MAGICKCORE_QUANTUM_DEPTH == 16) || (MAGICKCORE_QUANTUM_DEPTH == 32)
3134 if (image->colors > 256)
3135 quantum=((*p++) << 8);
3141 *r=ScaleShortToQuantum(quantum);
3144 if (ping_color_type == 4)
3146 if (image->colors > 256)
3147 quantum=((*p++) << 8);
3152 SetPixelAlpha(image,ScaleShortToQuantum(quantum),q);
3153 if (GetPixelAlpha(image,q) != OpaqueAlpha)
3154 found_transparent_pixel = MagickTrue;
3155 q+=GetPixelChannels(image);
3158 #else /* MAGICKCORE_QUANTUM_DEPTH == 8 */
3160 p++; /* strip low byte */
3162 if (ping_color_type == 4)
3164 SetPixelAlpha(image,*p++,q);
3165 if (GetPixelAlpha(image,q) != OpaqueAlpha)
3166 found_transparent_pixel = MagickTrue;
3168 q+=GetPixelChannels(image);
3181 Transfer image scanline.
3185 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
3187 if (q == (Quantum *) NULL)
3189 for (x=0; x < (ssize_t) image->columns; x++)
3191 SetPixelIndex(image,*r++,q);
3192 q+=GetPixelChannels(image);
3195 if (SyncAuthenticPixels(image,exception) == MagickFalse)
3198 if ((image->previous == (Image *) NULL) && (num_passes == 1))
3200 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
3203 if (status == MagickFalse)
3208 if ((image->previous == (Image *) NULL) && (num_passes != 1))
3210 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
3212 if (status == MagickFalse)
3216 quantum_scanline=(Quantum *) RelinquishMagickMemory(quantum_scanline);
3219 image->matte=found_transparent_pixel;
3221 if (logging != MagickFalse)
3223 if (found_transparent_pixel != MagickFalse)
3224 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3225 " Found transparent pixel");
3228 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3229 " No transparent pixel was found");
3231 ping_color_type&=0x03;
3236 if (quantum_info != (QuantumInfo *) NULL)
3237 quantum_info=DestroyQuantumInfo(quantum_info);
3239 if (image->storage_class == PseudoClass)
3245 image->matte=MagickFalse;
3246 (void) SyncImage(image,exception);
3250 png_read_end(ping,end_info);
3252 if (image_info->number_scenes != 0 && mng_info->scenes_found-1 <
3253 (ssize_t) image_info->first_scene && image->delay != 0)
3255 png_destroy_read_struct(&ping,&ping_info,&end_info);
3256 ping_pixels=(unsigned char *) RelinquishMagickMemory(ping_pixels);
3258 (void) SetImageBackgroundColor(image,exception);
3259 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
3260 UnlockSemaphoreInfo(ping_semaphore);
3262 if (logging != MagickFalse)
3263 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3264 " exit ReadOnePNGImage() early.");
3268 if (png_get_valid(ping,ping_info,PNG_INFO_tRNS))
3274 Image has a transparent background.
3276 storage_class=image->storage_class;
3277 image->matte=MagickTrue;
3279 /* Balfour fix from imagemagick discourse server, 5 Feb 2010 */
3281 if (storage_class == PseudoClass)
3283 if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
3285 for (x=0; x < ping_num_trans; x++)
3287 image->colormap[x].alpha =
3288 ScaleCharToQuantum((unsigned char)ping_trans_alpha[x]);
3292 else if (ping_color_type == PNG_COLOR_TYPE_GRAY)
3294 for (x=0; x < (int) image->colors; x++)
3296 if (ScaleQuantumToShort(image->colormap[x].red) ==
3297 transparent_color.alpha)
3299 image->colormap[x].alpha = (Quantum) TransparentAlpha;
3303 (void) SyncImage(image,exception);
3306 #if 1 /* Should have already been done above, but glennrp problem P10
3311 for (y=0; y < (ssize_t) image->rows; y++)
3313 image->storage_class=storage_class;
3314 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
3316 if (q == (Quantum *) NULL)
3320 /* Caution: on a Q8 build, this does not distinguish between
3321 * 16-bit colors that differ only in the low byte
3323 for (x=(ssize_t) image->columns-1; x >= 0; x--)
3325 if (ScaleQuantumToShort(GetPixelRed(image,q)) ==
3326 transparent_color.red &&
3327 ScaleQuantumToShort(GetPixelGreen(image,q)) ==
3328 transparent_color.green &&
3329 ScaleQuantumToShort(GetPixelBlue(image,q)) ==
3330 transparent_color.blue)
3332 SetPixelAlpha(image,TransparentAlpha,q);
3335 #if 0 /* I have not found a case where this is needed. */
3338 SetPixelAlpha(image,q)=(Quantum) OpaqueAlpha;
3342 q+=GetPixelChannels(image);
3345 if (SyncAuthenticPixels(image,exception) == MagickFalse)
3351 image->storage_class=DirectClass;
3354 if ((ping_color_type == PNG_COLOR_TYPE_GRAY) ||
3355 (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA))
3356 image->colorspace=GRAYColorspace;
3358 for (j = 0; j < 2; j++)
3361 status = png_get_text(ping,ping_info,&text,&num_text) != 0 ?
3362 MagickTrue : MagickFalse;
3364 status = png_get_text(ping,end_info,&text,&num_text) != 0 ?
3365 MagickTrue : MagickFalse;
3367 if (status != MagickFalse)
3368 for (i=0; i < (ssize_t) num_text; i++)
3370 /* Check for a profile */
3372 if (logging != MagickFalse)
3373 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3374 " Reading PNG text chunk");
3376 if (memcmp(text[i].key, "Raw profile type ",17) == 0)
3378 (void) Magick_png_read_raw_profile(image,image_info,text,(int) i,
3388 length=text[i].text_length;
3389 value=(char *) AcquireQuantumMemory(length+MaxTextExtent,
3391 if (value == (char *) NULL)
3393 (void) ThrowMagickException(exception,GetMagickModule(),
3394 ResourceLimitError,"MemoryAllocationFailed","`%s'",
3399 (void) ConcatenateMagickString(value,text[i].text,length+2);
3401 /* Don't save "density" or "units" property if we have a pHYs
3404 if (!png_get_valid(ping,ping_info,PNG_INFO_pHYs) ||
3405 (LocaleCompare(text[i].key,"density") != 0 &&
3406 LocaleCompare(text[i].key,"units") != 0))
3407 (void) SetImageProperty(image,text[i].key,value,exception);
3409 if (logging != MagickFalse)
3411 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3412 " length: %lu",(unsigned long) length);
3413 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3414 " Keyword: %s",text[i].key);
3417 value=DestroyString(value);
3420 num_text_total += num_text;
3423 #ifdef MNG_OBJECT_BUFFERS
3425 Store the object if necessary.
3427 if (object_id && !mng_info->frozen[object_id])
3429 if (mng_info->ob[object_id] == (MngBuffer *) NULL)
3432 create a new object buffer.
3434 mng_info->ob[object_id]=(MngBuffer *)
3435 AcquireMagickMemory(sizeof(MngBuffer));
3437 if (mng_info->ob[object_id] != (MngBuffer *) NULL)
3439 mng_info->ob[object_id]->image=(Image *) NULL;
3440 mng_info->ob[object_id]->reference_count=1;
3444 if ((mng_info->ob[object_id] == (MngBuffer *) NULL) ||
3445 mng_info->ob[object_id]->frozen)
3447 if (mng_info->ob[object_id] == (MngBuffer *) NULL)
3448 (void) ThrowMagickException(exception,GetMagickModule(),
3449 ResourceLimitError,"MemoryAllocationFailed","`%s'",
3452 if (mng_info->ob[object_id]->frozen)
3453 (void) ThrowMagickException(exception,GetMagickModule(),
3454 ResourceLimitError,"Cannot overwrite frozen MNG object buffer",
3455 "`%s'",image->filename);
3461 if (mng_info->ob[object_id]->image != (Image *) NULL)
3462 mng_info->ob[object_id]->image=DestroyImage
3463 (mng_info->ob[object_id]->image);
3465 mng_info->ob[object_id]->image=CloneImage(image,0,0,MagickTrue,
3468 if (mng_info->ob[object_id]->image != (Image *) NULL)
3469 mng_info->ob[object_id]->image->file=(FILE *) NULL;
3472 (void) ThrowMagickException(exception,GetMagickModule(),
3473 ResourceLimitError,"Cloning image for object buffer failed",
3474 "`%s'",image->filename);
3476 if (ping_width > 250000L || ping_height > 250000L)
3477 png_error(ping,"PNG Image dimensions are too large.");
3479 mng_info->ob[object_id]->width=ping_width;
3480 mng_info->ob[object_id]->height=ping_height;
3481 mng_info->ob[object_id]->color_type=ping_color_type;
3482 mng_info->ob[object_id]->sample_depth=ping_bit_depth;
3483 mng_info->ob[object_id]->interlace_method=ping_interlace_method;
3484 mng_info->ob[object_id]->compression_method=
3485 ping_compression_method;
3486 mng_info->ob[object_id]->filter_method=ping_filter_method;
3488 if (png_get_valid(ping,ping_info,PNG_INFO_PLTE))
3497 Copy the PLTE to the object buffer.
3499 png_get_PLTE(ping,ping_info,&plte,&number_colors);
3500 mng_info->ob[object_id]->plte_length=number_colors;
3502 for (i=0; i < number_colors; i++)
3504 mng_info->ob[object_id]->plte[i]=plte[i];
3509 mng_info->ob[object_id]->plte_length=0;
3514 /* Set image->matte to MagickTrue if the input colortype supports
3515 * alpha or if a valid tRNS chunk is present, no matter whether there
3516 * is actual transparency present.
3518 image->matte=(((int) ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA) ||
3519 ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) ||
3520 (png_get_valid(ping,ping_info,PNG_INFO_tRNS))) ?
3521 MagickTrue : MagickFalse;
3523 /* Set more properties for identify to retrieve */
3528 if (num_text_total != 0)
3530 /* libpng doesn't tell us whether they were tEXt, zTXt, or iTXt */
3531 (void) FormatLocaleString(msg,MaxTextExtent,
3532 "%d tEXt/zTXt/iTXt chunks were found", num_text_total);
3533 (void) SetImageProperty(image,"PNG:text ",msg,
3537 if (num_raw_profiles != 0)
3539 (void) FormatLocaleString(msg,MaxTextExtent,
3540 "%d were found", num_raw_profiles);
3541 (void) SetImageProperty(image,"PNG:text-encoded profiles",msg,
3545 if (png_get_valid(ping,ping_info,PNG_INFO_cHRM))
3547 (void) FormatLocaleString(msg,MaxTextExtent,"%s",
3548 "chunk was found (see Chromaticity, above)");
3549 (void) SetImageProperty(image,"PNG:cHRM ",msg,
3553 if (png_get_valid(ping,ping_info,PNG_INFO_bKGD))
3555 (void) FormatLocaleString(msg,MaxTextExtent,"%s",
3556 "chunk was found (see Background color, above)");
3557 (void) SetImageProperty(image,"PNG:bKGD ",msg,
3561 (void) FormatLocaleString(msg,MaxTextExtent,"%s",
3564 if (png_get_valid(ping,ping_info,PNG_INFO_iCCP))
3565 (void) SetImageProperty(image,"PNG:iCCP ",msg,
3568 if (png_get_valid(ping,ping_info,PNG_INFO_tRNS))
3569 (void) SetImageProperty(image,"PNG:tRNS ",msg,
3572 #if defined(PNG_sRGB_SUPPORTED)
3573 if (png_get_valid(ping,ping_info,PNG_INFO_sRGB))
3575 (void) FormatLocaleString(msg,MaxTextExtent,
3576 "intent=%d (See Rendering intent)",
3578 (void) SetImageProperty(image,"PNG:sRGB ",msg,
3583 if (png_get_valid(ping,ping_info,PNG_INFO_gAMA))
3585 (void) FormatLocaleString(msg,MaxTextExtent,
3586 "gamma=%.8g (See Gamma, above)",
3588 (void) SetImageProperty(image,"PNG:gAMA ",msg,
3592 #if defined(PNG_pHYs_SUPPORTED)
3593 if (png_get_valid(ping,ping_info,PNG_INFO_pHYs))
3595 (void) FormatLocaleString(msg,MaxTextExtent,
3596 "x_res=%.10g, y_res=%.10g, units=%d",
3597 (double) x_resolution,(double) y_resolution, unit_type);
3598 (void) SetImageProperty(image,"PNG:pHYs ",msg,
3603 #if defined(PNG_oFFs_SUPPORTED)
3604 if (png_get_valid(ping,ping_info,PNG_INFO_oFFs))
3606 (void) FormatLocaleString(msg,MaxTextExtent,"x_off=%.20g, y_off=%.20g",
3607 (double) image->page.x,(double) image->page.y);
3608 (void) SetImageProperty(image,"PNG:oFFs ",msg,
3613 if ((image->page.width != 0 && image->page.width != image->columns) ||
3614 (image->page.height != 0 && image->page.height != image->rows))
3616 (void) FormatLocaleString(msg,MaxTextExtent,
3617 "width=%.20g, height=%.20g",
3618 (double) image->page.width,(double) image->page.height);
3619 (void) SetImageProperty(image,"PNG:vpAg ",msg,
3625 Relinquish resources.
3627 png_destroy_read_struct(&ping,&ping_info,&end_info);
3629 ping_pixels=(unsigned char *) RelinquishMagickMemory(ping_pixels);
3630 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
3631 UnlockSemaphoreInfo(ping_semaphore);
3634 if (logging != MagickFalse)
3635 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3636 " exit ReadOnePNGImage()");
3640 /* end of reading one PNG image */
3643 static Image *ReadPNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
3658 magic_number[MaxTextExtent];
3666 assert(image_info != (const ImageInfo *) NULL);
3667 assert(image_info->signature == MagickSignature);
3669 if (image_info->debug != MagickFalse)
3670 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
3671 image_info->filename);
3673 assert(exception != (ExceptionInfo *) NULL);
3674 assert(exception->signature == MagickSignature);
3675 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter ReadPNGImage()");
3676 image=AcquireImage(image_info,exception);
3677 mng_info=(MngInfo *) NULL;
3678 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
3680 if (status == MagickFalse)
3681 ThrowReaderException(FileOpenError,"UnableToOpenFile");
3684 Verify PNG signature.
3686 count=ReadBlob(image,8,(unsigned char *) magic_number);
3688 if (count < 8 || memcmp(magic_number,"\211PNG\r\n\032\n",8) != 0)
3689 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
3692 Allocate a MngInfo structure.
3694 have_mng_structure=MagickFalse;
3695 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
3697 if (mng_info == (MngInfo *) NULL)
3698 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
3701 Initialize members of the MngInfo structure.
3703 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
3704 mng_info->image=image;
3705 have_mng_structure=MagickTrue;
3708 image=ReadOnePNGImage(mng_info,image_info,exception);
3709 MngInfoFreeStruct(mng_info,&have_mng_structure);
3711 if (image == (Image *) NULL)
3713 if (previous != (Image *) NULL)
3715 if (previous->signature != MagickSignature)
3716 ThrowReaderException(CorruptImageError,"CorruptImage");
3718 (void) CloseBlob(previous);
3719 (void) DestroyImageList(previous);
3722 if (logging != MagickFalse)
3723 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3724 "exit ReadPNGImage() with error");
3726 return((Image *) NULL);
3729 (void) CloseBlob(image);
3731 if ((image->columns == 0) || (image->rows == 0))
3733 if (logging != MagickFalse)
3734 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3735 "exit ReadPNGImage() with error.");
3737 ThrowReaderException(CorruptImageError,"CorruptImage");
3740 if (LocaleCompare(image_info->magick,"PNG24") == 0)
3742 (void) SetImageType(image,TrueColorType,exception);
3743 image->matte=MagickFalse;
3746 if (LocaleCompare(image_info->magick,"PNG32") == 0)
3747 (void) SetImageType(image,TrueColorMatteType,exception);
3749 if (logging != MagickFalse)
3750 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3751 " page.w: %.20g, page.h: %.20g,page.x: %.20g, page.y: %.20g.",
3752 (double) image->page.width,(double) image->page.height,
3753 (double) image->page.x,(double) image->page.y);
3755 if (logging != MagickFalse)
3756 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit ReadPNGImage()");
3763 #if defined(JNG_SUPPORTED)
3765 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3769 % R e a d O n e J N G I m a g e %
3773 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3775 % ReadOneJNGImage() reads a JPEG Network Graphics (JNG) image file
3776 % (minus the 8-byte signature) and returns it. It allocates the memory
3777 % necessary for the new Image structure and returns a pointer to the new
3780 % JNG support written by Glenn Randers-Pehrson, glennrp@image...
3782 % The format of the ReadOneJNGImage method is:
3784 % Image *ReadOneJNGImage(MngInfo *mng_info, const ImageInfo *image_info,
3785 % ExceptionInfo *exception)
3787 % A description of each parameter follows:
3789 % o mng_info: Specifies a pointer to a MngInfo structure.
3791 % o image_info: the image info.
3793 % o exception: return any errors or warnings in this structure.
3796 static Image *ReadOneJNGImage(MngInfo *mng_info,
3797 const ImageInfo *image_info, ExceptionInfo *exception)
3824 jng_image_sample_depth,
3825 jng_image_compression_method,
3826 jng_image_interlace_method,
3827 jng_alpha_sample_depth,
3828 jng_alpha_compression_method,
3829 jng_alpha_filter_method,
3830 jng_alpha_interlace_method;
3832 register const Quantum
3842 register unsigned char
3853 jng_alpha_compression_method=0;
3854 jng_alpha_sample_depth=8;
3858 alpha_image=(Image *) NULL;
3859 color_image=(Image *) NULL;
3860 alpha_image_info=(ImageInfo *) NULL;
3861 color_image_info=(ImageInfo *) NULL;
3863 logging=LogMagickEvent(CoderEvent,GetMagickModule(),
3864 " Enter ReadOneJNGImage()");
3866 image=mng_info->image;
3868 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
3871 Allocate next image structure.
3873 if (logging != MagickFalse)
3874 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3875 " AcquireNextImage()");
3877 AcquireNextImage(image_info,image,exception);
3879 if (GetNextImageInList(image) == (Image *) NULL)
3880 return((Image *) NULL);
3882 image=SyncNextImageInList(image);
3884 mng_info->image=image;
3887 Signature bytes have already been read.
3890 read_JSEP=MagickFalse;
3891 reading_idat=MagickFalse;
3892 skip_to_iend=MagickFalse;
3896 type[MaxTextExtent];
3905 Read a new JNG chunk.
3907 status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
3908 2*GetBlobSize(image));
3910 if (status == MagickFalse)
3914 (void) ConcatenateMagickString(type,"errr",MaxTextExtent);
3915 length=ReadBlobMSBLong(image);
3916 count=(unsigned int) ReadBlob(image,4,(unsigned char *) type);
3918 if (logging != MagickFalse)
3919 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3920 " Reading JNG chunk type %c%c%c%c, length: %.20g",
3921 type[0],type[1],type[2],type[3],(double) length);
3923 if (length > PNG_UINT_31_MAX || count == 0)
3924 ThrowReaderException(CorruptImageError,"CorruptImage");
3927 chunk=(unsigned char *) NULL;
3931 chunk=(unsigned char *) AcquireQuantumMemory(length,sizeof(*chunk));
3933 if (chunk == (unsigned char *) NULL)
3934 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
3936 for (i=0; i < (ssize_t) length; i++)
3937 chunk[i]=(unsigned char) ReadBlobByte(image);
3942 (void) ReadBlobMSBLong(image); /* read crc word */
3947 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
3952 if (memcmp(type,mng_JHDR,4) == 0)
3956 jng_width=(size_t) ((p[0] << 24) | (p[1] << 16) |
3957 (p[2] << 8) | p[3]);
3958 jng_height=(size_t) ((p[4] << 24) | (p[5] << 16) |
3959 (p[6] << 8) | p[7]);
3960 jng_color_type=p[8];
3961 jng_image_sample_depth=p[9];
3962 jng_image_compression_method=p[10];
3963 jng_image_interlace_method=p[11];
3965 image->interlace=jng_image_interlace_method != 0 ? PNGInterlace :
3968 jng_alpha_sample_depth=p[12];
3969 jng_alpha_compression_method=p[13];
3970 jng_alpha_filter_method=p[14];
3971 jng_alpha_interlace_method=p[15];
3973 if (logging != MagickFalse)
3975 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3976 " jng_width: %16lu",(unsigned long) jng_width);
3978 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3979 " jng_width: %16lu",(unsigned long) jng_height);
3981 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3982 " jng_color_type: %16d",jng_color_type);
3984 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3985 " jng_image_sample_depth: %3d",
3986 jng_image_sample_depth);
3988 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3989 " jng_image_compression_method:%3d",
3990 jng_image_compression_method);
3992 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3993 " jng_image_interlace_method: %3d",
3994 jng_image_interlace_method);
3996 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3997 " jng_alpha_sample_depth: %3d",
3998 jng_alpha_sample_depth);
4000 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4001 " jng_alpha_compression_method:%3d",
4002 jng_alpha_compression_method);
4004 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4005 " jng_alpha_filter_method: %3d",
4006 jng_alpha_filter_method);
4008 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4009 " jng_alpha_interlace_method: %3d",
4010 jng_alpha_interlace_method);
4015 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4021 if ((reading_idat == MagickFalse) && (read_JSEP == MagickFalse) &&
4022 ((memcmp(type,mng_JDAT,4) == 0) || (memcmp(type,mng_JdAA,4) == 0) ||
4023 (memcmp(type,mng_IDAT,4) == 0) || (memcmp(type,mng_JDAA,4) == 0)))
4026 o create color_image
4027 o open color_blob, attached to color_image
4028 o if (color type has alpha)
4029 open alpha_blob, attached to alpha_image
4032 color_image_info=(ImageInfo *)AcquireMagickMemory(sizeof(ImageInfo));
4034 if (color_image_info == (ImageInfo *) NULL)
4035 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
4037 GetImageInfo(color_image_info);
4038 color_image=AcquireImage(color_image_info,exception);
4040 if (color_image == (Image *) NULL)
4041 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
4043 if (logging != MagickFalse)
4044 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4045 " Creating color_blob.");
4047 (void) AcquireUniqueFilename(color_image->filename);
4048 status=OpenBlob(color_image_info,color_image,WriteBinaryBlobMode,
4051 if (status == MagickFalse)
4052 return((Image *) NULL);
4054 if ((image_info->ping == MagickFalse) && (jng_color_type >= 12))
4056 alpha_image_info=(ImageInfo *)
4057 AcquireMagickMemory(sizeof(ImageInfo));
4059 if (alpha_image_info == (ImageInfo *) NULL)
4060 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
4062 GetImageInfo(alpha_image_info);
4063 alpha_image=AcquireImage(alpha_image_info,exception);
4065 if (alpha_image == (Image *) NULL)
4067 alpha_image=DestroyImage(alpha_image);
4068 ThrowReaderException(ResourceLimitError,
4069 "MemoryAllocationFailed");
4072 if (logging != MagickFalse)
4073 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4074 " Creating alpha_blob.");
4076 (void) AcquireUniqueFilename(alpha_image->filename);
4077 status=OpenBlob(alpha_image_info,alpha_image,WriteBinaryBlobMode,
4080 if (status == MagickFalse)
4081 return((Image *) NULL);
4083 if (jng_alpha_compression_method == 0)
4088 if (logging != MagickFalse)
4089 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4090 " Writing IHDR chunk to alpha_blob.");
4092 (void) WriteBlob(alpha_image,8,(const unsigned char *)
4093 "\211PNG\r\n\032\n");
4095 (void) WriteBlobMSBULong(alpha_image,13L);
4096 PNGType(data,mng_IHDR);
4097 LogPNGChunk(logging,mng_IHDR,13L);
4098 PNGLong(data+4,jng_width);
4099 PNGLong(data+8,jng_height);
4100 data[12]=jng_alpha_sample_depth;
4101 data[13]=0; /* color_type gray */
4102 data[14]=0; /* compression method 0 */
4103 data[15]=0; /* filter_method 0 */
4104 data[16]=0; /* interlace_method 0 */
4105 (void) WriteBlob(alpha_image,17,data);
4106 (void) WriteBlobMSBULong(alpha_image,crc32(0,data,17));
4109 reading_idat=MagickTrue;
4112 if (memcmp(type,mng_JDAT,4) == 0)
4114 /* Copy chunk to color_image->blob */
4116 if (logging != MagickFalse)
4117 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4118 " Copying JDAT chunk data to color_blob.");
4120 (void) WriteBlob(color_image,length,chunk);
4123 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4128 if (memcmp(type,mng_IDAT,4) == 0)
4133 /* Copy IDAT header and chunk data to alpha_image->blob */
4135 if (image_info->ping == MagickFalse)
4137 if (logging != MagickFalse)
4138 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4139 " Copying IDAT chunk data to alpha_blob.");
4141 (void) WriteBlobMSBULong(alpha_image,(size_t) length);
4142 PNGType(data,mng_IDAT);
4143 LogPNGChunk(logging,mng_IDAT,length);
4144 (void) WriteBlob(alpha_image,4,data);
4145 (void) WriteBlob(alpha_image,length,chunk);
4146 (void) WriteBlobMSBULong(alpha_image,
4147 crc32(crc32(0,data,4),chunk,(uInt) length));
4151 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4156 if ((memcmp(type,mng_JDAA,4) == 0) || (memcmp(type,mng_JdAA,4) == 0))
4158 /* Copy chunk data to alpha_image->blob */
4160 if (image_info->ping == MagickFalse)
4162 if (logging != MagickFalse)
4163 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4164 " Copying JDAA chunk data to alpha_blob.");
4166 (void) WriteBlob(alpha_image,length,chunk);
4170 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4175 if (memcmp(type,mng_JSEP,4) == 0)
4177 read_JSEP=MagickTrue;
4180 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4185 if (memcmp(type,mng_bKGD,4) == 0)
4189 image->background_color.red=ScaleCharToQuantum(p[1]);
4190 image->background_color.green=image->background_color.red;
4191 image->background_color.blue=image->background_color.red;
4196 image->background_color.red=ScaleCharToQuantum(p[1]);
4197 image->background_color.green=ScaleCharToQuantum(p[3]);
4198 image->background_color.blue=ScaleCharToQuantum(p[5]);
4201 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4205 if (memcmp(type,mng_gAMA,4) == 0)
4208 image->gamma=((float) mng_get_long(p))*0.00001;
4210 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4214 if (memcmp(type,mng_cHRM,4) == 0)
4218 image->chromaticity.white_point.x=0.00001*mng_get_long(p);
4219 image->chromaticity.white_point.y=0.00001*mng_get_long(&p[4]);
4220 image->chromaticity.red_primary.x=0.00001*mng_get_long(&p[8]);
4221 image->chromaticity.red_primary.y=0.00001*mng_get_long(&p[12]);
4222 image->chromaticity.green_primary.x=0.00001*mng_get_long(&p[16]);
4223 image->chromaticity.green_primary.y=0.00001*mng_get_long(&p[20]);
4224 image->chromaticity.blue_primary.x=0.00001*mng_get_long(&p[24]);
4225 image->chromaticity.blue_primary.y=0.00001*mng_get_long(&p[28]);
4228 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4232 if (memcmp(type,mng_sRGB,4) == 0)
4236 image->rendering_intent=
4237 Magick_RenderingIntent_from_PNG_RenderingIntent(p[0]);
4238 image->gamma=0.45455f;
4239 image->chromaticity.red_primary.x=0.6400f;
4240 image->chromaticity.red_primary.y=0.3300f;
4241 image->chromaticity.green_primary.x=0.3000f;
4242 image->chromaticity.green_primary.y=0.6000f;
4243 image->chromaticity.blue_primary.x=0.1500f;
4244 image->chromaticity.blue_primary.y=0.0600f;
4245 image->chromaticity.white_point.x=0.3127f;
4246 image->chromaticity.white_point.y=0.3290f;
4249 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4253 if (memcmp(type,mng_oFFs,4) == 0)
4257 image->page.x=(ssize_t) mng_get_long(p);
4258 image->page.y=(ssize_t) mng_get_long(&p[4]);
4260 if ((int) p[8] != 0)
4262 image->page.x/=10000;
4263 image->page.y/=10000;
4268 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4273 if (memcmp(type,mng_pHYs,4) == 0)
4277 image->x_resolution=(double) mng_get_long(p);
4278 image->y_resolution=(double) mng_get_long(&p[4]);
4279 if ((int) p[8] == PNG_RESOLUTION_METER)
4281 image->units=PixelsPerCentimeterResolution;
4282 image->x_resolution=image->x_resolution/100.0f;
4283 image->y_resolution=image->y_resolution/100.0f;
4287 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4292 if (memcmp(type,mng_iCCP,4) == 0)
4296 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4303 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4305 if (memcmp(type,mng_IEND,4))
4315 Finish up reading image data:
4317 o read main image from color_blob.
4321 o if (color_type has alpha)
4322 if alpha_encoding is PNG
4323 read secondary image from alpha_blob via ReadPNG
4324 if alpha_encoding is JPEG
4325 read secondary image from alpha_blob via ReadJPEG
4329 o copy intensity of secondary image into
4330 alpha samples of main image.
4332 o destroy the secondary image.
4335 (void) CloseBlob(color_image);
4337 if (logging != MagickFalse)
4338 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4339 " Reading jng_image from color_blob.");
4341 (void) FormatLocaleString(color_image_info->filename,MaxTextExtent,"%s",
4342 color_image->filename);
4344 color_image_info->ping=MagickFalse; /* To do: avoid this */
4345 jng_image=ReadImage(color_image_info,exception);
4347 if (jng_image == (Image *) NULL)
4348 return((Image *) NULL);
4350 (void) RelinquishUniqueFileResource(color_image->filename);
4351 color_image=DestroyImage(color_image);
4352 color_image_info=DestroyImageInfo(color_image_info);
4354 if (jng_image == (Image *) NULL)
4355 return((Image *) NULL);
4357 if (logging != MagickFalse)
4358 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4359 " Copying jng_image pixels to main image.");
4361 image->rows=jng_height;
4362 image->columns=jng_width;
4364 for (y=0; y < (ssize_t) image->rows; y++)
4366 s=GetVirtualPixels(jng_image,0,y,image->columns,1,exception);
4367 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
4368 for (x=(ssize_t) image->columns; x != 0; x--)
4370 SetPixelRed(image,GetPixelRed(jng_image,s),q);
4371 SetPixelGreen(image,GetPixelGreen(jng_image,s),q);
4372 SetPixelBlue(image,GetPixelBlue(jng_image,s),q);
4373 q+=GetPixelChannels(image);
4374 s+=GetPixelChannels(jng_image);
4377 if (SyncAuthenticPixels(image,exception) == MagickFalse)
4381 jng_image=DestroyImage(jng_image);
4383 if (image_info->ping == MagickFalse)
4385 if (jng_color_type >= 12)
4387 if (jng_alpha_compression_method == 0)
4391 (void) WriteBlobMSBULong(alpha_image,0x00000000L);
4392 PNGType(data,mng_IEND);
4393 LogPNGChunk(logging,mng_IEND,0L);
4394 (void) WriteBlob(alpha_image,4,data);
4395 (void) WriteBlobMSBULong(alpha_image,crc32(0,data,4));
4398 (void) CloseBlob(alpha_image);
4400 if (logging != MagickFalse)
4401 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4402 " Reading alpha from alpha_blob.");
4404 (void) FormatLocaleString(alpha_image_info->filename,MaxTextExtent,
4405 "%s",alpha_image->filename);
4407 jng_image=ReadImage(alpha_image_info,exception);
4409 if (jng_image != (Image *) NULL)
4410 for (y=0; y < (ssize_t) image->rows; y++)
4412 s=GetVirtualPixels(jng_image,0,y,image->columns,1,
4414 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
4416 if (image->matte != MagickFalse)
4417 for (x=(ssize_t) image->columns; x != 0; x--)
4419 SetPixelAlpha(image,GetPixelRed(jng_image,s),q);
4420 q+=GetPixelChannels(image);
4421 s+=GetPixelChannels(jng_image);
4425 for (x=(ssize_t) image->columns; x != 0; x--)
4427 SetPixelAlpha(image,GetPixelRed(jng_image,s),q);
4428 if (GetPixelAlpha(image,q) != OpaqueAlpha)
4429 image->matte=MagickTrue;
4430 q+=GetPixelChannels(image);
4431 s+=GetPixelChannels(jng_image);
4434 if (SyncAuthenticPixels(image,exception) == MagickFalse)
4437 (void) RelinquishUniqueFileResource(alpha_image->filename);
4438 alpha_image=DestroyImage(alpha_image);
4439 alpha_image_info=DestroyImageInfo(alpha_image_info);
4440 if (jng_image != (Image *) NULL)
4441 jng_image=DestroyImage(jng_image);
4445 /* Read the JNG image. */
4447 if (mng_info->mng_type == 0)
4449 mng_info->mng_width=jng_width;
4450 mng_info->mng_height=jng_height;
4453 if (image->page.width == 0 && image->page.height == 0)
4455 image->page.width=jng_width;
4456 image->page.height=jng_height;
4459 if (image->page.x == 0 && image->page.y == 0)
4461 image->page.x=mng_info->x_off[mng_info->object_id];
4462 image->page.y=mng_info->y_off[mng_info->object_id];
4467 image->page.y=mng_info->y_off[mng_info->object_id];
4470 mng_info->image_found++;
4471 status=SetImageProgress(image,LoadImagesTag,2*TellBlob(image),
4472 2*GetBlobSize(image));
4474 if (logging != MagickFalse)
4475 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4476 " exit ReadOneJNGImage()");
4482 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4486 % R e a d J N G I m a g e %
4490 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4492 % ReadJNGImage() reads a JPEG Network Graphics (JNG) image file
4493 % (including the 8-byte signature) and returns it. It allocates the memory
4494 % necessary for the new Image structure and returns a pointer to the new
4497 % JNG support written by Glenn Randers-Pehrson, glennrp@image...
4499 % The format of the ReadJNGImage method is:
4501 % Image *ReadJNGImage(const ImageInfo *image_info, ExceptionInfo
4504 % A description of each parameter follows:
4506 % o image_info: the image info.
4508 % o exception: return any errors or warnings in this structure.
4512 static Image *ReadJNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
4527 magic_number[MaxTextExtent];
4535 assert(image_info != (const ImageInfo *) NULL);
4536 assert(image_info->signature == MagickSignature);
4537 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image_info->filename);
4538 assert(exception != (ExceptionInfo *) NULL);
4539 assert(exception->signature == MagickSignature);
4540 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter ReadJNGImage()");
4541 image=AcquireImage(image_info,exception);
4542 mng_info=(MngInfo *) NULL;
4543 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
4545 if (status == MagickFalse)
4546 return((Image *) NULL);
4548 if (LocaleCompare(image_info->magick,"JNG") != 0)
4549 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
4551 /* Verify JNG signature. */
4553 count=(size_t) ReadBlob(image,8,(unsigned char *) magic_number);
4555 if (count < 8 || memcmp(magic_number,"\213JNG\r\n\032\n",8) != 0)
4556 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
4558 /* Allocate a MngInfo structure. */
4560 have_mng_structure=MagickFalse;
4561 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(*mng_info));
4563 if (mng_info == (MngInfo *) NULL)
4564 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
4566 /* Initialize members of the MngInfo structure. */
4568 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
4569 have_mng_structure=MagickTrue;
4571 mng_info->image=image;
4573 image=ReadOneJNGImage(mng_info,image_info,exception);
4574 MngInfoFreeStruct(mng_info,&have_mng_structure);
4576 if (image == (Image *) NULL)
4578 if (IsImageObject(previous) != MagickFalse)
4580 (void) CloseBlob(previous);
4581 (void) DestroyImageList(previous);
4584 if (logging != MagickFalse)
4585 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4586 "exit ReadJNGImage() with error");
4588 return((Image *) NULL);
4590 (void) CloseBlob(image);
4592 if (image->columns == 0 || image->rows == 0)
4594 if (logging != MagickFalse)
4595 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4596 "exit ReadJNGImage() with error");
4598 ThrowReaderException(CorruptImageError,"CorruptImage");
4601 if (logging != MagickFalse)
4602 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit ReadJNGImage()");
4608 static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
4611 page_geometry[MaxTextExtent];
4644 #if defined(MNG_INSERT_LAYERS)
4646 mng_background_color;
4649 register unsigned char
4664 #if defined(MNG_INSERT_LAYERS)
4669 volatile unsigned int
4670 #ifdef MNG_OBJECT_BUFFERS
4671 mng_background_object=0,
4673 mng_type=0; /* 0: PNG or JNG; 1: MNG; 2: MNG-LC; 3: MNG-VLC */
4676 default_frame_timeout,
4678 #if defined(MNG_INSERT_LAYERS)
4684 /* These delays are all measured in image ticks_per_second,
4685 * not in MNG ticks_per_second
4688 default_frame_delay,
4692 #if defined(MNG_INSERT_LAYERS)
4701 previous_fb.bottom=0;
4703 previous_fb.right=0;
4705 default_fb.bottom=0;
4709 /* Open image file. */
4711 assert(image_info != (const ImageInfo *) NULL);
4712 assert(image_info->signature == MagickSignature);
4713 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image_info->filename);
4714 assert(exception != (ExceptionInfo *) NULL);
4715 assert(exception->signature == MagickSignature);
4716 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter ReadMNGImage()");
4717 image=AcquireImage(image_info,exception);
4718 mng_info=(MngInfo *) NULL;
4719 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
4721 if (status == MagickFalse)
4722 return((Image *) NULL);
4724 first_mng_object=MagickFalse;
4726 have_mng_structure=MagickFalse;
4728 /* Allocate a MngInfo structure. */
4730 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
4732 if (mng_info == (MngInfo *) NULL)
4733 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
4735 /* Initialize members of the MngInfo structure. */
4737 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
4738 mng_info->image=image;
4739 have_mng_structure=MagickTrue;
4741 if (LocaleCompare(image_info->magick,"MNG") == 0)
4744 magic_number[MaxTextExtent];
4746 /* Verify MNG signature. */
4747 count=(size_t) ReadBlob(image,8,(unsigned char *) magic_number);
4748 if (memcmp(magic_number,"\212MNG\r\n\032\n",8) != 0)
4749 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
4751 /* Initialize some nonzero members of the MngInfo structure. */
4752 for (i=0; i < MNG_MAX_OBJECTS; i++)
4754 mng_info->object_clip[i].right=(ssize_t) PNG_UINT_31_MAX;
4755 mng_info->object_clip[i].bottom=(ssize_t) PNG_UINT_31_MAX;
4757 mng_info->exists[0]=MagickTrue;
4760 first_mng_object=MagickTrue;
4762 #if defined(MNG_INSERT_LAYERS)
4763 insert_layers=MagickFalse; /* should be False when converting or mogrifying */
4765 default_frame_delay=0;
4766 default_frame_timeout=0;
4769 mng_info->ticks_per_second=1UL*image->ticks_per_second;
4771 skip_to_iend=MagickFalse;
4772 term_chunk_found=MagickFalse;
4773 mng_info->framing_mode=1;
4774 #if defined(MNG_INSERT_LAYERS)
4775 mandatory_back=MagickFalse;
4777 #if defined(MNG_INSERT_LAYERS)
4778 mng_background_color=image->background_color;
4780 default_fb=mng_info->frame;
4781 previous_fb=mng_info->frame;
4785 type[MaxTextExtent];
4787 if (LocaleCompare(image_info->magick,"MNG") == 0)
4796 (void) ConcatenateMagickString(type,"errr",MaxTextExtent);
4797 length=ReadBlobMSBLong(image);
4798 count=(size_t) ReadBlob(image,4,(unsigned char *) type);
4800 if (logging != MagickFalse)
4801 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4802 " Reading MNG chunk type %c%c%c%c, length: %.20g",
4803 type[0],type[1],type[2],type[3],(double) length);
4805 if (length > PNG_UINT_31_MAX)
4809 ThrowReaderException(CorruptImageError,"CorruptImage");
4812 chunk=(unsigned char *) NULL;
4816 chunk=(unsigned char *) AcquireQuantumMemory(length,sizeof(*chunk));
4818 if (chunk == (unsigned char *) NULL)
4819 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
4821 for (i=0; i < (ssize_t) length; i++)
4822 chunk[i]=(unsigned char) ReadBlobByte(image);
4827 (void) ReadBlobMSBLong(image); /* read crc word */
4829 #if !defined(JNG_SUPPORTED)
4830 if (memcmp(type,mng_JHDR,4) == 0)
4832 skip_to_iend=MagickTrue;
4834 if (mng_info->jhdr_warning == 0)
4835 (void) ThrowMagickException(exception,GetMagickModule(),
4836 CoderError,"JNGCompressNotSupported","`%s'",image->filename);
4838 mng_info->jhdr_warning++;
4841 if (memcmp(type,mng_DHDR,4) == 0)
4843 skip_to_iend=MagickTrue;
4845 if (mng_info->dhdr_warning == 0)
4846 (void) ThrowMagickException(exception,GetMagickModule(),
4847 CoderError,"DeltaPNGNotSupported","`%s'",image->filename);
4849 mng_info->dhdr_warning++;
4851 if (memcmp(type,mng_MEND,4) == 0)
4856 if (memcmp(type,mng_IEND,4) == 0)
4857 skip_to_iend=MagickFalse;
4860 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4862 if (logging != MagickFalse)
4863 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4869 if (memcmp(type,mng_MHDR,4) == 0)
4871 mng_info->mng_width=(size_t) ((p[0] << 24) | (p[1] << 16) |
4872 (p[2] << 8) | p[3]);
4874 mng_info->mng_height=(size_t) ((p[4] << 24) | (p[5] << 16) |
4875 (p[6] << 8) | p[7]);
4877 if (logging != MagickFalse)
4879 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4880 " MNG width: %.20g",(double) mng_info->mng_width);
4881 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4882 " MNG height: %.20g",(double) mng_info->mng_height);
4886 mng_info->ticks_per_second=(size_t) mng_get_long(p);
4888 if (mng_info->ticks_per_second == 0)
4889 default_frame_delay=0;
4892 default_frame_delay=1UL*image->ticks_per_second/
4893 mng_info->ticks_per_second;
4895 frame_delay=default_frame_delay;
4901 simplicity=(size_t) mng_get_long(p);
4904 mng_type=1; /* Full MNG */
4906 if ((simplicity != 0) && ((simplicity | 11) == 11))
4907 mng_type=2; /* LC */
4909 if ((simplicity != 0) && ((simplicity | 9) == 9))
4910 mng_type=3; /* VLC */
4912 #if defined(MNG_INSERT_LAYERS)
4914 insert_layers=MagickTrue;
4916 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
4918 /* Allocate next image structure. */
4919 AcquireNextImage(image_info,image,exception);
4921 if (GetNextImageInList(image) == (Image *) NULL)
4922 return((Image *) NULL);
4924 image=SyncNextImageInList(image);
4925 mng_info->image=image;
4928 if ((mng_info->mng_width > 65535L) ||
4929 (mng_info->mng_height > 65535L))
4930 ThrowReaderException(ImageError,"WidthOrHeightExceedsLimit");
4932 (void) FormatLocaleString(page_geometry,MaxTextExtent,
4933 "%.20gx%.20g+0+0",(double) mng_info->mng_width,(double)
4934 mng_info->mng_height);
4936 mng_info->frame.left=0;
4937 mng_info->frame.right=(ssize_t) mng_info->mng_width;
4938 mng_info->frame.top=0;
4939 mng_info->frame.bottom=(ssize_t) mng_info->mng_height;
4940 mng_info->clip=default_fb=previous_fb=mng_info->frame;
4942 for (i=0; i < MNG_MAX_OBJECTS; i++)
4943 mng_info->object_clip[i]=mng_info->frame;
4945 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4949 if (memcmp(type,mng_TERM,4) == 0)
4960 final_delay=(png_uint_32) mng_get_long(&p[2]);
4961 mng_iterations=(png_uint_32) mng_get_long(&p[6]);
4963 if (mng_iterations == PNG_UINT_31_MAX)
4966 image->iterations=mng_iterations;
4967 term_chunk_found=MagickTrue;
4970 if (logging != MagickFalse)
4972 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4973 " repeat=%d",repeat);
4975 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4976 " final_delay=%.20g",(double) final_delay);
4978 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4979 " image->iterations=%.20g",(double) image->iterations);
4982 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4985 if (memcmp(type,mng_DEFI,4) == 0)
4988 (void) ThrowMagickException(exception,GetMagickModule(),
4989 CoderError,"DEFI chunk found in MNG-VLC datastream","`%s'",
4992 object_id=(p[0] << 8) | p[1];
4994 if (mng_type == 2 && object_id != 0)
4995 (void) ThrowMagickException(exception,GetMagickModule(),
4996 CoderError,"Nonzero object_id in MNG-LC datastream","`%s'",
4999 if (object_id > MNG_MAX_OBJECTS)
5002 Instead ofsuing a warning we should allocate a larger
5003 MngInfo structure and continue.
5005 (void) ThrowMagickException(exception,GetMagickModule(),
5006 CoderError,"object id too large","`%s'",image->filename);
5007 object_id=MNG_MAX_OBJECTS;
5010 if (mng_info->exists[object_id])
5011 if (mng_info->frozen[object_id])
5013 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5014 (void) ThrowMagickException(exception,
5015 GetMagickModule(),CoderError,
5016 "DEFI cannot redefine a frozen MNG object","`%s'",
5021 mng_info->exists[object_id]=MagickTrue;
5024 mng_info->invisible[object_id]=p[2];
5027 Extract object offset info.
5031 mng_info->x_off[object_id]=(ssize_t) ((p[4] << 24) |
5032 (p[5] << 16) | (p[6] << 8) | p[7]);
5034 mng_info->y_off[object_id]=(ssize_t) ((p[8] << 24) |
5035 (p[9] << 16) | (p[10] << 8) | p[11]);
5037 if (logging != MagickFalse)
5039 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5040 " x_off[%d]: %.20g",object_id,(double)
5041 mng_info->x_off[object_id]);
5043 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5044 " y_off[%d]: %.20g",object_id,(double)
5045 mng_info->y_off[object_id]);
5050 Extract object clipping info.
5053 mng_info->object_clip[object_id]=mng_read_box(mng_info->frame,0,
5056 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5059 if (memcmp(type,mng_bKGD,4) == 0)
5061 mng_info->have_global_bkgd=MagickFalse;
5065 mng_info->mng_global_bkgd.red=
5066 ScaleShortToQuantum((unsigned short) ((p[0] << 8) | p[1]));
5068 mng_info->mng_global_bkgd.green=
5069 ScaleShortToQuantum((unsigned short) ((p[2] << 8) | p[3]));
5071 mng_info->mng_global_bkgd.blue=
5072 ScaleShortToQuantum((unsigned short) ((p[4] << 8) | p[5]));
5074 mng_info->have_global_bkgd=MagickTrue;
5077 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5080 if (memcmp(type,mng_BACK,4) == 0)
5082 #if defined(MNG_INSERT_LAYERS)
5084 mandatory_back=p[6];
5089 if (mandatory_back && length > 5)
5091 mng_background_color.red=
5092 ScaleShortToQuantum((unsigned short) ((p[0] << 8) | p[1]));
5094 mng_background_color.green=
5095 ScaleShortToQuantum((unsigned short) ((p[2] << 8) | p[3]));
5097 mng_background_color.blue=
5098 ScaleShortToQuantum((unsigned short) ((p[4] << 8) | p[5]));
5100 mng_background_color.alpha=OpaqueAlpha;
5103 #ifdef MNG_OBJECT_BUFFERS
5105 mng_background_object=(p[7] << 8) | p[8];
5108 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5112 if (memcmp(type,mng_PLTE,4) == 0)
5114 /* Read global PLTE. */
5116 if (length && (length < 769))
5118 if (mng_info->global_plte == (png_colorp) NULL)
5119 mng_info->global_plte=(png_colorp) AcquireQuantumMemory(256,
5120 sizeof(*mng_info->global_plte));
5122 for (i=0; i < (ssize_t) (length/3); i++)
5124 mng_info->global_plte[i].red=p[3*i];
5125 mng_info->global_plte[i].green=p[3*i+1];
5126 mng_info->global_plte[i].blue=p[3*i+2];
5129 mng_info->global_plte_length=(unsigned int) (length/3);
5132 for ( ; i < 256; i++)
5134 mng_info->global_plte[i].red=i;
5135 mng_info->global_plte[i].green=i;
5136 mng_info->global_plte[i].blue=i;
5140 mng_info->global_plte_length=256;
5143 mng_info->global_plte_length=0;
5145 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5149 if (memcmp(type,mng_tRNS,4) == 0)
5151 /* read global tRNS */
5154 for (i=0; i < (ssize_t) length; i++)
5155 mng_info->global_trns[i]=p[i];
5158 for ( ; i < 256; i++)
5159 mng_info->global_trns[i]=255;
5161 mng_info->global_trns_length=(unsigned int) length;
5162 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5165 if (memcmp(type,mng_gAMA,4) == 0)
5172 igamma=mng_get_long(p);
5173 mng_info->global_gamma=((float) igamma)*0.00001;
5174 mng_info->have_global_gama=MagickTrue;
5178 mng_info->have_global_gama=MagickFalse;
5180 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5184 if (memcmp(type,mng_cHRM,4) == 0)
5186 /* Read global cHRM */
5190 mng_info->global_chrm.white_point.x=0.00001*mng_get_long(p);
5191 mng_info->global_chrm.white_point.y=0.00001*mng_get_long(&p[4]);
5192 mng_info->global_chrm.red_primary.x=0.00001*mng_get_long(&p[8]);
5193 mng_info->global_chrm.red_primary.y=0.00001*
5194 mng_get_long(&p[12]);
5195 mng_info->global_chrm.green_primary.x=0.00001*
5196 mng_get_long(&p[16]);
5197 mng_info->global_chrm.green_primary.y=0.00001*
5198 mng_get_long(&p[20]);
5199 mng_info->global_chrm.blue_primary.x=0.00001*
5200 mng_get_long(&p[24]);
5201 mng_info->global_chrm.blue_primary.y=0.00001*
5202 mng_get_long(&p[28]);
5203 mng_info->have_global_chrm=MagickTrue;
5206 mng_info->have_global_chrm=MagickFalse;
5208 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5212 if (memcmp(type,mng_sRGB,4) == 0)
5219 mng_info->global_srgb_intent=
5220 Magick_RenderingIntent_from_PNG_RenderingIntent(p[0]);
5221 mng_info->have_global_srgb=MagickTrue;
5224 mng_info->have_global_srgb=MagickFalse;
5226 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5230 if (memcmp(type,mng_iCCP,4) == 0)
5238 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5243 if (memcmp(type,mng_FRAM,4) == 0)
5246 (void) ThrowMagickException(exception,GetMagickModule(),
5247 CoderError,"FRAM chunk found in MNG-VLC datastream","`%s'",
5250 if ((mng_info->framing_mode == 2) || (mng_info->framing_mode == 4))
5251 image->delay=frame_delay;
5253 frame_delay=default_frame_delay;
5254 frame_timeout=default_frame_timeout;
5259 mng_info->framing_mode=p[0];
5261 if (logging != MagickFalse)
5262 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5263 " Framing_mode=%d",mng_info->framing_mode);
5267 /* Note the delay and frame clipping boundaries. */
5269 p++; /* framing mode */
5271 while (*p && ((p-chunk) < (ssize_t) length))
5272 p++; /* frame name */
5274 p++; /* frame name terminator */
5276 if ((p-chunk) < (ssize_t) (length-4))
5283 change_delay=(*p++);
5284 change_timeout=(*p++);
5285 change_clipping=(*p++);
5286 p++; /* change_sync */
5290 frame_delay=1UL*image->ticks_per_second*
5293 if (mng_info->ticks_per_second != 0)
5294 frame_delay/=mng_info->ticks_per_second;
5297 frame_delay=PNG_UINT_31_MAX;
5299 if (change_delay == 2)
5300 default_frame_delay=frame_delay;
5304 if (logging != MagickFalse)
5305 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5306 " Framing_delay=%.20g",(double) frame_delay);
5311 frame_timeout=1UL*image->ticks_per_second*
5314 if (mng_info->ticks_per_second != 0)
5315 frame_timeout/=mng_info->ticks_per_second;
5318 frame_timeout=PNG_UINT_31_MAX;
5320 if (change_delay == 2)
5321 default_frame_timeout=frame_timeout;
5325 if (logging != MagickFalse)
5326 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5327 " Framing_timeout=%.20g",(double) frame_timeout);
5330 if (change_clipping)
5332 fb=mng_read_box(previous_fb,(char) p[0],&p[1]);
5336 if (logging != MagickFalse)
5337 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5338 " Frame_clip: L=%.20g R=%.20g T=%.20g B=%.20g",
5339 (double) fb.left,(double) fb.right,(double) fb.top,
5340 (double) fb.bottom);
5342 if (change_clipping == 2)
5348 mng_info->clip=mng_minimum_box(fb,mng_info->frame);
5350 subframe_width=(size_t) (mng_info->clip.right
5351 -mng_info->clip.left);
5353 subframe_height=(size_t) (mng_info->clip.bottom
5354 -mng_info->clip.top);
5356 Insert a background layer behind the frame if framing_mode is 4.
5358 #if defined(MNG_INSERT_LAYERS)
5359 if (logging != MagickFalse)
5360 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5361 " subframe_width=%.20g, subframe_height=%.20g",(double)
5362 subframe_width,(double) subframe_height);
5364 if (insert_layers && (mng_info->framing_mode == 4) &&
5365 (subframe_width) && (subframe_height))
5367 /* Allocate next image structure. */
5368 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
5370 AcquireNextImage(image_info,image,exception);
5372 if (GetNextImageInList(image) == (Image *) NULL)
5374 image=DestroyImageList(image);
5375 MngInfoFreeStruct(mng_info,&have_mng_structure);
5376 return((Image *) NULL);
5379 image=SyncNextImageInList(image);
5382 mng_info->image=image;
5384 if (term_chunk_found)
5386 image->start_loop=MagickTrue;
5387 image->iterations=mng_iterations;
5388 term_chunk_found=MagickFalse;
5392 image->start_loop=MagickFalse;
5394 image->columns=subframe_width;
5395 image->rows=subframe_height;
5396 image->page.width=subframe_width;
5397 image->page.height=subframe_height;
5398 image->page.x=mng_info->clip.left;
5399 image->page.y=mng_info->clip.top;
5400 image->background_color=mng_background_color;
5401 image->matte=MagickFalse;
5403 (void) SetImageBackgroundColor(image,exception);
5405 if (logging != MagickFalse)
5406 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5407 " Insert backgd layer, L=%.20g, R=%.20g T=%.20g, B=%.20g",
5408 (double) mng_info->clip.left,(double) mng_info->clip.right,
5409 (double) mng_info->clip.top,(double) mng_info->clip.bottom);
5412 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5415 if (memcmp(type,mng_CLIP,4) == 0)
5424 first_object=(p[0] << 8) | p[1];
5425 last_object=(p[2] << 8) | p[3];
5427 for (i=(int) first_object; i <= (int) last_object; i++)
5429 if (mng_info->exists[i] && !mng_info->frozen[i])
5434 box=mng_info->object_clip[i];
5435 mng_info->object_clip[i]=mng_read_box(box,(char) p[4],&p[5]);
5439 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5442 if (memcmp(type,mng_SAVE,4) == 0)
5444 for (i=1; i < MNG_MAX_OBJECTS; i++)
5445 if (mng_info->exists[i])
5447 mng_info->frozen[i]=MagickTrue;
5448 #ifdef MNG_OBJECT_BUFFERS
5449 if (mng_info->ob[i] != (MngBuffer *) NULL)
5450 mng_info->ob[i]->frozen=MagickTrue;
5455 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5460 if ((memcmp(type,mng_DISC,4) == 0) || (memcmp(type,mng_SEEK,4) == 0))
5462 /* Read DISC or SEEK. */
5464 if ((length == 0) || !memcmp(type,mng_SEEK,4))
5466 for (i=1; i < MNG_MAX_OBJECTS; i++)
5467 MngInfoDiscardObject(mng_info,i);
5475 for (j=0; j < (ssize_t) length; j+=2)
5477 i=p[j] << 8 | p[j+1];
5478 MngInfoDiscardObject(mng_info,i);
5483 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5488 if (memcmp(type,mng_MOVE,4) == 0)
5496 first_object=(p[0] << 8) | p[1];
5497 last_object=(p[2] << 8) | p[3];
5498 for (i=(ssize_t) first_object; i <= (ssize_t) last_object; i++)
5500 if (mng_info->exists[i] && !mng_info->frozen[i])
5508 old_pair.a=mng_info->x_off[i];
5509 old_pair.b=mng_info->y_off[i];
5510 new_pair=mng_read_pair(old_pair,(int) p[4],&p[5]);
5511 mng_info->x_off[i]=new_pair.a;
5512 mng_info->y_off[i]=new_pair.b;
5516 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5520 if (memcmp(type,mng_LOOP,4) == 0)
5522 ssize_t loop_iters=1;
5523 loop_level=chunk[0];
5524 mng_info->loop_active[loop_level]=1; /* mark loop active */
5526 /* Record starting point. */
5527 loop_iters=mng_get_long(&chunk[1]);
5529 if (logging != MagickFalse)
5530 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5531 " LOOP level %.20g has %.20g iterations ",(double) loop_level,
5532 (double) loop_iters);
5534 if (loop_iters == 0)
5535 skipping_loop=loop_level;
5539 mng_info->loop_jump[loop_level]=TellBlob(image);
5540 mng_info->loop_count[loop_level]=loop_iters;
5543 mng_info->loop_iteration[loop_level]=0;
5544 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5548 if (memcmp(type,mng_ENDL,4) == 0)
5550 loop_level=chunk[0];
5552 if (skipping_loop > 0)
5554 if (skipping_loop == loop_level)
5557 Found end of zero-iteration loop.
5560 mng_info->loop_active[loop_level]=0;
5566 if (mng_info->loop_active[loop_level] == 1)
5568 mng_info->loop_count[loop_level]--;
5569 mng_info->loop_iteration[loop_level]++;
5571 if (logging != MagickFalse)
5572 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5573 " ENDL: LOOP level %.20g has %.20g remaining iters ",
5574 (double) loop_level,(double)
5575 mng_info->loop_count[loop_level]);
5577 if (mng_info->loop_count[loop_level] != 0)
5579 offset=SeekBlob(image,mng_info->loop_jump[loop_level],
5583 ThrowReaderException(CorruptImageError,
5584 "ImproperImageHeader");
5595 mng_info->loop_active[loop_level]=0;
5597 for (i=0; i < loop_level; i++)
5598 if (mng_info->loop_active[i] == 1)
5599 last_level=(short) i;
5600 loop_level=last_level;
5605 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5609 if (memcmp(type,mng_CLON,4) == 0)
5611 if (mng_info->clon_warning == 0)
5612 (void) ThrowMagickException(exception,GetMagickModule(),
5613 CoderError,"CLON is not implemented yet","`%s'",
5616 mng_info->clon_warning++;
5619 if (memcmp(type,mng_MAGN,4) == 0)
5634 magn_first=(p[0] << 8) | p[1];
5640 magn_last=(p[2] << 8) | p[3];
5643 magn_last=magn_first;
5644 #ifndef MNG_OBJECT_BUFFERS
5645 if (magn_first || magn_last)
5646 if (mng_info->magn_warning == 0)
5648 (void) ThrowMagickException(exception,
5649 GetMagickModule(),CoderError,
5650 "MAGN is not implemented yet for nonzero objects",
5651 "`%s'",image->filename);
5653 mng_info->magn_warning++;
5663 magn_mx=(p[5] << 8) | p[6];
5672 magn_my=(p[7] << 8) | p[8];
5681 magn_ml=(p[9] << 8) | p[10];
5690 magn_mr=(p[11] << 8) | p[12];
5699 magn_mt=(p[13] << 8) | p[14];
5708 magn_mb=(p[15] << 8) | p[16];
5720 magn_methy=magn_methx;
5723 if (magn_methx > 5 || magn_methy > 5)
5724 if (mng_info->magn_warning == 0)
5726 (void) ThrowMagickException(exception,
5727 GetMagickModule(),CoderError,
5728 "Unknown MAGN method in MNG datastream","`%s'",
5731 mng_info->magn_warning++;
5733 #ifdef MNG_OBJECT_BUFFERS
5734 /* Magnify existing objects in the range magn_first to magn_last */
5736 if (magn_first == 0 || magn_last == 0)
5738 /* Save the magnification factors for object 0 */
5739 mng_info->magn_mb=magn_mb;
5740 mng_info->magn_ml=magn_ml;
5741 mng_info->magn_mr=magn_mr;
5742 mng_info->magn_mt=magn_mt;
5743 mng_info->magn_mx=magn_mx;
5744 mng_info->magn_my=magn_my;
5745 mng_info->magn_methx=magn_methx;
5746 mng_info->magn_methy=magn_methy;
5750 if (memcmp(type,mng_PAST,4) == 0)
5752 if (mng_info->past_warning == 0)
5753 (void) ThrowMagickException(exception,GetMagickModule(),
5754 CoderError,"PAST is not implemented yet","`%s'",
5757 mng_info->past_warning++;
5760 if (memcmp(type,mng_SHOW,4) == 0)
5762 if (mng_info->show_warning == 0)
5763 (void) ThrowMagickException(exception,GetMagickModule(),
5764 CoderError,"SHOW is not implemented yet","`%s'",
5767 mng_info->show_warning++;
5770 if (memcmp(type,mng_sBIT,4) == 0)
5773 mng_info->have_global_sbit=MagickFalse;
5777 mng_info->global_sbit.gray=p[0];
5778 mng_info->global_sbit.red=p[0];
5779 mng_info->global_sbit.green=p[1];
5780 mng_info->global_sbit.blue=p[2];
5781 mng_info->global_sbit.alpha=p[3];
5782 mng_info->have_global_sbit=MagickTrue;
5785 if (memcmp(type,mng_pHYs,4) == 0)
5789 mng_info->global_x_pixels_per_unit=
5790 (size_t) mng_get_long(p);
5791 mng_info->global_y_pixels_per_unit=
5792 (size_t) mng_get_long(&p[4]);
5793 mng_info->global_phys_unit_type=p[8];
5794 mng_info->have_global_phys=MagickTrue;
5798 mng_info->have_global_phys=MagickFalse;
5800 if (memcmp(type,mng_pHYg,4) == 0)
5802 if (mng_info->phyg_warning == 0)
5803 (void) ThrowMagickException(exception,GetMagickModule(),
5804 CoderError,"pHYg is not implemented.","`%s'",image->filename);
5806 mng_info->phyg_warning++;
5808 if (memcmp(type,mng_BASI,4) == 0)
5810 skip_to_iend=MagickTrue;
5812 if (mng_info->basi_warning == 0)
5813 (void) ThrowMagickException(exception,GetMagickModule(),
5814 CoderError,"BASI is not implemented yet","`%s'",
5817 mng_info->basi_warning++;
5818 #ifdef MNG_BASI_SUPPORTED
5819 basi_width=(size_t) ((p[0] << 24) | (p[1] << 16) |
5820 (p[2] << 8) | p[3]);
5821 basi_height=(size_t) ((p[4] << 24) | (p[5] << 16) |
5822 (p[6] << 8) | p[7]);
5823 basi_color_type=p[8];
5824 basi_compression_method=p[9];
5825 basi_filter_type=p[10];
5826 basi_interlace_method=p[11];
5828 basi_red=(p[12] << 8) & p[13];
5834 basi_green=(p[14] << 8) & p[15];
5840 basi_blue=(p[16] << 8) & p[17];
5846 basi_alpha=(p[18] << 8) & p[19];
5850 if (basi_sample_depth == 16)
5857 basi_viewable=p[20];
5863 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5867 if (memcmp(type,mng_IHDR,4)
5868 #if defined(JNG_SUPPORTED)
5869 && memcmp(type,mng_JHDR,4)
5873 /* Not an IHDR or JHDR chunk */
5875 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5880 if (logging != MagickFalse)
5881 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5882 " Processing %c%c%c%c chunk",type[0],type[1],type[2],type[3]);
5884 mng_info->exists[object_id]=MagickTrue;
5885 mng_info->viewable[object_id]=MagickTrue;
5887 if (mng_info->invisible[object_id])
5889 if (logging != MagickFalse)
5890 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5891 " Skipping invisible object");
5893 skip_to_iend=MagickTrue;
5894 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5897 #if defined(MNG_INSERT_LAYERS)
5899 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
5901 image_width=(size_t) mng_get_long(p);
5902 image_height=(size_t) mng_get_long(&p[4]);
5904 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5907 Insert a transparent background layer behind the entire animation
5908 if it is not full screen.
5910 #if defined(MNG_INSERT_LAYERS)
5911 if (insert_layers && mng_type && first_mng_object)
5913 if ((mng_info->clip.left > 0) || (mng_info->clip.top > 0) ||
5914 (image_width < mng_info->mng_width) ||
5915 (mng_info->clip.right < (ssize_t) mng_info->mng_width) ||
5916 (image_height < mng_info->mng_height) ||
5917 (mng_info->clip.bottom < (ssize_t) mng_info->mng_height))
5919 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
5922 Allocate next image structure.
5924 AcquireNextImage(image_info,image,exception);
5926 if (GetNextImageInList(image) == (Image *) NULL)
5928 image=DestroyImageList(image);
5929 MngInfoFreeStruct(mng_info,&have_mng_structure);
5930 return((Image *) NULL);
5933 image=SyncNextImageInList(image);
5935 mng_info->image=image;
5937 if (term_chunk_found)
5939 image->start_loop=MagickTrue;
5940 image->iterations=mng_iterations;
5941 term_chunk_found=MagickFalse;
5945 image->start_loop=MagickFalse;
5947 /* Make a background rectangle. */
5950 image->columns=mng_info->mng_width;
5951 image->rows=mng_info->mng_height;
5952 image->page.width=mng_info->mng_width;
5953 image->page.height=mng_info->mng_height;
5956 image->background_color=mng_background_color;
5957 (void) SetImageBackgroundColor(image,exception);
5958 if (logging != MagickFalse)
5959 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5960 " Inserted transparent background layer, W=%.20g, H=%.20g",
5961 (double) mng_info->mng_width,(double) mng_info->mng_height);
5965 Insert a background layer behind the upcoming image if
5966 framing_mode is 3, and we haven't already inserted one.
5968 if (insert_layers && (mng_info->framing_mode == 3) &&
5969 (subframe_width) && (subframe_height) && (simplicity == 0 ||
5970 (simplicity & 0x08)))
5972 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
5975 Allocate next image structure.
5977 AcquireNextImage(image_info,image,exception);
5979 if (GetNextImageInList(image) == (Image *) NULL)
5981 image=DestroyImageList(image);
5982 MngInfoFreeStruct(mng_info,&have_mng_structure);
5983 return((Image *) NULL);
5986 image=SyncNextImageInList(image);
5989 mng_info->image=image;
5991 if (term_chunk_found)
5993 image->start_loop=MagickTrue;
5994 image->iterations=mng_iterations;
5995 term_chunk_found=MagickFalse;
5999 image->start_loop=MagickFalse;
6002 image->columns=subframe_width;
6003 image->rows=subframe_height;
6004 image->page.width=subframe_width;
6005 image->page.height=subframe_height;
6006 image->page.x=mng_info->clip.left;
6007 image->page.y=mng_info->clip.top;
6008 image->background_color=mng_background_color;
6009 image->matte=MagickFalse;
6010 (void) SetImageBackgroundColor(image,exception);
6012 if (logging != MagickFalse)
6013 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6014 " Insert background layer, L=%.20g, R=%.20g T=%.20g, B=%.20g",
6015 (double) mng_info->clip.left,(double) mng_info->clip.right,
6016 (double) mng_info->clip.top,(double) mng_info->clip.bottom);
6018 #endif /* MNG_INSERT_LAYERS */
6019 first_mng_object=MagickFalse;
6021 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
6024 Allocate next image structure.
6026 AcquireNextImage(image_info,image,exception);
6028 if (GetNextImageInList(image) == (Image *) NULL)
6030 image=DestroyImageList(image);
6031 MngInfoFreeStruct(mng_info,&have_mng_structure);
6032 return((Image *) NULL);
6035 image=SyncNextImageInList(image);
6037 mng_info->image=image;
6038 status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
6039 GetBlobSize(image));
6041 if (status == MagickFalse)
6044 if (term_chunk_found)
6046 image->start_loop=MagickTrue;
6047 term_chunk_found=MagickFalse;
6051 image->start_loop=MagickFalse;
6053 if (mng_info->framing_mode == 1 || mng_info->framing_mode == 3)
6055 image->delay=frame_delay;
6056 frame_delay=default_frame_delay;
6062 image->page.width=mng_info->mng_width;
6063 image->page.height=mng_info->mng_height;
6064 image->page.x=mng_info->x_off[object_id];
6065 image->page.y=mng_info->y_off[object_id];
6066 image->iterations=mng_iterations;
6069 Seek back to the beginning of the IHDR or JHDR chunk's length field.
6072 if (logging != MagickFalse)
6073 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6074 " Seeking back to beginning of %c%c%c%c chunk",type[0],type[1],
6077 offset=SeekBlob(image,-((ssize_t) length+12),SEEK_CUR);
6080 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
6084 mng_info->image=image;
6085 mng_info->mng_type=mng_type;
6086 mng_info->object_id=object_id;
6088 if (memcmp(type,mng_IHDR,4) == 0)
6089 image=ReadOnePNGImage(mng_info,image_info,exception);
6091 #if defined(JNG_SUPPORTED)
6093 image=ReadOneJNGImage(mng_info,image_info,exception);
6096 if (image == (Image *) NULL)
6098 if (IsImageObject(previous) != MagickFalse)
6100 (void) DestroyImageList(previous);
6101 (void) CloseBlob(previous);
6104 MngInfoFreeStruct(mng_info,&have_mng_structure);
6105 return((Image *) NULL);
6108 if (image->columns == 0 || image->rows == 0)
6110 (void) CloseBlob(image);
6111 image=DestroyImageList(image);
6112 MngInfoFreeStruct(mng_info,&have_mng_structure);
6113 return((Image *) NULL);
6116 mng_info->image=image;
6123 if (mng_info->magn_methx || mng_info->magn_methy)
6129 if (logging != MagickFalse)
6130 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6131 " Processing MNG MAGN chunk");
6133 if (mng_info->magn_methx == 1)
6135 magnified_width=mng_info->magn_ml;
6137 if (image->columns > 1)
6138 magnified_width += mng_info->magn_mr;
6140 if (image->columns > 2)
6141 magnified_width += (png_uint_32)
6142 ((image->columns-2)*(mng_info->magn_mx));
6147 magnified_width=(png_uint_32) image->columns;
6149 if (image->columns > 1)
6150 magnified_width += mng_info->magn_ml-1;
6152 if (image->columns > 2)
6153 magnified_width += mng_info->magn_mr-1;
6155 if (image->columns > 3)
6156 magnified_width += (png_uint_32)
6157 ((image->columns-3)*(mng_info->magn_mx-1));
6160 if (mng_info->magn_methy == 1)
6162 magnified_height=mng_info->magn_mt;
6164 if (image->rows > 1)
6165 magnified_height += mng_info->magn_mb;
6167 if (image->rows > 2)
6168 magnified_height += (png_uint_32)
6169 ((image->rows-2)*(mng_info->magn_my));
6174 magnified_height=(png_uint_32) image->rows;
6176 if (image->rows > 1)
6177 magnified_height += mng_info->magn_mt-1;
6179 if (image->rows > 2)
6180 magnified_height += mng_info->magn_mb-1;
6182 if (image->rows > 3)
6183 magnified_height += (png_uint_32)
6184 ((image->rows-3)*(mng_info->magn_my-1));
6187 if (magnified_height > image->rows ||
6188 magnified_width > image->columns)
6215 /* Allocate next image structure. */
6217 if (logging != MagickFalse)
6218 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6219 " Allocate magnified image");
6221 AcquireNextImage(image_info,image,exception);
6223 if (GetNextImageInList(image) == (Image *) NULL)
6225 image=DestroyImageList(image);
6226 MngInfoFreeStruct(mng_info,&have_mng_structure);
6227 return((Image *) NULL);
6230 large_image=SyncNextImageInList(image);
6232 large_image->columns=magnified_width;
6233 large_image->rows=magnified_height;
6235 magn_methx=mng_info->magn_methx;
6236 magn_methy=mng_info->magn_methy;
6238 #if (MAGICKCORE_QUANTUM_DEPTH > 16)
6239 #define QM unsigned short
6240 if (magn_methx != 1 || magn_methy != 1)
6243 Scale pixels to unsigned shorts to prevent
6244 overflow of intermediate values of interpolations
6246 for (y=0; y < (ssize_t) image->rows; y++)
6248 q=GetAuthenticPixels(image,0,y,image->columns,1,
6251 for (x=(ssize_t) image->columns-1; x >= 0; x--)
6253 SetPixelRed(image,ScaleQuantumToShort(
6254 GetPixelRed(image,q)),q);
6255 SetPixelGreen(image,ScaleQuantumToShort(
6256 GetPixelGreen(image,q)),q);
6257 SetPixelBlue(image,ScaleQuantumToShort(
6258 GetPixelBlue(image,q)),q);
6259 SetPixelAlpha(image,ScaleQuantumToShort(
6260 GetPixelAlpha(image,q)),q);
6261 q+=GetPixelChannels(image);
6264 if (SyncAuthenticPixels(image,exception) == MagickFalse)
6272 if (image->matte != MagickFalse)
6273 (void) SetImageBackgroundColor(large_image,exception);
6277 large_image->background_color.alpha=OpaqueAlpha;
6278 (void) SetImageBackgroundColor(large_image,exception);
6280 if (magn_methx == 4)
6283 if (magn_methx == 5)
6286 if (magn_methy == 4)
6289 if (magn_methy == 5)
6293 /* magnify the rows into the right side of the large image */
6295 if (logging != MagickFalse)
6296 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6297 " Magnify the rows to %.20g",(double) large_image->rows);
6298 m=(ssize_t) mng_info->magn_mt;
6300 length=(size_t) image->columns;
6301 next=(Quantum *) AcquireQuantumMemory(length,sizeof(*next));
6302 prev=(Quantum *) AcquireQuantumMemory(length,sizeof(*prev));
6304 if ((prev == (Quantum *) NULL) ||
6305 (next == (Quantum *) NULL))
6307 image=DestroyImageList(image);
6308 MngInfoFreeStruct(mng_info,&have_mng_structure);
6309 ThrowReaderException(ResourceLimitError,
6310 "MemoryAllocationFailed");
6313 n=GetAuthenticPixels(image,0,0,image->columns,1,exception);
6314 (void) CopyMagickMemory(next,n,length);
6316 for (y=0; y < (ssize_t) image->rows; y++)
6319 m=(ssize_t) mng_info->magn_mt;
6321 else if (magn_methy > 1 && y == (ssize_t) image->rows-2)
6322 m=(ssize_t) mng_info->magn_mb;
6324 else if (magn_methy <= 1 && y == (ssize_t) image->rows-1)
6325 m=(ssize_t) mng_info->magn_mb;
6327 else if (magn_methy > 1 && y == (ssize_t) image->rows-1)
6331 m=(ssize_t) mng_info->magn_my;
6337 if (y < (ssize_t) image->rows-1)
6339 n=GetAuthenticPixels(image,0,y+1,image->columns,1,
6341 (void) CopyMagickMemory(next,n,length);
6344 for (i=0; i < m; i++, yy++)
6349 assert(yy < (ssize_t) large_image->rows);
6352 q=GetAuthenticPixels(large_image,0,yy,large_image->columns,
6354 q+=(large_image->columns-image->columns);
6356 for (x=(ssize_t) image->columns-1; x >= 0; x--)
6358 /* To do: get color as function of indexes[x] */
6360 if (image->storage_class == PseudoClass)
6365 if (magn_methy <= 1)
6367 /* replicate previous */
6368 SetPixelRed(large_image,GetPixelRed(image,pixels),q);
6369 SetPixelGreen(large_image,GetPixelGreen(image,
6371 SetPixelBlue(large_image,GetPixelBlue(image,
6373 SetPixelAlpha(large_image,GetPixelAlpha(image,
6377 else if (magn_methy == 2 || magn_methy == 4)
6381 SetPixelRed(large_image,GetPixelRed(image,
6383 SetPixelGreen(large_image,GetPixelGreen(image,
6385 SetPixelBlue(large_image,GetPixelBlue(image,
6387 SetPixelAlpha(large_image,GetPixelAlpha(image,
6394 SetPixelRed(large_image,((QM) (((ssize_t)
6395 (2*i*(GetPixelRed(image,n)
6396 -GetPixelRed(image,pixels)+m))/
6398 +GetPixelRed(image,pixels)))),q);
6399 SetPixelGreen(large_image,((QM) (((ssize_t)
6400 (2*i*(GetPixelGreen(image,n)
6401 -GetPixelGreen(image,pixels)+m))/
6403 +GetPixelGreen(image,pixels)))),q);
6404 SetPixelBlue(large_image,((QM) (((ssize_t)
6405 (2*i*(GetPixelBlue(image,n)
6406 -GetPixelBlue(image,pixels)+m))/
6408 +GetPixelBlue(image,pixels)))),q);
6410 if (image->matte != MagickFalse)
6411 SetPixelAlpha(large_image, ((QM) (((ssize_t)
6412 (2*i*(GetPixelAlpha(image,n)
6413 -GetPixelAlpha(image,pixels)+m))
6415 GetPixelAlpha(image,pixels)))),q);
6418 if (magn_methy == 4)
6420 /* Replicate nearest */
6421 if (i <= ((m+1) << 1))
6422 SetPixelAlpha(large_image,GetPixelAlpha(image,
6425 SetPixelAlpha(large_image,GetPixelAlpha(image,
6430 else /* if (magn_methy == 3 || magn_methy == 5) */
6432 /* Replicate nearest */
6433 if (i <= ((m+1) << 1))
6435 SetPixelRed(large_image,GetPixelRed(image,
6437 SetPixelGreen(large_image,GetPixelGreen(image,
6439 SetPixelBlue(large_image,GetPixelBlue(image,
6441 SetPixelAlpha(large_image,GetPixelAlpha(image,
6447 SetPixelRed(large_image,GetPixelRed(image,n),q);
6448 SetPixelGreen(large_image,GetPixelGreen(image,n),
6450 SetPixelBlue(large_image,GetPixelBlue(image,n),
6452 SetPixelAlpha(large_image,GetPixelAlpha(image,n),
6456 if (magn_methy == 5)
6458 SetPixelAlpha(large_image,(QM) (((ssize_t) (2*i*
6459 (GetPixelAlpha(image,n)
6460 -GetPixelAlpha(image,pixels))
6461 +m))/((ssize_t) (m*2))
6462 +GetPixelAlpha(image,pixels)),q);
6465 n+=GetPixelChannels(image);
6466 q+=GetPixelChannels(large_image);
6467 pixels+=GetPixelChannels(image);
6470 if (SyncAuthenticPixels(large_image,exception) == 0)
6476 prev=(Quantum *) RelinquishMagickMemory(prev);
6477 next=(Quantum *) RelinquishMagickMemory(next);
6479 length=image->columns;
6481 if (logging != MagickFalse)
6482 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6483 " Delete original image");
6485 DeleteImageFromList(&image);
6489 mng_info->image=image;
6491 /* magnify the columns */
6492 if (logging != MagickFalse)
6493 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6494 " Magnify the columns to %.20g",(double) image->columns);
6496 for (y=0; y < (ssize_t) image->rows; y++)
6501 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
6502 pixels=q+(image->columns-length)*GetPixelChannels(image);
6503 n=pixels+GetPixelChannels(image);
6505 for (x=(ssize_t) (image->columns-length);
6506 x < (ssize_t) image->columns; x++)
6508 /* To do: Rewrite using Get/Set***PixelChannel() */
6510 if (x == (ssize_t) (image->columns-length))
6511 m=(ssize_t) mng_info->magn_ml;
6513 else if (magn_methx > 1 && x == (ssize_t) image->columns-2)
6514 m=(ssize_t) mng_info->magn_mr;
6516 else if (magn_methx <= 1 && x == (ssize_t) image->columns-1)
6517 m=(ssize_t) mng_info->magn_mr;
6519 else if (magn_methx > 1 && x == (ssize_t) image->columns-1)
6523 m=(ssize_t) mng_info->magn_mx;
6525 for (i=0; i < m; i++)
6527 if (magn_methx <= 1)
6529 /* replicate previous */
6530 SetPixelRed(image,GetPixelRed(image,pixels),q);
6531 SetPixelGreen(image,GetPixelGreen(image,pixels),q);
6532 SetPixelBlue(image,GetPixelBlue(image,pixels),q);
6533 SetPixelAlpha(image,GetPixelAlpha(image,pixels),q);
6536 else if (magn_methx == 2 || magn_methx == 4)
6540 SetPixelRed(image,GetPixelRed(image,pixels),q);
6541 SetPixelGreen(image,GetPixelGreen(image,pixels),q);
6542 SetPixelBlue(image,GetPixelBlue(image,pixels),q);
6543 SetPixelAlpha(image,GetPixelAlpha(image,pixels),q);
6546 /* To do: Rewrite using Get/Set***PixelChannel() */
6550 SetPixelRed(image,(QM) ((2*i*(
6551 GetPixelRed(image,n)
6552 -GetPixelRed(image,pixels))+m)
6554 GetPixelRed(image,pixels)),q);
6556 SetPixelGreen(image,(QM) ((2*i*(
6557 GetPixelGreen(image,n)
6558 -GetPixelGreen(image,pixels))+m)
6560 GetPixelGreen(image,pixels)),q);
6562 SetPixelBlue(image,(QM) ((2*i*(
6563 GetPixelBlue(image,n)
6564 -GetPixelBlue(image,pixels))+m)
6566 GetPixelBlue(image,pixels)),q);
6567 if (image->matte != MagickFalse)
6568 SetPixelAlpha(image,(QM) ((2*i*(
6569 GetPixelAlpha(image,n)
6570 -GetPixelAlpha(image,pixels))+m)
6572 GetPixelAlpha(image,pixels)),q);
6575 if (magn_methx == 4)
6577 /* Replicate nearest */
6578 if (i <= ((m+1) << 1))
6580 SetPixelAlpha(image,
6581 GetPixelAlpha(image,pixels)+0,q);
6585 SetPixelAlpha(image,
6586 GetPixelAlpha(image,n)+0,q);
6591 else /* if (magn_methx == 3 || magn_methx == 5) */
6593 /* Replicate nearest */
6594 if (i <= ((m+1) << 1))
6596 SetPixelRed(image,GetPixelRed(image,pixels),q);
6597 SetPixelGreen(image,GetPixelGreen(image,pixels),q);
6598 SetPixelBlue(image,GetPixelBlue(image,pixels),q);
6599 SetPixelAlpha(image,GetPixelAlpha(image,pixels),q);
6604 SetPixelRed(image,GetPixelRed(image,n),q);
6605 SetPixelGreen(image,GetPixelGreen(image,n),q);
6606 SetPixelBlue(image,GetPixelBlue(image,n),q);
6607 SetPixelAlpha(image,GetPixelAlpha(image,n),q);
6610 if (magn_methx == 5)
6613 SetPixelAlpha(image,
6614 (QM) ((2*i*( GetPixelAlpha(image,n)
6615 -GetPixelAlpha(image,pixels))+m)/
6617 +GetPixelAlpha(image,pixels)),q);
6620 q+=GetPixelChannels(image);
6622 n+=GetPixelChannels(image);
6623 p+=GetPixelChannels(image);
6626 if (SyncAuthenticPixels(image,exception) == MagickFalse)
6629 #if (MAGICKCORE_QUANTUM_DEPTH > 16)
6630 if (magn_methx != 1 || magn_methy != 1)
6633 Rescale pixels to Quantum
6635 for (y=0; y < (ssize_t) image->rows; y++)
6637 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
6639 for (x=(ssize_t) image->columns-1; x >= 0; x--)
6641 SetPixelRed(image,ScaleShortToQuantum(
6642 GetPixelRed(image,q)),q);
6643 SetPixelGreen(image,ScaleShortToQuantum(
6644 GetPixelGreen(image,q)),q);
6645 SetPixelBlue(image,ScaleShortToQuantum(
6646 GetPixelBlue(image,q)),q);
6647 SetPixelAlpha(image,ScaleShortToQuantum(
6648 GetPixelAlpha(image,q)),q);
6649 q+=GetPixelChannels(image);
6652 if (SyncAuthenticPixels(image,exception) == MagickFalse)
6657 if (logging != MagickFalse)
6658 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6659 " Finished MAGN processing");
6664 Crop_box is with respect to the upper left corner of the MNG.
6666 crop_box.left=mng_info->image_box.left+mng_info->x_off[object_id];
6667 crop_box.right=mng_info->image_box.right+mng_info->x_off[object_id];
6668 crop_box.top=mng_info->image_box.top+mng_info->y_off[object_id];
6669 crop_box.bottom=mng_info->image_box.bottom+mng_info->y_off[object_id];
6670 crop_box=mng_minimum_box(crop_box,mng_info->clip);
6671 crop_box=mng_minimum_box(crop_box,mng_info->frame);
6672 crop_box=mng_minimum_box(crop_box,mng_info->object_clip[object_id]);
6673 if ((crop_box.left != (mng_info->image_box.left
6674 +mng_info->x_off[object_id])) ||
6675 (crop_box.right != (mng_info->image_box.right
6676 +mng_info->x_off[object_id])) ||
6677 (crop_box.top != (mng_info->image_box.top
6678 +mng_info->y_off[object_id])) ||
6679 (crop_box.bottom != (mng_info->image_box.bottom
6680 +mng_info->y_off[object_id])))
6682 if (logging != MagickFalse)
6683 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6684 " Crop the PNG image");
6686 if ((crop_box.left < crop_box.right) &&
6687 (crop_box.top < crop_box.bottom))
6696 Crop_info is with respect to the upper left corner of
6699 crop_info.x=(crop_box.left-mng_info->x_off[object_id]);
6700 crop_info.y=(crop_box.top-mng_info->y_off[object_id]);
6701 crop_info.width=(size_t) (crop_box.right-crop_box.left);
6702 crop_info.height=(size_t) (crop_box.bottom-crop_box.top);
6703 image->page.width=image->columns;
6704 image->page.height=image->rows;
6707 im=CropImage(image,&crop_info,exception);
6709 if (im != (Image *) NULL)
6711 image->columns=im->columns;
6712 image->rows=im->rows;
6713 im=DestroyImage(im);
6714 image->page.width=image->columns;
6715 image->page.height=image->rows;
6716 image->page.x=crop_box.left;
6717 image->page.y=crop_box.top;
6724 No pixels in crop area. The MNG spec still requires
6725 a layer, though, so make a single transparent pixel in
6726 the top left corner.
6731 (void) SetImageBackgroundColor(image,exception);
6732 image->page.width=1;
6733 image->page.height=1;
6738 #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
6739 image=mng_info->image;
6743 #if (MAGICKCORE_QUANTUM_DEPTH > 16)
6744 /* PNG does not handle depths greater than 16 so reduce it even
6747 if (image->depth > 16)
6751 #if (MAGICKCORE_QUANTUM_DEPTH > 8)
6752 if (LosslessReduceDepthOK(image,exception) != MagickFalse)
6756 if (image_info->number_scenes != 0)
6758 if (mng_info->scenes_found >
6759 (ssize_t) (image_info->first_scene+image_info->number_scenes))
6763 if (logging != MagickFalse)
6764 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6765 " Finished reading image datastream.");
6767 } while (LocaleCompare(image_info->magick,"MNG") == 0);
6769 (void) CloseBlob(image);
6771 if (logging != MagickFalse)
6772 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6773 " Finished reading all image datastreams.");
6775 #if defined(MNG_INSERT_LAYERS)
6776 if (insert_layers && !mng_info->image_found && (mng_info->mng_width) &&
6777 (mng_info->mng_height))
6780 Insert a background layer if nothing else was found.
6782 if (logging != MagickFalse)
6783 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6784 " No images found. Inserting a background layer.");
6786 if (GetAuthenticPixelQueue(image) != (Quantum *) NULL)
6789 Allocate next image structure.
6791 AcquireNextImage(image_info,image,exception);
6792 if (GetNextImageInList(image) == (Image *) NULL)
6794 image=DestroyImageList(image);
6795 MngInfoFreeStruct(mng_info,&have_mng_structure);
6797 if (logging != MagickFalse)
6798 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6799 " Allocation failed, returning NULL.");
6801 return((Image *) NULL);
6803 image=SyncNextImageInList(image);
6805 image->columns=mng_info->mng_width;
6806 image->rows=mng_info->mng_height;
6807 image->page.width=mng_info->mng_width;
6808 image->page.height=mng_info->mng_height;
6811 image->background_color=mng_background_color;
6812 image->matte=MagickFalse;
6814 if (image_info->ping == MagickFalse)
6815 (void) SetImageBackgroundColor(image,exception);
6817 mng_info->image_found++;
6820 image->iterations=mng_iterations;
6822 if (mng_iterations == 1)
6823 image->start_loop=MagickTrue;
6825 while (GetPreviousImageInList(image) != (Image *) NULL)
6828 if (image_count > 10*mng_info->image_found)
6830 if (logging != MagickFalse)
6831 (void) LogMagickEvent(CoderEvent,GetMagickModule()," No beginning");
6833 (void) ThrowMagickException(exception,GetMagickModule(),
6834 CoderError,"Linked list is corrupted, beginning of list not found",
6835 "`%s'",image_info->filename);
6837 return((Image *) NULL);
6840 image=GetPreviousImageInList(image);
6842 if (GetNextImageInList(image) == (Image *) NULL)
6844 if (logging != MagickFalse)
6845 (void) LogMagickEvent(CoderEvent,GetMagickModule()," Corrupt list");
6847 (void) ThrowMagickException(exception,GetMagickModule(),
6848 CoderError,"Linked list is corrupted; next_image is NULL","`%s'",
6849 image_info->filename);
6853 if (mng_info->ticks_per_second && mng_info->image_found > 1 &&
6854 GetNextImageInList(image) ==
6857 if (logging != MagickFalse)
6858 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6859 " First image null");
6861 (void) ThrowMagickException(exception,GetMagickModule(),
6862 CoderError,"image->next for first image is NULL but shouldn't be.",
6863 "`%s'",image_info->filename);
6866 if (mng_info->image_found == 0)
6868 if (logging != MagickFalse)
6869 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6870 " No visible images found.");
6872 (void) ThrowMagickException(exception,GetMagickModule(),
6873 CoderError,"No visible images in file","`%s'",image_info->filename);
6875 if (image != (Image *) NULL)
6876 image=DestroyImageList(image);
6878 MngInfoFreeStruct(mng_info,&have_mng_structure);
6879 return((Image *) NULL);
6882 if (mng_info->ticks_per_second)
6883 final_delay=1UL*MagickMax(image->ticks_per_second,1L)*
6884 final_delay/mng_info->ticks_per_second;
6887 image->start_loop=MagickTrue;
6889 /* Find final nonzero image delay */
6890 final_image_delay=0;
6892 while (GetNextImageInList(image) != (Image *) NULL)
6895 final_image_delay=image->delay;
6897 image=GetNextImageInList(image);
6900 if (final_delay < final_image_delay)
6901 final_delay=final_image_delay;
6903 image->delay=final_delay;
6905 if (logging != MagickFalse)
6906 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6907 " image->delay=%.20g, final_delay=%.20g",(double) image->delay,
6908 (double) final_delay);
6910 if (logging != MagickFalse)
6916 image=GetFirstImageInList(image);
6918 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6919 " Before coalesce:");
6921 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6922 " scene 0 delay=%.20g",(double) image->delay);
6924 while (GetNextImageInList(image) != (Image *) NULL)
6926 image=GetNextImageInList(image);
6927 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6928 " scene %.20g delay=%.20g",(double) scene++,(double) image->delay);
6932 image=GetFirstImageInList(image);
6933 #ifdef MNG_COALESCE_LAYERS
6943 if (logging != MagickFalse)
6944 (void) LogMagickEvent(CoderEvent,GetMagickModule()," Coalesce Images");
6947 next_image=CoalesceImages(image,exception);
6949 if (next_image == (Image *) NULL)
6950 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
6952 image=DestroyImageList(image);
6955 for (next=image; next != (Image *) NULL; next=next_image)
6957 next->page.width=mng_info->mng_width;
6958 next->page.height=mng_info->mng_height;
6961 next->scene=scene++;
6962 next_image=GetNextImageInList(next);
6964 if (next_image == (Image *) NULL)
6967 if (next->delay == 0)
6970 next_image->previous=GetPreviousImageInList(next);
6971 if (GetPreviousImageInList(next) == (Image *) NULL)
6974 next->previous->next=next_image;
6975 next=DestroyImage(next);
6981 while (GetNextImageInList(image) != (Image *) NULL)
6982 image=GetNextImageInList(image);
6984 image->dispose=BackgroundDispose;
6986 if (logging != MagickFalse)
6992 image=GetFirstImageInList(image);
6994 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6995 " After coalesce:");
6997 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6998 " scene 0 delay=%.20g dispose=%.20g",(double) image->delay,
6999 (double) image->dispose);
7001 while (GetNextImageInList(image) != (Image *) NULL)
7003 image=GetNextImageInList(image);
7005 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7006 " scene %.20g delay=%.20g dispose=%.20g",(double) scene++,
7007 (double) image->delay,(double) image->dispose);
7011 image=GetFirstImageInList(image);
7012 MngInfoFreeStruct(mng_info,&have_mng_structure);
7013 have_mng_structure=MagickFalse;
7015 if (logging != MagickFalse)
7016 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit ReadMNGImage()");
7018 return(GetFirstImageInList(image));
7020 #else /* PNG_LIBPNG_VER > 10011 */
7021 static Image *ReadPNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
7023 printf("Your PNG library is too old: You have libpng-%s\n",
7024 PNG_LIBPNG_VER_STRING);
7026 (void) ThrowMagickException(exception,GetMagickModule(),CoderError,
7027 "PNG library is too old","`%s'",image_info->filename);
7029 return(Image *) NULL;
7032 static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
7034 return(ReadPNGImage(image_info,exception));
7036 #endif /* PNG_LIBPNG_VER > 10011 */
7040 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7044 % R e g i s t e r P N G I m a g e %
7048 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7050 % RegisterPNGImage() adds properties for the PNG image format to
7051 % the list of supported formats. The properties include the image format
7052 % tag, a method to read and/or write the format, whether the format
7053 % supports the saving of more than one frame to the same file or blob,
7054 % whether the format supports native in-memory I/O, and a brief
7055 % description of the format.
7057 % The format of the RegisterPNGImage method is:
7059 % size_t RegisterPNGImage(void)
7062 ModuleExport size_t RegisterPNGImage(void)
7065 version[MaxTextExtent];
7073 "See http://www.libpng.org/ for details about the PNG format."
7078 "See http://www.libpng.org/pub/mng/ for details about the JNG\n"
7084 "See http://www.libpng.org/pub/mng/ for details about the MNG\n"
7090 #if defined(PNG_LIBPNG_VER_STRING)
7091 (void) ConcatenateMagickString(version,"libpng ",MaxTextExtent);
7092 (void) ConcatenateMagickString(version,PNG_LIBPNG_VER_STRING,MaxTextExtent);
7094 if (LocaleCompare(PNG_LIBPNG_VER_STRING,png_get_header_ver(NULL)) != 0)
7096 (void) ConcatenateMagickString(version,",",MaxTextExtent);
7097 (void) ConcatenateMagickString(version,png_get_libpng_ver(NULL),
7102 entry=SetMagickInfo("MNG");
7103 entry->seekable_stream=MagickTrue; /* To do: eliminate this. */
7105 #if defined(MAGICKCORE_PNG_DELEGATE)
7106 entry->decoder=(DecodeImageHandler *) ReadMNGImage;
7107 entry->encoder=(EncodeImageHandler *) WriteMNGImage;
7110 entry->magick=(IsImageFormatHandler *) IsMNG;
7111 entry->description=ConstantString("Multiple-image Network Graphics");
7113 if (*version != '\0')
7114 entry->version=ConstantString(version);
7116 entry->module=ConstantString("PNG");
7117 entry->note=ConstantString(MNGNote);
7118 (void) RegisterMagickInfo(entry);
7120 entry=SetMagickInfo("PNG");
7122 #if defined(MAGICKCORE_PNG_DELEGATE)
7123 entry->decoder=(DecodeImageHandler *) ReadPNGImage;
7124 entry->encoder=(EncodeImageHandler *) WritePNGImage;
7127 entry->magick=(IsImageFormatHandler *) IsPNG;
7128 entry->adjoin=MagickFalse;
7129 entry->description=ConstantString("Portable Network Graphics");
7130 entry->module=ConstantString("PNG");
7132 if (*version != '\0')
7133 entry->version=ConstantString(version);
7135 entry->note=ConstantString(PNGNote);
7136 (void) RegisterMagickInfo(entry);
7138 entry=SetMagickInfo("PNG8");
7140 #if defined(MAGICKCORE_PNG_DELEGATE)
7141 entry->decoder=(DecodeImageHandler *) ReadPNGImage;
7142 entry->encoder=(EncodeImageHandler *) WritePNGImage;
7145 entry->magick=(IsImageFormatHandler *) IsPNG;
7146 entry->adjoin=MagickFalse;
7147 entry->description=ConstantString(
7148 "8-bit indexed with optional binary transparency");
7149 entry->module=ConstantString("PNG");
7150 (void) RegisterMagickInfo(entry);
7152 entry=SetMagickInfo("PNG24");
7155 #if defined(ZLIB_VERSION)
7156 (void) ConcatenateMagickString(version,"zlib ",MaxTextExtent);
7157 (void) ConcatenateMagickString(version,ZLIB_VERSION,MaxTextExtent);
7159 if (LocaleCompare(ZLIB_VERSION,zlib_version) != 0)
7161 (void) ConcatenateMagickString(version,",",MaxTextExtent);
7162 (void) ConcatenateMagickString(version,zlib_version,MaxTextExtent);
7166 if (*version != '\0')
7167 entry->version=ConstantString(version);
7169 #if defined(MAGICKCORE_PNG_DELEGATE)
7170 entry->decoder=(DecodeImageHandler *) ReadPNGImage;
7171 entry->encoder=(EncodeImageHandler *) WritePNGImage;
7174 entry->magick=(IsImageFormatHandler *) IsPNG;
7175 entry->adjoin=MagickFalse;
7176 entry->description=ConstantString("opaque 24-bit RGB");
7177 entry->module=ConstantString("PNG");
7178 (void) RegisterMagickInfo(entry);
7180 entry=SetMagickInfo("PNG32");
7182 #if defined(MAGICKCORE_PNG_DELEGATE)
7183 entry->decoder=(DecodeImageHandler *) ReadPNGImage;
7184 entry->encoder=(EncodeImageHandler *) WritePNGImage;
7187 entry->magick=(IsImageFormatHandler *) IsPNG;
7188 entry->adjoin=MagickFalse;
7189 entry->description=ConstantString("opaque or transparent 32-bit RGBA");
7190 entry->module=ConstantString("PNG");
7191 (void) RegisterMagickInfo(entry);
7193 entry=SetMagickInfo("JNG");
7195 #if defined(JNG_SUPPORTED)
7196 #if defined(MAGICKCORE_PNG_DELEGATE)
7197 entry->decoder=(DecodeImageHandler *) ReadJNGImage;
7198 entry->encoder=(EncodeImageHandler *) WriteJNGImage;
7202 entry->magick=(IsImageFormatHandler *) IsJNG;
7203 entry->adjoin=MagickFalse;
7204 entry->description=ConstantString("JPEG Network Graphics");
7205 entry->module=ConstantString("PNG");
7206 entry->note=ConstantString(JNGNote);
7207 (void) RegisterMagickInfo(entry);
7209 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
7210 ping_semaphore=AllocateSemaphoreInfo();
7213 return(MagickImageCoderSignature);
7217 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7221 % U n r e g i s t e r P N G I m a g e %
7225 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7227 % UnregisterPNGImage() removes format registrations made by the
7228 % PNG module from the list of supported formats.
7230 % The format of the UnregisterPNGImage method is:
7232 % UnregisterPNGImage(void)
7235 ModuleExport void UnregisterPNGImage(void)
7237 (void) UnregisterMagickInfo("MNG");
7238 (void) UnregisterMagickInfo("PNG");
7239 (void) UnregisterMagickInfo("PNG8");
7240 (void) UnregisterMagickInfo("PNG24");
7241 (void) UnregisterMagickInfo("PNG32");
7242 (void) UnregisterMagickInfo("JNG");
7244 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
7245 if (ping_semaphore != (SemaphoreInfo *) NULL)
7246 DestroySemaphoreInfo(&ping_semaphore);
7250 #if defined(MAGICKCORE_PNG_DELEGATE)
7251 #if PNG_LIBPNG_VER > 10011
7253 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7257 % W r i t e M N G I m a g e %
7261 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7263 % WriteMNGImage() writes an image in the Portable Network Graphics
7264 % Group's "Multiple-image Network Graphics" encoded image format.
7266 % MNG support written by Glenn Randers-Pehrson, glennrp@image...
7268 % The format of the WriteMNGImage method is:
7270 % MagickBooleanType WriteMNGImage(const ImageInfo *image_info,
7271 % Image *image,ExceptionInfo *exception)
7273 % A description of each parameter follows.
7275 % o image_info: the image info.
7277 % o image: The image.
7279 % o exception: return any errors or warnings in this structure.
7281 % To do (as of version 5.5.2, November 26, 2002 -- glennrp -- see also
7282 % "To do" under ReadPNGImage):
7284 % Preserve all unknown and not-yet-handled known chunks found in input
7285 % PNG file and copy them into output PNG files according to the PNG
7288 % Write the iCCP chunk at MNG level when (icc profile length > 0)
7290 % Improve selection of color type (use indexed-colour or indexed-colour
7291 % with tRNS when 256 or fewer unique RGBA values are present).
7293 % Figure out what to do with "dispose=<restore-to-previous>" (dispose == 3)
7294 % This will be complicated if we limit ourselves to generating MNG-LC
7295 % files. For now we ignore disposal method 3 and simply overlay the next
7298 % Check for identical PLTE's or PLTE/tRNS combinations and use a
7299 % global MNG PLTE or PLTE/tRNS combination when appropriate.
7300 % [mostly done 15 June 1999 but still need to take care of tRNS]
7302 % Check for identical sRGB and replace with a global sRGB (and remove
7303 % gAMA/cHRM if sRGB is found; check for identical gAMA/cHRM and
7304 % replace with global gAMA/cHRM (or with sRGB if appropriate; replace
7305 % local gAMA/cHRM with local sRGB if appropriate).
7307 % Check for identical sBIT chunks and write global ones.
7309 % Provide option to skip writing the signature tEXt chunks.
7311 % Use signatures to detect identical objects and reuse the first
7312 % instance of such objects instead of writing duplicate objects.
7314 % Use a smaller-than-32k value of compression window size when
7317 % Encode JNG datastreams. Mostly done as of 5.5.2; need to write
7318 % ancillary text chunks and save profiles.
7320 % Provide an option to force LC files (to ensure exact framing rate)
7323 % Provide an option to force VLC files instead of LC, even when offsets
7324 % are present. This will involve expanding the embedded images with a
7325 % transparent region at the top and/or left.
7329 Magick_png_write_raw_profile(const ImageInfo *image_info,png_struct *ping,
7330 png_info *ping_info, unsigned char *profile_type, unsigned char
7331 *profile_description, unsigned char *profile_data, png_uint_32 length)
7350 hex[16]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
7352 if (LocaleNCompare((char *) profile_type+1, "ng-chunk-",9) == 0)
7355 if (image_info->verbose)
7357 (void) printf("writing raw profile: type=%s, length=%.20g\n",
7358 (char *) profile_type, (double) length);
7361 text=(png_textp) png_malloc(ping,(png_uint_32) sizeof(png_text));
7362 description_length=(png_uint_32) strlen((const char *) profile_description);
7363 allocated_length=(png_uint_32) (length*2 + (length >> 5) + 20
7364 + description_length);
7365 text[0].text=(png_charp) png_malloc(ping,allocated_length);
7366 text[0].key=(png_charp) png_malloc(ping, (png_uint_32) 80);
7367 text[0].key[0]='\0';
7368 (void) ConcatenateMagickString(text[0].key,
7369 "Raw profile type ",MaxTextExtent);
7370 (void) ConcatenateMagickString(text[0].key,(const char *) profile_type,62);
7374 (void) CopyMagickString(dp,(const char *) profile_description,
7376 dp+=description_length;
7378 (void) FormatLocaleString(dp,allocated_length-
7379 (png_size_t) (dp-text[0].text),"%8lu ",(unsigned long) length);
7382 for (i=0; i < (ssize_t) length; i++)
7386 *(dp++)=(char) hex[((*sp >> 4) & 0x0f)];
7387 *(dp++)=(char) hex[((*sp++ ) & 0x0f)];
7392 text[0].text_length=(png_size_t) (dp-text[0].text);
7393 text[0].compression=image_info->compression == NoCompression ||
7394 (image_info->compression == UndefinedCompression &&
7395 text[0].text_length < 128) ? -1 : 0;
7397 if (text[0].text_length <= allocated_length)
7398 png_set_text(ping,ping_info,text,1);
7400 png_free(ping,text[0].text);
7401 png_free(ping,text[0].key);
7402 png_free(ping,text);
7405 static MagickBooleanType Magick_png_write_chunk_from_profile(Image *image,
7406 const char *string, MagickBooleanType logging)
7419 ResetImageProfileIterator(image);
7421 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
7423 profile=GetImageProfile(image,name);
7425 if (profile != (const StringInfo *) NULL)
7430 if (LocaleNCompare(name,string,11) == 0)
7432 if (logging != MagickFalse)
7433 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7434 " Found %s profile",name);
7436 ping_profile=CloneStringInfo(profile);
7437 data=GetStringInfoDatum(ping_profile),
7438 length=(png_uint_32) GetStringInfoLength(ping_profile);
7443 (void) WriteBlobMSBULong(image,length-5); /* data length */
7444 (void) WriteBlob(image,length-1,data+1);
7445 (void) WriteBlobMSBULong(image,crc32(0,data+1,(uInt) length-1));
7446 ping_profile=DestroyStringInfo(ping_profile);
7450 name=GetNextImageProfile(image);
7457 /* Write one PNG image */
7458 static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
7459 const ImageInfo *IMimage_info,Image *IMimage,ExceptionInfo *exception)
7483 ping_trans_alpha[256];
7511 ping_have_cheap_transparency,
7522 /* ping_exclude_EXIF, */
7525 /* ping_exclude_iTXt, */
7530 /* ping_exclude_tRNS, */
7532 ping_exclude_zCCP, /* hex-encoded iCCP */
7535 ping_preserve_colormap,
7536 ping_need_colortype_warning,
7560 ping_interlace_method,
7561 ping_compression_method,
7578 number_semitransparent,
7580 ping_pHYs_unit_type;
7583 ping_pHYs_x_resolution,
7584 ping_pHYs_y_resolution;
7586 logging=LogMagickEvent(CoderEvent,GetMagickModule(),
7587 " Enter WriteOnePNGImage()");
7589 image = CloneImage(IMimage,0,0,MagickFalse,exception);
7590 image_info=(ImageInfo *) CloneImageInfo(IMimage_info);
7591 if (image_info == (ImageInfo *) NULL)
7592 ThrowWriterException(ResourceLimitError, "MemoryAllocationFailed");
7594 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
7595 LockSemaphoreInfo(ping_semaphore);
7598 /* Initialize some stuff */
7601 ping_interlace_method=0,
7602 ping_compression_method=0,
7603 ping_filter_method=0,
7606 ping_background.red = 0;
7607 ping_background.green = 0;
7608 ping_background.blue = 0;
7609 ping_background.gray = 0;
7610 ping_background.index = 0;
7612 ping_trans_color.red=0;
7613 ping_trans_color.green=0;
7614 ping_trans_color.blue=0;
7615 ping_trans_color.gray=0;
7617 ping_pHYs_unit_type = 0;
7618 ping_pHYs_x_resolution = 0;
7619 ping_pHYs_y_resolution = 0;
7621 ping_have_blob=MagickFalse;
7622 ping_have_color=MagickTrue;
7623 ping_have_non_bw=MagickTrue;
7624 ping_have_PLTE=MagickFalse;
7625 ping_have_bKGD=MagickFalse;
7626 ping_have_pHYs=MagickFalse;
7627 ping_have_tRNS=MagickFalse;
7629 ping_exclude_bKGD=mng_info->ping_exclude_bKGD;
7630 ping_exclude_cHRM=mng_info->ping_exclude_cHRM;
7631 ping_exclude_date=mng_info->ping_exclude_date;
7632 /* ping_exclude_EXIF=mng_info->ping_exclude_EXIF; */
7633 ping_exclude_gAMA=mng_info->ping_exclude_gAMA;
7634 ping_exclude_iCCP=mng_info->ping_exclude_iCCP;
7635 /* ping_exclude_iTXt=mng_info->ping_exclude_iTXt; */
7636 ping_exclude_oFFs=mng_info->ping_exclude_oFFs;
7637 ping_exclude_pHYs=mng_info->ping_exclude_pHYs;
7638 ping_exclude_sRGB=mng_info->ping_exclude_sRGB;
7639 ping_exclude_tEXt=mng_info->ping_exclude_tEXt;
7640 /* ping_exclude_tRNS=mng_info->ping_exclude_tRNS; */
7641 ping_exclude_vpAg=mng_info->ping_exclude_vpAg;
7642 ping_exclude_zCCP=mng_info->ping_exclude_zCCP; /* hex-encoded iCCP in zTXt */
7643 ping_exclude_zTXt=mng_info->ping_exclude_zTXt;
7645 ping_preserve_colormap = mng_info->ping_preserve_colormap;
7646 ping_need_colortype_warning = MagickFalse;
7648 /* Recognize the ICC sRGB profile and convert it to the sRGB chunk,
7649 * i.e., eliminate the ICC profile and set image->rendering_intent.
7650 * Note that this will not involve any changes to the actual pixels
7651 * but merely passes information to applications that read the resulting
7654 if (ping_exclude_sRGB == MagickFalse)
7662 ResetImageProfileIterator(image);
7663 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
7665 profile=GetImageProfile(image,name);
7667 if (profile != (StringInfo *) NULL)
7669 if ((LocaleCompare(name,"ICC") == 0) ||
7670 (LocaleCompare(name,"ICM") == 0))
7675 /* 0: not a known sRGB profile
7676 * 1: HP-Microsoft sRGB v2
7677 * 2: ICC sRGB v4 perceptual
7678 * 3: ICC sRGB v2 perceptual no black-compensation
7681 check_crc[4] = {0, 0xf29e526dUL, 0xbbef7812UL, 0x427ebb21UL},
7682 check_len[4] = {0, 3144, 60960, 3052};
7691 length=(png_uint_32) GetStringInfoLength(profile);
7693 for (icheck=3; icheck > 0; icheck--)
7695 if (length == check_len[icheck])
7697 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7698 " Got a %lu-byte ICC profile (potentially sRGB)",
7699 (unsigned long) length);
7701 data=GetStringInfoDatum(profile);
7702 profile_crc=crc32(0,data,length);
7704 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7705 " with crc=%8x",(unsigned int) profile_crc);
7707 if (profile_crc == check_crc[icheck])
7709 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7711 if (image->rendering_intent==UndefinedIntent)
7712 image->rendering_intent=PerceptualIntent;
7718 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7719 " Got a %lu-byte ICC profile",
7720 (unsigned long) length);
7723 name=GetNextImageProfile(image);
7728 number_semitransparent = 0;
7729 number_transparent = 0;
7731 if (logging != MagickFalse)
7733 if (image->storage_class == UndefinedClass)
7734 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7735 " storage_class=UndefinedClass");
7736 if (image->storage_class == DirectClass)
7737 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7738 " storage_class=DirectClass");
7739 if (image->storage_class == PseudoClass)
7740 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7741 " storage_class=PseudoClass");
7744 if (image->storage_class == PseudoClass &&
7745 (mng_info->write_png8 || mng_info->write_png24 || mng_info->write_png32 ||
7746 (mng_info->write_png_colortype != 0 &&
7747 mng_info->write_png_colortype != 4)))
7749 (void) SyncImage(image,exception);
7750 image->storage_class = DirectClass;
7753 if (ping_preserve_colormap == MagickFalse)
7755 if (image->storage_class != PseudoClass && image->colormap != NULL)
7757 /* Free the bogus colormap; it can cause trouble later */
7758 if (logging != MagickFalse)
7759 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7760 " Freeing bogus colormap");
7761 (void) RelinquishMagickMemory(image->colormap);
7762 image->colormap=NULL;
7766 if (IsRGBColorspace(image->colorspace) == MagickFalse)
7767 (void) TransformImageColorspace(image,RGBColorspace,exception);
7770 Sometimes we get PseudoClass images whose RGB values don't match
7771 the colors in the colormap. This code syncs the RGB values.
7773 if (image->depth <= 8 && image->taint && image->storage_class == PseudoClass)
7774 (void) SyncImage(image,exception);
7776 #if (MAGICKCORE_QUANTUM_DEPTH == 8)
7777 if (image->depth > 8)
7779 if (logging != MagickFalse)
7780 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7781 " Reducing PNG bit depth to 8 since this is a Q8 build.");
7787 /* Respect the -depth option */
7788 if (image->depth < MAGICKCORE_QUANTUM_DEPTH)
7793 if (image->depth > 8)
7795 #if MAGICKCORE_QUANTUM_DEPTH > 16
7796 /* Scale to 16-bit */
7797 LBR16PacketRGBO(image->background_color);
7799 for (y=0; y < (ssize_t) image->rows; y++)
7801 r=GetAuthenticPixels(image,0,y,image->columns,1,
7804 if (r == (Quantum *) NULL)
7807 for (x=0; x < (ssize_t) image->columns; x++)
7813 if (SyncAuthenticPixels(image,exception) == MagickFalse)
7817 if (image->storage_class == PseudoClass && image->colormap != NULL)
7819 for (i=0; i < (ssize_t) image->colors; i++)
7821 LBR16PacketRGBO(image->colormap[i]);
7824 #endif /* MAGICKCORE_QUANTUM_DEPTH > 16 */
7827 else if (image->depth > 4)
7829 #if MAGICKCORE_QUANTUM_DEPTH > 8
7830 /* Scale to 8-bit */
7831 LBR08PacketRGBO(image->background_color);
7833 for (y=0; y < (ssize_t) image->rows; y++)
7835 r=GetAuthenticPixels(image,0,y,image->columns,1,exception);
7837 if (r == (Quantum *) NULL)
7840 for (x=0; x < (ssize_t) image->columns; x++)
7846 if (SyncAuthenticPixels(image,exception) == MagickFalse)
7850 if (image->storage_class == PseudoClass && image->colormap != NULL)
7852 for (i=0; i < (ssize_t) image->colors; i++)
7854 LBR08PacketRGBO(image->colormap[i]);
7857 #endif /* MAGICKCORE_QUANTUM_DEPTH > 8 */
7860 if (image->depth > 2)
7862 /* Scale to 4-bit */
7863 LBR04PacketRGBO(image->background_color);
7865 for (y=0; y < (ssize_t) image->rows; y++)
7867 r=GetAuthenticPixels(image,0,y,image->columns,1,
7870 if (r == (Quantum *) NULL)
7873 for (x=0; x < (ssize_t) image->columns; x++)
7879 if (SyncAuthenticPixels(image,exception) == MagickFalse)
7883 if (image->storage_class == PseudoClass && image->colormap != NULL)
7885 for (i=0; i < (ssize_t) image->colors; i++)
7887 LBR04PacketRGBO(image->colormap[i]);
7892 else if (image->depth > 1)
7894 /* Scale to 2-bit */
7895 LBR02PacketRGBO(image->background_color);
7897 for (y=0; y < (ssize_t) image->rows; y++)
7899 r=GetAuthenticPixels(image,0,y,image->columns,1,
7902 if (r == (Quantum *) NULL)
7905 for (x=0; x < (ssize_t) image->columns; x++)
7911 if (SyncAuthenticPixels(image,exception) == MagickFalse)
7915 if (image->storage_class == PseudoClass && image->colormap != NULL)
7917 for (i=0; i < (ssize_t) image->colors; i++)
7919 LBR02PacketRGBO(image->colormap[i]);
7925 /* Scale to 1-bit */
7926 LBR01PacketRGBO(image->background_color);
7928 for (y=0; y < (ssize_t) image->rows; y++)
7930 r=GetAuthenticPixels(image,0,y,image->columns,1,
7933 if (r == (Quantum *) NULL)
7936 for (x=0; x < (ssize_t) image->columns; x++)
7942 if (SyncAuthenticPixels(image,exception) == MagickFalse)
7946 if (image->storage_class == PseudoClass && image->colormap != NULL)
7948 for (i=0; i < (ssize_t) image->colors; i++)
7950 LBR01PacketRGBO(image->colormap[i]);
7956 /* To do: set to next higher multiple of 8 */
7957 if (image->depth < 8)
7960 #if (MAGICKCORE_QUANTUM_DEPTH > 16)
7961 /* PNG does not handle depths greater than 16 so reduce it even
7964 if (image->depth > 8)
7968 #if (MAGICKCORE_QUANTUM_DEPTH > 8)
7969 if (image->depth == 16 && mng_info->write_png_depth != 16)
7970 if (mng_info->write_png8 || LosslessReduceDepthOK(image,exception) != MagickFalse)
7974 /* Normally we run this just once, but in the case of writing PNG8
7975 * we reduce the transparency to binary and run again, then if there
7976 * are still too many colors we reduce to a simple 4-4-4-1, then 3-3-3-1
7977 * RGBA palette and run again, and then to a simple 3-3-2-1 RGBA
7978 * palette. Then (To do) we take care of a final reduction that is only
7979 * needed if there are still 256 colors present and one of them has both
7980 * transparent and opaque instances.
7983 tried_332 = MagickFalse;
7984 tried_333 = MagickFalse;
7985 tried_444 = MagickFalse;
7991 * Sometimes we get DirectClass images that have 256 colors or fewer.
7992 * This code will build a colormap.
7994 * Also, sometimes we get PseudoClass images with an out-of-date
7995 * colormap. This code will replace the colormap with a new one.
7996 * Sometimes we get PseudoClass images that have more than 256 colors.
7997 * This code will delete the colormap and change the image to
8000 * If image->matte is MagickFalse, we ignore the alpha channel
8001 * even though it sometimes contains left-over non-opaque values.
8003 * Also we gather some information (number of opaque, transparent,
8004 * and semitransparent pixels, and whether the image has any non-gray
8005 * pixels or only black-and-white pixels) that we might need later.
8007 * Even if the user wants to force GrayAlpha or RGBA (colortype 4 or 6)
8008 * we need to check for bogus non-opaque values, at least.
8016 semitransparent[260],
8019 register const Quantum
8026 if (logging != MagickFalse)
8027 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8028 " Enter BUILD_PALETTE:");
8030 if (logging != MagickFalse)
8032 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8033 " image->columns=%.20g",(double) image->columns);
8034 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8035 " image->rows=%.20g",(double) image->rows);
8036 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8037 " image->matte=%.20g",(double) image->matte);
8038 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8039 " image->depth=%.20g",(double) image->depth);
8041 if (image->storage_class == PseudoClass && image->colormap != NULL)
8043 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8044 " Original colormap:");
8045 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8046 " i (red,green,blue,alpha)");
8048 for (i=0; i < 256; i++)
8050 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8051 " %d (%d,%d,%d,%d)",
8053 (int) image->colormap[i].red,
8054 (int) image->colormap[i].green,
8055 (int) image->colormap[i].blue,
8056 (int) image->colormap[i].alpha);
8059 for (i=image->colors - 10; i < (ssize_t) image->colors; i++)
8063 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8064 " %d (%d,%d,%d,%d)",
8066 (int) image->colormap[i].red,
8067 (int) image->colormap[i].green,
8068 (int) image->colormap[i].blue,
8069 (int) image->colormap[i].alpha);
8074 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8075 " image->colors=%d",(int) image->colors);
8077 if (image->colors == 0)
8078 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8079 " (zero means unknown)");
8081 if (ping_preserve_colormap == MagickFalse)
8082 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8083 " Regenerate the colormap");
8088 number_semitransparent = 0;
8089 number_transparent = 0;
8091 for (y=0; y < (ssize_t) image->rows; y++)
8093 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8095 if (q == (Quantum *) NULL)
8098 for (x=0; x < (ssize_t) image->columns; x++)
8100 if (image->matte == MagickFalse ||
8101 GetPixelAlpha(image,q) == OpaqueAlpha)
8103 if (number_opaque < 259)
8105 if (number_opaque == 0)
8107 GetPixelInfoPixel(image, q, opaque);
8108 opaque[0].alpha=OpaqueAlpha;
8112 for (i=0; i< (ssize_t) number_opaque; i++)
8114 if (IsPixelEquivalent(image,q, opaque+i))
8118 if (i == (ssize_t) number_opaque &&
8119 number_opaque < 259)
8122 GetPixelInfoPixel(image, q, opaque+i);
8123 opaque[i].alpha=OpaqueAlpha;
8127 else if (GetPixelAlpha(image,q) == TransparentAlpha)
8129 if (number_transparent < 259)
8131 if (number_transparent == 0)
8133 GetPixelInfoPixel(image, q, transparent);
8134 ping_trans_color.red=(unsigned short)
8135 GetPixelRed(image,q);
8136 ping_trans_color.green=(unsigned short)
8137 GetPixelGreen(image,q);
8138 ping_trans_color.blue=(unsigned short)
8139 GetPixelBlue(image,q);
8140 ping_trans_color.gray=(unsigned short)
8141 GetPixelRed(image,q);
8142 number_transparent = 1;
8145 for (i=0; i< (ssize_t) number_transparent; i++)
8147 if (IsPixelEquivalent(image,q, transparent+i))
8151 if (i == (ssize_t) number_transparent &&
8152 number_transparent < 259)
8154 number_transparent++;
8155 GetPixelInfoPixel(image,q,transparent+i);
8161 if (number_semitransparent < 259)
8163 if (number_semitransparent == 0)
8165 GetPixelInfoPixel(image,q,semitransparent);
8166 number_semitransparent = 1;
8169 for (i=0; i< (ssize_t) number_semitransparent; i++)
8171 if (IsPixelEquivalent(image,q, semitransparent+i)
8172 && GetPixelAlpha(image,q) ==
8173 semitransparent[i].alpha)
8177 if (i == (ssize_t) number_semitransparent &&
8178 number_semitransparent < 259)
8180 number_semitransparent++;
8181 GetPixelInfoPixel(image, q, semitransparent+i);
8185 q+=GetPixelChannels(image);
8189 if (mng_info->write_png8 == MagickFalse &&
8190 ping_exclude_bKGD == MagickFalse)
8192 /* Add the background color to the palette, if it
8193 * isn't already there.
8195 if (logging != MagickFalse)
8197 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8198 " Check colormap for background (%d,%d,%d)",
8199 (int) image->background_color.red,
8200 (int) image->background_color.green,
8201 (int) image->background_color.blue);
8203 for (i=0; i<number_opaque; i++)
8205 if (opaque[i].red == image->background_color.red &&
8206 opaque[i].green == image->background_color.green &&
8207 opaque[i].blue == image->background_color.blue)
8210 if (number_opaque < 259 && i == number_opaque)
8212 opaque[i] = image->background_color;
8213 ping_background.index = i;
8214 if (logging != MagickFalse)
8216 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8217 " background_color index is %d",(int) i);
8221 else if (logging != MagickFalse)
8222 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8223 " No room in the colormap to add background color");
8226 image_colors=number_opaque+number_transparent+number_semitransparent;
8228 if (mng_info->write_png8 != MagickFalse && image_colors > 256)
8230 /* No room for the background color; remove it. */
8235 if (logging != MagickFalse)
8237 if (image_colors > 256)
8238 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8239 " image has more than 256 colors");
8242 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8243 " image has %d colors",image_colors);
8246 if (ping_preserve_colormap != MagickFalse)
8249 if (mng_info->write_png_colortype != 7) /* We won't need this info */
8251 ping_have_color=MagickFalse;
8252 ping_have_non_bw=MagickFalse;
8254 if(image_colors > 256)
8256 for (y=0; y < (ssize_t) image->rows; y++)
8258 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
8260 if (q == (Quantum *) NULL)
8264 for (x=0; x < (ssize_t) image->columns; x++)
8266 if (GetPixelRed(image,s) != GetPixelGreen(image,s) ||
8267 GetPixelRed(image,s) != GetPixelBlue(image,s))
8269 ping_have_color=MagickTrue;
8270 ping_have_non_bw=MagickTrue;
8273 s+=GetPixelChannels(image);
8276 if (ping_have_color != MagickFalse)
8279 /* Worst case is black-and-white; we are looking at every
8283 if (ping_have_non_bw == MagickFalse)
8286 for (x=0; x < (ssize_t) image->columns; x++)
8288 if (GetPixelRed(image,s) != 0 &&
8289 GetPixelRed(image,s) != QuantumRange)
8291 ping_have_non_bw=MagickTrue;
8294 s+=GetPixelChannels(image);
8301 if (image_colors < 257)
8307 * Initialize image colormap.
8310 if (logging != MagickFalse)
8311 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8312 " Sort the new colormap");
8314 /* Sort palette, transparent first */;
8318 for (i=0; i<number_transparent; i++)
8319 colormap[n++] = transparent[i];
8321 for (i=0; i<number_semitransparent; i++)
8322 colormap[n++] = semitransparent[i];
8324 for (i=0; i<number_opaque; i++)
8325 colormap[n++] = opaque[i];
8327 ping_background.index +=
8328 (number_transparent + number_semitransparent);
8330 /* image_colors < 257; search the colormap instead of the pixels
8331 * to get ping_have_color and ping_have_non_bw
8335 if (ping_have_color == MagickFalse)
8337 if (colormap[i].red != colormap[i].green ||
8338 colormap[i].red != colormap[i].blue)
8340 ping_have_color=MagickTrue;
8341 ping_have_non_bw=MagickTrue;
8346 if (ping_have_non_bw == MagickFalse)
8348 if (colormap[i].red != 0 && colormap[i].red != QuantumRange)
8349 ping_have_non_bw=MagickTrue;
8353 if ((mng_info->ping_exclude_tRNS == MagickFalse ||
8354 (number_transparent == 0 && number_semitransparent == 0)) &&
8355 (((mng_info->write_png_colortype-1) ==
8356 PNG_COLOR_TYPE_PALETTE) ||
8357 (mng_info->write_png_colortype == 0)))
8359 if (logging != MagickFalse)
8361 if (n != (ssize_t) image_colors)
8362 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8363 " image_colors (%d) and n (%d) don't match",
8366 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8367 " AcquireImageColormap");
8370 image->colors = image_colors;
8372 if (AcquireImageColormap(image,image_colors,exception) ==
8374 ThrowWriterException(ResourceLimitError,
8375 "MemoryAllocationFailed");
8377 for (i=0; i< (ssize_t) image_colors; i++)
8378 image->colormap[i] = colormap[i];
8380 if (logging != MagickFalse)
8382 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8383 " image->colors=%d (%d)",
8384 (int) image->colors, image_colors);
8386 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8387 " Update the pixel indexes");
8390 /* Sync the pixel indices with the new colormap */
8392 for (y=0; y < (ssize_t) image->rows; y++)
8394 q=GetAuthenticPixels(image,0,y,image->columns,1,
8397 if (q == (Quantum *) NULL)
8401 for (x=0; x < (ssize_t) image->columns; x++)
8403 for (i=0; i< (ssize_t) image_colors; i++)
8405 if ((image->matte == MagickFalse ||
8406 image->colormap[i].alpha == GetPixelAlpha(image,q)) &&
8407 image->colormap[i].red == GetPixelRed(image,q) &&
8408 image->colormap[i].green == GetPixelGreen(image,q) &&
8409 image->colormap[i].blue == GetPixelBlue(image,q))
8411 SetPixelIndex(image,i,q);
8415 q+=GetPixelChannels(image);
8418 if (SyncAuthenticPixels(image,exception) == MagickFalse)
8424 if (logging != MagickFalse)
8426 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8427 " image->colors=%d", (int) image->colors);
8429 if (image->colormap != NULL)
8431 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8432 " i (red,green,blue,alpha)");
8434 for (i=0; i < (ssize_t) image->colors; i++)
8436 if (i < 300 || i >= (ssize_t) image->colors - 10)
8438 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8439 " %d (%d,%d,%d,%d)",
8441 (int) image->colormap[i].red,
8442 (int) image->colormap[i].green,
8443 (int) image->colormap[i].blue,
8444 (int) image->colormap[i].alpha);
8449 if (number_transparent < 257)
8450 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8451 " number_transparent = %d",
8452 number_transparent);
8455 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8456 " number_transparent > 256");
8458 if (number_opaque < 257)
8459 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8460 " number_opaque = %d",
8464 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8465 " number_opaque > 256");
8467 if (number_semitransparent < 257)
8468 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8469 " number_semitransparent = %d",
8470 number_semitransparent);
8473 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8474 " number_semitransparent > 256");
8476 if (ping_have_non_bw == MagickFalse)
8477 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8478 " All pixels and the background are black or white");
8480 else if (ping_have_color == MagickFalse)
8481 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8482 " All pixels and the background are gray");
8485 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8486 " At least one pixel or the background is non-gray");
8488 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8489 " Exit BUILD_PALETTE:");
8492 if (mng_info->write_png8 == MagickFalse)
8495 /* Make any reductions necessary for the PNG8 format */
8496 if (image_colors <= 256 &&
8497 image_colors != 0 && image->colormap != NULL &&
8498 number_semitransparent == 0 &&
8499 number_transparent <= 1)
8502 /* PNG8 can't have semitransparent colors so we threshold the
8503 * opacity to 0 or OpaqueOpacity, and PNG8 can only have one
8504 * transparent color so if more than one is transparent we merge
8505 * them into image->background_color.
8507 if (number_semitransparent != 0 || number_transparent > 1)
8509 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8510 " Thresholding the alpha channel to binary");
8512 for (y=0; y < (ssize_t) image->rows; y++)
8514 r=GetAuthenticPixels(image,0,y,image->columns,1,
8517 if (r == (Quantum *) NULL)
8520 for (x=0; x < (ssize_t) image->columns; x++)
8522 if (GetPixelAlpha(image,r) < OpaqueAlpha/2)
8524 SetPixelPixelInfo(image,&image->background_color,r);
8525 SetPixelAlpha(image,TransparentAlpha,r);
8528 SetPixelAlpha(image,OpaqueAlpha,r);
8529 r+=GetPixelChannels(image);
8532 if (SyncAuthenticPixels(image,exception) == MagickFalse)
8535 if (image_colors != 0 && image_colors <= 256 &&
8536 image->colormap != NULL)
8537 for (i=0; i<image_colors; i++)
8538 image->colormap[i].alpha =
8539 (image->colormap[i].alpha > TransparentAlpha/2 ?
8540 TransparentAlpha : OpaqueAlpha);
8545 /* PNG8 can't have more than 256 colors so we quantize the pixels and
8546 * background color to the 4-4-4-1, 3-3-3-1 or 3-3-2-1 palette. If the
8547 * image is mostly gray, the 4-4-4-1 palette is likely to end up with 256
8550 if (tried_444 == MagickFalse && (image_colors == 0 || image_colors > 256))
8552 if (logging != MagickFalse)
8553 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8554 " Quantizing the background color to 4-4-4");
8556 tried_444 = MagickTrue;
8558 LBR04PacketRGB(image->background_color);
8560 if (logging != MagickFalse)
8561 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8562 " Quantizing the pixel colors to 4-4-4");
8564 if (image->colormap == NULL)
8566 for (y=0; y < (ssize_t) image->rows; y++)
8568 r=GetAuthenticPixels(image,0,y,image->columns,1,
8571 if (r == (Quantum *) NULL)
8574 for (x=0; x < (ssize_t) image->columns; x++)
8576 if (GetPixelAlpha(image,r) == OpaqueAlpha)
8581 if (SyncAuthenticPixels(image,exception) == MagickFalse)
8586 else /* Should not reach this; colormap already exists and
8589 if (logging != MagickFalse)
8590 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8591 " Quantizing the colormap to 4-4-4");
8593 for (i=0; i<image_colors; i++)
8595 LBR04PacketRGB(image->colormap[i]);
8601 if (tried_333 == MagickFalse && (image_colors == 0 || image_colors > 256))
8603 if (logging != MagickFalse)
8604 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8605 " Quantizing the background color to 3-3-3");
8607 tried_333 = MagickTrue;
8609 LBR03PacketRGB(image->background_color);
8611 if (logging != MagickFalse)
8612 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8613 " Quantizing the pixel colors to 3-3-3-1");
8615 if (image->colormap == NULL)
8617 for (y=0; y < (ssize_t) image->rows; y++)
8619 r=GetAuthenticPixels(image,0,y,image->columns,1,
8622 if (r == (Quantum *) NULL)
8625 for (x=0; x < (ssize_t) image->columns; x++)
8627 if (GetPixelAlpha(image,r) == OpaqueAlpha)
8632 if (SyncAuthenticPixels(image,exception) == MagickFalse)
8637 else /* Should not reach this; colormap already exists and
8640 if (logging != MagickFalse)
8641 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8642 " Quantizing the colormap to 3-3-3-1");
8643 for (i=0; i<image_colors; i++)
8645 LBR03PacketRGB(image->colormap[i]);
8651 if (tried_332 == MagickFalse && (image_colors == 0 || image_colors > 256))
8653 if (logging != MagickFalse)
8654 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8655 " Quantizing the background color to 3-3-2");
8657 tried_332 = MagickTrue;
8659 /* Red and green were already done so we only quantize the blue
8663 LBR02PacketBlue(image->background_color);
8665 if (logging != MagickFalse)
8666 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8667 " Quantizing the pixel colors to 3-3-2-1");
8669 if (image->colormap == NULL)
8671 for (y=0; y < (ssize_t) image->rows; y++)
8673 r=GetAuthenticPixels(image,0,y,image->columns,1,
8676 if (r == (Quantum *) NULL)
8679 for (x=0; x < (ssize_t) image->columns; x++)
8681 if (GetPixelAlpha(image,r) == OpaqueAlpha)
8686 if (SyncAuthenticPixels(image,exception) == MagickFalse)
8691 else /* Should not reach this; colormap already exists and
8694 if (logging != MagickFalse)
8695 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8696 " Quantizing the colormap to 3-3-2-1");
8697 for (i=0; i<image_colors; i++)
8699 LBR02PacketBlue(image->colormap[i]);
8706 if (image_colors == 0 || image_colors > 256)
8708 /* Take care of special case with 256 colors + 1 transparent
8709 * color. We don't need to quantize to 2-3-2-1; we only need to
8710 * eliminate one color, so we'll merge the two darkest red
8711 * colors (0x49, 0, 0) -> (0x24, 0, 0).
8713 if (ScaleQuantumToChar(image->background_color.red) == 0x49 &&
8714 ScaleQuantumToChar(image->background_color.green) == 0x00 &&
8715 ScaleQuantumToChar(image->background_color.blue) == 0x00)
8717 image->background_color.red=ScaleCharToQuantum(0x24);
8720 if (image->colormap == NULL)
8722 for (y=0; y < (ssize_t) image->rows; y++)
8724 r=GetAuthenticPixels(image,0,y,image->columns,1,
8727 if (r == (Quantum *) NULL)
8730 for (x=0; x < (ssize_t) image->columns; x++)
8732 if (ScaleQuantumToChar(GetPixelRed(image,r)) == 0x49 &&
8733 ScaleQuantumToChar(GetPixelGreen(image,r)) == 0x00 &&
8734 ScaleQuantumToChar(GetPixelBlue(image,r)) == 0x00 &&
8735 GetPixelAlpha(image,r) == OpaqueAlpha)
8737 SetPixelRed(image,ScaleCharToQuantum(0x24),r);
8739 r+=GetPixelChannels(image);
8742 if (SyncAuthenticPixels(image,exception) == MagickFalse)
8750 for (i=0; i<image_colors; i++)
8752 if (ScaleQuantumToChar(image->colormap[i].red) == 0x49 &&
8753 ScaleQuantumToChar(image->colormap[i].green) == 0x00 &&
8754 ScaleQuantumToChar(image->colormap[i].blue) == 0x00)
8756 image->colormap[i].red=ScaleCharToQuantum(0x24);
8762 /* END OF BUILD_PALETTE */
8764 /* If we are excluding the tRNS chunk and there is transparency,
8765 * then we must write a Gray-Alpha (color-type 4) or RGBA (color-type 6)
8768 if (mng_info->ping_exclude_tRNS != MagickFalse &&
8769 (number_transparent != 0 || number_semitransparent != 0))
8771 unsigned int colortype=mng_info->write_png_colortype;
8773 if (ping_have_color == MagickFalse)
8774 mng_info->write_png_colortype = 5;
8777 mng_info->write_png_colortype = 7;
8779 if (colortype != 0 &&
8780 mng_info->write_png_colortype != colortype)
8781 ping_need_colortype_warning=MagickTrue;
8785 /* See if cheap transparency is possible. It is only possible
8786 * when there is a single transparent color, no semitransparent
8787 * color, and no opaque color that has the same RGB components
8788 * as the transparent color. We only need this information if
8789 * we are writing a PNG with colortype 0 or 2, and we have not
8790 * excluded the tRNS chunk.
8792 if (number_transparent == 1 &&
8793 mng_info->write_png_colortype < 4)
8795 ping_have_cheap_transparency = MagickTrue;
8797 if (number_semitransparent != 0)
8798 ping_have_cheap_transparency = MagickFalse;
8800 else if (image_colors == 0 || image_colors > 256 ||
8801 image->colormap == NULL)
8803 register const Quantum
8806 for (y=0; y < (ssize_t) image->rows; y++)
8808 q=GetVirtualPixels(image,0,y,image->columns,1, exception);
8810 if (q == (Quantum *) NULL)
8813 for (x=0; x < (ssize_t) image->columns; x++)
8815 if (GetPixelAlpha(image,q) != TransparentAlpha &&
8816 (unsigned short) GetPixelRed(image,q) ==
8817 ping_trans_color.red &&
8818 (unsigned short) GetPixelGreen(image,q) ==
8819 ping_trans_color.green &&
8820 (unsigned short) GetPixelBlue(image,q) ==
8821 ping_trans_color.blue)
8823 ping_have_cheap_transparency = MagickFalse;
8827 q+=GetPixelChannels(image);
8830 if (ping_have_cheap_transparency == MagickFalse)
8836 /* Assuming that image->colormap[0] is the one transparent color
8837 * and that all others are opaque.
8839 if (image_colors > 1)
8840 for (i=1; i<image_colors; i++)
8841 if (image->colormap[i].red == image->colormap[0].red &&
8842 image->colormap[i].green == image->colormap[0].green &&
8843 image->colormap[i].blue == image->colormap[0].blue)
8845 ping_have_cheap_transparency = MagickFalse;
8850 if (logging != MagickFalse)
8852 if (ping_have_cheap_transparency == MagickFalse)
8853 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8854 " Cheap transparency is not possible.");
8857 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8858 " Cheap transparency is possible.");
8862 ping_have_cheap_transparency = MagickFalse;
8864 image_depth=image->depth;
8866 quantum_info = (QuantumInfo *) NULL;
8868 image_colors=(int) image->colors;
8869 image_matte=image->matte;
8871 mng_info->IsPalette=image->storage_class == PseudoClass &&
8872 image_colors <= 256 && image->colormap != NULL;
8874 if ((mng_info->write_png_colortype == 4 || mng_info->write_png8) &&
8875 (image->colors == 0 || image->colormap == NULL))
8877 image_info=DestroyImageInfo(image_info);
8878 image=DestroyImage(image);
8879 (void) ThrowMagickException(exception,GetMagickModule(),CoderError,
8880 "Cannot write PNG8 or color-type 3; colormap is NULL",
8881 "`%s'",IMimage->filename);
8882 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
8883 UnlockSemaphoreInfo(ping_semaphore);
8885 return(MagickFalse);
8889 Allocate the PNG structures
8891 #ifdef PNG_USER_MEM_SUPPORTED
8892 error_info.image=image;
8893 error_info.exception=exception;
8894 ping=png_create_write_struct_2(PNG_LIBPNG_VER_STRING,&error_info,
8895 MagickPNGErrorHandler,MagickPNGWarningHandler,(void *) NULL,
8896 (png_malloc_ptr) Magick_png_malloc,(png_free_ptr) Magick_png_free);
8899 ping=png_create_write_struct(PNG_LIBPNG_VER_STRING,&error_info,
8900 MagickPNGErrorHandler,MagickPNGWarningHandler);
8903 if (ping == (png_struct *) NULL)
8904 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
8906 ping_info=png_create_info_struct(ping);
8908 if (ping_info == (png_info *) NULL)
8910 png_destroy_write_struct(&ping,(png_info **) NULL);
8911 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
8914 png_set_write_fn(ping,image,png_put_data,png_flush_data);
8915 ping_pixels=(unsigned char *) NULL;
8917 if (setjmp(png_jmpbuf(ping)))
8923 if (image_info->verbose)
8924 (void) printf("PNG write has failed.\n");
8926 png_destroy_write_struct(&ping,&ping_info);
8927 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
8928 UnlockSemaphoreInfo(ping_semaphore);
8930 if (ping_have_blob != MagickFalse)
8931 (void) CloseBlob(image);
8932 image_info=DestroyImageInfo(image_info);
8933 image=DestroyImage(image);
8934 return(MagickFalse);
8937 Prepare PNG for writing.
8939 #if defined(PNG_MNG_FEATURES_SUPPORTED)
8940 if (mng_info->write_mng)
8941 (void) png_permit_mng_features(ping,PNG_ALL_MNG_FEATURES);
8944 # ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
8945 if (mng_info->write_mng)
8946 png_permit_empty_plte(ping,MagickTrue);
8953 ping_width=(png_uint_32) image->columns;
8954 ping_height=(png_uint_32) image->rows;
8956 if (mng_info->write_png8 || mng_info->write_png24 || mng_info->write_png32)
8959 if (mng_info->write_png_depth != 0)
8960 image_depth=mng_info->write_png_depth;
8962 /* Adjust requested depth to next higher valid depth if necessary */
8963 if (image_depth > 8)
8966 if ((image_depth > 4) && (image_depth < 8))
8969 if (image_depth == 3)
8972 if (logging != MagickFalse)
8974 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8975 " width=%.20g",(double) ping_width);
8976 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8977 " height=%.20g",(double) ping_height);
8978 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8979 " image_matte=%.20g",(double) image->matte);
8980 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8981 " image->depth=%.20g",(double) image->depth);
8982 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8983 " Tentative ping_bit_depth=%.20g",(double) image_depth);
8986 save_image_depth=image_depth;
8987 ping_bit_depth=(png_byte) save_image_depth;
8990 #if defined(PNG_pHYs_SUPPORTED)
8991 if (ping_exclude_pHYs == MagickFalse)
8993 if ((image->x_resolution != 0) && (image->y_resolution != 0) &&
8994 (!mng_info->write_mng || !mng_info->equal_physs))
8996 if (logging != MagickFalse)
8997 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8998 " Setting up pHYs chunk");
9000 if (image->units == PixelsPerInchResolution)
9002 ping_pHYs_unit_type=PNG_RESOLUTION_METER;
9003 ping_pHYs_x_resolution=
9004 (png_uint_32) ((100.0*image->x_resolution+0.5)/2.54);
9005 ping_pHYs_y_resolution=
9006 (png_uint_32) ((100.0*image->y_resolution+0.5)/2.54);
9009 else if (image->units == PixelsPerCentimeterResolution)
9011 ping_pHYs_unit_type=PNG_RESOLUTION_METER;
9012 ping_pHYs_x_resolution=(png_uint_32) (100.0*image->x_resolution+0.5);
9013 ping_pHYs_y_resolution=(png_uint_32) (100.0*image->y_resolution+0.5);
9018 ping_pHYs_unit_type=PNG_RESOLUTION_UNKNOWN;
9019 ping_pHYs_x_resolution=(png_uint_32) image->x_resolution;
9020 ping_pHYs_y_resolution=(png_uint_32) image->y_resolution;
9023 if (logging != MagickFalse)
9024 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9025 " Set up PNG pHYs chunk: xres: %.20g, yres: %.20g, units: %d.",
9026 (double) ping_pHYs_x_resolution,(double) ping_pHYs_y_resolution,
9027 (int) ping_pHYs_unit_type);
9028 ping_have_pHYs = MagickTrue;
9033 if (ping_exclude_bKGD == MagickFalse)
9035 if ((!mng_info->adjoin || !mng_info->equal_backgrounds))
9041 if (ping_bit_depth == 8)
9044 if (ping_bit_depth == 4)
9047 if (ping_bit_depth == 2)
9050 if (ping_bit_depth == 1)
9053 ping_background.red=(png_uint_16)
9054 (ScaleQuantumToShort(image->background_color.red) & mask);
9056 ping_background.green=(png_uint_16)
9057 (ScaleQuantumToShort(image->background_color.green) & mask);
9059 ping_background.blue=(png_uint_16)
9060 (ScaleQuantumToShort(image->background_color.blue) & mask);
9062 ping_background.gray=(png_uint_16) ping_background.green;
9065 if (logging != MagickFalse)
9067 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9068 " Setting up bKGD chunk (1)");
9069 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9070 " background_color index is %d",
9071 (int) ping_background.index);
9073 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9074 " ping_bit_depth=%d",ping_bit_depth);
9077 ping_have_bKGD = MagickTrue;
9081 Select the color type.
9086 if (mng_info->IsPalette && mng_info->write_png8)
9089 /* To do: make this a function cause it's used twice, except
9090 for reducing the sample depth from 8. */
9092 number_colors=image_colors;
9094 ping_have_tRNS=MagickFalse;
9099 ping_color_type=(png_byte) PNG_COLOR_TYPE_PALETTE;
9101 if (logging != MagickFalse)
9102 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9103 " Setting up PLTE chunk with %d colors (%d)",
9104 number_colors, image_colors);
9106 for (i=0; i < (ssize_t) number_colors; i++)
9108 palette[i].red=ScaleQuantumToChar(image->colormap[i].red);
9109 palette[i].green=ScaleQuantumToChar(image->colormap[i].green);
9110 palette[i].blue=ScaleQuantumToChar(image->colormap[i].blue);
9111 if (logging != MagickFalse)
9112 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9113 #if MAGICKCORE_QUANTUM_DEPTH == 8
9114 " %3ld (%3d,%3d,%3d)",
9116 " %5ld (%5d,%5d,%5d)",
9118 (long) i,palette[i].red,palette[i].green,palette[i].blue);
9122 ping_have_PLTE=MagickTrue;
9123 image_depth=ping_bit_depth;
9126 if (matte != MagickFalse)
9129 Identify which colormap entry is transparent.
9131 assert(number_colors <= 256);
9132 assert(image->colormap != NULL);
9134 for (i=0; i < (ssize_t) number_transparent; i++)
9135 ping_trans_alpha[i]=0;
9138 ping_num_trans=(unsigned short) (number_transparent +
9139 number_semitransparent);
9141 if (ping_num_trans == 0)
9142 ping_have_tRNS=MagickFalse;
9145 ping_have_tRNS=MagickTrue;
9148 if (ping_exclude_bKGD == MagickFalse)
9151 * Identify which colormap entry is the background color.
9154 for (i=0; i < (ssize_t) MagickMax(1L*number_colors-1L,1L); i++)
9155 if (IsPNGColorEqual(ping_background,image->colormap[i]))
9158 ping_background.index=(png_byte) i;
9160 if (logging != MagickFalse)
9162 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9163 " background_color index is %d",
9164 (int) ping_background.index);
9167 } /* end of write_png8 */
9169 else if (mng_info->write_png24 || mng_info->write_png_colortype == 3)
9171 image_matte=MagickFalse;
9172 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB;
9175 else if (mng_info->write_png32 || mng_info->write_png_colortype == 7)
9177 image_matte=MagickTrue;
9178 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB_ALPHA;
9181 else /* mng_info->write_pngNN not specified */
9183 image_depth=ping_bit_depth;
9185 if (mng_info->write_png_colortype != 0)
9187 ping_color_type=(png_byte) mng_info->write_png_colortype-1;
9189 if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA ||
9190 ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA)
9191 image_matte=MagickTrue;
9194 image_matte=MagickFalse;
9196 if (logging != MagickFalse)
9197 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9198 " PNG colortype %d was specified:",(int) ping_color_type);
9201 else /* write_png_colortype not specified */
9203 if (logging != MagickFalse)
9204 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9205 " Selecting PNG colortype:");
9207 ping_color_type=(png_byte) ((matte != MagickFalse)?
9208 PNG_COLOR_TYPE_RGB_ALPHA:PNG_COLOR_TYPE_RGB);
9210 if (image_info->type == TrueColorType)
9212 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB;
9213 image_matte=MagickFalse;
9216 if (image_info->type == TrueColorMatteType)
9218 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB_ALPHA;
9219 image_matte=MagickTrue;
9222 if (image_info->type == PaletteType ||
9223 image_info->type == PaletteMatteType)
9224 ping_color_type=(png_byte) PNG_COLOR_TYPE_PALETTE;
9226 if (mng_info->write_png_colortype == 0 &&
9227 (image_info->type == UndefinedType ||
9228 image_info->type == OptimizeType))
9230 if (ping_have_color == MagickFalse)
9232 if (image_matte == MagickFalse)
9234 ping_color_type=(png_byte) PNG_COLOR_TYPE_GRAY;
9235 image_matte=MagickFalse;
9240 ping_color_type=(png_byte) PNG_COLOR_TYPE_GRAY_ALPHA;
9241 image_matte=MagickTrue;
9246 if (image_matte == MagickFalse)
9248 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB;
9249 image_matte=MagickFalse;
9254 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGBA;
9255 image_matte=MagickTrue;
9262 if (logging != MagickFalse)
9263 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9264 " Selected PNG colortype=%d",ping_color_type);
9266 if (ping_bit_depth < 8)
9268 if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA ||
9269 ping_color_type == PNG_COLOR_TYPE_RGB ||
9270 ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA)
9274 old_bit_depth=ping_bit_depth;
9276 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
9278 if (image->matte == MagickFalse && ping_have_non_bw == MagickFalse)
9282 if (ping_color_type == PNG_COLOR_TYPE_PALETTE)
9287 if (image->colors == 0)
9290 (void) ThrowMagickException(exception,
9291 GetMagickModule(),CoderError,
9292 "image has 0 colors", "`%s'","");
9295 while ((int) (one << ping_bit_depth) < (ssize_t) image_colors)
9296 ping_bit_depth <<= 1;
9299 if (logging != MagickFalse)
9301 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9302 " Number of colors: %.20g",(double) image_colors);
9304 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9305 " Tentative PNG bit depth: %d",ping_bit_depth);
9308 if (ping_bit_depth < (int) mng_info->write_png_depth)
9309 ping_bit_depth = mng_info->write_png_depth;
9312 image_depth=ping_bit_depth;
9314 if (logging != MagickFalse)
9316 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9317 " Tentative PNG color type: %.20g",(double) ping_color_type);
9319 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9320 " image_info->type: %.20g",(double) image_info->type);
9322 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9323 " image_depth: %.20g",(double) image_depth);
9325 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9327 " image->depth: %.20g",(double) image->depth);
9329 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9330 " ping_bit_depth: %.20g",(double) ping_bit_depth);
9333 if (matte != MagickFalse)
9335 if (mng_info->IsPalette)
9337 if (mng_info->write_png_colortype == 0)
9339 ping_color_type=PNG_COLOR_TYPE_GRAY_ALPHA;
9341 if (ping_have_color != MagickFalse)
9342 ping_color_type=PNG_COLOR_TYPE_RGBA;
9346 * Determine if there is any transparent color.
9348 if (number_transparent + number_semitransparent == 0)
9351 No transparent pixels are present. Change 4 or 6 to 0 or 2.
9354 image_matte=MagickFalse;
9356 if (mng_info->write_png_colortype == 0)
9357 ping_color_type&=0x03;
9367 if (ping_bit_depth == 8)
9370 if (ping_bit_depth == 4)
9373 if (ping_bit_depth == 2)
9376 if (ping_bit_depth == 1)
9379 ping_trans_color.red=(png_uint_16)
9380 (ScaleQuantumToShort(image->colormap[0].red) & mask);
9382 ping_trans_color.green=(png_uint_16)
9383 (ScaleQuantumToShort(image->colormap[0].green) & mask);
9385 ping_trans_color.blue=(png_uint_16)
9386 (ScaleQuantumToShort(image->colormap[0].blue) & mask);
9388 ping_trans_color.gray=(png_uint_16)
9389 (ScaleQuantumToShort(GetPixelInfoIntensity(
9390 image->colormap)) & mask);
9392 ping_trans_color.index=(png_byte) 0;
9394 ping_have_tRNS=MagickTrue;
9397 if (ping_have_tRNS != MagickFalse)
9400 * Determine if there is one and only one transparent color
9401 * and if so if it is fully transparent.
9403 if (ping_have_cheap_transparency == MagickFalse)
9404 ping_have_tRNS=MagickFalse;
9407 if (ping_have_tRNS != MagickFalse)
9409 if (mng_info->write_png_colortype == 0)
9410 ping_color_type &= 0x03; /* changes 4 or 6 to 0 or 2 */
9412 if (image_depth == 8)
9414 ping_trans_color.red&=0xff;
9415 ping_trans_color.green&=0xff;
9416 ping_trans_color.blue&=0xff;
9417 ping_trans_color.gray&=0xff;
9423 if (image_depth == 8)
9425 ping_trans_color.red&=0xff;
9426 ping_trans_color.green&=0xff;
9427 ping_trans_color.blue&=0xff;
9428 ping_trans_color.gray&=0xff;
9435 if (ping_have_tRNS != MagickFalse)
9436 image_matte=MagickFalse;
9438 if ((mng_info->IsPalette) &&
9439 mng_info->write_png_colortype-1 != PNG_COLOR_TYPE_PALETTE &&
9440 ping_have_color == MagickFalse &&
9441 (image_matte == MagickFalse || image_depth >= 8))
9445 if (image_matte != MagickFalse)
9446 ping_color_type=PNG_COLOR_TYPE_GRAY_ALPHA;
9448 else if (mng_info->write_png_colortype-1 != PNG_COLOR_TYPE_GRAY_ALPHA)
9450 ping_color_type=PNG_COLOR_TYPE_GRAY;
9452 if (save_image_depth == 16 && image_depth == 8)
9454 if (logging != MagickFalse)
9456 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9457 " Scaling ping_trans_color (0)");
9459 ping_trans_color.gray*=0x0101;
9463 if (image_depth > MAGICKCORE_QUANTUM_DEPTH)
9464 image_depth=MAGICKCORE_QUANTUM_DEPTH;
9466 if ((image_colors == 0) ||
9467 ((ssize_t) (image_colors-1) > (ssize_t) MaxColormapSize))
9468 image_colors=(int) (one << image_depth);
9470 if (image_depth > 8)
9476 if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
9478 if(!mng_info->write_png_depth)
9482 while ((int) (one << ping_bit_depth)
9483 < (ssize_t) image_colors)
9484 ping_bit_depth <<= 1;
9488 else if (ping_color_type ==
9489 PNG_COLOR_TYPE_GRAY && image_colors < 17 &&
9490 mng_info->IsPalette)
9492 /* Check if grayscale is reducible */
9495 depth_4_ok=MagickTrue,
9496 depth_2_ok=MagickTrue,
9497 depth_1_ok=MagickTrue;
9499 for (i=0; i < (ssize_t) image_colors; i++)
9504 intensity=ScaleQuantumToChar(image->colormap[i].red);
9506 if ((intensity & 0x0f) != ((intensity & 0xf0) >> 4))
9507 depth_4_ok=depth_2_ok=depth_1_ok=MagickFalse;
9508 else if ((intensity & 0x03) != ((intensity & 0x0c) >> 2))
9509 depth_2_ok=depth_1_ok=MagickFalse;
9510 else if ((intensity & 0x01) != ((intensity & 0x02) >> 1))
9511 depth_1_ok=MagickFalse;
9514 if (depth_1_ok && mng_info->write_png_depth <= 1)
9517 else if (depth_2_ok && mng_info->write_png_depth <= 2)
9520 else if (depth_4_ok && mng_info->write_png_depth <= 4)
9525 image_depth=ping_bit_depth;
9530 if (mng_info->IsPalette)
9532 number_colors=image_colors;
9534 if (image_depth <= 8)
9539 ping_color_type=(png_byte) PNG_COLOR_TYPE_PALETTE;
9541 if (mng_info->have_write_global_plte && matte == MagickFalse)
9543 png_set_PLTE(ping,ping_info,NULL,0);
9545 if (logging != MagickFalse)
9546 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9547 " Setting up empty PLTE chunk");
9552 for (i=0; i < (ssize_t) number_colors; i++)
9554 palette[i].red=ScaleQuantumToChar(image->colormap[i].red);
9555 palette[i].green=ScaleQuantumToChar(image->colormap[i].green);
9556 palette[i].blue=ScaleQuantumToChar(image->colormap[i].blue);
9559 if (logging != MagickFalse)
9560 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9561 " Setting up PLTE chunk with %d colors",
9564 ping_have_PLTE=MagickTrue;
9567 /* color_type is PNG_COLOR_TYPE_PALETTE */
9568 if (mng_info->write_png_depth == 0)
9576 while ((one << ping_bit_depth) < (size_t) number_colors)
9577 ping_bit_depth <<= 1;
9582 if (matte != MagickFalse)
9585 * Set up trans_colors array.
9587 assert(number_colors <= 256);
9589 ping_num_trans=(unsigned short) (number_transparent +
9590 number_semitransparent);
9592 if (ping_num_trans == 0)
9593 ping_have_tRNS=MagickFalse;
9597 if (logging != MagickFalse)
9599 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9600 " Scaling ping_trans_color (1)");
9602 ping_have_tRNS=MagickTrue;
9604 for (i=0; i < ping_num_trans; i++)
9606 ping_trans_alpha[i]= (png_byte)
9607 ScaleQuantumToChar(image->colormap[i].alpha);
9617 if (image_depth < 8)
9620 if ((save_image_depth == 16) && (image_depth == 8))
9622 if (logging != MagickFalse)
9624 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9625 " Scaling ping_trans_color from (%d,%d,%d)",
9626 (int) ping_trans_color.red,
9627 (int) ping_trans_color.green,
9628 (int) ping_trans_color.blue);
9631 ping_trans_color.red*=0x0101;
9632 ping_trans_color.green*=0x0101;
9633 ping_trans_color.blue*=0x0101;
9634 ping_trans_color.gray*=0x0101;
9636 if (logging != MagickFalse)
9638 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9640 (int) ping_trans_color.red,
9641 (int) ping_trans_color.green,
9642 (int) ping_trans_color.blue);
9647 if (ping_bit_depth < (ssize_t) mng_info->write_png_depth)
9648 ping_bit_depth = (ssize_t) mng_info->write_png_depth;
9651 Adjust background and transparency samples in sub-8-bit grayscale files.
9653 if (ping_bit_depth < 8 && ping_color_type ==
9654 PNG_COLOR_TYPE_GRAY)
9662 maxval=(png_uint_16) ((one << ping_bit_depth)-1);
9664 if (ping_exclude_bKGD == MagickFalse)
9667 ping_background.gray=(png_uint_16)
9668 ((maxval/255.)*((GetPixelInfoIntensity(&image->background_color)))
9671 if (logging != MagickFalse)
9672 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9673 " Setting up bKGD chunk (2)");
9674 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9675 " background_color index is %d",
9676 (int) ping_background.index);
9678 ping_have_bKGD = MagickTrue;
9681 if (logging != MagickFalse)
9682 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9683 " Scaling ping_trans_color.gray from %d",
9684 (int)ping_trans_color.gray);
9686 ping_trans_color.gray=(png_uint_16) ((maxval/255.)*(
9687 ping_trans_color.gray)+.5);
9689 if (logging != MagickFalse)
9690 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9691 " to %d", (int)ping_trans_color.gray);
9694 if (ping_exclude_bKGD == MagickFalse)
9696 if (mng_info->IsPalette && (int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
9699 Identify which colormap entry is the background color.
9702 number_colors=image_colors;
9704 for (i=0; i < (ssize_t) MagickMax(1L*number_colors,1L); i++)
9705 if (IsPNGColorEqual(image->background_color,image->colormap[i]))
9708 ping_background.index=(png_byte) i;
9710 if (logging != MagickFalse)
9712 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9713 " Setting up bKGD chunk with index=%d",(int) i);
9716 if (i < (ssize_t) number_colors)
9718 ping_have_bKGD = MagickTrue;
9720 if (logging != MagickFalse)
9722 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9723 " background =(%d,%d,%d)",
9724 (int) ping_background.red,
9725 (int) ping_background.green,
9726 (int) ping_background.blue);
9730 else /* Can't happen */
9732 if (logging != MagickFalse)
9733 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9734 " No room in PLTE to add bKGD color");
9735 ping_have_bKGD = MagickFalse;
9740 if (logging != MagickFalse)
9741 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9742 " PNG color type: %d",ping_color_type);
9744 Initialize compression level and filtering.
9746 if (logging != MagickFalse)
9748 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9749 " Setting up deflate compression");
9751 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9752 " Compression buffer size: 32768");
9755 png_set_compression_buffer_size(ping,32768L);
9757 if (logging != MagickFalse)
9758 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9759 " Compression mem level: 9");
9761 png_set_compression_mem_level(ping, 9);
9763 /* Untangle the "-quality" setting:
9765 Undefined is 0; the default is used.
9770 0: Use Z_HUFFMAN_ONLY strategy with the
9771 zlib default compression level
9773 1-9: the zlib compression level
9777 0-4: the PNG filter method
9779 5: libpng adaptive filtering if compression level > 5
9780 libpng filter type "none" if compression level <= 5
9781 or if image is grayscale or palette
9783 6: libpng adaptive filtering
9785 7: "LOCO" filtering (intrapixel differing) if writing
9786 a MNG, othewise "none". Did not work in IM-6.7.0-9
9787 and earlier because of a missing "else".
9789 8: Z_RLE strategy, all filters
9790 Unused prior to IM-6.7.0-10, was same as 6
9792 9: Z_RLE strategy, no PNG filters
9793 Unused prior to IM-6.7.0-10, was same as 6
9795 Note that using the -quality option, not all combinations of
9796 PNG filter type, zlib compression level, and zlib compression
9797 strategy are possible. This will be addressed soon in a
9798 release that accomodates "-define PNG:compression-strategy", etc.
9802 quality=image->quality == UndefinedCompressionQuality ? 75UL :
9807 if (mng_info->write_png_compression_strategy == 0)
9808 mng_info->write_png_compression_strategy = Z_HUFFMAN_ONLY+1;
9811 else if (mng_info->write_png_compression_level == 0)
9816 level=(int) MagickMin((ssize_t) quality/10,9);
9818 mng_info->write_png_compression_level = level+1;
9821 if (mng_info->write_png_compression_strategy == 0)
9823 if ((quality %10) == 8 || (quality %10) == 9)
9824 mng_info->write_png_compression_strategy=Z_RLE;
9827 if (mng_info->write_png_compression_filter == 0)
9828 mng_info->write_png_compression_filter=((int) quality % 10) + 1;
9830 if (logging != MagickFalse)
9832 if (mng_info->write_png_compression_level)
9833 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9834 " Compression level: %d",
9835 (int) mng_info->write_png_compression_level-1);
9837 if (mng_info->write_png_compression_strategy)
9838 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9839 " Compression strategy: %d",
9840 (int) mng_info->write_png_compression_strategy-1);
9842 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9843 " Setting up filtering");
9845 if (mng_info->write_png_compression_filter == 6)
9846 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9847 " Base filter method: ADAPTIVE");
9848 else if (mng_info->write_png_compression_filter == 0 ||
9849 mng_info->write_png_compression_filter == 1)
9850 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9851 " Base filter method: NONE");
9853 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9854 " Base filter method: %d",
9855 (int) mng_info->write_png_compression_filter-1);
9858 if (mng_info->write_png_compression_level != 0)
9859 png_set_compression_level(ping,mng_info->write_png_compression_level-1);
9861 if (mng_info->write_png_compression_filter == 6)
9863 if (((int) ping_color_type == PNG_COLOR_TYPE_GRAY) ||
9864 ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE) ||
9866 png_set_filter(ping,PNG_FILTER_TYPE_BASE,PNG_NO_FILTERS);
9868 png_set_filter(ping,PNG_FILTER_TYPE_BASE,PNG_ALL_FILTERS);
9870 else if (mng_info->write_png_compression_filter == 7 ||
9871 mng_info->write_png_compression_filter == 10)
9872 png_set_filter(ping,PNG_FILTER_TYPE_BASE,PNG_ALL_FILTERS);
9874 else if (mng_info->write_png_compression_filter == 8)
9876 #if defined(PNG_MNG_FEATURES_SUPPORTED) && defined(PNG_INTRAPIXEL_DIFFERENCING)
9877 if (mng_info->write_mng)
9879 if (((int) ping_color_type == PNG_COLOR_TYPE_RGB) ||
9880 ((int) ping_color_type == PNG_COLOR_TYPE_RGBA))
9881 ping_filter_method=PNG_INTRAPIXEL_DIFFERENCING;
9884 png_set_filter(ping,PNG_FILTER_TYPE_BASE,PNG_NO_FILTERS);
9887 else if (mng_info->write_png_compression_filter == 9)
9888 png_set_filter(ping,PNG_FILTER_TYPE_BASE,PNG_NO_FILTERS);
9890 else if (mng_info->write_png_compression_filter != 0)
9891 png_set_filter(ping,PNG_FILTER_TYPE_BASE,
9892 mng_info->write_png_compression_filter-1);
9894 if (mng_info->write_png_compression_strategy != 0)
9895 png_set_compression_strategy(ping,
9896 mng_info->write_png_compression_strategy-1);
9898 /* Only write the iCCP chunk if we are not writing the sRGB chunk. */
9899 if (ping_exclude_sRGB != MagickFalse ||
9900 (image->rendering_intent == UndefinedIntent))
9902 if ((ping_exclude_tEXt == MagickFalse ||
9903 ping_exclude_zTXt == MagickFalse) &&
9904 (ping_exclude_iCCP == MagickFalse || ping_exclude_zCCP == MagickFalse))
9906 ResetImageProfileIterator(image);
9907 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
9909 profile=GetImageProfile(image,name);
9911 if (profile != (StringInfo *) NULL)
9913 #ifdef PNG_WRITE_iCCP_SUPPORTED
9914 if ((LocaleCompare(name,"ICC") == 0) ||
9915 (LocaleCompare(name,"ICM") == 0))
9918 if (ping_exclude_iCCP == MagickFalse)
9920 png_set_iCCP(ping,ping_info,(png_charp) name,0,
9921 #if (PNG_LIBPNG_VER < 10500)
9922 (png_charp) GetStringInfoDatum(profile),
9924 (png_const_bytep) GetStringInfoDatum(profile),
9926 (png_uint_32) GetStringInfoLength(profile));
9932 if (ping_exclude_zCCP == MagickFalse)
9934 Magick_png_write_raw_profile(image_info,ping,ping_info,
9935 (unsigned char *) name,(unsigned char *) name,
9936 GetStringInfoDatum(profile),
9937 (png_uint_32) GetStringInfoLength(profile));
9941 if (logging != MagickFalse)
9942 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9943 " Setting up text chunk with %s profile",name);
9945 name=GetNextImageProfile(image);
9950 #if defined(PNG_WRITE_sRGB_SUPPORTED)
9951 if ((mng_info->have_write_global_srgb == 0) &&
9952 ((image->rendering_intent != UndefinedIntent) ||
9953 (image->colorspace == sRGBColorspace)))
9955 if (ping_exclude_sRGB == MagickFalse)
9958 Note image rendering intent.
9960 if (logging != MagickFalse)
9961 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9962 " Setting up sRGB chunk");
9964 (void) png_set_sRGB(ping,ping_info,(
9965 Magick_RenderingIntent_to_PNG_RenderingIntent(
9966 image->rendering_intent)));
9970 if ((!mng_info->write_mng) || (!png_get_valid(ping,ping_info,PNG_INFO_sRGB)))
9973 if (ping_exclude_gAMA == MagickFalse &&
9974 (ping_exclude_sRGB == MagickFalse ||
9975 (image->gamma < .45 || image->gamma > .46)))
9977 if ((mng_info->have_write_global_gama == 0) && (image->gamma != 0.0))
9981 To do: check for cHRM+gAMA == sRGB, and write sRGB instead.
9983 if (logging != MagickFalse)
9984 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9985 " Setting up gAMA chunk");
9987 png_set_gAMA(ping,ping_info,image->gamma);
9991 if (ping_exclude_cHRM == MagickFalse)
9993 if ((mng_info->have_write_global_chrm == 0) &&
9994 (image->chromaticity.red_primary.x != 0.0))
9997 Note image chromaticity.
9998 To do: check for cHRM+gAMA == sRGB, and write sRGB instead.
10006 wp=image->chromaticity.white_point;
10007 rp=image->chromaticity.red_primary;
10008 gp=image->chromaticity.green_primary;
10009 bp=image->chromaticity.blue_primary;
10011 if (logging != MagickFalse)
10012 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10013 " Setting up cHRM chunk");
10015 png_set_cHRM(ping,ping_info,wp.x,wp.y,rp.x,rp.y,gp.x,gp.y,
10021 ping_interlace_method=image_info->interlace != NoInterlace;
10023 if (mng_info->write_mng)
10024 png_set_sig_bytes(ping,8);
10026 /* Bail out if cannot meet defined PNG:bit-depth or PNG:color-type */
10028 if (mng_info->write_png_colortype != 0)
10030 if (mng_info->write_png_colortype-1 == PNG_COLOR_TYPE_GRAY)
10031 if (ping_have_color != MagickFalse)
10033 ping_color_type = PNG_COLOR_TYPE_RGB;
10035 if (ping_bit_depth < 8)
10039 if (mng_info->write_png_colortype-1 == PNG_COLOR_TYPE_GRAY_ALPHA)
10040 if (ping_have_color != MagickFalse)
10041 ping_color_type = PNG_COLOR_TYPE_RGB_ALPHA;
10044 if (ping_need_colortype_warning != MagickFalse ||
10045 ((mng_info->write_png_depth &&
10046 (int) mng_info->write_png_depth != ping_bit_depth) ||
10047 (mng_info->write_png_colortype &&
10048 ((int) mng_info->write_png_colortype-1 != ping_color_type &&
10049 mng_info->write_png_colortype != 7 &&
10050 !(mng_info->write_png_colortype == 5 && ping_color_type == 0)))))
10052 if (logging != MagickFalse)
10054 if (ping_need_colortype_warning != MagickFalse)
10056 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10057 " Image has transparency but tRNS chunk was excluded");
10060 if (mng_info->write_png_depth)
10062 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10063 " Defined PNG:bit-depth=%u, Computed depth=%u",
10064 mng_info->write_png_depth,
10068 if (mng_info->write_png_colortype)
10070 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10071 " Defined PNG:color-type=%u, Computed color type=%u",
10072 mng_info->write_png_colortype-1,
10078 "Cannot write image with defined PNG:bit-depth or PNG:color-type.");
10081 if (image_matte != MagickFalse && image->matte == MagickFalse)
10083 /* Add an opaque matte channel */
10084 image->matte = MagickTrue;
10085 (void) SetImageAlpha(image,OpaqueAlpha,exception);
10087 if (logging != MagickFalse)
10088 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10089 " Added an opaque matte channel");
10092 if (number_transparent != 0 || number_semitransparent != 0)
10094 if (ping_color_type < 4)
10096 ping_have_tRNS=MagickTrue;
10097 if (logging != MagickFalse)
10098 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10099 " Setting ping_have_tRNS=MagickTrue.");
10103 if (logging != MagickFalse)
10104 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10105 " Writing PNG header chunks");
10107 png_set_IHDR(ping,ping_info,ping_width,ping_height,
10108 ping_bit_depth,ping_color_type,
10109 ping_interlace_method,ping_compression_method,
10110 ping_filter_method);
10112 if (ping_color_type == 3 && ping_have_PLTE != MagickFalse)
10114 png_set_PLTE(ping,ping_info,palette,number_colors);
10116 if (logging != MagickFalse)
10118 for (i=0; i< (ssize_t) number_colors; i++)
10120 if (i < ping_num_trans)
10121 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10122 " PLTE[%d] = (%d,%d,%d), tRNS[%d] = (%d)",
10124 (int) palette[i].red,
10125 (int) palette[i].green,
10126 (int) palette[i].blue,
10128 (int) ping_trans_alpha[i]);
10130 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10131 " PLTE[%d] = (%d,%d,%d)",
10133 (int) palette[i].red,
10134 (int) palette[i].green,
10135 (int) palette[i].blue);
10140 if (ping_exclude_bKGD == MagickFalse)
10142 if (ping_have_bKGD != MagickFalse)
10144 png_set_bKGD(ping,ping_info,&ping_background);
10147 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10148 " Setting up bKGD chunk");
10149 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10150 " background color = (%d,%d,%d)",
10151 (int) ping_background.red,
10152 (int) ping_background.green,
10153 (int) ping_background.blue);
10154 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10155 " index = %d, gray=%d",
10156 (int) ping_background.index,
10157 (int) ping_background.gray);
10162 if (ping_exclude_pHYs == MagickFalse)
10164 if (ping_have_pHYs != MagickFalse)
10166 png_set_pHYs(ping,ping_info,
10167 ping_pHYs_x_resolution,
10168 ping_pHYs_y_resolution,
10169 ping_pHYs_unit_type);
10173 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10174 " Setting up pHYs chunk");
10175 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10176 " x_resolution=%lu",
10177 (unsigned long) ping_pHYs_x_resolution);
10178 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10179 " y_resolution=%lu",
10180 (unsigned long) ping_pHYs_y_resolution);
10181 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10183 (unsigned long) ping_pHYs_unit_type);
10188 #if defined(PNG_oFFs_SUPPORTED)
10189 if (ping_exclude_oFFs == MagickFalse)
10191 if (image->page.x || image->page.y)
10193 png_set_oFFs(ping,ping_info,(png_int_32) image->page.x,
10194 (png_int_32) image->page.y, 0);
10196 if (logging != MagickFalse)
10197 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10198 " Setting up oFFs chunk with x=%d, y=%d, units=0",
10199 (int) image->page.x, (int) image->page.y);
10204 if (mng_info->need_blob != MagickFalse)
10206 if (OpenBlob(image_info,image,WriteBinaryBlobMode,exception) ==
10208 png_error(ping,"WriteBlob Failed");
10210 ping_have_blob=MagickTrue;
10213 png_write_info_before_PLTE(ping, ping_info);
10215 if (ping_have_tRNS != MagickFalse && ping_color_type < 4)
10217 if (logging != MagickFalse)
10219 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10220 " Calling png_set_tRNS with num_trans=%d",ping_num_trans);
10223 if (ping_color_type == 3)
10224 (void) png_set_tRNS(ping, ping_info,
10231 (void) png_set_tRNS(ping, ping_info,
10234 &ping_trans_color);
10236 if (logging != MagickFalse)
10238 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10239 " tRNS color =(%d,%d,%d)",
10240 (int) ping_trans_color.red,
10241 (int) ping_trans_color.green,
10242 (int) ping_trans_color.blue);
10247 /* write any png-chunk-b profiles */
10248 (void) Magick_png_write_chunk_from_profile(image,"PNG-chunk-b",logging);
10250 png_write_info(ping,ping_info);
10252 /* write any PNG-chunk-m profiles */
10253 (void) Magick_png_write_chunk_from_profile(image,"PNG-chunk-m",logging);
10255 if (ping_exclude_vpAg == MagickFalse)
10257 if ((image->page.width != 0 && image->page.width != image->columns) ||
10258 (image->page.height != 0 && image->page.height != image->rows))
10263 (void) WriteBlobMSBULong(image,9L); /* data length=8 */
10264 PNGType(chunk,mng_vpAg);
10265 LogPNGChunk(logging,mng_vpAg,9L);
10266 PNGLong(chunk+4,(png_uint_32) image->page.width);
10267 PNGLong(chunk+8,(png_uint_32) image->page.height);
10268 chunk[12]=0; /* unit = pixels */
10269 (void) WriteBlob(image,13,chunk);
10270 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
10274 #if (PNG_LIBPNG_VER == 10206)
10275 /* avoid libpng-1.2.6 bug by setting PNG_HAVE_IDAT flag */
10276 #define PNG_HAVE_IDAT 0x04
10277 ping->mode |= PNG_HAVE_IDAT;
10278 #undef PNG_HAVE_IDAT
10281 png_set_packing(ping);
10285 rowbytes=image->columns;
10286 if (image_depth > 8)
10288 switch (ping_color_type)
10290 case PNG_COLOR_TYPE_RGB:
10294 case PNG_COLOR_TYPE_GRAY_ALPHA:
10298 case PNG_COLOR_TYPE_RGBA:
10306 if (logging != MagickFalse)
10308 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10309 " Writing PNG image data");
10311 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10312 " Allocating %.20g bytes of memory for pixels",(double) rowbytes);
10314 ping_pixels=(unsigned char *) AcquireQuantumMemory(rowbytes,
10315 sizeof(*ping_pixels));
10317 if (ping_pixels == (unsigned char *) NULL)
10318 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
10321 Initialize image scanlines.
10323 if (setjmp(png_jmpbuf(ping)))
10329 if (image_info->verbose)
10330 (void) printf("PNG write has failed.\n");
10332 png_destroy_write_struct(&ping,&ping_info);
10333 if (quantum_info != (QuantumInfo *) NULL)
10334 quantum_info=DestroyQuantumInfo(quantum_info);
10335 if (ping_pixels != (unsigned char *) NULL)
10336 ping_pixels=(unsigned char *) RelinquishMagickMemory(ping_pixels);
10337 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
10338 UnlockSemaphoreInfo(ping_semaphore);
10340 if (ping_have_blob != MagickFalse)
10341 (void) CloseBlob(image);
10342 image_info=DestroyImageInfo(image_info);
10343 image=DestroyImage(image);
10344 return(MagickFalse);
10346 quantum_info=AcquireQuantumInfo(image_info,image);
10347 if (quantum_info == (QuantumInfo *) NULL)
10348 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
10349 quantum_info->format=UndefinedQuantumFormat;
10350 quantum_info->depth=image_depth;
10351 num_passes=png_set_interlace_handling(ping);
10353 if ((!mng_info->write_png8 && !mng_info->write_png24 &&
10354 !mng_info->write_png32) &&
10355 (mng_info->IsPalette ||
10356 (image_info->type == BilevelType)) &&
10357 image_matte == MagickFalse &&
10358 ping_have_non_bw == MagickFalse)
10360 /* Palette, Bilevel, or Opaque Monochrome */
10361 register const Quantum
10364 quantum_info->depth=8;
10365 for (pass=0; pass < num_passes; pass++)
10368 Convert PseudoClass image to a PNG monochrome image.
10370 for (y=0; y < (ssize_t) image->rows; y++)
10372 if (logging != MagickFalse && y == 0)
10373 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10374 " Writing row of pixels (0)");
10376 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
10378 if (p == (const Quantum *) NULL)
10381 if (mng_info->IsPalette)
10383 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10384 quantum_info,GrayQuantum,ping_pixels,exception);
10385 if (mng_info->write_png_colortype-1 == PNG_COLOR_TYPE_PALETTE &&
10386 mng_info->write_png_depth &&
10387 mng_info->write_png_depth != old_bit_depth)
10389 /* Undo pixel scaling */
10390 for (i=0; i < (ssize_t) image->columns; i++)
10391 *(ping_pixels+i)=(unsigned char) (*(ping_pixels+i)
10392 >> (8-old_bit_depth));
10398 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10399 quantum_info,RedQuantum,ping_pixels,exception);
10402 if (mng_info->write_png_colortype-1 != PNG_COLOR_TYPE_PALETTE)
10403 for (i=0; i < (ssize_t) image->columns; i++)
10404 *(ping_pixels+i)=(unsigned char) ((*(ping_pixels+i) > 127) ?
10407 if (logging != MagickFalse && y == 0)
10408 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10409 " Writing row of pixels (1)");
10411 png_write_row(ping,ping_pixels);
10413 if (image->previous == (Image *) NULL)
10415 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
10416 if (status == MagickFalse)
10422 else /* Not Palette, Bilevel, or Opaque Monochrome */
10424 if ((!mng_info->write_png8 && !mng_info->write_png24 &&
10425 !mng_info->write_png32) &&
10426 (image_matte != MagickFalse ||
10427 (ping_bit_depth >= MAGICKCORE_QUANTUM_DEPTH)) &&
10428 (mng_info->IsPalette) && ping_have_color == MagickFalse)
10430 register const Quantum
10433 for (pass=0; pass < num_passes; pass++)
10436 for (y=0; y < (ssize_t) image->rows; y++)
10438 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
10440 if (p == (const Quantum *) NULL)
10443 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
10445 if (mng_info->IsPalette)
10446 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10447 quantum_info,GrayQuantum,ping_pixels,exception);
10450 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10451 quantum_info,RedQuantum,ping_pixels,exception);
10453 if (logging != MagickFalse && y == 0)
10454 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10455 " Writing GRAY PNG pixels (2)");
10458 else /* PNG_COLOR_TYPE_GRAY_ALPHA */
10460 if (logging != MagickFalse && y == 0)
10461 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10462 " Writing GRAY_ALPHA PNG pixels (2)");
10464 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10465 quantum_info,GrayAlphaQuantum,ping_pixels,exception);
10468 if (logging != MagickFalse && y == 0)
10469 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10470 " Writing row of pixels (2)");
10472 png_write_row(ping,ping_pixels);
10475 if (image->previous == (Image *) NULL)
10477 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
10478 if (status == MagickFalse)
10486 register const Quantum
10489 for (pass=0; pass < num_passes; pass++)
10491 if ((image_depth > 8) || (mng_info->write_png24 ||
10492 mng_info->write_png32 ||
10493 (!mng_info->write_png8 && !mng_info->IsPalette)))
10495 for (y=0; y < (ssize_t) image->rows; y++)
10497 p=GetVirtualPixels(image,0,y,image->columns,1,
10500 if (p == (const Quantum *) NULL)
10503 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
10505 if (image->storage_class == DirectClass)
10506 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10507 quantum_info,RedQuantum,ping_pixels,exception);
10510 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10511 quantum_info,GrayQuantum,ping_pixels,exception);
10514 else if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
10516 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10517 quantum_info,GrayAlphaQuantum,ping_pixels,
10520 if (logging != MagickFalse && y == 0)
10521 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10522 " Writing GRAY_ALPHA PNG pixels (3)");
10525 else if (image_matte != MagickFalse)
10526 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10527 quantum_info,RGBAQuantum,ping_pixels,exception);
10530 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10531 quantum_info,RGBQuantum,ping_pixels,exception);
10533 if (logging != MagickFalse && y == 0)
10534 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10535 " Writing row of pixels (3)");
10537 png_write_row(ping,ping_pixels);
10542 /* not ((image_depth > 8) || (mng_info->write_png24 ||
10543 mng_info->write_png32 ||
10544 (!mng_info->write_png8 && !mng_info->IsPalette))) */
10546 if ((ping_color_type != PNG_COLOR_TYPE_GRAY) &&
10547 (ping_color_type != PNG_COLOR_TYPE_GRAY_ALPHA))
10549 if (logging != MagickFalse)
10550 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10551 " pass %d, Image Is not GRAY or GRAY_ALPHA",pass);
10553 quantum_info->depth=8;
10557 for (y=0; y < (ssize_t) image->rows; y++)
10559 if (logging != MagickFalse && y == 0)
10560 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10561 " pass %d, Image Is RGB, 16-bit GRAY, or GRAY_ALPHA",pass);
10563 p=GetVirtualPixels(image,0,y,image->columns,1,
10566 if (p == (const Quantum *) NULL)
10569 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
10571 quantum_info->depth=image->depth;
10573 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10574 quantum_info,GrayQuantum,ping_pixels,exception);
10577 else if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
10579 if (logging != MagickFalse && y == 0)
10580 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10581 " Writing GRAY_ALPHA PNG pixels (4)");
10583 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10584 quantum_info,GrayAlphaQuantum,ping_pixels,
10590 (void) ExportQuantumPixels(image,(CacheView *) NULL,
10591 quantum_info,IndexQuantum,ping_pixels,exception);
10593 if (logging != MagickFalse && y <= 2)
10595 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10596 " Writing row of non-gray pixels (4)");
10598 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10599 " ping_pixels[0]=%d,ping_pixels[1]=%d",
10600 (int)ping_pixels[0],(int)ping_pixels[1]);
10603 png_write_row(ping,ping_pixels);
10607 if (image->previous == (Image *) NULL)
10609 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
10610 if (status == MagickFalse)
10617 if (quantum_info != (QuantumInfo *) NULL)
10618 quantum_info=DestroyQuantumInfo(quantum_info);
10620 if (logging != MagickFalse)
10622 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10623 " Wrote PNG image data");
10625 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10626 " Width: %.20g",(double) ping_width);
10628 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10629 " Height: %.20g",(double) ping_height);
10631 if (mng_info->write_png_depth)
10633 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10634 " Defined PNG:bit-depth: %d",mng_info->write_png_depth);
10637 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10638 " PNG bit-depth written: %d",ping_bit_depth);
10640 if (mng_info->write_png_colortype)
10642 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10643 " Defined PNG:color-type: %d",mng_info->write_png_colortype-1);
10646 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10647 " PNG color-type written: %d",ping_color_type);
10649 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10650 " PNG Interlace method: %d",ping_interlace_method);
10653 Generate text chunks after IDAT.
10655 if (ping_exclude_tEXt == MagickFalse || ping_exclude_zTXt == MagickFalse)
10657 ResetImagePropertyIterator(image);
10658 property=GetNextImageProperty(image);
10659 while (property != (const char *) NULL)
10664 value=GetImageProperty(image,property,exception);
10666 /* Don't write any "png:" properties; those are just for "identify" */
10667 if (LocaleNCompare(property,"png:",4) != 0 &&
10669 /* Suppress density and units if we wrote a pHYs chunk */
10670 (ping_exclude_pHYs != MagickFalse ||
10671 LocaleCompare(property,"density") != 0 ||
10672 LocaleCompare(property,"units") != 0) &&
10674 /* Suppress the IM-generated Date:create and Date:modify */
10675 (ping_exclude_date == MagickFalse ||
10676 LocaleNCompare(property, "Date:",5) != 0))
10678 if (value != (const char *) NULL)
10680 text=(png_textp) png_malloc(ping,(png_uint_32) sizeof(png_text));
10681 text[0].key=(char *) property;
10682 text[0].text=(char *) value;
10683 text[0].text_length=strlen(value);
10685 if (ping_exclude_tEXt != MagickFalse)
10686 text[0].compression=PNG_TEXT_COMPRESSION_zTXt;
10688 else if (ping_exclude_zTXt != MagickFalse)
10689 text[0].compression=PNG_TEXT_COMPRESSION_NONE;
10693 text[0].compression=image_info->compression == NoCompression ||
10694 (image_info->compression == UndefinedCompression &&
10695 text[0].text_length < 128) ? PNG_TEXT_COMPRESSION_NONE :
10696 PNG_TEXT_COMPRESSION_zTXt ;
10699 if (logging != MagickFalse)
10701 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10702 " Setting up text chunk");
10704 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10705 " keyword: %s",text[0].key);
10708 png_set_text(ping,ping_info,text,1);
10709 png_free(ping,text);
10712 property=GetNextImageProperty(image);
10716 /* write any PNG-chunk-e profiles */
10717 (void) Magick_png_write_chunk_from_profile(image,"PNG-chunk-e",logging);
10719 if (logging != MagickFalse)
10720 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10721 " Writing PNG end info");
10723 png_write_end(ping,ping_info);
10725 if (mng_info->need_fram && (int) image->dispose == BackgroundDispose)
10727 if (mng_info->page.x || mng_info->page.y ||
10728 (ping_width != mng_info->page.width) ||
10729 (ping_height != mng_info->page.height))
10735 Write FRAM 4 with clipping boundaries followed by FRAM 1.
10737 (void) WriteBlobMSBULong(image,27L); /* data length=27 */
10738 PNGType(chunk,mng_FRAM);
10739 LogPNGChunk(logging,mng_FRAM,27L);
10741 chunk[5]=0; /* frame name separator (no name) */
10742 chunk[6]=1; /* flag for changing delay, for next frame only */
10743 chunk[7]=0; /* flag for changing frame timeout */
10744 chunk[8]=1; /* flag for changing frame clipping for next frame */
10745 chunk[9]=0; /* flag for changing frame sync_id */
10746 PNGLong(chunk+10,(png_uint_32) (0L)); /* temporary 0 delay */
10747 chunk[14]=0; /* clipping boundaries delta type */
10748 PNGLong(chunk+15,(png_uint_32) (mng_info->page.x)); /* left cb */
10750 (png_uint_32) (mng_info->page.x + ping_width));
10751 PNGLong(chunk+23,(png_uint_32) (mng_info->page.y)); /* top cb */
10753 (png_uint_32) (mng_info->page.y + ping_height));
10754 (void) WriteBlob(image,31,chunk);
10755 (void) WriteBlobMSBULong(image,crc32(0,chunk,31));
10756 mng_info->old_framing_mode=4;
10757 mng_info->framing_mode=1;
10761 mng_info->framing_mode=3;
10763 if (mng_info->write_mng && !mng_info->need_fram &&
10764 ((int) image->dispose == 3))
10765 (void) ThrowMagickException(exception,GetMagickModule(),
10766 CoderError,"Cannot convert GIF with disposal method 3 to MNG-LC",
10767 "`%s'",image->filename);
10770 Free PNG resources.
10773 png_destroy_write_struct(&ping,&ping_info);
10775 ping_pixels=(unsigned char *) RelinquishMagickMemory(ping_pixels);
10777 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
10778 UnlockSemaphoreInfo(ping_semaphore);
10781 if (ping_have_blob != MagickFalse)
10782 (void) CloseBlob(image);
10784 image_info=DestroyImageInfo(image_info);
10785 image=DestroyImage(image);
10787 /* Store bit depth actually written */
10788 s[0]=(char) ping_bit_depth;
10791 (void) SetImageProperty(IMimage,"png:bit-depth-written",s,exception);
10793 if (logging != MagickFalse)
10794 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10795 " exit WriteOnePNGImage()");
10797 return(MagickTrue);
10798 /* End write one PNG image */
10802 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10806 % W r i t e P N G I m a g e %
10810 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10812 % WritePNGImage() writes a Portable Network Graphics (PNG) or
10813 % Multiple-image Network Graphics (MNG) image file.
10815 % MNG support written by Glenn Randers-Pehrson, glennrp@image...
10817 % The format of the WritePNGImage method is:
10819 % MagickBooleanType WritePNGImage(const ImageInfo *image_info,
10820 % Image *image,ExceptionInfo *exception)
10822 % A description of each parameter follows:
10824 % o image_info: the image info.
10826 % o image: The image.
10828 % o exception: return any errors or warnings in this structure.
10830 % Returns MagickTrue on success, MagickFalse on failure.
10832 % Communicating with the PNG encoder:
10834 % While the datastream written is always in PNG format and normally would
10835 % be given the "png" file extension, this method also writes the following
10836 % pseudo-formats which are subsets of PNG:
10838 % o PNG8: An 8-bit indexed PNG datastream is written. If the image has
10839 % a depth greater than 8, the depth is reduced. If transparency
10840 % is present, the tRNS chunk must only have values 0 and 255
10841 % (i.e., transparency is binary: fully opaque or fully
10842 % transparent). If other values are present they will be
10843 % 50%-thresholded to binary transparency. If more than 256
10844 % colors are present, they will be quantized to the 4-4-4-1,
10845 % 3-3-3-1, or 3-3-2-1 palette. The underlying RGB color
10846 % of any resulting fully-transparent pixels is changed to
10847 % the image's background color.
10849 % If you want better quantization or dithering of the colors
10850 % or alpha than that, you need to do it before calling the
10851 % PNG encoder. The pixels contain 8-bit indices even if
10852 % they could be represented with 1, 2, or 4 bits. Grayscale
10853 % images will be written as indexed PNG files even though the
10854 % PNG grayscale type might be slightly more efficient. Please
10855 % note that writing to the PNG8 format may result in loss
10856 % of color and alpha data.
10858 % o PNG24: An 8-bit per sample RGB PNG datastream is written. The tRNS
10859 % chunk can be present to convey binary transparency by naming
10860 % one of the colors as transparent. The only loss incurred
10861 % is reduction of sample depth to 8. If the image has more
10862 % than one transparent color, has semitransparent pixels, or
10863 % has an opaque pixel with the same RGB components as the
10864 % transparent color, an image is not written.
10866 % o PNG32: An 8-bit per sample RGBA PNG is written. Partial
10867 % transparency is permitted, i.e., the alpha sample for
10868 % each pixel can have any value from 0 to 255. The alpha
10869 % channel is present even if the image is fully opaque.
10870 % The only loss in data is the reduction of the sample depth
10873 % o -define: For more precise control of the PNG output, you can use the
10874 % Image options "png:bit-depth" and "png:color-type". These
10875 % can be set from the commandline with "-define" and also
10876 % from the application programming interfaces. The options
10877 % are case-independent and are converted to lowercase before
10878 % being passed to this encoder.
10880 % png:color-type can be 0, 2, 3, 4, or 6.
10882 % When png:color-type is 0 (Grayscale), png:bit-depth can
10883 % be 1, 2, 4, 8, or 16.
10885 % When png:color-type is 2 (RGB), png:bit-depth can
10888 % When png:color-type is 3 (Indexed), png:bit-depth can
10889 % be 1, 2, 4, or 8. This refers to the number of bits
10890 % used to store the index. The color samples always have
10891 % bit-depth 8 in indexed PNG files.
10893 % When png:color-type is 4 (Gray-Matte) or 6 (RGB-Matte),
10894 % png:bit-depth can be 8 or 16.
10896 % If the image cannot be written without loss with the requested bit-depth
10897 % and color-type, a PNG file will not be written, and the encoder will
10898 % return MagickFalse.
10900 % Since image encoders should not be responsible for the "heavy lifting",
10901 % the user should make sure that ImageMagick has already reduced the
10902 % image depth and number of colors and limit transparency to binary
10903 % transparency prior to attempting to write the image with depth, color,
10904 % or transparency limitations.
10906 % Note that another definition, "png:bit-depth-written" exists, but it
10907 % is not intended for external use. It is only used internally by the
10908 % PNG encoder to inform the JNG encoder of the depth of the alpha channel.
10910 % It is possible to request that the PNG encoder write previously-formatted
10911 % ancillary chunks in the output PNG file, using the "-profile" commandline
10912 % option as shown below or by setting the profile via a programming
10915 % -profile PNG-chunk-x:<file>
10917 % where x is a location flag and <file> is a file containing the chunk
10918 % name in the first 4 bytes, then a colon (":"), followed by the chunk data.
10919 % This encoder will compute the chunk length and CRC, so those must not
10920 % be included in the file.
10922 % "x" can be "b" (before PLTE), "m" (middle, i.e., between PLTE and IDAT),
10923 % or "e" (end, i.e., after IDAT). If you want to write multiple chunks
10924 % of the same type, then add a short unique string after the "x" to prevent
10925 % subsequent profiles from overwriting the preceding ones, e.g.,
10927 % -profile PNG-chunk-b01:file01 -profile PNG-chunk-b02:file02
10929 % As of version 6.6.6 the following optimizations are always done:
10931 % o 32-bit depth is reduced to 16.
10932 % o 16-bit depth is reduced to 8 if all pixels contain samples whose
10933 % high byte and low byte are identical.
10934 % o Palette is sorted to remove unused entries and to put a
10935 % transparent color first, if BUILD_PNG_PALETTE is defined.
10936 % o Opaque matte channel is removed when writing an indexed PNG.
10937 % o Grayscale images are reduced to 1, 2, or 4 bit depth if
10938 % this can be done without loss and a larger bit depth N was not
10939 % requested via the "-define PNG:bit-depth=N" option.
10940 % o If matte channel is present but only one transparent color is
10941 % present, RGB+tRNS is written instead of RGBA
10942 % o Opaque matte channel is removed (or added, if color-type 4 or 6
10943 % was requested when converting an opaque image).
10945 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10947 static MagickBooleanType WritePNGImage(const ImageInfo *image_info,
10948 Image *image,ExceptionInfo *exception)
10953 have_mng_structure,
10969 assert(image_info != (const ImageInfo *) NULL);
10970 assert(image_info->signature == MagickSignature);
10971 assert(image != (Image *) NULL);
10972 assert(image->signature == MagickSignature);
10973 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
10974 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter WritePNGImage()");
10976 Allocate a MngInfo structure.
10978 have_mng_structure=MagickFalse;
10979 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
10981 if (mng_info == (MngInfo *) NULL)
10982 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
10985 Initialize members of the MngInfo structure.
10987 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
10988 mng_info->image=image;
10989 mng_info->equal_backgrounds=MagickTrue;
10990 have_mng_structure=MagickTrue;
10992 /* See if user has requested a specific PNG subformat */
10994 mng_info->write_png8=LocaleCompare(image_info->magick,"PNG8") == 0;
10995 mng_info->write_png24=LocaleCompare(image_info->magick,"PNG24") == 0;
10996 mng_info->write_png32=LocaleCompare(image_info->magick,"PNG32") == 0;
10998 if (mng_info->write_png8)
11000 mng_info->write_png_colortype = /* 3 */ 4;
11001 mng_info->write_png_depth = 8;
11005 if (mng_info->write_png24)
11007 mng_info->write_png_colortype = /* 2 */ 3;
11008 mng_info->write_png_depth = 8;
11011 if (image->matte == MagickTrue)
11012 (void) SetImageType(image,TrueColorMatteType,exception);
11015 (void) SetImageType(image,TrueColorType,exception);
11017 (void) SyncImage(image,exception);
11020 if (mng_info->write_png32)
11022 mng_info->write_png_colortype = /* 6 */ 7;
11023 mng_info->write_png_depth = 8;
11026 if (image->matte == MagickTrue)
11027 (void) SetImageType(image,TrueColorMatteType,exception);
11030 (void) SetImageType(image,TrueColorType,exception);
11032 (void) SyncImage(image,exception);
11035 value=GetImageOption(image_info,"png:bit-depth");
11037 if (value != (char *) NULL)
11039 if (LocaleCompare(value,"1") == 0)
11040 mng_info->write_png_depth = 1;
11042 else if (LocaleCompare(value,"2") == 0)
11043 mng_info->write_png_depth = 2;
11045 else if (LocaleCompare(value,"4") == 0)
11046 mng_info->write_png_depth = 4;
11048 else if (LocaleCompare(value,"8") == 0)
11049 mng_info->write_png_depth = 8;
11051 else if (LocaleCompare(value,"16") == 0)
11052 mng_info->write_png_depth = 16;
11055 (void) ThrowMagickException(exception,
11056 GetMagickModule(),CoderWarning,
11057 "ignoring invalid defined png:bit-depth",
11060 if (logging != MagickFalse)
11061 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11062 " png:bit-depth=%d was defined.\n",mng_info->write_png_depth);
11065 value=GetImageOption(image_info,"png:color-type");
11067 if (value != (char *) NULL)
11069 /* We must store colortype+1 because 0 is a valid colortype */
11070 if (LocaleCompare(value,"0") == 0)
11071 mng_info->write_png_colortype = 1;
11073 else if (LocaleCompare(value,"2") == 0)
11074 mng_info->write_png_colortype = 3;
11076 else if (LocaleCompare(value,"3") == 0)
11077 mng_info->write_png_colortype = 4;
11079 else if (LocaleCompare(value,"4") == 0)
11080 mng_info->write_png_colortype = 5;
11082 else if (LocaleCompare(value,"6") == 0)
11083 mng_info->write_png_colortype = 7;
11086 (void) ThrowMagickException(exception,
11087 GetMagickModule(),CoderWarning,
11088 "ignoring invalid defined png:color-type",
11091 if (logging != MagickFalse)
11092 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11093 " png:color-type=%d was defined.\n",mng_info->write_png_colortype-1);
11096 /* Check for chunks to be excluded:
11098 * The default is to not exclude any known chunks except for any
11099 * listed in the "unused_chunks" array, above.
11101 * Chunks can be listed for exclusion via a "PNG:exclude-chunk"
11102 * define (in the image properties or in the image artifacts)
11103 * or via a mng_info member. For convenience, in addition
11104 * to or instead of a comma-separated list of chunks, the
11105 * "exclude-chunk" string can be simply "all" or "none".
11107 * The exclude-chunk define takes priority over the mng_info.
11109 * A "PNG:include-chunk" define takes priority over both the
11110 * mng_info and the "PNG:exclude-chunk" define. Like the
11111 * "exclude-chunk" string, it can define "all" or "none" as
11112 * well as a comma-separated list. Chunks that are unknown to
11113 * ImageMagick are always excluded, regardless of their "copy-safe"
11114 * status according to the PNG specification, and even if they
11115 * appear in the "include-chunk" list.
11117 * Finally, all chunks listed in the "unused_chunks" array are
11118 * automatically excluded, regardless of the other instructions
11121 * if you exclude sRGB but not gAMA (recommended), then sRGB chunk
11122 * will not be written and the gAMA chunk will only be written if it
11123 * is not between .45 and .46, or approximately (1.0/2.2).
11125 * If you exclude tRNS and the image has transparency, the colortype
11126 * is forced to be 4 or 6 (GRAY_ALPHA or RGB_ALPHA).
11128 * The -strip option causes StripImage() to set the png:include-chunk
11129 * artifact to "none,trns,gama".
11132 mng_info->ping_exclude_bKGD=MagickFalse;
11133 mng_info->ping_exclude_cHRM=MagickFalse;
11134 mng_info->ping_exclude_date=MagickFalse;
11135 mng_info->ping_exclude_EXIF=MagickFalse; /* hex-encoded EXIF in zTXt */
11136 mng_info->ping_exclude_gAMA=MagickFalse;
11137 mng_info->ping_exclude_iCCP=MagickFalse;
11138 /* mng_info->ping_exclude_iTXt=MagickFalse; */
11139 mng_info->ping_exclude_oFFs=MagickFalse;
11140 mng_info->ping_exclude_pHYs=MagickFalse;
11141 mng_info->ping_exclude_sRGB=MagickFalse;
11142 mng_info->ping_exclude_tEXt=MagickFalse;
11143 mng_info->ping_exclude_tRNS=MagickFalse;
11144 mng_info->ping_exclude_vpAg=MagickFalse;
11145 mng_info->ping_exclude_zCCP=MagickFalse; /* hex-encoded iCCP in zTXt */
11146 mng_info->ping_exclude_zTXt=MagickFalse;
11148 mng_info->ping_preserve_colormap=MagickFalse;
11150 value=GetImageArtifact(image,"png:preserve-colormap");
11152 value=GetImageOption(image_info,"png:preserve-colormap");
11154 mng_info->ping_preserve_colormap=MagickTrue;
11156 /* Thes compression-level, compression-strategy, and compression-filter
11157 * defines take precedence over values from the -quality option.
11159 value=GetImageArtifact(image,"png:compression-level");
11161 value=GetImageOption(image_info,"png:compression-level");
11164 /* We have to add 1 to everything because 0 is a valid input,
11165 * and we want to use 0 (the default) to mean undefined.
11167 if (LocaleCompare(value,"0") == 0)
11168 mng_info->write_png_compression_level = 1;
11170 if (LocaleCompare(value,"1") == 0)
11171 mng_info->write_png_compression_level = 2;
11173 else if (LocaleCompare(value,"2") == 0)
11174 mng_info->write_png_compression_level = 3;
11176 else if (LocaleCompare(value,"3") == 0)
11177 mng_info->write_png_compression_level = 4;
11179 else if (LocaleCompare(value,"4") == 0)
11180 mng_info->write_png_compression_level = 5;
11182 else if (LocaleCompare(value,"5") == 0)
11183 mng_info->write_png_compression_level = 6;
11185 else if (LocaleCompare(value,"6") == 0)
11186 mng_info->write_png_compression_level = 7;
11188 else if (LocaleCompare(value,"7") == 0)
11189 mng_info->write_png_compression_level = 8;
11191 else if (LocaleCompare(value,"8") == 0)
11192 mng_info->write_png_compression_level = 9;
11194 else if (LocaleCompare(value,"9") == 0)
11195 mng_info->write_png_compression_level = 10;
11198 (void) ThrowMagickException(exception,
11199 GetMagickModule(),CoderWarning,
11200 "ignoring invalid defined png:compression-level",
11204 value=GetImageArtifact(image,"png:compression-strategy");
11206 value=GetImageOption(image_info,"png:compression-strategy");
11210 if (LocaleCompare(value,"0") == 0)
11211 mng_info->write_png_compression_strategy = Z_DEFAULT_STRATEGY+1;
11213 else if (LocaleCompare(value,"1") == 0)
11214 mng_info->write_png_compression_strategy = Z_FILTERED+1;
11216 else if (LocaleCompare(value,"2") == 0)
11217 mng_info->write_png_compression_strategy = Z_HUFFMAN_ONLY+1;
11219 else if (LocaleCompare(value,"3") == 0)
11220 #ifdef Z_RLE /* Z_RLE was added to zlib-1.2.0 */
11221 mng_info->write_png_compression_strategy = Z_RLE+1;
11223 mng_info->write_png_compression_strategy = Z_DEFAULT_STRATEGY+1;
11226 else if (LocaleCompare(value,"4") == 0)
11227 #ifdef Z_FIXED /* Z_FIXED was added to zlib-1.2.2.2 */
11228 mng_info->write_png_compression_strategy = Z_FIXED+1;
11230 mng_info->write_png_compression_strategy = Z_DEFAULT_STRATEGY+1;
11234 (void) ThrowMagickException(exception,
11235 GetMagickModule(),CoderWarning,
11236 "ignoring invalid defined png:compression-strategy",
11240 value=GetImageArtifact(image,"png:compression-filter");
11242 value=GetImageOption(image_info,"png:compression-filter");
11246 /* To do: combinations of filters allowed by libpng
11247 * masks 0x08 through 0xf8
11249 * Implement this as a comma-separated list of 0,1,2,3,4,5
11250 * where 5 is a special case meaning PNG_ALL_FILTERS.
11253 if (LocaleCompare(value,"0") == 0)
11254 mng_info->write_png_compression_filter = 1;
11256 if (LocaleCompare(value,"1") == 0)
11257 mng_info->write_png_compression_filter = 2;
11259 else if (LocaleCompare(value,"2") == 0)
11260 mng_info->write_png_compression_filter = 3;
11262 else if (LocaleCompare(value,"3") == 0)
11263 mng_info->write_png_compression_filter = 4;
11265 else if (LocaleCompare(value,"4") == 0)
11266 mng_info->write_png_compression_filter = 5;
11268 else if (LocaleCompare(value,"5") == 0)
11269 mng_info->write_png_compression_filter = 6;
11272 (void) ThrowMagickException(exception,
11273 GetMagickModule(),CoderWarning,
11274 "ignoring invalid defined png:compression-filter",
11278 excluding=MagickFalse;
11280 for (source=0; source<1; source++)
11284 value=GetImageArtifact(image,"png:exclude-chunk");
11287 value=GetImageArtifact(image,"png:exclude-chunks");
11291 value=GetImageOption(image_info,"png:exclude-chunk");
11294 value=GetImageOption(image_info,"png:exclude-chunks");
11303 excluding=MagickTrue;
11305 if (logging != MagickFalse)
11308 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11309 " png:exclude-chunk=%s found in image artifacts.\n", value);
11311 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11312 " png:exclude-chunk=%s found in image properties.\n", value);
11315 last=strlen(value);
11317 for (i=0; i<(int) last; i+=5)
11320 if (LocaleNCompare(value+i,"all",3) == 0)
11322 mng_info->ping_exclude_bKGD=MagickTrue;
11323 mng_info->ping_exclude_cHRM=MagickTrue;
11324 mng_info->ping_exclude_date=MagickTrue;
11325 mng_info->ping_exclude_EXIF=MagickTrue;
11326 mng_info->ping_exclude_gAMA=MagickTrue;
11327 mng_info->ping_exclude_iCCP=MagickTrue;
11328 /* mng_info->ping_exclude_iTXt=MagickTrue; */
11329 mng_info->ping_exclude_oFFs=MagickTrue;
11330 mng_info->ping_exclude_pHYs=MagickTrue;
11331 mng_info->ping_exclude_sRGB=MagickTrue;
11332 mng_info->ping_exclude_tEXt=MagickTrue;
11333 mng_info->ping_exclude_tRNS=MagickTrue;
11334 mng_info->ping_exclude_vpAg=MagickTrue;
11335 mng_info->ping_exclude_zCCP=MagickTrue;
11336 mng_info->ping_exclude_zTXt=MagickTrue;
11340 if (LocaleNCompare(value+i,"none",4) == 0)
11342 mng_info->ping_exclude_bKGD=MagickFalse;
11343 mng_info->ping_exclude_cHRM=MagickFalse;
11344 mng_info->ping_exclude_date=MagickFalse;
11345 mng_info->ping_exclude_EXIF=MagickFalse;
11346 mng_info->ping_exclude_gAMA=MagickFalse;
11347 mng_info->ping_exclude_iCCP=MagickFalse;
11348 /* mng_info->ping_exclude_iTXt=MagickFalse; */
11349 mng_info->ping_exclude_oFFs=MagickFalse;
11350 mng_info->ping_exclude_pHYs=MagickFalse;
11351 mng_info->ping_exclude_sRGB=MagickFalse;
11352 mng_info->ping_exclude_tEXt=MagickFalse;
11353 mng_info->ping_exclude_tRNS=MagickFalse;
11354 mng_info->ping_exclude_vpAg=MagickFalse;
11355 mng_info->ping_exclude_zCCP=MagickFalse;
11356 mng_info->ping_exclude_zTXt=MagickFalse;
11359 if (LocaleNCompare(value+i,"bkgd",4) == 0)
11360 mng_info->ping_exclude_bKGD=MagickTrue;
11362 if (LocaleNCompare(value+i,"chrm",4) == 0)
11363 mng_info->ping_exclude_cHRM=MagickTrue;
11365 if (LocaleNCompare(value+i,"date",4) == 0)
11366 mng_info->ping_exclude_date=MagickTrue;
11368 if (LocaleNCompare(value+i,"exif",4) == 0)
11369 mng_info->ping_exclude_EXIF=MagickTrue;
11371 if (LocaleNCompare(value+i,"gama",4) == 0)
11372 mng_info->ping_exclude_gAMA=MagickTrue;
11374 if (LocaleNCompare(value+i,"iccp",4) == 0)
11375 mng_info->ping_exclude_iCCP=MagickTrue;
11378 if (LocaleNCompare(value+i,"itxt",4) == 0)
11379 mng_info->ping_exclude_iTXt=MagickTrue;
11382 if (LocaleNCompare(value+i,"gama",4) == 0)
11383 mng_info->ping_exclude_gAMA=MagickTrue;
11385 if (LocaleNCompare(value+i,"offs",4) == 0)
11386 mng_info->ping_exclude_oFFs=MagickTrue;
11388 if (LocaleNCompare(value+i,"phys",4) == 0)
11389 mng_info->ping_exclude_pHYs=MagickTrue;
11391 if (LocaleNCompare(value+i,"srgb",4) == 0)
11392 mng_info->ping_exclude_sRGB=MagickTrue;
11394 if (LocaleNCompare(value+i,"text",4) == 0)
11395 mng_info->ping_exclude_tEXt=MagickTrue;
11397 if (LocaleNCompare(value+i,"trns",4) == 0)
11398 mng_info->ping_exclude_tRNS=MagickTrue;
11400 if (LocaleNCompare(value+i,"vpag",4) == 0)
11401 mng_info->ping_exclude_vpAg=MagickTrue;
11403 if (LocaleNCompare(value+i,"zccp",4) == 0)
11404 mng_info->ping_exclude_zCCP=MagickTrue;
11406 if (LocaleNCompare(value+i,"ztxt",4) == 0)
11407 mng_info->ping_exclude_zTXt=MagickTrue;
11413 for (source=0; source<1; source++)
11417 value=GetImageArtifact(image,"png:include-chunk");
11420 value=GetImageArtifact(image,"png:include-chunks");
11424 value=GetImageOption(image_info,"png:include-chunk");
11427 value=GetImageOption(image_info,"png:include-chunks");
11435 excluding=MagickTrue;
11437 if (logging != MagickFalse)
11440 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11441 " png:include-chunk=%s found in image artifacts.\n", value);
11443 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11444 " png:include-chunk=%s found in image properties.\n", value);
11447 last=strlen(value);
11449 for (i=0; i<(int) last; i+=5)
11451 if (LocaleNCompare(value+i,"all",3) == 0)
11453 mng_info->ping_exclude_bKGD=MagickFalse;
11454 mng_info->ping_exclude_cHRM=MagickFalse;
11455 mng_info->ping_exclude_date=MagickFalse;
11456 mng_info->ping_exclude_EXIF=MagickFalse;
11457 mng_info->ping_exclude_gAMA=MagickFalse;
11458 mng_info->ping_exclude_iCCP=MagickFalse;
11459 /* mng_info->ping_exclude_iTXt=MagickFalse; */
11460 mng_info->ping_exclude_oFFs=MagickFalse;
11461 mng_info->ping_exclude_pHYs=MagickFalse;
11462 mng_info->ping_exclude_sRGB=MagickFalse;
11463 mng_info->ping_exclude_tEXt=MagickFalse;
11464 mng_info->ping_exclude_tRNS=MagickFalse;
11465 mng_info->ping_exclude_vpAg=MagickFalse;
11466 mng_info->ping_exclude_zCCP=MagickFalse;
11467 mng_info->ping_exclude_zTXt=MagickFalse;
11471 if (LocaleNCompare(value+i,"none",4) == 0)
11473 mng_info->ping_exclude_bKGD=MagickTrue;
11474 mng_info->ping_exclude_cHRM=MagickTrue;
11475 mng_info->ping_exclude_date=MagickTrue;
11476 mng_info->ping_exclude_EXIF=MagickTrue;
11477 mng_info->ping_exclude_gAMA=MagickTrue;
11478 mng_info->ping_exclude_iCCP=MagickTrue;
11479 /* mng_info->ping_exclude_iTXt=MagickTrue; */
11480 mng_info->ping_exclude_oFFs=MagickTrue;
11481 mng_info->ping_exclude_pHYs=MagickTrue;
11482 mng_info->ping_exclude_sRGB=MagickTrue;
11483 mng_info->ping_exclude_tEXt=MagickTrue;
11484 mng_info->ping_exclude_tRNS=MagickTrue;
11485 mng_info->ping_exclude_vpAg=MagickTrue;
11486 mng_info->ping_exclude_zCCP=MagickTrue;
11487 mng_info->ping_exclude_zTXt=MagickTrue;
11490 if (LocaleNCompare(value+i,"bkgd",4) == 0)
11491 mng_info->ping_exclude_bKGD=MagickFalse;
11493 if (LocaleNCompare(value+i,"chrm",4) == 0)
11494 mng_info->ping_exclude_cHRM=MagickFalse;
11496 if (LocaleNCompare(value+i,"date",4) == 0)
11497 mng_info->ping_exclude_date=MagickFalse;
11499 if (LocaleNCompare(value+i,"exif",4) == 0)
11500 mng_info->ping_exclude_EXIF=MagickFalse;
11502 if (LocaleNCompare(value+i,"gama",4) == 0)
11503 mng_info->ping_exclude_gAMA=MagickFalse;
11505 if (LocaleNCompare(value+i,"iccp",4) == 0)
11506 mng_info->ping_exclude_iCCP=MagickFalse;
11509 if (LocaleNCompare(value+i,"itxt",4) == 0)
11510 mng_info->ping_exclude_iTXt=MagickFalse;
11513 if (LocaleNCompare(value+i,"gama",4) == 0)
11514 mng_info->ping_exclude_gAMA=MagickFalse;
11516 if (LocaleNCompare(value+i,"offs",4) == 0)
11517 mng_info->ping_exclude_oFFs=MagickFalse;
11519 if (LocaleNCompare(value+i,"phys",4) == 0)
11520 mng_info->ping_exclude_pHYs=MagickFalse;
11522 if (LocaleNCompare(value+i,"srgb",4) == 0)
11523 mng_info->ping_exclude_sRGB=MagickFalse;
11525 if (LocaleNCompare(value+i,"text",4) == 0)
11526 mng_info->ping_exclude_tEXt=MagickFalse;
11528 if (LocaleNCompare(value+i,"trns",4) == 0)
11529 mng_info->ping_exclude_tRNS=MagickFalse;
11531 if (LocaleNCompare(value+i,"vpag",4) == 0)
11532 mng_info->ping_exclude_vpAg=MagickFalse;
11534 if (LocaleNCompare(value+i,"zccp",4) == 0)
11535 mng_info->ping_exclude_zCCP=MagickFalse;
11537 if (LocaleNCompare(value+i,"ztxt",4) == 0)
11538 mng_info->ping_exclude_zTXt=MagickFalse;
11544 if (excluding != MagickFalse && logging != MagickFalse)
11546 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11547 " Chunks to be excluded from the output PNG:");
11548 if (mng_info->ping_exclude_bKGD != MagickFalse)
11549 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11551 if (mng_info->ping_exclude_cHRM != MagickFalse)
11552 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11554 if (mng_info->ping_exclude_date != MagickFalse)
11555 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11557 if (mng_info->ping_exclude_EXIF != MagickFalse)
11558 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11560 if (mng_info->ping_exclude_gAMA != MagickFalse)
11561 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11563 if (mng_info->ping_exclude_iCCP != MagickFalse)
11564 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11567 if (mng_info->ping_exclude_iTXt != MagickFalse)
11568 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11571 if (mng_info->ping_exclude_oFFs != MagickFalse)
11572 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11574 if (mng_info->ping_exclude_pHYs != MagickFalse)
11575 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11577 if (mng_info->ping_exclude_sRGB != MagickFalse)
11578 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11580 if (mng_info->ping_exclude_tEXt != MagickFalse)
11581 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11583 if (mng_info->ping_exclude_tRNS != MagickFalse)
11584 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11586 if (mng_info->ping_exclude_vpAg != MagickFalse)
11587 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11589 if (mng_info->ping_exclude_zCCP != MagickFalse)
11590 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11592 if (mng_info->ping_exclude_zTXt != MagickFalse)
11593 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11597 mng_info->need_blob = MagickTrue;
11599 status=WriteOnePNGImage(mng_info,image_info,image,exception);
11601 MngInfoFreeStruct(mng_info,&have_mng_structure);
11603 if (logging != MagickFalse)
11604 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit WritePNGImage()");
11609 #if defined(JNG_SUPPORTED)
11611 /* Write one JNG image */
11612 static MagickBooleanType WriteOneJNGImage(MngInfo *mng_info,
11613 const ImageInfo *image_info,Image *image,ExceptionInfo *exception)
11634 jng_alpha_compression_method,
11635 jng_alpha_sample_depth,
11642 logging=LogMagickEvent(CoderEvent,GetMagickModule(),
11643 " Enter WriteOneJNGImage()");
11645 blob=(unsigned char *) NULL;
11646 jpeg_image=(Image *) NULL;
11647 jpeg_image_info=(ImageInfo *) NULL;
11650 transparent=image_info->type==GrayscaleMatteType ||
11651 image_info->type==TrueColorMatteType;
11653 jng_alpha_sample_depth=0;
11654 jng_quality=image_info->quality == 0UL ? 75UL : image_info->quality;
11655 jng_alpha_compression_method=0;
11657 if (image->matte != MagickFalse)
11659 /* if any pixels are transparent */
11660 transparent=MagickTrue;
11661 if (image_info->compression==JPEGCompression)
11662 jng_alpha_compression_method=8;
11672 /* Create JPEG blob, image, and image_info */
11673 if (logging != MagickFalse)
11674 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11675 " Creating jpeg_image_info for alpha.");
11677 jpeg_image_info=(ImageInfo *) CloneImageInfo(image_info);
11679 if (jpeg_image_info == (ImageInfo *) NULL)
11680 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
11682 if (logging != MagickFalse)
11683 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11684 " Creating jpeg_image.");
11686 jpeg_image=CloneImage(image,0,0,MagickTrue,exception);
11688 if (jpeg_image == (Image *) NULL)
11689 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
11691 (void) CopyMagickString(jpeg_image->magick,"JPEG",MaxTextExtent);
11692 channel_mask=SetPixelChannelMask(jpeg_image,AlphaChannel);
11693 status=SeparateImage(jpeg_image,exception);
11694 (void) SetPixelChannelMap(jpeg_image,channel_mask);
11695 jpeg_image->matte=MagickFalse;
11697 if (jng_quality >= 1000)
11698 jpeg_image_info->quality=jng_quality/1000;
11701 jpeg_image_info->quality=jng_quality;
11703 jpeg_image_info->type=GrayscaleType;
11704 (void) SetImageType(jpeg_image,GrayscaleType,exception);
11705 (void) AcquireUniqueFilename(jpeg_image->filename);
11706 (void) FormatLocaleString(jpeg_image_info->filename,MaxTextExtent,
11707 "%s",jpeg_image->filename);
11710 /* To do: check bit depth of PNG alpha channel */
11712 /* Check if image is grayscale. */
11713 if (image_info->type != TrueColorMatteType && image_info->type !=
11714 TrueColorType && ImageIsGray(image,exception))
11719 if (jng_alpha_compression_method==0)
11724 /* Encode alpha as a grayscale PNG blob */
11725 status=OpenBlob(jpeg_image_info,jpeg_image,WriteBinaryBlobMode,
11727 if (logging != MagickFalse)
11728 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11729 " Creating PNG blob.");
11732 (void) CopyMagickString(jpeg_image_info->magick,"PNG",MaxTextExtent);
11733 (void) CopyMagickString(jpeg_image->magick,"PNG",MaxTextExtent);
11734 jpeg_image_info->interlace=NoInterlace;
11736 blob=ImageToBlob(jpeg_image_info,jpeg_image,&length,
11739 /* Retrieve sample depth used */
11740 value=GetImageProperty(jpeg_image,"png:bit-depth-written",exception);
11741 if (value != (char *) NULL)
11742 jng_alpha_sample_depth= (unsigned int) value[0];
11746 /* Encode alpha as a grayscale JPEG blob */
11748 status=OpenBlob(jpeg_image_info,jpeg_image,WriteBinaryBlobMode,
11751 (void) CopyMagickString(jpeg_image_info->magick,"JPEG",MaxTextExtent);
11752 (void) CopyMagickString(jpeg_image->magick,"JPEG",MaxTextExtent);
11753 jpeg_image_info->interlace=NoInterlace;
11754 if (logging != MagickFalse)
11755 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11756 " Creating blob.");
11757 blob=ImageToBlob(jpeg_image_info,jpeg_image,&length,
11759 jng_alpha_sample_depth=8;
11761 if (logging != MagickFalse)
11762 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11763 " Successfully read jpeg_image into a blob, length=%.20g.",
11767 /* Destroy JPEG image and image_info */
11768 jpeg_image=DestroyImage(jpeg_image);
11769 (void) RelinquishUniqueFileResource(jpeg_image_info->filename);
11770 jpeg_image_info=DestroyImageInfo(jpeg_image_info);
11773 /* Write JHDR chunk */
11774 (void) WriteBlobMSBULong(image,16L); /* chunk data length=16 */
11775 PNGType(chunk,mng_JHDR);
11776 LogPNGChunk(logging,mng_JHDR,16L);
11777 PNGLong(chunk+4,(png_uint_32) image->columns);
11778 PNGLong(chunk+8,(png_uint_32) image->rows);
11779 chunk[12]=jng_color_type;
11780 chunk[13]=8; /* sample depth */
11781 chunk[14]=8; /*jng_image_compression_method */
11782 chunk[15]=(unsigned char) (image_info->interlace == NoInterlace ? 0 : 8);
11783 chunk[16]=jng_alpha_sample_depth;
11784 chunk[17]=jng_alpha_compression_method;
11785 chunk[18]=0; /*jng_alpha_filter_method */
11786 chunk[19]=0; /*jng_alpha_interlace_method */
11787 (void) WriteBlob(image,20,chunk);
11788 (void) WriteBlobMSBULong(image,crc32(0,chunk,20));
11789 if (logging != MagickFalse)
11791 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11792 " JNG width:%15lu",(unsigned long) image->columns);
11794 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11795 " JNG height:%14lu",(unsigned long) image->rows);
11797 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11798 " JNG color type:%10d",jng_color_type);
11800 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11801 " JNG sample depth:%8d",8);
11803 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11804 " JNG compression:%9d",8);
11806 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11807 " JNG interlace:%11d",0);
11809 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11810 " JNG alpha depth:%9d",jng_alpha_sample_depth);
11812 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11813 " JNG alpha compression:%3d",jng_alpha_compression_method);
11815 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11816 " JNG alpha filter:%8d",0);
11818 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11819 " JNG alpha interlace:%5d",0);
11822 /* Write any JNG-chunk-b profiles */
11823 (void) Magick_png_write_chunk_from_profile(image,"JNG-chunk-b",logging);
11826 Write leading ancillary chunks
11832 Write JNG bKGD chunk
11843 if (jng_color_type == 8 || jng_color_type == 12)
11847 (void) WriteBlobMSBULong(image,(size_t) (num_bytes-4L));
11848 PNGType(chunk,mng_bKGD);
11849 LogPNGChunk(logging,mng_bKGD,(size_t) (num_bytes-4L));
11850 red=ScaleQuantumToChar(image->background_color.red);
11851 green=ScaleQuantumToChar(image->background_color.green);
11852 blue=ScaleQuantumToChar(image->background_color.blue);
11859 (void) WriteBlob(image,(size_t) num_bytes,chunk);
11860 (void) WriteBlobMSBULong(image,crc32(0,chunk,(uInt) num_bytes));
11863 if ((image->colorspace == sRGBColorspace || image->rendering_intent))
11866 Write JNG sRGB chunk
11868 (void) WriteBlobMSBULong(image,1L);
11869 PNGType(chunk,mng_sRGB);
11870 LogPNGChunk(logging,mng_sRGB,1L);
11872 if (image->rendering_intent != UndefinedIntent)
11873 chunk[4]=(unsigned char)
11874 Magick_RenderingIntent_to_PNG_RenderingIntent(
11875 (image->rendering_intent));
11878 chunk[4]=(unsigned char)
11879 Magick_RenderingIntent_to_PNG_RenderingIntent(
11880 (PerceptualIntent));
11882 (void) WriteBlob(image,5,chunk);
11883 (void) WriteBlobMSBULong(image,crc32(0,chunk,5));
11887 if (image->gamma != 0.0)
11890 Write JNG gAMA chunk
11892 (void) WriteBlobMSBULong(image,4L);
11893 PNGType(chunk,mng_gAMA);
11894 LogPNGChunk(logging,mng_gAMA,4L);
11895 PNGLong(chunk+4,(png_uint_32) (100000*image->gamma+0.5));
11896 (void) WriteBlob(image,8,chunk);
11897 (void) WriteBlobMSBULong(image,crc32(0,chunk,8));
11900 if ((mng_info->equal_chrms == MagickFalse) &&
11901 (image->chromaticity.red_primary.x != 0.0))
11907 Write JNG cHRM chunk
11909 (void) WriteBlobMSBULong(image,32L);
11910 PNGType(chunk,mng_cHRM);
11911 LogPNGChunk(logging,mng_cHRM,32L);
11912 primary=image->chromaticity.white_point;
11913 PNGLong(chunk+4,(png_uint_32) (100000*primary.x+0.5));
11914 PNGLong(chunk+8,(png_uint_32) (100000*primary.y+0.5));
11915 primary=image->chromaticity.red_primary;
11916 PNGLong(chunk+12,(png_uint_32) (100000*primary.x+0.5));
11917 PNGLong(chunk+16,(png_uint_32) (100000*primary.y+0.5));
11918 primary=image->chromaticity.green_primary;
11919 PNGLong(chunk+20,(png_uint_32) (100000*primary.x+0.5));
11920 PNGLong(chunk+24,(png_uint_32) (100000*primary.y+0.5));
11921 primary=image->chromaticity.blue_primary;
11922 PNGLong(chunk+28,(png_uint_32) (100000*primary.x+0.5));
11923 PNGLong(chunk+32,(png_uint_32) (100000*primary.y+0.5));
11924 (void) WriteBlob(image,36,chunk);
11925 (void) WriteBlobMSBULong(image,crc32(0,chunk,36));
11929 if (image->x_resolution && image->y_resolution && !mng_info->equal_physs)
11932 Write JNG pHYs chunk
11934 (void) WriteBlobMSBULong(image,9L);
11935 PNGType(chunk,mng_pHYs);
11936 LogPNGChunk(logging,mng_pHYs,9L);
11937 if (image->units == PixelsPerInchResolution)
11939 PNGLong(chunk+4,(png_uint_32)
11940 (image->x_resolution*100.0/2.54+0.5));
11942 PNGLong(chunk+8,(png_uint_32)
11943 (image->y_resolution*100.0/2.54+0.5));
11950 if (image->units == PixelsPerCentimeterResolution)
11952 PNGLong(chunk+4,(png_uint_32)
11953 (image->x_resolution*100.0+0.5));
11955 PNGLong(chunk+8,(png_uint_32)
11956 (image->y_resolution*100.0+0.5));
11963 PNGLong(chunk+4,(png_uint_32) (image->x_resolution+0.5));
11964 PNGLong(chunk+8,(png_uint_32) (image->y_resolution+0.5));
11968 (void) WriteBlob(image,13,chunk);
11969 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
11972 if (mng_info->write_mng == 0 && (image->page.x || image->page.y))
11975 Write JNG oFFs chunk
11977 (void) WriteBlobMSBULong(image,9L);
11978 PNGType(chunk,mng_oFFs);
11979 LogPNGChunk(logging,mng_oFFs,9L);
11980 PNGsLong(chunk+4,(ssize_t) (image->page.x));
11981 PNGsLong(chunk+8,(ssize_t) (image->page.y));
11983 (void) WriteBlob(image,13,chunk);
11984 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
11986 if (mng_info->write_mng == 0 && (image->page.width || image->page.height))
11988 (void) WriteBlobMSBULong(image,9L); /* data length=8 */
11989 PNGType(chunk,mng_vpAg);
11990 LogPNGChunk(logging,mng_vpAg,9L);
11991 PNGLong(chunk+4,(png_uint_32) image->page.width);
11992 PNGLong(chunk+8,(png_uint_32) image->page.height);
11993 chunk[12]=0; /* unit = pixels */
11994 (void) WriteBlob(image,13,chunk);
11995 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
12001 if (jng_alpha_compression_method==0)
12009 /* Write IDAT chunk header */
12010 if (logging != MagickFalse)
12011 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12012 " Write IDAT chunks from blob, length=%.20g.",(double)
12015 /* Copy IDAT chunks */
12018 for (i=8; i<(ssize_t) length; i+=len+12)
12020 len=(*p<<24)|((*(p+1))<<16)|((*(p+2))<<8)|(*(p+3));
12023 if (*(p)==73 && *(p+1)==68 && *(p+2)==65 && *(p+3)==84) /* IDAT */
12025 /* Found an IDAT chunk. */
12026 (void) WriteBlobMSBULong(image,(size_t) len);
12027 LogPNGChunk(logging,mng_IDAT,(size_t) len);
12028 (void) WriteBlob(image,(size_t) len+4,p);
12029 (void) WriteBlobMSBULong(image,
12030 crc32(0,p,(uInt) len+4));
12035 if (logging != MagickFalse)
12036 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12037 " Skipping %c%c%c%c chunk, length=%.20g.",
12038 *(p),*(p+1),*(p+2),*(p+3),(double) len);
12045 /* Write JDAA chunk header */
12046 if (logging != MagickFalse)
12047 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12048 " Write JDAA chunk, length=%.20g.",(double) length);
12049 (void) WriteBlobMSBULong(image,(size_t) length);
12050 PNGType(chunk,mng_JDAA);
12051 LogPNGChunk(logging,mng_JDAA,length);
12052 /* Write JDAT chunk(s) data */
12053 (void) WriteBlob(image,4,chunk);
12054 (void) WriteBlob(image,length,blob);
12055 (void) WriteBlobMSBULong(image,crc32(crc32(0,chunk,4),blob,
12058 blob=(unsigned char *) RelinquishMagickMemory(blob);
12061 /* Encode image as a JPEG blob */
12062 if (logging != MagickFalse)
12063 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12064 " Creating jpeg_image_info.");
12065 jpeg_image_info=(ImageInfo *) CloneImageInfo(image_info);
12066 if (jpeg_image_info == (ImageInfo *) NULL)
12067 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
12069 if (logging != MagickFalse)
12070 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12071 " Creating jpeg_image.");
12073 jpeg_image=CloneImage(image,0,0,MagickTrue,exception);
12074 if (jpeg_image == (Image *) NULL)
12075 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
12076 (void) CopyMagickString(jpeg_image->magick,"JPEG",MaxTextExtent);
12078 (void) AcquireUniqueFilename(jpeg_image->filename);
12079 (void) FormatLocaleString(jpeg_image_info->filename,MaxTextExtent,"%s",
12080 jpeg_image->filename);
12082 status=OpenBlob(jpeg_image_info,jpeg_image,WriteBinaryBlobMode,
12085 if (logging != MagickFalse)
12086 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12087 " Created jpeg_image, %.20g x %.20g.",(double) jpeg_image->columns,
12088 (double) jpeg_image->rows);
12090 if (jng_color_type == 8 || jng_color_type == 12)
12091 jpeg_image_info->type=GrayscaleType;
12093 jpeg_image_info->quality=jng_quality % 1000;
12094 (void) CopyMagickString(jpeg_image_info->magick,"JPEG",MaxTextExtent);
12095 (void) CopyMagickString(jpeg_image->magick,"JPEG",MaxTextExtent);
12097 if (logging != MagickFalse)
12098 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12099 " Creating blob.");
12101 blob=ImageToBlob(jpeg_image_info,jpeg_image,&length,exception);
12103 if (logging != MagickFalse)
12105 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12106 " Successfully read jpeg_image into a blob, length=%.20g.",
12109 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12110 " Write JDAT chunk, length=%.20g.",(double) length);
12113 /* Write JDAT chunk(s) */
12114 (void) WriteBlobMSBULong(image,(size_t) length);
12115 PNGType(chunk,mng_JDAT);
12116 LogPNGChunk(logging,mng_JDAT,length);
12117 (void) WriteBlob(image,4,chunk);
12118 (void) WriteBlob(image,length,blob);
12119 (void) WriteBlobMSBULong(image,crc32(crc32(0,chunk,4),blob,(uInt) length));
12121 jpeg_image=DestroyImage(jpeg_image);
12122 (void) RelinquishUniqueFileResource(jpeg_image_info->filename);
12123 jpeg_image_info=DestroyImageInfo(jpeg_image_info);
12124 blob=(unsigned char *) RelinquishMagickMemory(blob);
12126 /* Write any JNG-chunk-e profiles */
12127 (void) Magick_png_write_chunk_from_profile(image,"JNG-chunk-e",logging);
12129 /* Write IEND chunk */
12130 (void) WriteBlobMSBULong(image,0L);
12131 PNGType(chunk,mng_IEND);
12132 LogPNGChunk(logging,mng_IEND,0);
12133 (void) WriteBlob(image,4,chunk);
12134 (void) WriteBlobMSBULong(image,crc32(0,chunk,4));
12136 if (logging != MagickFalse)
12137 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12138 " exit WriteOneJNGImage()");
12145 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12149 % W r i t e J N G I m a g e %
12153 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12155 % WriteJNGImage() writes a JPEG Network Graphics (JNG) image file.
12157 % JNG support written by Glenn Randers-Pehrson, glennrp@image...
12159 % The format of the WriteJNGImage method is:
12161 % MagickBooleanType WriteJNGImage(const ImageInfo *image_info,
12162 % Image *image,ExceptionInfo *exception)
12164 % A description of each parameter follows:
12166 % o image_info: the image info.
12168 % o image: The image.
12170 % o exception: return any errors or warnings in this structure.
12172 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12174 static MagickBooleanType WriteJNGImage(const ImageInfo *image_info,Image *image,
12175 ExceptionInfo *exception)
12178 have_mng_structure,
12188 assert(image_info != (const ImageInfo *) NULL);
12189 assert(image_info->signature == MagickSignature);
12190 assert(image != (Image *) NULL);
12191 assert(image->signature == MagickSignature);
12192 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
12193 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter WriteJNGImage()");
12194 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
12195 if (status == MagickFalse)
12199 Allocate a MngInfo structure.
12201 have_mng_structure=MagickFalse;
12202 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
12203 if (mng_info == (MngInfo *) NULL)
12204 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
12206 Initialize members of the MngInfo structure.
12208 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
12209 mng_info->image=image;
12210 have_mng_structure=MagickTrue;
12212 (void) WriteBlob(image,8,(const unsigned char *) "\213JNG\r\n\032\n");
12214 status=WriteOneJNGImage(mng_info,image_info,image,exception);
12215 (void) CloseBlob(image);
12217 (void) CatchImageException(image);
12218 MngInfoFreeStruct(mng_info,&have_mng_structure);
12219 if (logging != MagickFalse)
12220 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit WriteJNGImage()");
12225 static MagickBooleanType WriteMNGImage(const ImageInfo *image_info,Image *image,
12226 ExceptionInfo *exception)
12235 have_mng_structure,
12238 volatile MagickBooleanType
12250 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
12251 defined(PNG_MNG_FEATURES_SUPPORTED)
12254 all_images_are_gray,
12264 volatile unsigned int
12275 #if (PNG_LIBPNG_VER < 10200)
12276 if (image_info->verbose)
12277 printf("Your PNG library (libpng-%s) is rather old.\n",
12278 PNG_LIBPNG_VER_STRING);
12284 assert(image_info != (const ImageInfo *) NULL);
12285 assert(image_info->signature == MagickSignature);
12286 assert(image != (Image *) NULL);
12287 assert(image->signature == MagickSignature);
12288 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
12289 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter WriteMNGImage()");
12290 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
12291 if (status == MagickFalse)
12295 Allocate a MngInfo structure.
12297 have_mng_structure=MagickFalse;
12298 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
12299 if (mng_info == (MngInfo *) NULL)
12300 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
12302 Initialize members of the MngInfo structure.
12304 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
12305 mng_info->image=image;
12306 have_mng_structure=MagickTrue;
12307 write_mng=LocaleCompare(image_info->magick,"MNG") == 0;
12310 * See if user has requested a specific PNG subformat to be used
12311 * for all of the PNGs in the MNG being written, e.g.,
12313 * convert *.png png8:animation.mng
12315 * To do: check -define png:bit_depth and png:color_type as well,
12316 * or perhaps use mng:bit_depth and mng:color_type instead for
12320 mng_info->write_png8=LocaleCompare(image_info->magick,"PNG8") == 0;
12321 mng_info->write_png24=LocaleCompare(image_info->magick,"PNG24") == 0;
12322 mng_info->write_png32=LocaleCompare(image_info->magick,"PNG32") == 0;
12324 write_jng=MagickFalse;
12325 if (image_info->compression == JPEGCompression)
12326 write_jng=MagickTrue;
12328 mng_info->adjoin=image_info->adjoin &&
12329 (GetNextImageInList(image) != (Image *) NULL) && write_mng;
12331 if (logging != MagickFalse)
12333 /* Log some info about the input */
12337 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12338 " Checking input image(s)");
12340 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12341 " Image_info depth: %.20g",(double) image_info->depth);
12343 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12344 " Type: %d",image_info->type);
12347 for (p=image; p != (Image *) NULL; p=GetNextImageInList(p))
12349 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12350 " Scene: %.20g",(double) scene++);
12352 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12353 " Image depth: %.20g",(double) p->depth);
12356 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12360 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12363 if (p->storage_class == PseudoClass)
12364 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12365 " Storage class: PseudoClass");
12368 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12369 " Storage class: DirectClass");
12372 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12373 " Number of colors: %.20g",(double) p->colors);
12376 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12377 " Number of colors: unspecified");
12379 if (mng_info->adjoin == MagickFalse)
12384 use_global_plte=MagickFalse;
12385 all_images_are_gray=MagickFalse;
12386 #ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
12387 need_local_plte=MagickTrue;
12389 need_defi=MagickFalse;
12390 need_matte=MagickFalse;
12391 mng_info->framing_mode=1;
12392 mng_info->old_framing_mode=1;
12395 if (image_info->page != (char *) NULL)
12398 Determine image bounding box.
12400 SetGeometry(image,&mng_info->page);
12401 (void) ParseMetaGeometry(image_info->page,&mng_info->page.x,
12402 &mng_info->page.y,&mng_info->page.width,&mng_info->page.height);
12414 mng_info->page=image->page;
12415 need_geom=MagickTrue;
12416 if (mng_info->page.width || mng_info->page.height)
12417 need_geom=MagickFalse;
12419 Check all the scenes.
12421 initial_delay=image->delay;
12422 need_iterations=MagickFalse;
12423 mng_info->equal_chrms=image->chromaticity.red_primary.x != 0.0;
12424 mng_info->equal_physs=MagickTrue,
12425 mng_info->equal_gammas=MagickTrue;
12426 mng_info->equal_srgbs=MagickTrue;
12427 mng_info->equal_backgrounds=MagickTrue;
12429 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
12430 defined(PNG_MNG_FEATURES_SUPPORTED)
12431 all_images_are_gray=MagickTrue;
12432 mng_info->equal_palettes=MagickFalse;
12433 need_local_plte=MagickFalse;
12435 for (next_image=image; next_image != (Image *) NULL; )
12439 if ((next_image->columns+next_image->page.x) > mng_info->page.width)
12440 mng_info->page.width=next_image->columns+next_image->page.x;
12442 if ((next_image->rows+next_image->page.y) > mng_info->page.height)
12443 mng_info->page.height=next_image->rows+next_image->page.y;
12446 if (next_image->page.x || next_image->page.y)
12447 need_defi=MagickTrue;
12449 if (next_image->matte)
12450 need_matte=MagickTrue;
12452 if ((int) next_image->dispose >= BackgroundDispose)
12453 if (next_image->matte || next_image->page.x || next_image->page.y ||
12454 ((next_image->columns < mng_info->page.width) &&
12455 (next_image->rows < mng_info->page.height)))
12456 mng_info->need_fram=MagickTrue;
12458 if (next_image->iterations)
12459 need_iterations=MagickTrue;
12461 final_delay=next_image->delay;
12463 if (final_delay != initial_delay || final_delay > 1UL*
12464 next_image->ticks_per_second)
12465 mng_info->need_fram=1;
12467 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
12468 defined(PNG_MNG_FEATURES_SUPPORTED)
12470 check for global palette possibility.
12472 if (image->matte != MagickFalse)
12473 need_local_plte=MagickTrue;
12475 if (need_local_plte == 0)
12477 if (ImageIsGray(image,exception) == MagickFalse)
12478 all_images_are_gray=MagickFalse;
12479 mng_info->equal_palettes=PalettesAreEqual(image,next_image);
12480 if (use_global_plte == 0)
12481 use_global_plte=mng_info->equal_palettes;
12482 need_local_plte=!mng_info->equal_palettes;
12485 if (GetNextImageInList(next_image) != (Image *) NULL)
12487 if (next_image->background_color.red !=
12488 next_image->next->background_color.red ||
12489 next_image->background_color.green !=
12490 next_image->next->background_color.green ||
12491 next_image->background_color.blue !=
12492 next_image->next->background_color.blue)
12493 mng_info->equal_backgrounds=MagickFalse;
12495 if (next_image->gamma != next_image->next->gamma)
12496 mng_info->equal_gammas=MagickFalse;
12498 if (next_image->rendering_intent !=
12499 next_image->next->rendering_intent)
12500 mng_info->equal_srgbs=MagickFalse;
12502 if ((next_image->units != next_image->next->units) ||
12503 (next_image->x_resolution != next_image->next->x_resolution) ||
12504 (next_image->y_resolution != next_image->next->y_resolution))
12505 mng_info->equal_physs=MagickFalse;
12507 if (mng_info->equal_chrms)
12509 if (next_image->chromaticity.red_primary.x !=
12510 next_image->next->chromaticity.red_primary.x ||
12511 next_image->chromaticity.red_primary.y !=
12512 next_image->next->chromaticity.red_primary.y ||
12513 next_image->chromaticity.green_primary.x !=
12514 next_image->next->chromaticity.green_primary.x ||
12515 next_image->chromaticity.green_primary.y !=
12516 next_image->next->chromaticity.green_primary.y ||
12517 next_image->chromaticity.blue_primary.x !=
12518 next_image->next->chromaticity.blue_primary.x ||
12519 next_image->chromaticity.blue_primary.y !=
12520 next_image->next->chromaticity.blue_primary.y ||
12521 next_image->chromaticity.white_point.x !=
12522 next_image->next->chromaticity.white_point.x ||
12523 next_image->chromaticity.white_point.y !=
12524 next_image->next->chromaticity.white_point.y)
12525 mng_info->equal_chrms=MagickFalse;
12529 next_image=GetNextImageInList(next_image);
12531 if (image_count < 2)
12533 mng_info->equal_backgrounds=MagickFalse;
12534 mng_info->equal_chrms=MagickFalse;
12535 mng_info->equal_gammas=MagickFalse;
12536 mng_info->equal_srgbs=MagickFalse;
12537 mng_info->equal_physs=MagickFalse;
12538 use_global_plte=MagickFalse;
12539 #ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
12540 need_local_plte=MagickTrue;
12542 need_iterations=MagickFalse;
12545 if (mng_info->need_fram == MagickFalse)
12548 Only certain framing rates 100/n are exactly representable without
12549 the FRAM chunk but we'll allow some slop in VLC files
12551 if (final_delay == 0)
12553 if (need_iterations != MagickFalse)
12556 It's probably a GIF with loop; don't run it *too* fast.
12558 if (mng_info->adjoin)
12561 (void) ThrowMagickException(exception,GetMagickModule(),
12563 "input has zero delay between all frames; assuming",
12568 mng_info->ticks_per_second=0;
12570 if (final_delay != 0)
12571 mng_info->ticks_per_second=(png_uint_32)
12572 (image->ticks_per_second/final_delay);
12573 if (final_delay > 50)
12574 mng_info->ticks_per_second=2;
12576 if (final_delay > 75)
12577 mng_info->ticks_per_second=1;
12579 if (final_delay > 125)
12580 mng_info->need_fram=MagickTrue;
12582 if (need_defi && final_delay > 2 && (final_delay != 4) &&
12583 (final_delay != 5) && (final_delay != 10) && (final_delay != 20) &&
12584 (final_delay != 25) && (final_delay != 50) && (final_delay !=
12585 1UL*image->ticks_per_second))
12586 mng_info->need_fram=MagickTrue; /* make it exact; cannot be VLC */
12589 if (mng_info->need_fram != MagickFalse)
12590 mng_info->ticks_per_second=1UL*image->ticks_per_second;
12592 If pseudocolor, we should also check to see if all the
12593 palettes are identical and write a global PLTE if they are.
12597 Write the MNG version 1.0 signature and MHDR chunk.
12599 (void) WriteBlob(image,8,(const unsigned char *) "\212MNG\r\n\032\n");
12600 (void) WriteBlobMSBULong(image,28L); /* chunk data length=28 */
12601 PNGType(chunk,mng_MHDR);
12602 LogPNGChunk(logging,mng_MHDR,28L);
12603 PNGLong(chunk+4,(png_uint_32) mng_info->page.width);
12604 PNGLong(chunk+8,(png_uint_32) mng_info->page.height);
12605 PNGLong(chunk+12,mng_info->ticks_per_second);
12606 PNGLong(chunk+16,0L); /* layer count=unknown */
12607 PNGLong(chunk+20,0L); /* frame count=unknown */
12608 PNGLong(chunk+24,0L); /* play time=unknown */
12613 if (need_defi || mng_info->need_fram || use_global_plte)
12614 PNGLong(chunk+28,27L); /* simplicity=LC+JNG */
12617 PNGLong(chunk+28,25L); /* simplicity=VLC+JNG */
12622 if (need_defi || mng_info->need_fram || use_global_plte)
12623 PNGLong(chunk+28,19L); /* simplicity=LC+JNG, no transparency */
12626 PNGLong(chunk+28,17L); /* simplicity=VLC+JNG, no transparency */
12634 if (need_defi || mng_info->need_fram || use_global_plte)
12635 PNGLong(chunk+28,11L); /* simplicity=LC */
12638 PNGLong(chunk+28,9L); /* simplicity=VLC */
12643 if (need_defi || mng_info->need_fram || use_global_plte)
12644 PNGLong(chunk+28,3L); /* simplicity=LC, no transparency */
12647 PNGLong(chunk+28,1L); /* simplicity=VLC, no transparency */
12650 (void) WriteBlob(image,32,chunk);
12651 (void) WriteBlobMSBULong(image,crc32(0,chunk,32));
12652 option=GetImageOption(image_info,"mng:need-cacheoff");
12653 if (option != (const char *) NULL)
12659 Write "nEED CACHEOFF" to turn playback caching off for streaming MNG.
12661 PNGType(chunk,mng_nEED);
12662 length=CopyMagickString((char *) chunk+4,"CACHEOFF",20);
12663 (void) WriteBlobMSBULong(image,(size_t) length);
12664 LogPNGChunk(logging,mng_nEED,(size_t) length);
12666 (void) WriteBlob(image,length,chunk);
12667 (void) WriteBlobMSBULong(image,crc32(0,chunk,(uInt) length));
12669 if ((GetPreviousImageInList(image) == (Image *) NULL) &&
12670 (GetNextImageInList(image) != (Image *) NULL) &&
12671 (image->iterations != 1))
12674 Write MNG TERM chunk
12676 (void) WriteBlobMSBULong(image,10L); /* data length=10 */
12677 PNGType(chunk,mng_TERM);
12678 LogPNGChunk(logging,mng_TERM,10L);
12679 chunk[4]=3; /* repeat animation */
12680 chunk[5]=0; /* show last frame when done */
12681 PNGLong(chunk+6,(png_uint_32) (mng_info->ticks_per_second*
12682 final_delay/MagickMax(image->ticks_per_second,1)));
12684 if (image->iterations == 0)
12685 PNGLong(chunk+10,PNG_UINT_31_MAX);
12688 PNGLong(chunk+10,(png_uint_32) image->iterations);
12690 if (logging != MagickFalse)
12692 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12693 " TERM delay: %.20g",(double) (mng_info->ticks_per_second*
12694 final_delay/MagickMax(image->ticks_per_second,1)));
12696 if (image->iterations == 0)
12697 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12698 " TERM iterations: %.20g",(double) PNG_UINT_31_MAX);
12701 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
12702 " Image iterations: %.20g",(double) image->iterations);
12704 (void) WriteBlob(image,14,chunk);
12705 (void) WriteBlobMSBULong(image,crc32(0,chunk,14));
12708 To do: check for cHRM+gAMA == sRGB, and write sRGB instead.
12710 if ((image->colorspace == sRGBColorspace || image->rendering_intent) &&
12711 mng_info->equal_srgbs)
12714 Write MNG sRGB chunk
12716 (void) WriteBlobMSBULong(image,1L);
12717 PNGType(chunk,mng_sRGB);
12718 LogPNGChunk(logging,mng_sRGB,1L);
12720 if (image->rendering_intent != UndefinedIntent)
12721 chunk[4]=(unsigned char)
12722 Magick_RenderingIntent_to_PNG_RenderingIntent(
12723 (image->rendering_intent));
12726 chunk[4]=(unsigned char)
12727 Magick_RenderingIntent_to_PNG_RenderingIntent(
12728 (PerceptualIntent));
12730 (void) WriteBlob(image,5,chunk);
12731 (void) WriteBlobMSBULong(image,crc32(0,chunk,5));
12732 mng_info->have_write_global_srgb=MagickTrue;
12737 if (image->gamma && mng_info->equal_gammas)
12740 Write MNG gAMA chunk
12742 (void) WriteBlobMSBULong(image,4L);
12743 PNGType(chunk,mng_gAMA);
12744 LogPNGChunk(logging,mng_gAMA,4L);
12745 PNGLong(chunk+4,(png_uint_32) (100000*image->gamma+0.5));
12746 (void) WriteBlob(image,8,chunk);
12747 (void) WriteBlobMSBULong(image,crc32(0,chunk,8));
12748 mng_info->have_write_global_gama=MagickTrue;
12750 if (mng_info->equal_chrms)
12756 Write MNG cHRM chunk
12758 (void) WriteBlobMSBULong(image,32L);
12759 PNGType(chunk,mng_cHRM);
12760 LogPNGChunk(logging,mng_cHRM,32L);
12761 primary=image->chromaticity.white_point;
12762 PNGLong(chunk+4,(png_uint_32) (100000*primary.x+0.5));
12763 PNGLong(chunk+8,(png_uint_32) (100000*primary.y+0.5));
12764 primary=image->chromaticity.red_primary;
12765 PNGLong(chunk+12,(png_uint_32) (100000*primary.x+0.5));
12766 PNGLong(chunk+16,(png_uint_32) (100000*primary.y+0.5));
12767 primary=image->chromaticity.green_primary;
12768 PNGLong(chunk+20,(png_uint_32) (100000*primary.x+0.5));
12769 PNGLong(chunk+24,(png_uint_32) (100000*primary.y+0.5));
12770 primary=image->chromaticity.blue_primary;
12771 PNGLong(chunk+28,(png_uint_32) (100000*primary.x+0.5));
12772 PNGLong(chunk+32,(png_uint_32) (100000*primary.y+0.5));
12773 (void) WriteBlob(image,36,chunk);
12774 (void) WriteBlobMSBULong(image,crc32(0,chunk,36));
12775 mng_info->have_write_global_chrm=MagickTrue;
12778 if (image->x_resolution && image->y_resolution && mng_info->equal_physs)
12781 Write MNG pHYs chunk
12783 (void) WriteBlobMSBULong(image,9L);
12784 PNGType(chunk,mng_pHYs);
12785 LogPNGChunk(logging,mng_pHYs,9L);
12787 if (image->units == PixelsPerInchResolution)
12789 PNGLong(chunk+4,(png_uint_32)
12790 (image->x_resolution*100.0/2.54+0.5));
12792 PNGLong(chunk+8,(png_uint_32)
12793 (image->y_resolution*100.0/2.54+0.5));
12800 if (image->units == PixelsPerCentimeterResolution)
12802 PNGLong(chunk+4,(png_uint_32)
12803 (image->x_resolution*100.0+0.5));
12805 PNGLong(chunk+8,(png_uint_32)
12806 (image->y_resolution*100.0+0.5));
12813 PNGLong(chunk+4,(png_uint_32) (image->x_resolution+0.5));
12814 PNGLong(chunk+8,(png_uint_32) (image->y_resolution+0.5));
12818 (void) WriteBlob(image,13,chunk);
12819 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
12822 Write MNG BACK chunk and global bKGD chunk, if the image is transparent
12823 or does not cover the entire frame.
12825 if (write_mng && (image->matte || image->page.x > 0 ||
12826 image->page.y > 0 || (image->page.width &&
12827 (image->page.width+image->page.x < mng_info->page.width))
12828 || (image->page.height && (image->page.height+image->page.y
12829 < mng_info->page.height))))
12831 (void) WriteBlobMSBULong(image,6L);
12832 PNGType(chunk,mng_BACK);
12833 LogPNGChunk(logging,mng_BACK,6L);
12834 red=ScaleQuantumToShort(image->background_color.red);
12835 green=ScaleQuantumToShort(image->background_color.green);
12836 blue=ScaleQuantumToShort(image->background_color.blue);
12837 PNGShort(chunk+4,red);
12838 PNGShort(chunk+6,green);
12839 PNGShort(chunk+8,blue);
12840 (void) WriteBlob(image,10,chunk);
12841 (void) WriteBlobMSBULong(image,crc32(0,chunk,10));
12842 if (mng_info->equal_backgrounds)
12844 (void) WriteBlobMSBULong(image,6L);
12845 PNGType(chunk,mng_bKGD);
12846 LogPNGChunk(logging,mng_bKGD,6L);
12847 (void) WriteBlob(image,10,chunk);
12848 (void) WriteBlobMSBULong(image,crc32(0,chunk,10));
12852 #ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
12853 if ((need_local_plte == MagickFalse) &&
12854 (image->storage_class == PseudoClass) &&
12855 (all_images_are_gray == MagickFalse))
12861 Write MNG PLTE chunk
12863 data_length=3*image->colors;
12864 (void) WriteBlobMSBULong(image,data_length);
12865 PNGType(chunk,mng_PLTE);
12866 LogPNGChunk(logging,mng_PLTE,data_length);
12868 for (i=0; i < (ssize_t) image->colors; i++)
12870 chunk[4+i*3]=(unsigned char) (ScaleQuantumToChar(
12871 image->colormap[i].red) & 0xff);
12872 chunk[5+i*3]=(unsigned char) (ScaleQuantumToChar(
12873 image->colormap[i].green) & 0xff);
12874 chunk[6+i*3]=(unsigned char) (ScaleQuantumToChar(
12875 image->colormap[i].blue) & 0xff);
12878 (void) WriteBlob(image,data_length+4,chunk);
12879 (void) WriteBlobMSBULong(image,crc32(0,chunk,(uInt) (data_length+4)));
12880 mng_info->have_write_global_plte=MagickTrue;
12886 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
12887 defined(PNG_MNG_FEATURES_SUPPORTED)
12888 mng_info->equal_palettes=MagickFalse;
12892 if (mng_info->adjoin)
12894 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
12895 defined(PNG_MNG_FEATURES_SUPPORTED)
12897 If we aren't using a global palette for the entire MNG, check to
12898 see if we can use one for two or more consecutive images.
12900 if (need_local_plte && use_global_plte && !all_images_are_gray)
12902 if (mng_info->IsPalette)
12905 When equal_palettes is true, this image has the same palette
12906 as the previous PseudoClass image
12908 mng_info->have_write_global_plte=mng_info->equal_palettes;
12909 mng_info->equal_palettes=PalettesAreEqual(image,image->next);
12910 if (mng_info->equal_palettes && !mng_info->have_write_global_plte)
12913 Write MNG PLTE chunk
12918 data_length=3*image->colors;
12919 (void) WriteBlobMSBULong(image,data_length);
12920 PNGType(chunk,mng_PLTE);
12921 LogPNGChunk(logging,mng_PLTE,data_length);
12923 for (i=0; i < (ssize_t) image->colors; i++)
12925 chunk[4+i*3]=ScaleQuantumToChar(image->colormap[i].red);
12926 chunk[5+i*3]=ScaleQuantumToChar(image->colormap[i].green);
12927 chunk[6+i*3]=ScaleQuantumToChar(image->colormap[i].blue);
12930 (void) WriteBlob(image,data_length+4,chunk);
12931 (void) WriteBlobMSBULong(image,crc32(0,chunk,
12932 (uInt) (data_length+4)));
12933 mng_info->have_write_global_plte=MagickTrue;
12937 mng_info->have_write_global_plte=MagickFalse;
12948 previous_x=mng_info->page.x;
12949 previous_y=mng_info->page.y;
12956 mng_info->page=image->page;
12957 if ((mng_info->page.x != previous_x) ||
12958 (mng_info->page.y != previous_y))
12960 (void) WriteBlobMSBULong(image,12L); /* data length=12 */
12961 PNGType(chunk,mng_DEFI);
12962 LogPNGChunk(logging,mng_DEFI,12L);
12963 chunk[4]=0; /* object 0 MSB */
12964 chunk[5]=0; /* object 0 LSB */
12965 chunk[6]=0; /* visible */
12966 chunk[7]=0; /* abstract */
12967 PNGLong(chunk+8,(png_uint_32) mng_info->page.x);
12968 PNGLong(chunk+12,(png_uint_32) mng_info->page.y);
12969 (void) WriteBlob(image,16,chunk);
12970 (void) WriteBlobMSBULong(image,crc32(0,chunk,16));
12975 mng_info->write_mng=write_mng;
12977 if ((int) image->dispose >= 3)
12978 mng_info->framing_mode=3;
12980 if (mng_info->need_fram && mng_info->adjoin &&
12981 ((image->delay != mng_info->delay) ||
12982 (mng_info->framing_mode != mng_info->old_framing_mode)))
12984 if (image->delay == mng_info->delay)
12987 Write a MNG FRAM chunk with the new framing mode.
12989 (void) WriteBlobMSBULong(image,1L); /* data length=1 */
12990 PNGType(chunk,mng_FRAM);
12991 LogPNGChunk(logging,mng_FRAM,1L);
12992 chunk[4]=(unsigned char) mng_info->framing_mode;
12993 (void) WriteBlob(image,5,chunk);
12994 (void) WriteBlobMSBULong(image,crc32(0,chunk,5));
12999 Write a MNG FRAM chunk with the delay.
13001 (void) WriteBlobMSBULong(image,10L); /* data length=10 */
13002 PNGType(chunk,mng_FRAM);
13003 LogPNGChunk(logging,mng_FRAM,10L);
13004 chunk[4]=(unsigned char) mng_info->framing_mode;
13005 chunk[5]=0; /* frame name separator (no name) */
13006 chunk[6]=2; /* flag for changing default delay */
13007 chunk[7]=0; /* flag for changing frame timeout */
13008 chunk[8]=0; /* flag for changing frame clipping */
13009 chunk[9]=0; /* flag for changing frame sync_id */
13010 PNGLong(chunk+10,(png_uint_32)
13011 ((mng_info->ticks_per_second*
13012 image->delay)/MagickMax(image->ticks_per_second,1)));
13013 (void) WriteBlob(image,14,chunk);
13014 (void) WriteBlobMSBULong(image,crc32(0,chunk,14));
13015 mng_info->delay=(png_uint_32) image->delay;
13017 mng_info->old_framing_mode=mng_info->framing_mode;
13020 #if defined(JNG_SUPPORTED)
13021 if (image_info->compression == JPEGCompression)
13026 if (logging != MagickFalse)
13027 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
13028 " Writing JNG object.");
13029 /* To do: specify the desired alpha compression method. */
13030 write_info=CloneImageInfo(image_info);
13031 write_info->compression=UndefinedCompression;
13032 status=WriteOneJNGImage(mng_info,write_info,image,exception);
13033 write_info=DestroyImageInfo(write_info);
13038 if (logging != MagickFalse)
13039 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
13040 " Writing PNG object.");
13042 mng_info->need_blob = MagickFalse;
13043 mng_info->ping_preserve_colormap = MagickFalse;
13045 /* We don't want any ancillary chunks written */
13046 mng_info->ping_exclude_bKGD=MagickTrue;
13047 mng_info->ping_exclude_cHRM=MagickTrue;
13048 mng_info->ping_exclude_date=MagickTrue;
13049 mng_info->ping_exclude_EXIF=MagickTrue;
13050 mng_info->ping_exclude_gAMA=MagickTrue;
13051 mng_info->ping_exclude_iCCP=MagickTrue;
13052 /* mng_info->ping_exclude_iTXt=MagickTrue; */
13053 mng_info->ping_exclude_oFFs=MagickTrue;
13054 mng_info->ping_exclude_pHYs=MagickTrue;
13055 mng_info->ping_exclude_sRGB=MagickTrue;
13056 mng_info->ping_exclude_tEXt=MagickTrue;
13057 mng_info->ping_exclude_tRNS=MagickTrue;
13058 mng_info->ping_exclude_vpAg=MagickTrue;
13059 mng_info->ping_exclude_zCCP=MagickTrue;
13060 mng_info->ping_exclude_zTXt=MagickTrue;
13062 status=WriteOnePNGImage(mng_info,image_info,image,exception);
13065 if (status == MagickFalse)
13067 MngInfoFreeStruct(mng_info,&have_mng_structure);
13068 (void) CloseBlob(image);
13069 return(MagickFalse);
13071 (void) CatchImageException(image);
13072 if (GetNextImageInList(image) == (Image *) NULL)
13074 image=SyncNextImageInList(image);
13075 status=SetImageProgress(image,SaveImagesTag,scene++,
13076 GetImageListLength(image));
13078 if (status == MagickFalse)
13081 } while (mng_info->adjoin);
13085 while (GetPreviousImageInList(image) != (Image *) NULL)
13086 image=GetPreviousImageInList(image);
13088 Write the MEND chunk.
13090 (void) WriteBlobMSBULong(image,0x00000000L);
13091 PNGType(chunk,mng_MEND);
13092 LogPNGChunk(logging,mng_MEND,0L);
13093 (void) WriteBlob(image,4,chunk);
13094 (void) WriteBlobMSBULong(image,crc32(0,chunk,4));
13097 Relinquish resources.
13099 (void) CloseBlob(image);
13100 MngInfoFreeStruct(mng_info,&have_mng_structure);
13102 if (logging != MagickFalse)
13103 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit WriteMNGImage()");
13105 return(MagickTrue);
13107 #else /* PNG_LIBPNG_VER > 10011 */
13109 static MagickBooleanType WritePNGImage(const ImageInfo *image_info,Image *image)
13112 printf("Your PNG library is too old: You have libpng-%s\n",
13113 PNG_LIBPNG_VER_STRING);
13115 ThrowBinaryException(CoderError,"PNG library is too old",
13116 image_info->filename);
13119 static MagickBooleanType WriteMNGImage(const ImageInfo *image_info,Image *image)
13121 return(WritePNGImage(image_info,image));
13123 #endif /* PNG_LIBPNG_VER > 10011 */