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 "magick/studio.h"
45 #include "magick/artifact.h"
46 #include "magick/attribute.h"
47 #include "magick/blob.h"
48 #include "magick/blob-private.h"
49 #include "magick/cache.h"
50 #include "magick/color.h"
51 #include "magick/color-private.h"
52 #include "magick/colormap.h"
53 #include "magick/colorspace.h"
54 #include "magick/constitute.h"
55 #include "magick/enhance.h"
56 #include "magick/exception.h"
57 #include "magick/exception-private.h"
58 #include "magick/geometry.h"
59 #include "magick/histogram.h"
60 #include "magick/image.h"
61 #include "magick/image-private.h"
62 #include "magick/layer.h"
63 #include "magick/list.h"
64 #include "magick/log.h"
65 #include "magick/magick.h"
66 #include "magick/memory_.h"
67 #include "magick/module.h"
68 #include "magick/monitor.h"
69 #include "magick/monitor-private.h"
70 #include "magick/option.h"
71 #include "magick/quantum-private.h"
72 #include "magick/profile.h"
73 #include "magick/property.h"
74 #include "magick/resource_.h"
75 #include "magick/semaphore.h"
76 #include "magick/quantum-private.h"
77 #include "magick/static.h"
78 #include "magick/statistic.h"
79 #include "magick/string_.h"
80 #include "magick/string-private.h"
81 #include "magick/transform.h"
82 #include "magick/utility.h"
83 #if defined(MAGICKCORE_PNG_DELEGATE)
85 /* Suppress libpng pedantic warnings that were added in
86 * libpng-1.2.41 and libpng-1.4.0. If you are working on
87 * migration to libpng-1.5, remove these defines and then
88 * fix any code that generates warnings.
90 /* #define PNG_DEPRECATED Use of this function is deprecated */
91 /* #define PNG_USE_RESULT The result of this function must be checked */
92 /* #define PNG_NORETURN This function does not return */
93 /* #define PNG_ALLOCATED The result of the function is new memory */
94 /* #define PNG_DEPSTRUCT Access to this struct member is deprecated */
99 /* ImageMagick differences */
100 #define first_scene scene
102 #if PNG_LIBPNG_VER > 10011
104 Optional declarations. Define or undefine them as you like.
106 /* #define PNG_DEBUG -- turning this on breaks VisualC compiling */
109 Features under construction. Define these to work on them.
111 #undef MNG_OBJECT_BUFFERS
112 #undef MNG_BASI_SUPPORTED
113 #define MNG_COALESCE_LAYERS /* In 5.4.4, this interfered with MMAP'ed files. */
114 #define MNG_INSERT_LAYERS /* Troublesome, but seem to work as of 5.4.4 */
115 #define PNG_BUILD_PALETTE /* This works as of 6.6.6 */
116 #if defined(MAGICKCORE_JPEG_DELEGATE)
117 # define JNG_SUPPORTED /* Not finished as of 5.5.2. See "To do" comments. */
119 #if !defined(RGBColorMatchExact)
120 #define IsPNGColorEqual(color,target) \
121 (((color).red == (target).red) && \
122 ((color).green == (target).green) && \
123 ((color).blue == (target).blue))
127 Establish thread safety.
128 setjmp/longjmp is claimed to be safe on these platforms:
129 setjmp/longjmp is alleged to be unsafe on these platforms:
131 #ifndef SETJMP_IS_THREAD_SAFE
132 #define PNG_SETJMP_NOT_THREAD_SAFE
135 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
137 *png_semaphore = (SemaphoreInfo *) NULL;
141 This temporary until I set up malloc'ed object attributes array.
142 Recompile with MNG_MAX_OBJECTS=65536L to avoid this limit but
145 #define MNG_MAX_OBJECTS 256
148 If this not defined, spec is interpreted strictly. If it is
149 defined, an attempt will be made to recover from some errors,
151 o global PLTE too short
156 Don't try to define PNG_MNG_FEATURES_SUPPORTED here. Make sure
157 it's defined in libpng/pngconf.h, version 1.0.9 or later. It won't work
158 with earlier versions of libpng. From libpng-1.0.3a to libpng-1.0.8,
159 PNG_READ|WRITE_EMPTY_PLTE were used but those have been deprecated in
160 libpng in favor of PNG_MNG_FEATURES_SUPPORTED, so we set them here.
161 PNG_MNG_FEATURES_SUPPORTED is disabled by default in libpng-1.0.9 and
162 will be enabled by default in libpng-1.2.0.
164 #ifdef PNG_MNG_FEATURES_SUPPORTED
165 # ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
166 # define PNG_READ_EMPTY_PLTE_SUPPORTED
168 # ifndef PNG_WRITE_EMPTY_PLTE_SUPPORTED
169 # define PNG_WRITE_EMPTY_PLTE_SUPPORTED
174 Maximum valid size_t in PNG/MNG chunks is (2^31)-1
175 This macro is only defined in libpng-1.0.3 and later.
176 Previously it was PNG_MAX_UINT but that was deprecated in libpng-1.2.6
178 #ifndef PNG_UINT_31_MAX
179 #define PNG_UINT_31_MAX (png_uint_32) 0x7fffffffL
183 Constant strings for known chunk types. If you need to add a chunk,
184 add a string holding the name here. To make the code more
185 portable, we use ASCII numbers like this, not characters.
188 static png_byte FARDATA mng_MHDR[5]={ 77, 72, 68, 82, (png_byte) '\0'};
189 static png_byte FARDATA mng_BACK[5]={ 66, 65, 67, 75, (png_byte) '\0'};
190 static png_byte FARDATA mng_BASI[5]={ 66, 65, 83, 73, (png_byte) '\0'};
191 static png_byte FARDATA mng_CLIP[5]={ 67, 76, 73, 80, (png_byte) '\0'};
192 static png_byte FARDATA mng_CLON[5]={ 67, 76, 79, 78, (png_byte) '\0'};
193 static png_byte FARDATA mng_DEFI[5]={ 68, 69, 70, 73, (png_byte) '\0'};
194 static png_byte FARDATA mng_DHDR[5]={ 68, 72, 68, 82, (png_byte) '\0'};
195 static png_byte FARDATA mng_DISC[5]={ 68, 73, 83, 67, (png_byte) '\0'};
196 static png_byte FARDATA mng_ENDL[5]={ 69, 78, 68, 76, (png_byte) '\0'};
197 static png_byte FARDATA mng_FRAM[5]={ 70, 82, 65, 77, (png_byte) '\0'};
198 static png_byte FARDATA mng_IEND[5]={ 73, 69, 78, 68, (png_byte) '\0'};
199 static png_byte FARDATA mng_IHDR[5]={ 73, 72, 68, 82, (png_byte) '\0'};
200 static png_byte FARDATA mng_JHDR[5]={ 74, 72, 68, 82, (png_byte) '\0'};
201 static png_byte FARDATA mng_LOOP[5]={ 76, 79, 79, 80, (png_byte) '\0'};
202 static png_byte FARDATA mng_MAGN[5]={ 77, 65, 71, 78, (png_byte) '\0'};
203 static png_byte FARDATA mng_MEND[5]={ 77, 69, 78, 68, (png_byte) '\0'};
204 static png_byte FARDATA mng_MOVE[5]={ 77, 79, 86, 69, (png_byte) '\0'};
205 static png_byte FARDATA mng_PAST[5]={ 80, 65, 83, 84, (png_byte) '\0'};
206 static png_byte FARDATA mng_PLTE[5]={ 80, 76, 84, 69, (png_byte) '\0'};
207 static png_byte FARDATA mng_SAVE[5]={ 83, 65, 86, 69, (png_byte) '\0'};
208 static png_byte FARDATA mng_SEEK[5]={ 83, 69, 69, 75, (png_byte) '\0'};
209 static png_byte FARDATA mng_SHOW[5]={ 83, 72, 79, 87, (png_byte) '\0'};
210 static png_byte FARDATA mng_TERM[5]={ 84, 69, 82, 77, (png_byte) '\0'};
211 static png_byte FARDATA mng_bKGD[5]={ 98, 75, 71, 68, (png_byte) '\0'};
212 static png_byte FARDATA mng_cHRM[5]={ 99, 72, 82, 77, (png_byte) '\0'};
213 static png_byte FARDATA mng_gAMA[5]={103, 65, 77, 65, (png_byte) '\0'};
214 static png_byte FARDATA mng_iCCP[5]={105, 67, 67, 80, (png_byte) '\0'};
215 static png_byte FARDATA mng_nEED[5]={110, 69, 69, 68, (png_byte) '\0'};
216 static png_byte FARDATA mng_pHYg[5]={112, 72, 89, 103, (png_byte) '\0'};
217 static png_byte FARDATA mng_vpAg[5]={118, 112, 65, 103, (png_byte) '\0'};
218 static png_byte FARDATA mng_pHYs[5]={112, 72, 89, 115, (png_byte) '\0'};
219 static png_byte FARDATA mng_sBIT[5]={115, 66, 73, 84, (png_byte) '\0'};
220 static png_byte FARDATA mng_sRGB[5]={115, 82, 71, 66, (png_byte) '\0'};
221 static png_byte FARDATA mng_tRNS[5]={116, 82, 78, 83, (png_byte) '\0'};
223 #if defined(JNG_SUPPORTED)
224 static png_byte FARDATA mng_IDAT[5]={ 73, 68, 65, 84, (png_byte) '\0'};
225 static png_byte FARDATA mng_JDAT[5]={ 74, 68, 65, 84, (png_byte) '\0'};
226 static png_byte FARDATA mng_JDAA[5]={ 74, 68, 65, 65, (png_byte) '\0'};
227 static png_byte FARDATA mng_JdAA[5]={ 74, 100, 65, 65, (png_byte) '\0'};
228 static png_byte FARDATA mng_JSEP[5]={ 74, 83, 69, 80, (png_byte) '\0'};
229 static png_byte FARDATA mng_oFFs[5]={111, 70, 70, 115, (png_byte) '\0'};
233 Other known chunks that are not yet supported by ImageMagick:
234 static png_byte FARDATA mng_hIST[5]={104, 73, 83, 84, (png_byte) '\0'};
235 static png_byte FARDATA mng_iCCP[5]={105, 67, 67, 80, (png_byte) '\0'};
236 static png_byte FARDATA mng_iTXt[5]={105, 84, 88, 116, (png_byte) '\0'};
237 static png_byte FARDATA mng_sPLT[5]={115, 80, 76, 84, (png_byte) '\0'};
238 static png_byte FARDATA mng_sTER[5]={115, 84, 69, 82, (png_byte) '\0'};
239 static png_byte FARDATA mng_tEXt[5]={116, 69, 88, 116, (png_byte) '\0'};
240 static png_byte FARDATA mng_tIME[5]={116, 73, 77, 69, (png_byte) '\0'};
241 static png_byte FARDATA mng_zTXt[5]={122, 84, 88, 116, (png_byte) '\0'};
244 typedef struct _MngBox
253 typedef struct _MngPair
260 #ifdef MNG_OBJECT_BUFFERS
261 typedef struct _MngBuffer
293 typedef struct _MngInfo
296 #ifdef MNG_OBJECT_BUFFERS
298 *ob[MNG_MAX_OBJECTS];
309 #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
310 bytes_in_read_buffer,
316 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
317 defined(PNG_MNG_FEATURES_SUPPORTED)
329 have_saved_bkgd_index,
330 have_write_global_chrm,
331 have_write_global_gama,
332 have_write_global_plte,
333 have_write_global_srgb,
347 x_off[MNG_MAX_OBJECTS],
348 y_off[MNG_MAX_OBJECTS];
354 object_clip[MNG_MAX_OBJECTS];
357 /* These flags could be combined into one byte */
358 exists[MNG_MAX_OBJECTS],
359 frozen[MNG_MAX_OBJECTS],
361 invisible[MNG_MAX_OBJECTS],
362 viewable[MNG_MAX_OBJECTS];
374 #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
392 global_x_pixels_per_unit,
393 global_y_pixels_per_unit,
403 global_phys_unit_type,
422 #ifdef MNG_BASI_SUPPORTED
430 basi_compression_method,
432 basi_interlace_method,
455 /* Added at version 6.6.6-7 */
462 /* ping_exclude_iTXt, */
469 ping_exclude_zCCP, /* hex-encoded iCCP */
476 Forward declarations.
478 static MagickBooleanType
479 WritePNGImage(const ImageInfo *,Image *);
481 static MagickBooleanType
482 WriteMNGImage(const ImageInfo *,Image *);
484 #if defined(JNG_SUPPORTED)
485 static MagickBooleanType
486 WriteJNGImage(const ImageInfo *,Image *);
489 #if PNG_LIBPNG_VER > 10011
491 #if (MAGICKCORE_QUANTUM_DEPTH >= 16)
492 static MagickBooleanType
493 LosslessReduceDepthOK(Image *image)
496 ok_to_reduce=MagickFalse;
498 /* Reduce bit depth if it can be reduced losslessly from 16 to 8.
499 * Note that the method GetImageDepth doesn't check background
500 * and doesn't handle PseudoClass specially. Also it uses
501 * multiplication and division by 257 instead of shifting, so
505 if (image->depth == 16)
512 (((((size_t) image->background_color.red >> 8) & 0xff)
513 == ((size_t) image->background_color.red & 0xff)) &&
514 ((((size_t) image->background_color.green >> 8) & 0xff)
515 == ((size_t) image->background_color.green & 0xff)) &&
516 ((((size_t) image->background_color.blue >> 8) & 0xff)
517 == ((size_t) image->background_color.blue & 0xff))) ? MagickTrue :
520 if (ok_to_reduce != MagickFalse && image->storage_class == PseudoClass)
524 for (indx=0; indx < (ssize_t) image->colors; indx++)
526 ok_to_reduce=(((((size_t) image->colormap[indx].red >>
528 == ((size_t) image->colormap[indx].red & 0xff)) &&
529 ((((size_t) image->colormap[indx].green >> 8) & 0xff)
530 == ((size_t) image->colormap[indx].green & 0xff)) &&
531 ((((size_t) image->colormap[indx].blue >> 8) & 0xff)
532 == ((size_t) image->colormap[indx].blue & 0xff)) &&
533 ((((size_t) image->colormap[indx].opacity >> 8) & 0xff)
534 == ((size_t) image->colormap[indx].opacity & 0xff))) ?
535 MagickTrue : MagickFalse;
536 if (ok_to_reduce == MagickFalse)
541 if ((ok_to_reduce != MagickFalse) &&
542 (image->storage_class != PseudoClass))
550 for (y=0; y < (ssize_t) image->rows; y++)
552 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
554 if (p == (const PixelPacket *) NULL)
556 ok_to_reduce = MagickFalse;
560 for (x=(ssize_t) image->columns-1; x >= 0; x--)
563 (((size_t) p->red >> 8) & 0xff) ==
564 ((size_t) p->red & 0xff)) &&
565 ((((size_t) p->green >> 8) & 0xff) ==
566 ((size_t) p->green & 0xff)) &&
567 ((((size_t) p->blue >> 8) & 0xff) ==
568 ((size_t) p->blue & 0xff)) &&
570 (((size_t) p->opacity >> 8) & 0xff) ==
571 ((size_t) p->opacity & 0xff))))) ? MagickTrue : MagickFalse;
573 if (ok_to_reduce == MagickFalse)
583 if (ok_to_reduce != MagickFalse)
585 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
586 " OK to reduce PNG bit depth to 8 without loss of info");
590 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
591 " Not OK to reduce PNG bit depth to 8 without loss of info");
597 #endif /* MAGICKCORE_QUANTUM_DEPTH >= 16 */
600 PNG_RenderingIntent_from_Magick_RenderingIntent(const RenderingIntent intent)
604 case PerceptualIntent:
610 case SaturationIntent:
621 static RenderingIntent
622 PNG_RenderingIntent_to_Magick_RenderingIntent(const int png_intent)
627 return PerceptualIntent;
630 return RelativeIntent;
633 return SaturationIntent;
636 return AbsoluteIntent;
639 return UndefinedIntent;
643 static inline ssize_t MagickMax(const ssize_t x,const ssize_t y)
651 static inline ssize_t MagickMin(const ssize_t x,const ssize_t y)
661 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
665 % I m a g e I s G r a y %
669 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
671 % Like IsGrayImage except does not change DirectClass to PseudoClass %
673 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
675 static MagickBooleanType ImageIsGray(Image *image)
677 register const PixelPacket
685 assert(image != (Image *) NULL);
686 assert(image->signature == MagickSignature);
687 if (image->debug != MagickFalse)
688 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
690 if (image->storage_class == PseudoClass)
692 for (i=0; i < (ssize_t) image->colors; i++)
693 if (IsGray(image->colormap+i) == MagickFalse)
697 for (y=0; y < (ssize_t) image->rows; y++)
699 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
700 if (p == (const PixelPacket *) NULL)
702 for (x=(ssize_t) image->columns-1; x >= 0; x--)
704 if (IsGray(p) == MagickFalse)
713 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
717 % I m a g e I s M o n o c h r o m e %
721 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
723 % Like IsMonochromeImage except does not change DirectClass to PseudoClass %
724 % and is more accurate. %
726 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
728 static MagickBooleanType ImageIsMonochrome(Image *image)
730 register const PixelPacket
738 assert(image != (Image *) NULL);
739 assert(image->signature == MagickSignature);
740 if (image->debug != MagickFalse)
741 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
742 if (image->storage_class == PseudoClass)
744 for (i=0; i < (ssize_t) image->colors; i++)
746 if ((IsGray(image->colormap+i) == MagickFalse) ||
747 ((image->colormap[i].red != 0) &&
748 (image->colormap[i].red != (Quantum) QuantumRange)))
753 for (y=0; y < (ssize_t) image->rows; y++)
755 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
756 if (p == (const PixelPacket *) NULL)
758 for (x=(ssize_t) image->columns-1; x >= 0; x--)
760 if ((p->red != 0) && (p->red != (Quantum) QuantumRange))
763 if (IsGray(p) == MagickFalse)
766 if ((p->opacity != OpaqueOpacity) &&
767 (p->opacity != (Quantum) TransparentOpacity))
775 #endif /* PNG_LIBPNG_VER > 10011 */
776 #endif /* MAGICKCORE_PNG_DELEGATE */
779 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
787 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
789 % IsMNG() returns MagickTrue if the image format type, identified by the
790 % magick string, is MNG.
792 % The format of the IsMNG method is:
794 % MagickBooleanType IsMNG(const unsigned char *magick,const size_t length)
796 % A description of each parameter follows:
798 % o magick: compare image format pattern against these bytes.
800 % o length: Specifies the length of the magick string.
804 static MagickBooleanType IsMNG(const unsigned char *magick,const size_t length)
809 if (memcmp(magick,"\212MNG\r\n\032\n",8) == 0)
816 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
824 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
826 % IsJNG() returns MagickTrue if the image format type, identified by the
827 % magick string, is JNG.
829 % The format of the IsJNG method is:
831 % MagickBooleanType IsJNG(const unsigned char *magick,const size_t length)
833 % A description of each parameter follows:
835 % o magick: compare image format pattern against these bytes.
837 % o length: Specifies the length of the magick string.
841 static MagickBooleanType IsJNG(const unsigned char *magick,const size_t length)
846 if (memcmp(magick,"\213JNG\r\n\032\n",8) == 0)
853 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
861 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
863 % IsPNG() returns MagickTrue if the image format type, identified by the
864 % magick string, is PNG.
866 % The format of the IsPNG method is:
868 % MagickBooleanType IsPNG(const unsigned char *magick,const size_t length)
870 % A description of each parameter follows:
872 % o magick: compare image format pattern against these bytes.
874 % o length: Specifies the length of the magick string.
877 static MagickBooleanType IsPNG(const unsigned char *magick,const size_t length)
882 if (memcmp(magick,"\211PNG\r\n\032\n",8) == 0)
888 #if defined(MAGICKCORE_PNG_DELEGATE)
889 #if defined(__cplusplus) || defined(c_plusplus)
893 #if (PNG_LIBPNG_VER > 10011)
894 static size_t WriteBlobMSBULong(Image *image,const size_t value)
899 assert(image != (Image *) NULL);
900 assert(image->signature == MagickSignature);
901 buffer[0]=(unsigned char) (value >> 24);
902 buffer[1]=(unsigned char) (value >> 16);
903 buffer[2]=(unsigned char) (value >> 8);
904 buffer[3]=(unsigned char) value;
905 return((size_t) WriteBlob(image,4,buffer));
908 static void PNGLong(png_bytep p,png_uint_32 value)
910 *p++=(png_byte) ((value >> 24) & 0xff);
911 *p++=(png_byte) ((value >> 16) & 0xff);
912 *p++=(png_byte) ((value >> 8) & 0xff);
913 *p++=(png_byte) (value & 0xff);
916 #if defined(JNG_SUPPORTED)
917 static void PNGsLong(png_bytep p,png_int_32 value)
919 *p++=(png_byte) ((value >> 24) & 0xff);
920 *p++=(png_byte) ((value >> 16) & 0xff);
921 *p++=(png_byte) ((value >> 8) & 0xff);
922 *p++=(png_byte) (value & 0xff);
926 static void PNGShort(png_bytep p,png_uint_16 value)
928 *p++=(png_byte) ((value >> 8) & 0xff);
929 *p++=(png_byte) (value & 0xff);
932 static void PNGType(png_bytep p,png_bytep type)
934 (void) CopyMagickMemory(p,type,4*sizeof(png_byte));
937 static void LogPNGChunk(MagickBooleanType logging, png_bytep type,
940 if (logging != MagickFalse)
941 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
942 " Writing %c%c%c%c chunk, length: %.20g",
943 type[0],type[1],type[2],type[3],(double) length);
945 #endif /* PNG_LIBPNG_VER > 10011 */
947 #if defined(__cplusplus) || defined(c_plusplus)
951 #if PNG_LIBPNG_VER > 10011
953 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
957 % R e a d P N G I m a g e %
961 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
963 % ReadPNGImage() reads a Portable Network Graphics (PNG) or
964 % Multiple-image Network Graphics (MNG) image file and returns it. It
965 % allocates the memory necessary for the new Image structure and returns a
966 % pointer to the new image or set of images.
968 % MNG support written by Glenn Randers-Pehrson, glennrp@image...
970 % The format of the ReadPNGImage method is:
972 % Image *ReadPNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
974 % A description of each parameter follows:
976 % o image_info: the image info.
978 % o exception: return any errors or warnings in this structure.
980 % To do, more or less in chronological order (as of version 5.5.2,
981 % November 26, 2002 -- glennrp -- see also "To do" under WriteMNGImage):
983 % Get 16-bit cheap transparency working.
985 % (At this point, PNG decoding is supposed to be in full MNG-LC compliance)
987 % Preserve all unknown and not-yet-handled known chunks found in input
988 % PNG file and copy them into output PNG files according to the PNG
991 % (At this point, PNG encoding should be in full MNG compliance)
993 % Provide options for choice of background to use when the MNG BACK
994 % chunk is not present or is not mandatory (i.e., leave transparent,
995 % user specified, MNG BACK, PNG bKGD)
997 % Implement LOOP/ENDL [done, but could do discretionary loops more
998 % efficiently by linking in the duplicate frames.].
1000 % Decode and act on the MHDR simplicity profile (offer option to reject
1001 % files or attempt to process them anyway when the profile isn't LC or VLC).
1003 % Upgrade to full MNG without Delta-PNG.
1005 % o BACK [done a while ago except for background image ID]
1006 % o MOVE [done 15 May 1999]
1007 % o CLIP [done 15 May 1999]
1008 % o DISC [done 19 May 1999]
1009 % o SAVE [partially done 19 May 1999 (marks objects frozen)]
1010 % o SEEK [partially done 19 May 1999 (discard function only)]
1014 % o MNG-level tEXt/iTXt/zTXt
1019 % o iTXt (wait for libpng implementation).
1021 % Use the scene signature to discover when an identical scene is
1022 % being reused, and just point to the original image->exception instead
1023 % of storing another set of pixels. This not specific to MNG
1024 % but could be applied generally.
1026 % Upgrade to full MNG with Delta-PNG.
1028 % JNG tEXt/iTXt/zTXt
1030 % We will not attempt to read files containing the CgBI chunk.
1031 % They are really Xcode files meant for display on the iPhone.
1032 % These are not valid PNG files and it is impossible to recover
1033 % the orginal PNG from files that have been converted to Xcode-PNG,
1034 % since irretrievable loss of color data has occurred due to the
1035 % use of premultiplied alpha.
1038 #if defined(__cplusplus) || defined(c_plusplus)
1043 This the function that does the actual reading of data. It is
1044 the same as the one supplied in libpng, except that it receives the
1045 datastream from the ReadBlob() function instead of standard input.
1047 static void png_get_data(png_structp png_ptr,png_bytep data,png_size_t length)
1052 image=(Image *) png_get_io_ptr(png_ptr);
1058 check=(png_size_t) ReadBlob(image,(size_t) length,data);
1059 if (check != length)
1064 (void) FormatMagickString(msg,MaxTextExtent,
1065 "Expected %.20g bytes; found %.20g bytes",(double) length,
1067 png_warning(png_ptr,msg);
1068 png_error(png_ptr,"Read Exception");
1073 #if !defined(PNG_READ_EMPTY_PLTE_SUPPORTED) && \
1074 !defined(PNG_MNG_FEATURES_SUPPORTED)
1075 /* We use mng_get_data() instead of png_get_data() if we have a libpng
1076 * older than libpng-1.0.3a, which was the first to allow the empty
1077 * PLTE, or a newer libpng in which PNG_MNG_FEATURES_SUPPORTED was
1078 * ifdef'ed out. Earlier versions would crash if the bKGD chunk was
1079 * encountered after an empty PLTE, so we have to look ahead for bKGD
1080 * chunks and remove them from the datastream that is passed to libpng,
1081 * and store their contents for later use.
1083 static void mng_get_data(png_structp png_ptr,png_bytep data,png_size_t length)
1098 mng_info=(MngInfo *) png_get_io_ptr(png_ptr);
1099 image=(Image *) mng_info->image;
1100 while (mng_info->bytes_in_read_buffer && length)
1102 data[i]=mng_info->read_buffer[i];
1103 mng_info->bytes_in_read_buffer--;
1109 check=(png_size_t) ReadBlob(image,(size_t) length,(char *) data);
1111 if (check != length)
1112 png_error(png_ptr,"Read Exception");
1116 if ((data[0] == 0) && (data[1] == 0) && (data[2] == 0) &&
1119 check=(png_size_t) ReadBlob(image,(size_t) length,
1120 (char *) mng_info->read_buffer);
1121 mng_info->read_buffer[4]=0;
1122 mng_info->bytes_in_read_buffer=4;
1123 if (memcmp(mng_info->read_buffer,mng_PLTE,4) == 0)
1124 mng_info->found_empty_plte=MagickTrue;
1125 if (memcmp(mng_info->read_buffer,mng_IEND,4) == 0)
1127 mng_info->found_empty_plte=MagickFalse;
1128 mng_info->have_saved_bkgd_index=MagickFalse;
1132 if ((data[0] == 0) && (data[1] == 0) && (data[2] == 0) &&
1135 check=(png_size_t) ReadBlob(image,(size_t) length,
1136 (char *) mng_info->read_buffer);
1137 mng_info->read_buffer[4]=0;
1138 mng_info->bytes_in_read_buffer=4;
1139 if (memcmp(mng_info->read_buffer,mng_bKGD,4) == 0)
1140 if (mng_info->found_empty_plte)
1143 Skip the bKGD data byte and CRC.
1146 ReadBlob(image,5,(char *) mng_info->read_buffer);
1147 check=(png_size_t) ReadBlob(image,(size_t) length,
1148 (char *) mng_info->read_buffer);
1149 mng_info->saved_bkgd_index=mng_info->read_buffer[0];
1150 mng_info->have_saved_bkgd_index=MagickTrue;
1151 mng_info->bytes_in_read_buffer=0;
1159 static void png_put_data(png_structp png_ptr,png_bytep data,png_size_t length)
1164 image=(Image *) png_get_io_ptr(png_ptr);
1170 check=(png_size_t) WriteBlob(image,(size_t) length,data);
1172 if (check != length)
1173 png_error(png_ptr,"WriteBlob Failed");
1177 static void png_flush_data(png_structp png_ptr)
1182 #ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
1183 static int PalettesAreEqual(Image *a,Image *b)
1188 if ((a == (Image *) NULL) || (b == (Image *) NULL))
1189 return((int) MagickFalse);
1191 if (a->storage_class != PseudoClass || b->storage_class != PseudoClass)
1192 return((int) MagickFalse);
1194 if (a->colors != b->colors)
1195 return((int) MagickFalse);
1197 for (i=0; i < (ssize_t) a->colors; i++)
1199 if ((a->colormap[i].red != b->colormap[i].red) ||
1200 (a->colormap[i].green != b->colormap[i].green) ||
1201 (a->colormap[i].blue != b->colormap[i].blue))
1202 return((int) MagickFalse);
1205 return((int) MagickTrue);
1209 static void MngInfoDiscardObject(MngInfo *mng_info,int i)
1211 if (i && (i < MNG_MAX_OBJECTS) && (mng_info != (MngInfo *) NULL) &&
1212 mng_info->exists[i] && !mng_info->frozen[i])
1214 #ifdef MNG_OBJECT_BUFFERS
1215 if (mng_info->ob[i] != (MngBuffer *) NULL)
1217 if (mng_info->ob[i]->reference_count > 0)
1218 mng_info->ob[i]->reference_count--;
1220 if (mng_info->ob[i]->reference_count == 0)
1222 if (mng_info->ob[i]->image != (Image *) NULL)
1223 mng_info->ob[i]->image=DestroyImage(mng_info->ob[i]->image);
1225 mng_info->ob[i]=DestroyString(mng_info->ob[i]);
1228 mng_info->ob[i]=(MngBuffer *) NULL;
1230 mng_info->exists[i]=MagickFalse;
1231 mng_info->invisible[i]=MagickFalse;
1232 mng_info->viewable[i]=MagickFalse;
1233 mng_info->frozen[i]=MagickFalse;
1234 mng_info->x_off[i]=0;
1235 mng_info->y_off[i]=0;
1236 mng_info->object_clip[i].left=0;
1237 mng_info->object_clip[i].right=(ssize_t) PNG_UINT_31_MAX;
1238 mng_info->object_clip[i].top=0;
1239 mng_info->object_clip[i].bottom=(ssize_t) PNG_UINT_31_MAX;
1243 static void MngInfoFreeStruct(MngInfo *mng_info,
1244 MagickBooleanType *have_mng_structure)
1246 if (*have_mng_structure != MagickFalse && (mng_info != (MngInfo *) NULL))
1251 for (i=1; i < MNG_MAX_OBJECTS; i++)
1252 MngInfoDiscardObject(mng_info,i);
1254 if (mng_info->global_plte != (png_colorp) NULL)
1255 mng_info->global_plte=(png_colorp)
1256 RelinquishMagickMemory(mng_info->global_plte);
1258 mng_info=(MngInfo *) RelinquishMagickMemory(mng_info);
1259 *have_mng_structure=MagickFalse;
1263 static MngBox mng_minimum_box(MngBox box1,MngBox box2)
1269 if (box.left < box2.left)
1272 if (box.top < box2.top)
1275 if (box.right > box2.right)
1276 box.right=box2.right;
1278 if (box.bottom > box2.bottom)
1279 box.bottom=box2.bottom;
1284 static MngBox mng_read_box(MngBox previous_box,char delta_type,unsigned char *p)
1290 Read clipping boundaries from DEFI, CLIP, FRAM, or PAST chunk.
1292 box.left=(ssize_t) ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]);
1293 box.right=(ssize_t) ((p[4] << 24) | (p[5] << 16) | (p[6] << 8) | p[7]);
1294 box.top=(ssize_t) ((p[8] << 24) | (p[9] << 16) | (p[10] << 8) | p[11]);
1295 box.bottom=(ssize_t) ((p[12] << 24) | (p[13] << 16) | (p[14] << 8) | p[15]);
1296 if (delta_type != 0)
1298 box.left+=previous_box.left;
1299 box.right+=previous_box.right;
1300 box.top+=previous_box.top;
1301 box.bottom+=previous_box.bottom;
1307 static MngPair mng_read_pair(MngPair previous_pair,int delta_type,
1313 Read two ssize_ts from CLON, MOVE or PAST chunk
1315 pair.a=(long) ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]);
1316 pair.b=(long) ((p[4] << 24) | (p[5] << 16) | (p[6] << 8) | p[7]);
1318 if (delta_type != 0)
1320 pair.a+=previous_pair.a;
1321 pair.b+=previous_pair.b;
1327 static long mng_get_long(unsigned char *p)
1329 return((long) ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]));
1332 static void PNGErrorHandler(png_struct *ping,png_const_charp message)
1337 image=(Image *) png_get_error_ptr(ping);
1339 if (image->debug != MagickFalse)
1340 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1341 " libpng-%s error: %s", PNG_LIBPNG_VER_STRING,message);
1343 (void) ThrowMagickException(&image->exception,GetMagickModule(),CoderError,
1344 message,"`%s'",image->filename);
1346 #if (PNG_LIBPNG_VER < 10500)
1347 longjmp(ping->jmpbuf,1);
1349 png_longjmp(ping,1);
1353 static void PNGWarningHandler(png_struct *ping,png_const_charp message)
1358 if (LocaleCompare(message, "Missing PLTE before tRNS") == 0)
1359 png_error(ping, message);
1361 image=(Image *) png_get_error_ptr(ping);
1362 if (image->debug != MagickFalse)
1363 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1364 " libpng-%s warning: %s", PNG_LIBPNG_VER_STRING,message);
1366 (void) ThrowMagickException(&image->exception,GetMagickModule(),CoderWarning,
1367 message,"`%s'",image->filename);
1370 #ifdef PNG_USER_MEM_SUPPORTED
1371 static png_voidp png_IM_malloc(png_structp png_ptr,png_uint_32 size)
1373 #if (PNG_LIBPNG_VER < 10011)
1378 ret=((png_voidp) AcquireMagickMemory((size_t) size));
1381 png_error("Insufficient memory.");
1386 return((png_voidp) AcquireMagickMemory((size_t) size));
1391 Free a pointer. It is removed from the list at the same time.
1393 static png_free_ptr png_IM_free(png_structp png_ptr,png_voidp ptr)
1396 ptr=RelinquishMagickMemory(ptr);
1397 return((png_free_ptr) NULL);
1401 #if defined(__cplusplus) || defined(c_plusplus)
1406 png_read_raw_profile(Image *image, const ImageInfo *image_info,
1407 png_textp text,int ii)
1412 register unsigned char
1426 unhex[103]={0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,
1427 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,
1428 0,0,0,0,0,0,0,0,0,1, 2,3,4,5,6,7,8,9,0,0,
1429 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,
1430 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,10,11,12,
1434 /* look for newline */
1438 /* look for length */
1439 while (*sp == '\0' || *sp == ' ' || *sp == '\n')
1442 length=(png_uint_32) StringToLong(sp);
1444 while (*sp != ' ' && *sp != '\n')
1447 /* allocate space */
1450 (void) ThrowMagickException(&image->exception,GetMagickModule(),
1451 CoderWarning,"UnableToCopyProfile","`%s'","invalid profile length");
1452 return(MagickFalse);
1455 profile=AcquireStringInfo(length);
1457 if (profile == (StringInfo *) NULL)
1459 (void) ThrowMagickException(&image->exception,GetMagickModule(),
1460 ResourceLimitError,"MemoryAllocationFailed","`%s'",
1461 "unable to copy profile");
1462 return(MagickFalse);
1465 /* copy profile, skipping white space and column 1 "=" signs */
1466 dp=GetStringInfoDatum(profile);
1469 for (i=0; i < (ssize_t) nibbles; i++)
1471 while (*sp < '0' || (*sp > '9' && *sp < 'a') || *sp > 'f')
1475 (void) ThrowMagickException(&image->exception,GetMagickModule(),
1476 CoderWarning,"UnableToCopyProfile","`%s'","ran out of data");
1477 profile=DestroyStringInfo(profile);
1478 return(MagickFalse);
1484 *dp=(unsigned char) (16*unhex[(int) *sp++]);
1487 (*dp++)+=unhex[(int) *sp++];
1490 We have already read "Raw profile type.
1492 (void) SetImageProfile(image,&text[ii].key[17],profile);
1493 profile=DestroyStringInfo(profile);
1495 if (image_info->verbose)
1496 (void) printf(" Found a generic profile, type %s\n",&text[ii].key[17]);
1501 #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
1502 static int read_vpag_chunk_callback(png_struct *ping, png_unknown_chunkp chunk)
1508 /* The unknown chunk structure contains the chunk data:
1513 Note that libpng has already taken care of the CRC handling.
1517 if (chunk->name[0] != 118 || chunk->name[1] != 112 ||
1518 chunk->name[2] != 65 ||chunk-> name[3] != 103)
1519 return(0); /* Did not recognize */
1521 /* recognized vpAg */
1523 if (chunk->size != 9)
1524 return(-1); /* Error return */
1526 if (chunk->data[8] != 0)
1527 return(0); /* ImageMagick requires pixel units */
1529 image=(Image *) png_get_user_chunk_ptr(ping);
1531 image->page.width=(size_t) ((chunk->data[0] << 24) |
1532 (chunk->data[1] << 16) | (chunk->data[2] << 8) | chunk->data[3]);
1534 image->page.height=(size_t) ((chunk->data[4] << 24) |
1535 (chunk->data[5] << 16) | (chunk->data[6] << 8) | chunk->data[7]);
1537 /* Return one of the following: */
1538 /* return(-n); chunk had an error */
1539 /* return(0); did not recognize */
1540 /* return(n); success */
1548 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1552 % R e a d O n e P N G I m a g e %
1556 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1558 % ReadOnePNGImage() reads a Portable Network Graphics (PNG) image file
1559 % (minus the 8-byte signature) and returns it. It allocates the memory
1560 % necessary for the new Image structure and returns a pointer to the new
1563 % The format of the ReadOnePNGImage method is:
1565 % Image *ReadOnePNGImage(MngInfo *mng_info, const ImageInfo *image_info,
1566 % ExceptionInfo *exception)
1568 % A description of each parameter follows:
1570 % o mng_info: Specifies a pointer to a MngInfo structure.
1572 % o image_info: the image info.
1574 % o exception: return any errors or warnings in this structure.
1577 static Image *ReadOnePNGImage(MngInfo *mng_info,
1578 const ImageInfo *image_info, ExceptionInfo *exception)
1580 /* Read one PNG image */
1591 ping_interlace_method,
1592 ping_compression_method,
1634 register unsigned char
1637 register IndexPacket
1644 register PixelPacket
1651 #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
1652 png_byte unused_chunks[]=
1654 104, 73, 83, 84, (png_byte) '\0', /* hIST */
1655 105, 84, 88, 116, (png_byte) '\0', /* iTXt */
1656 112, 67, 65, 76, (png_byte) '\0', /* pCAL */
1657 115, 67, 65, 76, (png_byte) '\0', /* sCAL */
1658 115, 80, 76, 84, (png_byte) '\0', /* sPLT */
1659 116, 73, 77, 69, (png_byte) '\0', /* tIME */
1663 logging=LogMagickEvent(CoderEvent,GetMagickModule(),
1664 " enter ReadOnePNGImage()");
1666 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
1667 LockSemaphoreInfo(png_semaphore);
1670 #if (PNG_LIBPNG_VER < 10200)
1671 if (image_info->verbose)
1672 printf("Your PNG library (libpng-%s) is rather old.\n",
1673 PNG_LIBPNG_VER_STRING);
1676 #if (PNG_LIBPNG_VER >= 10400)
1677 # ifndef PNG_TRANSFORM_GRAY_TO_RGB /* Added at libpng-1.4.0beta67 */
1678 if (image_info->verbose)
1680 printf("Your PNG library (libpng-%s) is an old beta version.\n",
1681 PNG_LIBPNG_VER_STRING);
1682 printf("Please update it.\n");
1688 quantum_info = (QuantumInfo *) NULL;
1689 image=mng_info->image;
1691 if (logging != MagickFalse)
1692 (void)LogMagickEvent(CoderEvent,GetMagickModule(),
1693 " image->matte=%d",(int) image->matte);
1695 /* Set to an out-of-range color unless tRNS chunk is present */
1696 transparent_color.red=65537;
1697 transparent_color.green=65537;
1698 transparent_color.blue=65537;
1699 transparent_color.opacity=65537;
1702 Allocate the PNG structures
1704 #ifdef PNG_USER_MEM_SUPPORTED
1705 ping=png_create_read_struct_2(PNG_LIBPNG_VER_STRING, image,
1706 PNGErrorHandler,PNGWarningHandler, NULL,
1707 (png_malloc_ptr) png_IM_malloc,(png_free_ptr) png_IM_free);
1709 ping=png_create_read_struct(PNG_LIBPNG_VER_STRING,image,
1710 PNGErrorHandler,PNGWarningHandler);
1712 if (ping == (png_struct *) NULL)
1713 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1715 ping_info=png_create_info_struct(ping);
1717 if (ping_info == (png_info *) NULL)
1719 png_destroy_read_struct(&ping,(png_info **) NULL,(png_info **) NULL);
1720 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1723 end_info=png_create_info_struct(ping);
1725 if (end_info == (png_info *) NULL)
1727 png_destroy_read_struct(&ping,&ping_info,(png_info **) NULL);
1728 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1731 png_pixels=(unsigned char *) NULL;
1733 if (setjmp(png_jmpbuf(ping)))
1736 PNG image is corrupt.
1738 png_destroy_read_struct(&ping,&ping_info,&end_info);
1739 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
1740 UnlockSemaphoreInfo(png_semaphore);
1742 if (logging != MagickFalse)
1743 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1744 " exit ReadOnePNGImage() with error.");
1746 if (image != (Image *) NULL)
1748 InheritException(exception,&image->exception);
1752 return(GetFirstImageInList(image));
1755 Prepare PNG for reading.
1758 mng_info->image_found++;
1759 png_set_sig_bytes(ping,8);
1761 if (LocaleCompare(image_info->magick,"MNG") == 0)
1763 #if defined(PNG_MNG_FEATURES_SUPPORTED)
1764 (void) png_permit_mng_features(ping,PNG_ALL_MNG_FEATURES);
1765 png_set_read_fn(ping,image,png_get_data);
1767 #if defined(PNG_READ_EMPTY_PLTE_SUPPORTED)
1768 png_permit_empty_plte(ping,MagickTrue);
1769 png_set_read_fn(ping,image,png_get_data);
1771 mng_info->image=image;
1772 mng_info->bytes_in_read_buffer=0;
1773 mng_info->found_empty_plte=MagickFalse;
1774 mng_info->have_saved_bkgd_index=MagickFalse;
1775 png_set_read_fn(ping,mng_info,mng_get_data);
1781 png_set_read_fn(ping,image,png_get_data);
1783 #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
1784 /* Ignore unused chunks and all unknown chunks except for vpAg */
1785 png_set_keep_unknown_chunks(ping, 1, NULL, 0);
1786 png_set_keep_unknown_chunks(ping, 2, mng_vpAg, 1);
1787 png_set_keep_unknown_chunks(ping, 1, unused_chunks,
1788 (int)sizeof(unused_chunks)/5);
1789 /* Callback for other unknown chunks */
1790 png_set_read_user_chunk_fn(ping, image, read_vpag_chunk_callback);
1793 #if (PNG_LIBPNG_VER < 10400)
1794 # if defined(PNG_USE_PNGGCCRD) && defined(PNG_ASSEMBLER_CODE_SUPPORTED) && \
1795 (PNG_LIBPNG_VER >= 10200) && (PNG_LIBPNG_VER < 10220) && defined(__i386__)
1796 /* Disable thread-unsafe features of pnggccrd */
1797 if (png_access_version_number() >= 10200)
1799 png_uint_32 mmx_disable_mask=0;
1800 png_uint_32 asm_flags;
1802 mmx_disable_mask |= ( PNG_ASM_FLAG_MMX_READ_COMBINE_ROW \
1803 | PNG_ASM_FLAG_MMX_READ_FILTER_SUB \
1804 | PNG_ASM_FLAG_MMX_READ_FILTER_AVG \
1805 | PNG_ASM_FLAG_MMX_READ_FILTER_PAETH );
1806 asm_flags=png_get_asm_flags(ping);
1807 png_set_asm_flags(ping, asm_flags & ~mmx_disable_mask);
1812 png_read_info(ping,ping_info);
1814 png_get_IHDR(ping,ping_info,&ping_width,&ping_height,
1815 &ping_bit_depth,&ping_color_type,
1816 &ping_interlace_method,&ping_compression_method,
1817 &ping_filter_method);
1819 (void) png_get_tRNS(ping, ping_info, &ping_trans_alpha, &ping_num_trans,
1822 (void) png_get_bKGD(ping, ping_info, &ping_background);
1824 if (ping_bit_depth < 8)
1826 if (((int) ping_color_type == PNG_COLOR_TYPE_PALETTE))
1828 png_set_packing(ping);
1833 image->depth=ping_bit_depth;
1834 image->depth=GetImageQuantumDepth(image,MagickFalse);
1835 image->interlace=ping_interlace_method != 0 ? PNGInterlace : NoInterlace;
1836 if (logging != MagickFalse)
1838 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1839 " PNG width: %.20g, height: %.20g",
1840 (double) ping_width, (double) ping_height);
1842 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1843 " PNG color_type: %d, bit_depth: %d",
1844 ping_color_type, ping_bit_depth);
1846 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1847 " PNG compression_method: %d",
1848 ping_compression_method);
1850 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1851 " PNG interlace_method: %d, filter_method: %d",
1852 ping_interlace_method,ping_filter_method);
1855 #ifdef PNG_READ_iCCP_SUPPORTED
1856 if (png_get_valid(ping,ping_info,PNG_INFO_iCCP))
1861 #if (PNG_LIBPNG_VER < 10500)
1875 (void) png_get_iCCP(ping,ping_info,&name,(int *) &compression,&info,
1878 if (profile_length != 0)
1883 if (logging != MagickFalse)
1884 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1885 " Reading PNG iCCP chunk.");
1886 profile=AcquireStringInfo(profile_length);
1887 SetStringInfoDatum(profile,(const unsigned char *) info);
1888 (void) SetImageProfile(image,"icc",profile);
1889 profile=DestroyStringInfo(profile);
1893 #if defined(PNG_READ_sRGB_SUPPORTED)
1898 if (mng_info->have_global_srgb)
1899 image->rendering_intent=PNG_RenderingIntent_to_Magick_RenderingIntent(
1900 mng_info->global_srgb_intent);
1902 if (png_get_sRGB(ping,ping_info,&intent))
1904 image->rendering_intent=PNG_RenderingIntent_to_Magick_RenderingIntent(
1907 if (logging != MagickFalse)
1908 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1909 " Reading PNG sRGB chunk: rendering_intent: %d",intent);
1917 if (!png_get_gAMA(ping,ping_info,&file_gamma))
1918 if (mng_info->have_global_gama)
1919 png_set_gAMA(ping,ping_info,mng_info->global_gamma);
1921 if (png_get_gAMA(ping,ping_info,&file_gamma))
1923 image->gamma=(float) file_gamma;
1924 if (logging != MagickFalse)
1925 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1926 " Reading PNG gAMA chunk: gamma: %f",file_gamma);
1929 if (!png_get_valid(ping,ping_info,PNG_INFO_cHRM))
1931 if (mng_info->have_global_chrm != MagickFalse)
1933 (void) png_set_cHRM(ping,ping_info,
1934 mng_info->global_chrm.white_point.x,
1935 mng_info->global_chrm.white_point.y,
1936 mng_info->global_chrm.red_primary.x,
1937 mng_info->global_chrm.red_primary.y,
1938 mng_info->global_chrm.green_primary.x,
1939 mng_info->global_chrm.green_primary.y,
1940 mng_info->global_chrm.blue_primary.x,
1941 mng_info->global_chrm.blue_primary.y);
1945 if (png_get_valid(ping,ping_info,PNG_INFO_cHRM))
1947 (void) png_get_cHRM(ping,ping_info,
1948 &image->chromaticity.white_point.x,
1949 &image->chromaticity.white_point.y,
1950 &image->chromaticity.red_primary.x,
1951 &image->chromaticity.red_primary.y,
1952 &image->chromaticity.green_primary.x,
1953 &image->chromaticity.green_primary.y,
1954 &image->chromaticity.blue_primary.x,
1955 &image->chromaticity.blue_primary.y);
1957 if (logging != MagickFalse)
1958 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1959 " Reading PNG cHRM chunk.");
1962 if (image->rendering_intent != UndefinedIntent)
1964 png_set_sRGB(ping,ping_info,
1965 PNG_RenderingIntent_from_Magick_RenderingIntent(
1966 image->rendering_intent));
1967 png_set_gAMA(ping,ping_info,0.45455f);
1968 png_set_cHRM(ping,ping_info,
1969 0.6400f, 0.3300f, 0.3000f, 0.6000f,
1970 0.1500f, 0.0600f, 0.3127f, 0.3290f);
1972 #if defined(PNG_oFFs_SUPPORTED)
1973 if (png_get_valid(ping,ping_info,PNG_INFO_oFFs))
1975 image->page.x=png_get_x_offset_pixels(ping, ping_info);
1976 image->page.y=png_get_y_offset_pixels(ping, ping_info);
1978 if (logging != MagickFalse)
1979 if (image->page.x || image->page.y)
1980 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1981 " Reading PNG oFFs chunk: x: %.20g, y: %.20g.",(double)
1982 image->page.x,(double) image->page.y);
1985 #if defined(PNG_pHYs_SUPPORTED)
1986 if (!png_get_valid(ping,ping_info,PNG_INFO_pHYs))
1988 if (mng_info->have_global_phys)
1990 png_set_pHYs(ping,ping_info,
1991 mng_info->global_x_pixels_per_unit,
1992 mng_info->global_y_pixels_per_unit,
1993 mng_info->global_phys_unit_type);
1997 if (png_get_valid(ping,ping_info,PNG_INFO_pHYs))
2007 Set image resolution.
2009 (void) png_get_pHYs(ping,ping_info,&x_resolution,&y_resolution,
2011 image->x_resolution=(double) x_resolution;
2012 image->y_resolution=(double) y_resolution;
2014 if (unit_type == PNG_RESOLUTION_METER)
2016 image->units=PixelsPerCentimeterResolution;
2017 image->x_resolution=(double) x_resolution/100.0;
2018 image->y_resolution=(double) y_resolution/100.0;
2021 if (logging != MagickFalse)
2022 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2023 " Reading PNG pHYs chunk: xres: %.20g, yres: %.20g, units: %d.",
2024 (double) x_resolution,(double) y_resolution,unit_type);
2027 if (png_get_valid(ping,ping_info,PNG_INFO_PLTE))
2035 (void) png_get_PLTE(ping,ping_info,&palette,&number_colors);
2037 if ((number_colors == 0) &&
2038 ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE))
2040 if (mng_info->global_plte_length)
2042 png_set_PLTE(ping,ping_info,mng_info->global_plte,
2043 (int) mng_info->global_plte_length);
2045 if (!png_get_valid(ping,ping_info,PNG_INFO_tRNS))
2046 if (mng_info->global_trns_length)
2048 if (mng_info->global_trns_length >
2049 mng_info->global_plte_length)
2050 (void) ThrowMagickException(&image->exception,
2051 GetMagickModule(),CoderError,
2052 "global tRNS has more entries than global PLTE",
2053 "`%s'",image_info->filename);
2054 png_set_tRNS(ping,ping_info,mng_info->global_trns,
2055 (int) mng_info->global_trns_length,NULL);
2057 #if defined(PNG_READ_bKGD_SUPPORTED)
2059 #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
2060 mng_info->have_saved_bkgd_index ||
2062 png_get_valid(ping,ping_info,PNG_INFO_bKGD))
2067 #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
2068 if (mng_info->have_saved_bkgd_index)
2069 background.index=mng_info->saved_bkgd_index;
2071 if (png_get_valid(ping, ping_info, PNG_INFO_bKGD))
2072 background.index=ping_background->index;
2074 background.red=(png_uint_16)
2075 mng_info->global_plte[background.index].red;
2077 background.green=(png_uint_16)
2078 mng_info->global_plte[background.index].green;
2080 background.blue=(png_uint_16)
2081 mng_info->global_plte[background.index].blue;
2083 png_set_bKGD(ping,ping_info,&background);
2088 (void) ThrowMagickException(&image->exception,GetMagickModule(),
2089 CoderError,"No global PLTE in file","`%s'",
2090 image_info->filename);
2094 #if defined(PNG_READ_bKGD_SUPPORTED)
2095 if (mng_info->have_global_bkgd &&
2096 (!png_get_valid(ping,ping_info,PNG_INFO_bKGD)))
2097 image->background_color=mng_info->mng_global_bkgd;
2099 if (png_get_valid(ping,ping_info,PNG_INFO_bKGD))
2102 Set image background color.
2104 if (logging != MagickFalse)
2105 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2106 " Reading PNG bKGD chunk.");
2108 if (ping_bit_depth == MAGICKCORE_QUANTUM_DEPTH)
2110 image->background_color.red=ping_background->red;
2111 image->background_color.green=ping_background->green;
2112 image->background_color.blue=ping_background->blue;
2115 else /* Scale background components to 16-bit */
2120 if (logging != MagickFalse)
2121 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2122 " raw ping_background=(%d,%d,%d).",ping_background->red,
2123 ping_background->green,ping_background->blue);
2127 if (ping_bit_depth == 1)
2130 else if (ping_bit_depth == 2)
2133 else if (ping_bit_depth == 4)
2136 if (ping_bit_depth <= 8)
2139 ping_background->red *= bkgd_scale;
2140 ping_background->green *= bkgd_scale;
2141 ping_background->blue *= bkgd_scale;
2143 if (logging != MagickFalse)
2145 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2146 " bkgd_scale=%d.",bkgd_scale);
2148 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2149 " ping_background=(%d,%d,%d).",ping_background->red,
2150 ping_background->green,ping_background->blue);
2153 image->background_color.red=
2154 ScaleShortToQuantum(ping_background->red);
2156 image->background_color.green=
2157 ScaleShortToQuantum(ping_background->green);
2159 image->background_color.blue=
2160 ScaleShortToQuantum(ping_background->blue);
2162 image->background_color.opacity=OpaqueOpacity;
2164 if (logging != MagickFalse)
2165 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2166 " image->background_color=(%.20g,%.20g,%.20g).",
2167 (double) image->background_color.red,
2168 (double) image->background_color.green,
2169 (double) image->background_color.blue);
2174 if (png_get_valid(ping,ping_info,PNG_INFO_tRNS))
2177 Image has a tRNS chunk.
2185 if (logging != MagickFalse)
2186 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2187 " Reading PNG tRNS chunk.");
2189 max_sample = (int) ((one << ping_bit_depth) - 1);
2191 if ((ping_color_type == PNG_COLOR_TYPE_GRAY &&
2192 (int)ping_trans_color->gray > max_sample) ||
2193 (ping_color_type == PNG_COLOR_TYPE_RGB &&
2194 ((int)ping_trans_color->red > max_sample ||
2195 (int)ping_trans_color->green > max_sample ||
2196 (int)ping_trans_color->blue > max_sample)))
2198 if (logging != MagickFalse)
2199 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2200 " Ignoring PNG tRNS chunk with out-of-range sample.");
2201 png_free_data(ping, ping_info, PNG_FREE_TRNS, 0);
2202 png_set_invalid(ping,ping_info,PNG_INFO_tRNS);
2203 image->matte=MagickFalse;
2210 scale_to_short = 65535L/((1UL << ping_bit_depth)-1);
2212 /* Scale transparent_color to short */
2213 transparent_color.red= scale_to_short*ping_trans_color->red;
2214 transparent_color.green= scale_to_short*ping_trans_color->green;
2215 transparent_color.blue= scale_to_short*ping_trans_color->blue;
2216 transparent_color.opacity= scale_to_short*ping_trans_color->gray;
2218 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
2220 if (logging != MagickFalse)
2222 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2223 " Raw tRNS graylevel is %d.",ping_trans_color->gray);
2225 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2226 " scaled graylevel is %d.",transparent_color.opacity);
2228 transparent_color.red=transparent_color.opacity;
2229 transparent_color.green=transparent_color.opacity;
2230 transparent_color.blue=transparent_color.opacity;
2234 #if defined(PNG_READ_sBIT_SUPPORTED)
2235 if (mng_info->have_global_sbit)
2237 if (!png_get_valid(ping,ping_info,PNG_INFO_sBIT))
2238 png_set_sBIT(ping,ping_info,&mng_info->global_sbit);
2241 num_passes=png_set_interlace_handling(ping);
2243 png_read_update_info(ping,ping_info);
2245 ping_rowbytes=png_get_rowbytes(ping,ping_info);
2248 Initialize image structure.
2250 mng_info->image_box.left=0;
2251 mng_info->image_box.right=(ssize_t) ping_width;
2252 mng_info->image_box.top=0;
2253 mng_info->image_box.bottom=(ssize_t) ping_height;
2254 if (mng_info->mng_type == 0)
2256 mng_info->mng_width=ping_width;
2257 mng_info->mng_height=ping_height;
2258 mng_info->frame=mng_info->image_box;
2259 mng_info->clip=mng_info->image_box;
2264 image->page.y=mng_info->y_off[mng_info->object_id];
2267 image->compression=ZipCompression;
2268 image->columns=ping_width;
2269 image->rows=ping_height;
2270 if (((int) ping_color_type == PNG_COLOR_TYPE_PALETTE) ||
2271 ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) ||
2272 ((int) ping_color_type == PNG_COLOR_TYPE_GRAY))
2277 image->storage_class=PseudoClass;
2279 image->colors=one << ping_bit_depth;
2280 #if (MAGICKCORE_QUANTUM_DEPTH == 8)
2281 if (image->colors > 256)
2284 if (image->colors > 65536L)
2285 image->colors=65536L;
2287 if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
2295 (void) png_get_PLTE(ping,ping_info,&palette,&number_colors);
2296 image->colors=(size_t) number_colors;
2298 if (logging != MagickFalse)
2299 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2300 " Reading PNG PLTE chunk: number_colors: %d.",number_colors);
2304 if (image->storage_class == PseudoClass)
2307 Initialize image colormap.
2309 if (AcquireImageColormap(image,image->colors) == MagickFalse)
2310 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2312 if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
2320 (void) png_get_PLTE(ping,ping_info,&palette,&number_colors);
2322 for (i=0; i < (ssize_t) image->colors; i++)
2324 image->colormap[i].red=ScaleCharToQuantum(palette[i].red);
2325 image->colormap[i].green=ScaleCharToQuantum(palette[i].green);
2326 image->colormap[i].blue=ScaleCharToQuantum(palette[i].blue);
2335 scale=(QuantumRange/((1UL << ping_bit_depth)-1));
2340 for (i=0; i < (ssize_t) image->colors; i++)
2342 image->colormap[i].red=(Quantum) (i*scale);
2343 image->colormap[i].green=(Quantum) (i*scale);
2344 image->colormap[i].blue=(Quantum) (i*scale);
2349 Read image scanlines.
2351 if (image->delay != 0)
2352 mng_info->scenes_found++;
2354 if ((mng_info->mng_type == 0 && (image->ping != MagickFalse)) || (
2355 (image_info->number_scenes != 0) && (mng_info->scenes_found > (ssize_t)
2356 (image_info->first_scene+image_info->number_scenes))))
2358 if (logging != MagickFalse)
2359 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2360 " Skipping PNG image data for scene %.20g",(double)
2361 mng_info->scenes_found-1);
2362 png_destroy_read_struct(&ping,&ping_info,&end_info);
2363 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
2364 UnlockSemaphoreInfo(png_semaphore);
2366 if (logging != MagickFalse)
2367 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2368 " exit ReadOnePNGImage().");
2373 if (logging != MagickFalse)
2374 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2375 " Reading PNG IDAT chunk(s)");
2378 png_pixels=(unsigned char *) AcquireQuantumMemory(image->rows,
2379 ping_rowbytes*sizeof(*png_pixels));
2382 png_pixels=(unsigned char *) AcquireQuantumMemory(ping_rowbytes,
2383 sizeof(*png_pixels));
2385 if (png_pixels == (unsigned char *) NULL)
2386 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2388 if (logging != MagickFalse)
2389 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2390 " Converting PNG pixels to pixel packets");
2392 Convert PNG pixels to pixel packets.
2394 if (setjmp(png_jmpbuf(ping)))
2397 PNG image is corrupt.
2399 png_destroy_read_struct(&ping,&ping_info,&end_info);
2400 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
2401 UnlockSemaphoreInfo(png_semaphore);
2403 if (quantum_info != (QuantumInfo *) NULL)
2404 quantum_info = DestroyQuantumInfo(quantum_info);
2406 if (png_pixels != (unsigned char *) NULL)
2407 png_pixels=(unsigned char *) RelinquishMagickMemory(png_pixels);
2409 if (logging != MagickFalse)
2410 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2411 " exit ReadOnePNGImage() with error.");
2413 if (image != (Image *) NULL)
2415 InheritException(exception,&image->exception);
2419 return(GetFirstImageInList(image));
2422 quantum_info=AcquireQuantumInfo(image_info,image);
2424 if (quantum_info == (QuantumInfo *) NULL)
2425 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2430 found_transparent_pixel;
2432 found_transparent_pixel=MagickFalse;
2434 if (image->storage_class == DirectClass)
2436 for (pass=0; pass < num_passes; pass++)
2439 Convert image to DirectClass pixel packets.
2441 #if (MAGICKCORE_QUANTUM_DEPTH == 8)
2445 depth=(ssize_t) ping_bit_depth;
2447 image->matte=(((int) ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA) ||
2448 ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) ||
2449 (png_get_valid(ping,ping_info,PNG_INFO_tRNS))) ?
2450 MagickTrue : MagickFalse;
2452 for (y=0; y < (ssize_t) image->rows; y++)
2455 row_offset=ping_rowbytes*y;
2460 png_read_row(ping,png_pixels+row_offset,NULL);
2461 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
2463 if (q == (PixelPacket *) NULL)
2466 #if (0 && (MAGICKCORE_QUANTUM_DEPTH == 8) && !defined(MAGICKCORE_HDRI_SUPPORT))
2467 /* code deleted from version 6.6.6-8 */
2468 #else /* (MAGICKCORE_QUANTUM_DEPTH != 8) */
2470 if ((int) ping_color_type == PNG_COLOR_TYPE_GRAY)
2471 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
2472 GrayQuantum,png_pixels+row_offset,exception);
2474 else if ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
2475 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
2476 GrayAlphaQuantum,png_pixels+row_offset,exception);
2478 else if ((int) ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA)
2479 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
2480 RGBAQuantum,png_pixels+row_offset,exception);
2482 else if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
2483 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
2484 IndexQuantum,png_pixels+row_offset,exception);
2486 else /* ping_color_type == PNG_COLOR_TYPE_RGB */
2487 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
2488 RGBQuantum,png_pixels+row_offset,exception);
2490 if (found_transparent_pixel == MagickFalse)
2492 /* Is there a transparent pixel in the row? */
2493 if (y== 0 && logging != MagickFalse)
2494 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2495 " Looking for cheap transparent pixel");
2497 for (x=(ssize_t) image->columns-1; x >= 0; x--)
2499 if ((ping_color_type == PNG_COLOR_TYPE_RGBA ||
2500 ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) &&
2501 (q->opacity != OpaqueOpacity))
2503 if (logging != MagickFalse)
2504 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2507 found_transparent_pixel = MagickTrue;
2510 if ((ping_color_type == PNG_COLOR_TYPE_RGB ||
2511 ping_color_type == PNG_COLOR_TYPE_GRAY) &&
2512 (ScaleQuantumToShort(q->red) == transparent_color.red &&
2513 ScaleQuantumToShort(q->green) == transparent_color.green &&
2514 ScaleQuantumToShort(q->blue) == transparent_color.blue))
2516 if (logging != MagickFalse)
2517 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2519 found_transparent_pixel = MagickTrue;
2526 if ((image->previous == (Image *) NULL) && (num_passes == 1))
2528 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
2531 if (status == MagickFalse)
2534 if (SyncAuthenticPixels(image,exception) == MagickFalse)
2538 if ((image->previous == (Image *) NULL) && (num_passes != 1))
2540 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
2541 if (status == MagickFalse)
2547 else /* image->storage_class != DirectClass */
2549 for (pass=0; pass < num_passes; pass++)
2558 Convert grayscale image to PseudoClass pixel packets.
2560 image->matte=ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA ?
2561 MagickTrue : MagickFalse;
2563 quantum_scanline=(Quantum *) AcquireQuantumMemory(image->columns,
2564 (image->matte ? 2 : 1)*sizeof(*quantum_scanline));
2566 if (quantum_scanline == (Quantum *) NULL)
2567 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2569 for (y=0; y < (ssize_t) image->rows; y++)
2572 row_offset=ping_rowbytes*y;
2577 png_read_row(ping,png_pixels+row_offset,NULL);
2578 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
2580 if (q == (PixelPacket *) NULL)
2583 indexes=GetAuthenticIndexQueue(image);
2584 p=png_pixels+row_offset;
2587 switch (ping_bit_depth)
2594 for (x=(ssize_t) image->columns-7; x > 0; x-=8)
2596 for (bit=7; bit >= 0; bit--)
2597 *r++=(Quantum) ((*p) & (0x01 << bit) ? 0x01 : 0x00);
2601 if ((image->columns % 8) != 0)
2603 for (bit=7; bit >= (ssize_t) (8-(image->columns % 8)); bit--)
2604 *r++=(Quantum) ((*p) & (0x01 << bit) ? 0x01 : 0x00);
2612 for (x=(ssize_t) image->columns-3; x > 0; x-=4)
2614 *r++=(*p >> 6) & 0x03;
2615 *r++=(*p >> 4) & 0x03;
2616 *r++=(*p >> 2) & 0x03;
2620 if ((image->columns % 4) != 0)
2622 for (i=3; i >= (ssize_t) (4-(image->columns % 4)); i--)
2623 *r++=(Quantum) ((*p >> (i*2)) & 0x03);
2631 for (x=(ssize_t) image->columns-1; x > 0; x-=2)
2633 *r++=(*p >> 4) & 0x0f;
2637 if ((image->columns % 2) != 0)
2638 *r++=(*p++ >> 4) & 0x0f;
2645 if (ping_color_type == 4)
2646 for (x=(ssize_t) image->columns-1; x >= 0; x--)
2649 /* In image.h, OpaqueOpacity is 0
2650 * TransparentOpacity is QuantumRange
2651 * In a PNG datastream, Opaque is QuantumRange
2652 * and Transparent is 0.
2654 q->opacity=ScaleCharToQuantum((unsigned char) (255-(*p++)));
2655 if (q->opacity != OpaqueOpacity)
2656 found_transparent_pixel = MagickTrue;
2661 for (x=(ssize_t) image->columns-1; x >= 0; x--)
2669 for (x=(ssize_t) image->columns-1; x >= 0; x--)
2671 #if (MAGICKCORE_QUANTUM_DEPTH == 16)
2675 if (image->colors > 256)
2683 *r=(Quantum) quantum;
2686 if (ping_color_type == 4)
2688 quantum=((*p++) << 8);
2690 q->opacity=(Quantum) (QuantumRange-quantum);
2691 if (q->opacity != OpaqueOpacity)
2692 found_transparent_pixel = MagickTrue;
2696 #if (MAGICKCORE_QUANTUM_DEPTH == 32)
2700 if (image->colors > 256)
2711 if (ping_color_type == 4)
2713 q->opacity=(*p << 8) | *(p+1);
2715 q->opacity=(Quantum) GetAlphaPixelComponent(q);
2716 if (q->opacity != OpaqueOpacity)
2717 found_transparent_pixel = MagickTrue;
2722 #else /* MAGICKCORE_QUANTUM_DEPTH == 8 */
2724 p++; /* strip low byte */
2726 if (ping_color_type == 4)
2728 q->opacity=(Quantum) (QuantumRange-(*p++));
2729 if (q->opacity != OpaqueOpacity)
2730 found_transparent_pixel = MagickTrue;
2745 Transfer image scanline.
2749 for (x=0; x < (ssize_t) image->columns; x++)
2750 indexes[x]=(IndexPacket) (*r++);
2752 if (SyncAuthenticPixels(image,exception) == MagickFalse)
2755 if ((image->previous == (Image *) NULL) && (num_passes == 1))
2757 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
2760 if (status == MagickFalse)
2765 if ((image->previous == (Image *) NULL) && (num_passes != 1))
2767 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
2769 if (status == MagickFalse)
2773 quantum_scanline=(Quantum *) RelinquishMagickMemory(quantum_scanline);
2776 image->matte=found_transparent_pixel;
2778 if (logging != MagickFalse)
2780 if (found_transparent_pixel != MagickFalse)
2781 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2782 " Found transparent pixel");
2785 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2786 " No transparent pixel was found");
2788 ping_color_type&=0x03;
2793 if (quantum_info != (QuantumInfo *) NULL)
2794 quantum_info=DestroyQuantumInfo(quantum_info);
2796 if (image->storage_class == PseudoClass)
2802 image->matte=MagickFalse;
2803 (void) SyncImage(image);
2807 png_read_end(ping,ping_info);
2809 if (image_info->number_scenes != 0 && mng_info->scenes_found-1 <
2810 (ssize_t) image_info->first_scene && image->delay != 0)
2812 png_destroy_read_struct(&ping,&ping_info,&end_info);
2813 png_pixels=(unsigned char *) RelinquishMagickMemory(png_pixels);
2815 (void) SetImageBackgroundColor(image);
2816 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
2817 UnlockSemaphoreInfo(png_semaphore);
2819 if (logging != MagickFalse)
2820 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2821 " exit ReadOnePNGImage() early.");
2825 if (png_get_valid(ping,ping_info,PNG_INFO_tRNS))
2831 Image has a transparent background.
2833 storage_class=image->storage_class;
2834 image->matte=MagickTrue;
2836 /* Balfour fix from imagemagick discourse server, 5 Feb 2010 */
2838 if (storage_class == PseudoClass)
2840 if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
2842 for (x=0; x < ping_num_trans; x++)
2844 image->colormap[x].opacity =
2845 ScaleCharToQuantum((unsigned char)(255-ping_trans_alpha[x]));
2849 else if (ping_color_type == PNG_COLOR_TYPE_GRAY)
2851 for (x=0; x < (int) image->colors; x++)
2853 if (ScaleQuantumToShort(image->colormap[x].red) ==
2854 transparent_color.opacity)
2856 image->colormap[x].opacity = (Quantum) TransparentOpacity;
2860 (void) SyncImage(image);
2863 #if 1 /* Should have already been done above, but glennrp problem P10
2868 for (y=0; y < (ssize_t) image->rows; y++)
2870 image->storage_class=storage_class;
2871 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
2873 if (q == (PixelPacket *) NULL)
2876 indexes=GetAuthenticIndexQueue(image);
2878 /* Caution: on a Q8 build, this does not distinguish between
2879 * 16-bit colors that differ only in the low byte
2881 for (x=(ssize_t) image->columns-1; x >= 0; x--)
2883 if (ScaleQuantumToShort(q->red) == transparent_color.red &&
2884 ScaleQuantumToShort(q->green) == transparent_color.green &&
2885 ScaleQuantumToShort(q->blue) == transparent_color.blue)
2887 q->opacity=(Quantum) TransparentOpacity;
2890 #if 0 /* I have not found a case where this is needed. */
2893 q->opacity=(Quantum) OpaqueOpacity;
2900 if (SyncAuthenticPixels(image,exception) == MagickFalse)
2906 image->storage_class=DirectClass;
2909 if ((ping_color_type == PNG_COLOR_TYPE_GRAY) ||
2910 (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA))
2911 image->colorspace=GRAYColorspace;
2913 if (png_get_text(ping,ping_info,&text,&num_text) != 0)
2914 for (i=0; i < (ssize_t) num_text; i++)
2916 /* Check for a profile */
2918 if (logging != MagickFalse)
2919 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2920 " Reading PNG text chunk");
2922 if (memcmp(text[i].key, "Raw profile type ",17) == 0)
2923 (void) png_read_raw_profile(image,image_info,text,(int) i);
2930 length=text[i].text_length;
2931 value=(char *) AcquireQuantumMemory(length+MaxTextExtent,
2933 if (value == (char *) NULL)
2935 (void) ThrowMagickException(&image->exception,GetMagickModule(),
2936 ResourceLimitError,"MemoryAllocationFailed","`%s'",
2941 (void) ConcatenateMagickString(value,text[i].text,length+2);
2942 (void) SetImageProperty(image,text[i].key,value);
2944 if (logging != MagickFalse)
2945 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2946 " Keyword: %s",text[i].key);
2948 value=DestroyString(value);
2952 #ifdef MNG_OBJECT_BUFFERS
2954 Store the object if necessary.
2956 if (object_id && !mng_info->frozen[object_id])
2958 if (mng_info->ob[object_id] == (MngBuffer *) NULL)
2961 create a new object buffer.
2963 mng_info->ob[object_id]=(MngBuffer *)
2964 AcquireMagickMemory(sizeof(MngBuffer));
2966 if (mng_info->ob[object_id] != (MngBuffer *) NULL)
2968 mng_info->ob[object_id]->image=(Image *) NULL;
2969 mng_info->ob[object_id]->reference_count=1;
2973 if ((mng_info->ob[object_id] == (MngBuffer *) NULL) ||
2974 mng_info->ob[object_id]->frozen)
2976 if (mng_info->ob[object_id] == (MngBuffer *) NULL)
2977 (void) ThrowMagickException(&image->exception,GetMagickModule(),
2978 ResourceLimitError,"MemoryAllocationFailed","`%s'",
2981 if (mng_info->ob[object_id]->frozen)
2982 (void) ThrowMagickException(&image->exception,GetMagickModule(),
2983 ResourceLimitError,"Cannot overwrite frozen MNG object buffer",
2984 "`%s'",image->filename);
2990 if (mng_info->ob[object_id]->image != (Image *) NULL)
2991 mng_info->ob[object_id]->image=DestroyImage
2992 (mng_info->ob[object_id]->image);
2994 mng_info->ob[object_id]->image=CloneImage(image,0,0,MagickTrue,
2997 if (mng_info->ob[object_id]->image != (Image *) NULL)
2998 mng_info->ob[object_id]->image->file=(FILE *) NULL;
3001 (void) ThrowMagickException(&image->exception,GetMagickModule(),
3002 ResourceLimitError,"Cloning image for object buffer failed",
3003 "`%s'",image->filename);
3005 if (ping_width > 250000L || ping_height > 250000L)
3006 png_error(ping,"PNG Image dimensions are too large.");
3008 mng_info->ob[object_id]->width=ping_width;
3009 mng_info->ob[object_id]->height=ping_height;
3010 mng_info->ob[object_id]->color_type=ping_color_type;
3011 mng_info->ob[object_id]->sample_depth=ping_bit_depth;
3012 mng_info->ob[object_id]->interlace_method=ping_interlace_method;
3013 mng_info->ob[object_id]->compression_method=
3014 ping_compression_method;
3015 mng_info->ob[object_id]->filter_method=ping_filter_method;
3017 if (png_get_valid(ping,ping_info,PNG_INFO_PLTE))
3026 Copy the PLTE to the object buffer.
3028 png_get_PLTE(ping,ping_info,&plte,&number_colors);
3029 mng_info->ob[object_id]->plte_length=number_colors;
3031 for (i=0; i < number_colors; i++)
3033 mng_info->ob[object_id]->plte[i]=plte[i];
3038 mng_info->ob[object_id]->plte_length=0;
3043 Relinquish resources.
3045 png_destroy_read_struct(&ping,&ping_info,&end_info);
3047 png_pixels=(unsigned char *) RelinquishMagickMemory(png_pixels);
3048 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
3049 UnlockSemaphoreInfo(png_semaphore);
3052 if (logging != MagickFalse)
3053 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3054 " exit ReadOnePNGImage()");
3058 /* end of reading one PNG image */
3061 static Image *ReadPNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
3076 magic_number[MaxTextExtent];
3084 assert(image_info != (const ImageInfo *) NULL);
3085 assert(image_info->signature == MagickSignature);
3087 if (image_info->debug != MagickFalse)
3088 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
3089 image_info->filename);
3091 assert(exception != (ExceptionInfo *) NULL);
3092 assert(exception->signature == MagickSignature);
3093 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"enter ReadPNGImage()");
3094 image=AcquireImage(image_info);
3095 mng_info=(MngInfo *) NULL;
3096 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
3098 if (status == MagickFalse)
3099 ThrowReaderException(FileOpenError,"UnableToOpenFile");
3102 Verify PNG signature.
3104 count=ReadBlob(image,8,(unsigned char *) magic_number);
3106 if (memcmp(magic_number,"\211PNG\r\n\032\n",8) != 0)
3107 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
3110 Allocate a MngInfo structure.
3112 have_mng_structure=MagickFalse;
3113 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
3115 if (mng_info == (MngInfo *) NULL)
3116 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
3119 Initialize members of the MngInfo structure.
3121 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
3122 mng_info->image=image;
3123 have_mng_structure=MagickTrue;
3126 image=ReadOnePNGImage(mng_info,image_info,exception);
3127 MngInfoFreeStruct(mng_info,&have_mng_structure);
3129 if (image == (Image *) NULL)
3131 if (previous != (Image *) NULL)
3133 if (previous->signature != MagickSignature)
3134 ThrowReaderException(CorruptImageError,"CorruptImage");
3136 (void) CloseBlob(previous);
3137 (void) DestroyImageList(previous);
3140 if (logging != MagickFalse)
3141 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3142 "exit ReadPNGImage() with error");
3144 return((Image *) NULL);
3147 (void) CloseBlob(image);
3149 if ((image->columns == 0) || (image->rows == 0))
3151 if (logging != MagickFalse)
3152 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3153 "exit ReadPNGImage() with error.");
3155 ThrowReaderException(CorruptImageError,"CorruptImage");
3158 if (LocaleCompare(image_info->magick,"PNG8") == 0)
3160 (void) SetImageType(image,PaletteType);
3162 if (image->matte != MagickFalse)
3164 /* To do: Reduce to binary transparency */
3168 if (LocaleCompare(image_info->magick,"PNG24") == 0)
3170 (void) SetImageType(image,TrueColorType);
3171 image->matte=MagickFalse;
3174 if (LocaleCompare(image_info->magick,"PNG32") == 0)
3175 (void) SetImageType(image,TrueColorMatteType);
3177 if (logging != MagickFalse)
3178 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit ReadPNGImage()");
3185 #if defined(JNG_SUPPORTED)
3187 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3191 % R e a d O n e J N G I m a g e %
3195 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3197 % ReadOneJNGImage() reads a JPEG Network Graphics (JNG) image file
3198 % (minus the 8-byte signature) and returns it. It allocates the memory
3199 % necessary for the new Image structure and returns a pointer to the new
3202 % JNG support written by Glenn Randers-Pehrson, glennrp@image...
3204 % The format of the ReadOneJNGImage method is:
3206 % Image *ReadOneJNGImage(MngInfo *mng_info, const ImageInfo *image_info,
3207 % ExceptionInfo *exception)
3209 % A description of each parameter follows:
3211 % o mng_info: Specifies a pointer to a MngInfo structure.
3213 % o image_info: the image info.
3215 % o exception: return any errors or warnings in this structure.
3218 static Image *ReadOneJNGImage(MngInfo *mng_info,
3219 const ImageInfo *image_info, ExceptionInfo *exception)
3246 jng_image_sample_depth,
3247 jng_image_compression_method,
3248 jng_image_interlace_method,
3249 jng_alpha_sample_depth,
3250 jng_alpha_compression_method,
3251 jng_alpha_filter_method,
3252 jng_alpha_interlace_method;
3254 register const PixelPacket
3261 register PixelPacket
3264 register unsigned char
3275 jng_alpha_compression_method=0;
3276 jng_alpha_sample_depth=8;
3280 alpha_image=(Image *) NULL;
3281 color_image=(Image *) NULL;
3282 alpha_image_info=(ImageInfo *) NULL;
3283 color_image_info=(ImageInfo *) NULL;
3285 logging=LogMagickEvent(CoderEvent,GetMagickModule(),
3286 " enter ReadOneJNGImage()");
3288 image=mng_info->image;
3290 if (GetAuthenticPixelQueue(image) != (PixelPacket *) NULL)
3293 Allocate next image structure.
3295 if (logging != MagickFalse)
3296 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3297 " AcquireNextImage()");
3299 AcquireNextImage(image_info,image);
3301 if (GetNextImageInList(image) == (Image *) NULL)
3302 return((Image *) NULL);
3304 image=SyncNextImageInList(image);
3306 mng_info->image=image;
3309 Signature bytes have already been read.
3312 read_JSEP=MagickFalse;
3313 reading_idat=MagickFalse;
3314 skip_to_iend=MagickFalse;
3318 type[MaxTextExtent];
3327 Read a new JNG chunk.
3329 status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
3330 2*GetBlobSize(image));
3332 if (status == MagickFalse)
3336 (void) ConcatenateMagickString(type,"errr",MaxTextExtent);
3337 length=ReadBlobMSBLong(image);
3338 count=(unsigned int) ReadBlob(image,4,(unsigned char *) type);
3340 if (logging != MagickFalse)
3341 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3342 " Reading JNG chunk type %c%c%c%c, length: %.20g",
3343 type[0],type[1],type[2],type[3],(double) length);
3345 if (length > PNG_UINT_31_MAX || count == 0)
3346 ThrowReaderException(CorruptImageError,"CorruptImage");
3349 chunk=(unsigned char *) NULL;
3353 chunk=(unsigned char *) AcquireQuantumMemory(length,sizeof(*chunk));
3355 if (chunk == (unsigned char *) NULL)
3356 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
3358 for (i=0; i < (ssize_t) length; i++)
3359 chunk[i]=(unsigned char) ReadBlobByte(image);
3364 (void) ReadBlobMSBLong(image); /* read crc word */
3369 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
3374 if (memcmp(type,mng_JHDR,4) == 0)
3378 jng_width=(size_t) ((p[0] << 24) | (p[1] << 16) |
3379 (p[2] << 8) | p[3]);
3380 jng_height=(size_t) ((p[4] << 24) | (p[5] << 16) |
3381 (p[6] << 8) | p[7]);
3382 jng_color_type=p[8];
3383 jng_image_sample_depth=p[9];
3384 jng_image_compression_method=p[10];
3385 jng_image_interlace_method=p[11];
3387 image->interlace=jng_image_interlace_method != 0 ? PNGInterlace :
3390 jng_alpha_sample_depth=p[12];
3391 jng_alpha_compression_method=p[13];
3392 jng_alpha_filter_method=p[14];
3393 jng_alpha_interlace_method=p[15];
3395 if (logging != MagickFalse)
3397 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3398 " jng_width: %16lu",(unsigned long) jng_width);
3400 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3401 " jng_width: %16lu",(unsigned long) jng_height);
3403 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3404 " jng_color_type: %16d",jng_color_type);
3406 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3407 " jng_image_sample_depth: %3d",
3408 jng_image_sample_depth);
3410 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3411 " jng_image_compression_method:%3d",
3412 jng_image_compression_method);
3414 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3415 " jng_image_interlace_method: %3d",
3416 jng_image_interlace_method);
3418 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3419 " jng_alpha_sample_depth: %3d",
3420 jng_alpha_sample_depth);
3422 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3423 " jng_alpha_compression_method:%3d",
3424 jng_alpha_compression_method);
3426 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3427 " jng_alpha_filter_method: %3d",
3428 jng_alpha_filter_method);
3430 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3431 " jng_alpha_interlace_method: %3d",
3432 jng_alpha_interlace_method);
3437 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
3443 if ((reading_idat == MagickFalse) && (read_JSEP == MagickFalse) &&
3444 ((memcmp(type,mng_JDAT,4) == 0) || (memcmp(type,mng_JdAA,4) == 0) ||
3445 (memcmp(type,mng_IDAT,4) == 0) || (memcmp(type,mng_JDAA,4) == 0)))
3448 o create color_image
3449 o open color_blob, attached to color_image
3450 o if (color type has alpha)
3451 open alpha_blob, attached to alpha_image
3454 color_image_info=(ImageInfo *)AcquireMagickMemory(sizeof(ImageInfo));
3456 if (color_image_info == (ImageInfo *) NULL)
3457 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
3459 GetImageInfo(color_image_info);
3460 color_image=AcquireImage(color_image_info);
3462 if (color_image == (Image *) NULL)
3463 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
3465 if (logging != MagickFalse)
3466 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3467 " Creating color_blob.");
3469 (void) AcquireUniqueFilename(color_image->filename);
3470 status=OpenBlob(color_image_info,color_image,WriteBinaryBlobMode,
3473 if (status == MagickFalse)
3474 return((Image *) NULL);
3476 if ((image_info->ping == MagickFalse) && (jng_color_type >= 12))
3478 alpha_image_info=(ImageInfo *)
3479 AcquireMagickMemory(sizeof(ImageInfo));
3481 if (alpha_image_info == (ImageInfo *) NULL)
3482 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
3484 GetImageInfo(alpha_image_info);
3485 alpha_image=AcquireImage(alpha_image_info);
3487 if (alpha_image == (Image *) NULL)
3489 alpha_image=DestroyImage(alpha_image);
3490 ThrowReaderException(ResourceLimitError,
3491 "MemoryAllocationFailed");
3494 if (logging != MagickFalse)
3495 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3496 " Creating alpha_blob.");
3498 (void) AcquireUniqueFilename(alpha_image->filename);
3499 status=OpenBlob(alpha_image_info,alpha_image,WriteBinaryBlobMode,
3502 if (status == MagickFalse)
3503 return((Image *) NULL);
3505 if (jng_alpha_compression_method == 0)
3510 if (logging != MagickFalse)
3511 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3512 " Writing IHDR chunk to alpha_blob.");
3514 (void) WriteBlob(alpha_image,8,(const unsigned char *)
3515 "\211PNG\r\n\032\n");
3517 (void) WriteBlobMSBULong(alpha_image,13L);
3518 PNGType(data,mng_IHDR);
3519 LogPNGChunk(logging,mng_IHDR,13L);
3520 PNGLong(data+4,jng_width);
3521 PNGLong(data+8,jng_height);
3522 data[12]=jng_alpha_sample_depth;
3523 data[13]=0; /* color_type gray */
3524 data[14]=0; /* compression method 0 */
3525 data[15]=0; /* filter_method 0 */
3526 data[16]=0; /* interlace_method 0 */
3527 (void) WriteBlob(alpha_image,17,data);
3528 (void) WriteBlobMSBULong(alpha_image,crc32(0,data,17));
3531 reading_idat=MagickTrue;
3534 if (memcmp(type,mng_JDAT,4) == 0)
3536 /* Copy chunk to color_image->blob */
3538 if (logging != MagickFalse)
3539 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3540 " Copying JDAT chunk data to color_blob.");
3542 (void) WriteBlob(color_image,length,chunk);
3545 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
3550 if (memcmp(type,mng_IDAT,4) == 0)
3555 /* Copy IDAT header and chunk data to alpha_image->blob */
3557 if (image_info->ping == MagickFalse)
3559 if (logging != MagickFalse)
3560 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3561 " Copying IDAT chunk data to alpha_blob.");
3563 (void) WriteBlobMSBULong(alpha_image,(size_t) length);
3564 PNGType(data,mng_IDAT);
3565 LogPNGChunk(logging,mng_IDAT,length);
3566 (void) WriteBlob(alpha_image,4,data);
3567 (void) WriteBlob(alpha_image,length,chunk);
3568 (void) WriteBlobMSBULong(alpha_image,
3569 crc32(crc32(0,data,4),chunk,(uInt) length));
3573 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
3578 if ((memcmp(type,mng_JDAA,4) == 0) || (memcmp(type,mng_JdAA,4) == 0))
3580 /* Copy chunk data to alpha_image->blob */
3582 if (image_info->ping == MagickFalse)
3584 if (logging != MagickFalse)
3585 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3586 " Copying JDAA chunk data to alpha_blob.");
3588 (void) WriteBlob(alpha_image,length,chunk);
3592 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
3597 if (memcmp(type,mng_JSEP,4) == 0)
3599 read_JSEP=MagickTrue;
3602 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
3607 if (memcmp(type,mng_bKGD,4) == 0)
3611 image->background_color.red=ScaleCharToQuantum(p[1]);
3612 image->background_color.green=image->background_color.red;
3613 image->background_color.blue=image->background_color.red;
3618 image->background_color.red=ScaleCharToQuantum(p[1]);
3619 image->background_color.green=ScaleCharToQuantum(p[3]);
3620 image->background_color.blue=ScaleCharToQuantum(p[5]);
3623 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
3627 if (memcmp(type,mng_gAMA,4) == 0)
3630 image->gamma=((float) mng_get_long(p))*0.00001;
3632 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
3636 if (memcmp(type,mng_cHRM,4) == 0)
3640 image->chromaticity.white_point.x=0.00001*mng_get_long(p);
3641 image->chromaticity.white_point.y=0.00001*mng_get_long(&p[4]);
3642 image->chromaticity.red_primary.x=0.00001*mng_get_long(&p[8]);
3643 image->chromaticity.red_primary.y=0.00001*mng_get_long(&p[12]);
3644 image->chromaticity.green_primary.x=0.00001*mng_get_long(&p[16]);
3645 image->chromaticity.green_primary.y=0.00001*mng_get_long(&p[20]);
3646 image->chromaticity.blue_primary.x=0.00001*mng_get_long(&p[24]);
3647 image->chromaticity.blue_primary.y=0.00001*mng_get_long(&p[28]);
3650 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
3654 if (memcmp(type,mng_sRGB,4) == 0)
3658 image->rendering_intent=
3659 PNG_RenderingIntent_to_Magick_RenderingIntent(p[0]);
3660 image->gamma=0.45455f;
3661 image->chromaticity.red_primary.x=0.6400f;
3662 image->chromaticity.red_primary.y=0.3300f;
3663 image->chromaticity.green_primary.x=0.3000f;
3664 image->chromaticity.green_primary.y=0.6000f;
3665 image->chromaticity.blue_primary.x=0.1500f;
3666 image->chromaticity.blue_primary.y=0.0600f;
3667 image->chromaticity.white_point.x=0.3127f;
3668 image->chromaticity.white_point.y=0.3290f;
3671 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
3675 if (memcmp(type,mng_oFFs,4) == 0)
3679 image->page.x=mng_get_long(p);
3680 image->page.y=mng_get_long(&p[4]);
3682 if ((int) p[8] != 0)
3684 image->page.x/=10000;
3685 image->page.y/=10000;
3690 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
3695 if (memcmp(type,mng_pHYs,4) == 0)
3699 image->x_resolution=(double) mng_get_long(p);
3700 image->y_resolution=(double) mng_get_long(&p[4]);
3701 if ((int) p[8] == PNG_RESOLUTION_METER)
3703 image->units=PixelsPerCentimeterResolution;
3704 image->x_resolution=image->x_resolution/100.0f;
3705 image->y_resolution=image->y_resolution/100.0f;
3709 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
3714 if (memcmp(type,mng_iCCP,4) == 0)
3718 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
3725 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
3727 if (memcmp(type,mng_IEND,4))
3737 Finish up reading image data:
3739 o read main image from color_blob.
3743 o if (color_type has alpha)
3744 if alpha_encoding is PNG
3745 read secondary image from alpha_blob via ReadPNG
3746 if alpha_encoding is JPEG
3747 read secondary image from alpha_blob via ReadJPEG
3751 o copy intensity of secondary image into
3752 opacity samples of main image.
3754 o destroy the secondary image.
3757 (void) CloseBlob(color_image);
3759 if (logging != MagickFalse)
3760 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3761 " Reading jng_image from color_blob.");
3763 (void) FormatMagickString(color_image_info->filename,MaxTextExtent,"%s",
3764 color_image->filename);
3766 color_image_info->ping=MagickFalse; /* To do: avoid this */
3767 jng_image=ReadImage(color_image_info,exception);
3769 if (jng_image == (Image *) NULL)
3770 return((Image *) NULL);
3772 (void) RelinquishUniqueFileResource(color_image->filename);
3773 color_image=DestroyImage(color_image);
3774 color_image_info=DestroyImageInfo(color_image_info);
3776 if (jng_image == (Image *) NULL)
3777 return((Image *) NULL);
3779 if (logging != MagickFalse)
3780 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3781 " Copying jng_image pixels to main image.");
3783 image->rows=jng_height;
3784 image->columns=jng_width;
3785 length=image->columns*sizeof(PixelPacket);
3787 for (y=0; y < (ssize_t) image->rows; y++)
3789 s=GetVirtualPixels(jng_image,0,y,image->columns,1,&image->exception);
3790 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
3791 (void) CopyMagickMemory(q,s,length);
3793 if (SyncAuthenticPixels(image,exception) == MagickFalse)
3797 jng_image=DestroyImage(jng_image);
3799 if (image_info->ping == MagickFalse)
3801 if (jng_color_type >= 12)
3803 if (jng_alpha_compression_method == 0)
3807 (void) WriteBlobMSBULong(alpha_image,0x00000000L);
3808 PNGType(data,mng_IEND);
3809 LogPNGChunk(logging,mng_IEND,0L);
3810 (void) WriteBlob(alpha_image,4,data);
3811 (void) WriteBlobMSBULong(alpha_image,crc32(0,data,4));
3814 (void) CloseBlob(alpha_image);
3816 if (logging != MagickFalse)
3817 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3818 " Reading opacity from alpha_blob.");
3820 (void) FormatMagickString(alpha_image_info->filename,MaxTextExtent,
3821 "%s",alpha_image->filename);
3823 jng_image=ReadImage(alpha_image_info,exception);
3825 if (jng_image != (Image *) NULL)
3826 for (y=0; y < (ssize_t) image->rows; y++)
3828 s=GetVirtualPixels(jng_image,0,y,image->columns,1,
3830 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
3832 if (image->matte != MagickFalse)
3833 for (x=(ssize_t) image->columns; x != 0; x--,q++,s++)
3834 q->opacity=(Quantum) QuantumRange-s->red;
3837 for (x=(ssize_t) image->columns; x != 0; x--,q++,s++)
3839 q->opacity=(Quantum) QuantumRange-s->red;
3840 if (q->opacity != OpaqueOpacity)
3841 image->matte=MagickTrue;
3844 if (SyncAuthenticPixels(image,exception) == MagickFalse)
3847 (void) RelinquishUniqueFileResource(alpha_image->filename);
3848 alpha_image=DestroyImage(alpha_image);
3849 alpha_image_info=DestroyImageInfo(alpha_image_info);
3850 if (jng_image != (Image *) NULL)
3851 jng_image=DestroyImage(jng_image);
3855 /* Read the JNG image. */
3857 if (mng_info->mng_type == 0)
3859 mng_info->mng_width=jng_width;
3860 mng_info->mng_height=jng_height;
3863 if (image->page.width == 0 && image->page.height == 0)
3865 image->page.width=jng_width;
3866 image->page.height=jng_height;
3869 if (image->page.x == 0 && image->page.y == 0)
3871 image->page.x=mng_info->x_off[mng_info->object_id];
3872 image->page.y=mng_info->y_off[mng_info->object_id];
3877 image->page.y=mng_info->y_off[mng_info->object_id];
3880 mng_info->image_found++;
3881 status=SetImageProgress(image,LoadImagesTag,2*TellBlob(image),
3882 2*GetBlobSize(image));
3884 if (logging != MagickFalse)
3885 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3886 " exit ReadOneJNGImage()");
3892 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3896 % R e a d J N G I m a g e %
3900 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3902 % ReadJNGImage() reads a JPEG Network Graphics (JNG) image file
3903 % (including the 8-byte signature) and returns it. It allocates the memory
3904 % necessary for the new Image structure and returns a pointer to the new
3907 % JNG support written by Glenn Randers-Pehrson, glennrp@image...
3909 % The format of the ReadJNGImage method is:
3911 % Image *ReadJNGImage(const ImageInfo *image_info, ExceptionInfo
3914 % A description of each parameter follows:
3916 % o image_info: the image info.
3918 % o exception: return any errors or warnings in this structure.
3922 static Image *ReadJNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
3937 magic_number[MaxTextExtent];
3945 assert(image_info != (const ImageInfo *) NULL);
3946 assert(image_info->signature == MagickSignature);
3947 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image_info->filename);
3948 assert(exception != (ExceptionInfo *) NULL);
3949 assert(exception->signature == MagickSignature);
3950 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"enter ReadJNGImage()");
3951 image=AcquireImage(image_info);
3952 mng_info=(MngInfo *) NULL;
3953 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
3955 if (status == MagickFalse)
3956 return((Image *) NULL);
3958 if (LocaleCompare(image_info->magick,"JNG") != 0)
3959 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
3961 /* Verify JNG signature. */
3963 count=(size_t) ReadBlob(image,8,(unsigned char *) magic_number);
3965 if (memcmp(magic_number,"\213JNG\r\n\032\n",8) != 0)
3966 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
3968 /* Allocate a MngInfo structure. */
3970 have_mng_structure=MagickFalse;
3971 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(*mng_info));
3973 if (mng_info == (MngInfo *) NULL)
3974 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
3976 /* Initialize members of the MngInfo structure. */
3978 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
3979 have_mng_structure=MagickTrue;
3981 mng_info->image=image;
3983 image=ReadOneJNGImage(mng_info,image_info,exception);
3984 MngInfoFreeStruct(mng_info,&have_mng_structure);
3986 if (image == (Image *) NULL)
3988 if (IsImageObject(previous) != MagickFalse)
3990 (void) CloseBlob(previous);
3991 (void) DestroyImageList(previous);
3994 if (logging != MagickFalse)
3995 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3996 "exit ReadJNGImage() with error");
3998 return((Image *) NULL);
4000 (void) CloseBlob(image);
4002 if (image->columns == 0 || image->rows == 0)
4004 if (logging != MagickFalse)
4005 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4006 "exit ReadJNGImage() with error");
4008 ThrowReaderException(CorruptImageError,"CorruptImage");
4011 if (logging != MagickFalse)
4012 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit ReadJNGImage()");
4018 static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
4021 page_geometry[MaxTextExtent];
4054 #if defined(MNG_INSERT_LAYERS)
4056 mng_background_color;
4059 register unsigned char
4074 #if defined(MNG_INSERT_LAYERS)
4079 volatile unsigned int
4080 #ifdef MNG_OBJECT_BUFFERS
4081 mng_background_object=0,
4083 mng_type=0; /* 0: PNG or JNG; 1: MNG; 2: MNG-LC; 3: MNG-VLC */
4086 default_frame_timeout,
4088 #if defined(MNG_INSERT_LAYERS)
4094 /* These delays are all measured in image ticks_per_second,
4095 * not in MNG ticks_per_second
4098 default_frame_delay,
4102 #if defined(MNG_INSERT_LAYERS)
4111 previous_fb.bottom=0;
4113 previous_fb.right=0;
4115 default_fb.bottom=0;
4119 /* Open image file. */
4121 assert(image_info != (const ImageInfo *) NULL);
4122 assert(image_info->signature == MagickSignature);
4123 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image_info->filename);
4124 assert(exception != (ExceptionInfo *) NULL);
4125 assert(exception->signature == MagickSignature);
4126 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"enter ReadMNGImage()");
4127 image=AcquireImage(image_info);
4128 mng_info=(MngInfo *) NULL;
4129 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
4131 if (status == MagickFalse)
4132 return((Image *) NULL);
4134 first_mng_object=MagickFalse;
4136 have_mng_structure=MagickFalse;
4138 /* Allocate a MngInfo structure. */
4140 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
4142 if (mng_info == (MngInfo *) NULL)
4143 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
4145 /* Initialize members of the MngInfo structure. */
4147 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
4148 mng_info->image=image;
4149 have_mng_structure=MagickTrue;
4151 if (LocaleCompare(image_info->magick,"MNG") == 0)
4154 magic_number[MaxTextExtent];
4156 /* Verify MNG signature. */
4157 count=(size_t) ReadBlob(image,8,(unsigned char *) magic_number);
4158 if (memcmp(magic_number,"\212MNG\r\n\032\n",8) != 0)
4159 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
4161 /* Initialize some nonzero members of the MngInfo structure. */
4162 for (i=0; i < MNG_MAX_OBJECTS; i++)
4164 mng_info->object_clip[i].right=(ssize_t) PNG_UINT_31_MAX;
4165 mng_info->object_clip[i].bottom=(ssize_t) PNG_UINT_31_MAX;
4167 mng_info->exists[0]=MagickTrue;
4170 first_mng_object=MagickTrue;
4172 #if defined(MNG_INSERT_LAYERS)
4173 insert_layers=MagickFalse; /* should be False when converting or mogrifying */
4175 default_frame_delay=0;
4176 default_frame_timeout=0;
4179 mng_info->ticks_per_second=1UL*image->ticks_per_second;
4181 skip_to_iend=MagickFalse;
4182 term_chunk_found=MagickFalse;
4183 mng_info->framing_mode=1;
4184 #if defined(MNG_INSERT_LAYERS)
4185 mandatory_back=MagickFalse;
4187 #if defined(MNG_INSERT_LAYERS)
4188 mng_background_color=image->background_color;
4190 default_fb=mng_info->frame;
4191 previous_fb=mng_info->frame;
4195 type[MaxTextExtent];
4197 if (LocaleCompare(image_info->magick,"MNG") == 0)
4206 (void) ConcatenateMagickString(type,"errr",MaxTextExtent);
4207 length=ReadBlobMSBLong(image);
4208 count=(size_t) ReadBlob(image,4,(unsigned char *) type);
4210 if (logging != MagickFalse)
4211 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4212 " Reading MNG chunk type %c%c%c%c, length: %.20g",
4213 type[0],type[1],type[2],type[3],(double) length);
4215 if (length > PNG_UINT_31_MAX)
4219 ThrowReaderException(CorruptImageError,"CorruptImage");
4222 chunk=(unsigned char *) NULL;
4226 chunk=(unsigned char *) AcquireQuantumMemory(length,sizeof(*chunk));
4228 if (chunk == (unsigned char *) NULL)
4229 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
4231 for (i=0; i < (ssize_t) length; i++)
4232 chunk[i]=(unsigned char) ReadBlobByte(image);
4237 (void) ReadBlobMSBLong(image); /* read crc word */
4239 #if !defined(JNG_SUPPORTED)
4240 if (memcmp(type,mng_JHDR,4) == 0)
4242 skip_to_iend=MagickTrue;
4244 if (mng_info->jhdr_warning == 0)
4245 (void) ThrowMagickException(&image->exception,GetMagickModule(),
4246 CoderError,"JNGCompressNotSupported","`%s'",image->filename);
4248 mng_info->jhdr_warning++;
4251 if (memcmp(type,mng_DHDR,4) == 0)
4253 skip_to_iend=MagickTrue;
4255 if (mng_info->dhdr_warning == 0)
4256 (void) ThrowMagickException(&image->exception,GetMagickModule(),
4257 CoderError,"DeltaPNGNotSupported","`%s'",image->filename);
4259 mng_info->dhdr_warning++;
4261 if (memcmp(type,mng_MEND,4) == 0)
4266 if (memcmp(type,mng_IEND,4) == 0)
4267 skip_to_iend=MagickFalse;
4270 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4272 if (logging != MagickFalse)
4273 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4279 if (memcmp(type,mng_MHDR,4) == 0)
4281 mng_info->mng_width=(size_t) ((p[0] << 24) | (p[1] << 16) |
4282 (p[2] << 8) | p[3]);
4284 mng_info->mng_height=(size_t) ((p[4] << 24) | (p[5] << 16) |
4285 (p[6] << 8) | p[7]);
4287 if (logging != MagickFalse)
4289 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4290 " MNG width: %.20g",(double) mng_info->mng_width);
4291 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4292 " MNG height: %.20g",(double) mng_info->mng_height);
4296 mng_info->ticks_per_second=(size_t) mng_get_long(p);
4298 if (mng_info->ticks_per_second == 0)
4299 default_frame_delay=0;
4302 default_frame_delay=1UL*image->ticks_per_second/
4303 mng_info->ticks_per_second;
4305 frame_delay=default_frame_delay;
4311 simplicity=(size_t) mng_get_long(p);
4314 mng_type=1; /* Full MNG */
4316 if ((simplicity != 0) && ((simplicity | 11) == 11))
4317 mng_type=2; /* LC */
4319 if ((simplicity != 0) && ((simplicity | 9) == 9))
4320 mng_type=3; /* VLC */
4322 #if defined(MNG_INSERT_LAYERS)
4324 insert_layers=MagickTrue;
4326 if (GetAuthenticPixelQueue(image) != (PixelPacket *) NULL)
4328 /* Allocate next image structure. */
4329 AcquireNextImage(image_info,image);
4331 if (GetNextImageInList(image) == (Image *) NULL)
4332 return((Image *) NULL);
4334 image=SyncNextImageInList(image);
4335 mng_info->image=image;
4338 if ((mng_info->mng_width > 65535L) ||
4339 (mng_info->mng_height > 65535L))
4340 ThrowReaderException(ImageError,"WidthOrHeightExceedsLimit");
4342 (void) FormatMagickString(page_geometry,MaxTextExtent,
4343 "%.20gx%.20g+0+0",(double) mng_info->mng_width,(double)
4344 mng_info->mng_height);
4346 mng_info->frame.left=0;
4347 mng_info->frame.right=(ssize_t) mng_info->mng_width;
4348 mng_info->frame.top=0;
4349 mng_info->frame.bottom=(ssize_t) mng_info->mng_height;
4350 mng_info->clip=default_fb=previous_fb=mng_info->frame;
4352 for (i=0; i < MNG_MAX_OBJECTS; i++)
4353 mng_info->object_clip[i]=mng_info->frame;
4355 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4359 if (memcmp(type,mng_TERM,4) == 0)
4370 final_delay=(png_uint_32) mng_get_long(&p[2]);
4371 mng_iterations=(png_uint_32) mng_get_long(&p[6]);
4373 if (mng_iterations == PNG_UINT_31_MAX)
4376 image->iterations=mng_iterations;
4377 term_chunk_found=MagickTrue;
4380 if (logging != MagickFalse)
4382 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4383 " repeat=%d",repeat);
4385 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4386 " final_delay=%.20g",(double) final_delay);
4388 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4389 " image->iterations=%.20g",(double) image->iterations);
4392 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4395 if (memcmp(type,mng_DEFI,4) == 0)
4398 (void) ThrowMagickException(&image->exception,GetMagickModule(),
4399 CoderError,"DEFI chunk found in MNG-VLC datastream","`%s'",
4402 object_id=(p[0] << 8) | p[1];
4404 if (mng_type == 2 && object_id != 0)
4405 (void) ThrowMagickException(&image->exception,GetMagickModule(),
4406 CoderError,"Nonzero object_id in MNG-LC datastream","`%s'",
4409 if (object_id > MNG_MAX_OBJECTS)
4412 Instead ofsuing a warning we should allocate a larger
4413 MngInfo structure and continue.
4415 (void) ThrowMagickException(&image->exception,GetMagickModule(),
4416 CoderError,"object id too large","`%s'",image->filename);
4417 object_id=MNG_MAX_OBJECTS;
4420 if (mng_info->exists[object_id])
4421 if (mng_info->frozen[object_id])
4423 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4424 (void) ThrowMagickException(&image->exception,
4425 GetMagickModule(),CoderError,
4426 "DEFI cannot redefine a frozen MNG object","`%s'",
4431 mng_info->exists[object_id]=MagickTrue;
4434 mng_info->invisible[object_id]=p[2];
4437 Extract object offset info.
4441 mng_info->x_off[object_id]=(ssize_t) ((p[4] << 24) |
4442 (p[5] << 16) | (p[6] << 8) | p[7]);
4444 mng_info->y_off[object_id]=(ssize_t) ((p[8] << 24) |
4445 (p[9] << 16) | (p[10] << 8) | p[11]);
4447 if (logging != MagickFalse)
4449 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4450 " x_off[%d]: %.20g",object_id,(double)
4451 mng_info->x_off[object_id]);
4453 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4454 " y_off[%d]: %.20g",object_id,(double)
4455 mng_info->y_off[object_id]);
4460 Extract object clipping info.
4463 mng_info->object_clip[object_id]=mng_read_box(mng_info->frame,0,
4466 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4469 if (memcmp(type,mng_bKGD,4) == 0)
4471 mng_info->have_global_bkgd=MagickFalse;
4475 mng_info->mng_global_bkgd.red=
4476 ScaleShortToQuantum((unsigned short) ((p[0] << 8) | p[1]));
4478 mng_info->mng_global_bkgd.green=
4479 ScaleShortToQuantum((unsigned short) ((p[2] << 8) | p[3]));
4481 mng_info->mng_global_bkgd.blue=
4482 ScaleShortToQuantum((unsigned short) ((p[4] << 8) | p[5]));
4484 mng_info->have_global_bkgd=MagickTrue;
4487 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4490 if (memcmp(type,mng_BACK,4) == 0)
4492 #if defined(MNG_INSERT_LAYERS)
4494 mandatory_back=p[6];
4499 if (mandatory_back && length > 5)
4501 mng_background_color.red=
4502 ScaleShortToQuantum((unsigned short) ((p[0] << 8) | p[1]));
4504 mng_background_color.green=
4505 ScaleShortToQuantum((unsigned short) ((p[2] << 8) | p[3]));
4507 mng_background_color.blue=
4508 ScaleShortToQuantum((unsigned short) ((p[4] << 8) | p[5]));
4510 mng_background_color.opacity=OpaqueOpacity;
4513 #ifdef MNG_OBJECT_BUFFERS
4515 mng_background_object=(p[7] << 8) | p[8];
4518 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4522 if (memcmp(type,mng_PLTE,4) == 0)
4524 /* Read global PLTE. */
4526 if (length && (length < 769))
4528 if (mng_info->global_plte == (png_colorp) NULL)
4529 mng_info->global_plte=(png_colorp) AcquireQuantumMemory(256,
4530 sizeof(*mng_info->global_plte));
4532 for (i=0; i < (ssize_t) (length/3); i++)
4534 mng_info->global_plte[i].red=p[3*i];
4535 mng_info->global_plte[i].green=p[3*i+1];
4536 mng_info->global_plte[i].blue=p[3*i+2];
4539 mng_info->global_plte_length=(unsigned int) (length/3);
4542 for ( ; i < 256; i++)
4544 mng_info->global_plte[i].red=i;
4545 mng_info->global_plte[i].green=i;
4546 mng_info->global_plte[i].blue=i;
4550 mng_info->global_plte_length=256;
4553 mng_info->global_plte_length=0;
4555 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4559 if (memcmp(type,mng_tRNS,4) == 0)
4561 /* read global tRNS */
4564 for (i=0; i < (ssize_t) length; i++)
4565 mng_info->global_trns[i]=p[i];
4568 for ( ; i < 256; i++)
4569 mng_info->global_trns[i]=255;
4571 mng_info->global_trns_length=(unsigned int) length;
4572 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4575 if (memcmp(type,mng_gAMA,4) == 0)
4582 igamma=mng_get_long(p);
4583 mng_info->global_gamma=((float) igamma)*0.00001;
4584 mng_info->have_global_gama=MagickTrue;
4588 mng_info->have_global_gama=MagickFalse;
4590 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4594 if (memcmp(type,mng_cHRM,4) == 0)
4596 /* Read global cHRM */
4600 mng_info->global_chrm.white_point.x=0.00001*mng_get_long(p);
4601 mng_info->global_chrm.white_point.y=0.00001*mng_get_long(&p[4]);
4602 mng_info->global_chrm.red_primary.x=0.00001*mng_get_long(&p[8]);
4603 mng_info->global_chrm.red_primary.y=0.00001*
4604 mng_get_long(&p[12]);
4605 mng_info->global_chrm.green_primary.x=0.00001*
4606 mng_get_long(&p[16]);
4607 mng_info->global_chrm.green_primary.y=0.00001*
4608 mng_get_long(&p[20]);
4609 mng_info->global_chrm.blue_primary.x=0.00001*
4610 mng_get_long(&p[24]);
4611 mng_info->global_chrm.blue_primary.y=0.00001*
4612 mng_get_long(&p[28]);
4613 mng_info->have_global_chrm=MagickTrue;
4616 mng_info->have_global_chrm=MagickFalse;
4618 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4622 if (memcmp(type,mng_sRGB,4) == 0)
4629 mng_info->global_srgb_intent=
4630 PNG_RenderingIntent_to_Magick_RenderingIntent(p[0]);
4631 mng_info->have_global_srgb=MagickTrue;
4634 mng_info->have_global_srgb=MagickFalse;
4636 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4640 if (memcmp(type,mng_iCCP,4) == 0)
4648 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4653 if (memcmp(type,mng_FRAM,4) == 0)
4656 (void) ThrowMagickException(&image->exception,GetMagickModule(),
4657 CoderError,"FRAM chunk found in MNG-VLC datastream","`%s'",
4660 if ((mng_info->framing_mode == 2) || (mng_info->framing_mode == 4))
4661 image->delay=frame_delay;
4663 frame_delay=default_frame_delay;
4664 frame_timeout=default_frame_timeout;
4669 mng_info->framing_mode=p[0];
4671 if (logging != MagickFalse)
4672 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4673 " Framing_mode=%d",mng_info->framing_mode);
4677 /* Note the delay and frame clipping boundaries. */
4679 p++; /* framing mode */
4681 while (*p && ((p-chunk) < (ssize_t) length))
4682 p++; /* frame name */
4684 p++; /* frame name terminator */
4686 if ((p-chunk) < (ssize_t) (length-4))
4693 change_delay=(*p++);
4694 change_timeout=(*p++);
4695 change_clipping=(*p++);
4696 p++; /* change_sync */
4700 frame_delay=1UL*image->ticks_per_second*
4703 if (mng_info->ticks_per_second != 0)
4704 frame_delay/=mng_info->ticks_per_second;
4707 frame_delay=PNG_UINT_31_MAX;
4709 if (change_delay == 2)
4710 default_frame_delay=frame_delay;
4714 if (logging != MagickFalse)
4715 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4716 " Framing_delay=%.20g",(double) frame_delay);
4721 frame_timeout=1UL*image->ticks_per_second*
4724 if (mng_info->ticks_per_second != 0)
4725 frame_timeout/=mng_info->ticks_per_second;
4728 frame_timeout=PNG_UINT_31_MAX;
4730 if (change_delay == 2)
4731 default_frame_timeout=frame_timeout;
4735 if (logging != MagickFalse)
4736 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4737 " Framing_timeout=%.20g",(double) frame_timeout);
4740 if (change_clipping)
4742 fb=mng_read_box(previous_fb,(char) p[0],&p[1]);
4746 if (logging != MagickFalse)
4747 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4748 " Frame_clip: L=%.20g R=%.20g T=%.20g B=%.20g",
4749 (double) fb.left,(double) fb.right,(double) fb.top,
4750 (double) fb.bottom);
4752 if (change_clipping == 2)
4758 mng_info->clip=mng_minimum_box(fb,mng_info->frame);
4760 subframe_width=(size_t) (mng_info->clip.right
4761 -mng_info->clip.left);
4763 subframe_height=(size_t) (mng_info->clip.bottom
4764 -mng_info->clip.top);
4766 Insert a background layer behind the frame if framing_mode is 4.
4768 #if defined(MNG_INSERT_LAYERS)
4769 if (logging != MagickFalse)
4770 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4771 " subframe_width=%.20g, subframe_height=%.20g",(double)
4772 subframe_width,(double) subframe_height);
4774 if (insert_layers && (mng_info->framing_mode == 4) &&
4775 (subframe_width) && (subframe_height))
4777 /* Allocate next image structure. */
4778 if (GetAuthenticPixelQueue(image) != (PixelPacket *) NULL)
4780 AcquireNextImage(image_info,image);
4782 if (GetNextImageInList(image) == (Image *) NULL)
4784 image=DestroyImageList(image);
4785 MngInfoFreeStruct(mng_info,&have_mng_structure);
4786 return((Image *) NULL);
4789 image=SyncNextImageInList(image);
4792 mng_info->image=image;
4794 if (term_chunk_found)
4796 image->start_loop=MagickTrue;
4797 image->iterations=mng_iterations;
4798 term_chunk_found=MagickFalse;
4802 image->start_loop=MagickFalse;
4804 image->columns=subframe_width;
4805 image->rows=subframe_height;
4806 image->page.width=subframe_width;
4807 image->page.height=subframe_height;
4808 image->page.x=mng_info->clip.left;
4809 image->page.y=mng_info->clip.top;
4810 image->background_color=mng_background_color;
4811 image->matte=MagickFalse;
4813 (void) SetImageBackgroundColor(image);
4815 if (logging != MagickFalse)
4816 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4817 " Insert backgd layer, L=%.20g, R=%.20g T=%.20g, B=%.20g",
4818 (double) mng_info->clip.left,(double) mng_info->clip.right,
4819 (double) mng_info->clip.top,(double) mng_info->clip.bottom);
4822 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4825 if (memcmp(type,mng_CLIP,4) == 0)
4834 first_object=(p[0] << 8) | p[1];
4835 last_object=(p[2] << 8) | p[3];
4837 for (i=(int) first_object; i <= (int) last_object; i++)
4839 if (mng_info->exists[i] && !mng_info->frozen[i])
4844 box=mng_info->object_clip[i];
4845 mng_info->object_clip[i]=mng_read_box(box,(char) p[4],&p[5]);
4849 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4852 if (memcmp(type,mng_SAVE,4) == 0)
4854 for (i=1; i < MNG_MAX_OBJECTS; i++)
4855 if (mng_info->exists[i])
4857 mng_info->frozen[i]=MagickTrue;
4858 #ifdef MNG_OBJECT_BUFFERS
4859 if (mng_info->ob[i] != (MngBuffer *) NULL)
4860 mng_info->ob[i]->frozen=MagickTrue;
4865 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4870 if ((memcmp(type,mng_DISC,4) == 0) || (memcmp(type,mng_SEEK,4) == 0))
4872 /* Read DISC or SEEK. */
4874 if ((length == 0) || !memcmp(type,mng_SEEK,4))
4876 for (i=1; i < MNG_MAX_OBJECTS; i++)
4877 MngInfoDiscardObject(mng_info,i);
4885 for (j=0; j < (ssize_t) length; j+=2)
4887 i=p[j] << 8 | p[j+1];
4888 MngInfoDiscardObject(mng_info,i);
4893 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4898 if (memcmp(type,mng_MOVE,4) == 0)
4906 first_object=(p[0] << 8) | p[1];
4907 last_object=(p[2] << 8) | p[3];
4908 for (i=(ssize_t) first_object; i <= (ssize_t) last_object; i++)
4910 if (mng_info->exists[i] && !mng_info->frozen[i])
4918 old_pair.a=mng_info->x_off[i];
4919 old_pair.b=mng_info->y_off[i];
4920 new_pair=mng_read_pair(old_pair,(int) p[4],&p[5]);
4921 mng_info->x_off[i]=new_pair.a;
4922 mng_info->y_off[i]=new_pair.b;
4926 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4930 if (memcmp(type,mng_LOOP,4) == 0)
4932 ssize_t loop_iters=1;
4933 loop_level=chunk[0];
4934 mng_info->loop_active[loop_level]=1; /* mark loop active */
4936 /* Record starting point. */
4937 loop_iters=mng_get_long(&chunk[1]);
4939 if (logging != MagickFalse)
4940 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4941 " LOOP level %.20g has %.20g iterations ",(double) loop_level,
4942 (double) loop_iters);
4944 if (loop_iters == 0)
4945 skipping_loop=loop_level;
4949 mng_info->loop_jump[loop_level]=TellBlob(image);
4950 mng_info->loop_count[loop_level]=loop_iters;
4953 mng_info->loop_iteration[loop_level]=0;
4954 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
4958 if (memcmp(type,mng_ENDL,4) == 0)
4960 loop_level=chunk[0];
4962 if (skipping_loop > 0)
4964 if (skipping_loop == loop_level)
4967 Found end of zero-iteration loop.
4970 mng_info->loop_active[loop_level]=0;
4976 if (mng_info->loop_active[loop_level] == 1)
4978 mng_info->loop_count[loop_level]--;
4979 mng_info->loop_iteration[loop_level]++;
4981 if (logging != MagickFalse)
4982 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4983 " ENDL: LOOP level %.20g has %.20g remaining iters ",
4984 (double) loop_level,(double)
4985 mng_info->loop_count[loop_level]);
4987 if (mng_info->loop_count[loop_level] != 0)
4989 offset=SeekBlob(image,mng_info->loop_jump[loop_level],
4993 ThrowReaderException(CorruptImageError,
4994 "ImproperImageHeader");
5005 mng_info->loop_active[loop_level]=0;
5007 for (i=0; i < loop_level; i++)
5008 if (mng_info->loop_active[i] == 1)
5009 last_level=(short) i;
5010 loop_level=last_level;
5015 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5019 if (memcmp(type,mng_CLON,4) == 0)
5021 if (mng_info->clon_warning == 0)
5022 (void) ThrowMagickException(&image->exception,GetMagickModule(),
5023 CoderError,"CLON is not implemented yet","`%s'",
5026 mng_info->clon_warning++;
5029 if (memcmp(type,mng_MAGN,4) == 0)
5044 magn_first=(p[0] << 8) | p[1];
5050 magn_last=(p[2] << 8) | p[3];
5053 magn_last=magn_first;
5054 #ifndef MNG_OBJECT_BUFFERS
5055 if (magn_first || magn_last)
5056 if (mng_info->magn_warning == 0)
5058 (void) ThrowMagickException(&image->exception,
5059 GetMagickModule(),CoderError,
5060 "MAGN is not implemented yet for nonzero objects",
5061 "`%s'",image->filename);
5063 mng_info->magn_warning++;
5073 magn_mx=(p[5] << 8) | p[6];
5082 magn_my=(p[7] << 8) | p[8];
5091 magn_ml=(p[9] << 8) | p[10];
5100 magn_mr=(p[11] << 8) | p[12];
5109 magn_mt=(p[13] << 8) | p[14];
5118 magn_mb=(p[15] << 8) | p[16];
5130 magn_methy=magn_methx;
5133 if (magn_methx > 5 || magn_methy > 5)
5134 if (mng_info->magn_warning == 0)
5136 (void) ThrowMagickException(&image->exception,
5137 GetMagickModule(),CoderError,
5138 "Unknown MAGN method in MNG datastream","`%s'",
5141 mng_info->magn_warning++;
5143 #ifdef MNG_OBJECT_BUFFERS
5144 /* Magnify existing objects in the range magn_first to magn_last */
5146 if (magn_first == 0 || magn_last == 0)
5148 /* Save the magnification factors for object 0 */
5149 mng_info->magn_mb=magn_mb;
5150 mng_info->magn_ml=magn_ml;
5151 mng_info->magn_mr=magn_mr;
5152 mng_info->magn_mt=magn_mt;
5153 mng_info->magn_mx=magn_mx;
5154 mng_info->magn_my=magn_my;
5155 mng_info->magn_methx=magn_methx;
5156 mng_info->magn_methy=magn_methy;
5160 if (memcmp(type,mng_PAST,4) == 0)
5162 if (mng_info->past_warning == 0)
5163 (void) ThrowMagickException(&image->exception,GetMagickModule(),
5164 CoderError,"PAST is not implemented yet","`%s'",
5167 mng_info->past_warning++;
5170 if (memcmp(type,mng_SHOW,4) == 0)
5172 if (mng_info->show_warning == 0)
5173 (void) ThrowMagickException(&image->exception,GetMagickModule(),
5174 CoderError,"SHOW is not implemented yet","`%s'",
5177 mng_info->show_warning++;
5180 if (memcmp(type,mng_sBIT,4) == 0)
5183 mng_info->have_global_sbit=MagickFalse;
5187 mng_info->global_sbit.gray=p[0];
5188 mng_info->global_sbit.red=p[0];
5189 mng_info->global_sbit.green=p[1];
5190 mng_info->global_sbit.blue=p[2];
5191 mng_info->global_sbit.alpha=p[3];
5192 mng_info->have_global_sbit=MagickTrue;
5195 if (memcmp(type,mng_pHYs,4) == 0)
5199 mng_info->global_x_pixels_per_unit=
5200 (size_t) mng_get_long(p);
5201 mng_info->global_y_pixels_per_unit=
5202 (size_t) mng_get_long(&p[4]);
5203 mng_info->global_phys_unit_type=p[8];
5204 mng_info->have_global_phys=MagickTrue;
5208 mng_info->have_global_phys=MagickFalse;
5210 if (memcmp(type,mng_pHYg,4) == 0)
5212 if (mng_info->phyg_warning == 0)
5213 (void) ThrowMagickException(&image->exception,GetMagickModule(),
5214 CoderError,"pHYg is not implemented.","`%s'",image->filename);
5216 mng_info->phyg_warning++;
5218 if (memcmp(type,mng_BASI,4) == 0)
5220 skip_to_iend=MagickTrue;
5222 if (mng_info->basi_warning == 0)
5223 (void) ThrowMagickException(&image->exception,GetMagickModule(),
5224 CoderError,"BASI is not implemented yet","`%s'",
5227 mng_info->basi_warning++;
5228 #ifdef MNG_BASI_SUPPORTED
5229 basi_width=(size_t) ((p[0] << 24) | (p[1] << 16) |
5230 (p[2] << 8) | p[3]);
5231 basi_height=(size_t) ((p[4] << 24) | (p[5] << 16) |
5232 (p[6] << 8) | p[7]);
5233 basi_color_type=p[8];
5234 basi_compression_method=p[9];
5235 basi_filter_type=p[10];
5236 basi_interlace_method=p[11];
5238 basi_red=(p[12] << 8) & p[13];
5244 basi_green=(p[14] << 8) & p[15];
5250 basi_blue=(p[16] << 8) & p[17];
5256 basi_alpha=(p[18] << 8) & p[19];
5260 if (basi_sample_depth == 16)
5267 basi_viewable=p[20];
5273 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5277 if (memcmp(type,mng_IHDR,4)
5278 #if defined(JNG_SUPPORTED)
5279 && memcmp(type,mng_JHDR,4)
5283 /* Not an IHDR or JHDR chunk */
5285 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5290 if (logging != MagickFalse)
5291 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5292 " Processing %c%c%c%c chunk",type[0],type[1],type[2],type[3]);
5294 mng_info->exists[object_id]=MagickTrue;
5295 mng_info->viewable[object_id]=MagickTrue;
5297 if (mng_info->invisible[object_id])
5299 if (logging != MagickFalse)
5300 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5301 " Skipping invisible object");
5303 skip_to_iend=MagickTrue;
5304 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5307 #if defined(MNG_INSERT_LAYERS)
5309 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
5311 image_width=(size_t) mng_get_long(p);
5312 image_height=(size_t) mng_get_long(&p[4]);
5314 chunk=(unsigned char *) RelinquishMagickMemory(chunk);
5317 Insert a transparent background layer behind the entire animation
5318 if it is not full screen.
5320 #if defined(MNG_INSERT_LAYERS)
5321 if (insert_layers && mng_type && first_mng_object)
5323 if ((mng_info->clip.left > 0) || (mng_info->clip.top > 0) ||
5324 (image_width < mng_info->mng_width) ||
5325 (mng_info->clip.right < (ssize_t) mng_info->mng_width) ||
5326 (image_height < mng_info->mng_height) ||
5327 (mng_info->clip.bottom < (ssize_t) mng_info->mng_height))
5329 if (GetAuthenticPixelQueue(image) != (PixelPacket *) NULL)
5332 Allocate next image structure.
5334 AcquireNextImage(image_info,image);
5336 if (GetNextImageInList(image) == (Image *) NULL)
5338 image=DestroyImageList(image);
5339 MngInfoFreeStruct(mng_info,&have_mng_structure);
5340 return((Image *) NULL);
5343 image=SyncNextImageInList(image);
5345 mng_info->image=image;
5347 if (term_chunk_found)
5349 image->start_loop=MagickTrue;
5350 image->iterations=mng_iterations;
5351 term_chunk_found=MagickFalse;
5355 image->start_loop=MagickFalse;
5357 /* Make a background rectangle. */
5360 image->columns=mng_info->mng_width;
5361 image->rows=mng_info->mng_height;
5362 image->page.width=mng_info->mng_width;
5363 image->page.height=mng_info->mng_height;
5366 image->background_color=mng_background_color;
5367 (void) SetImageBackgroundColor(image);
5368 if (logging != MagickFalse)
5369 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5370 " Inserted transparent background layer, W=%.20g, H=%.20g",
5371 (double) mng_info->mng_width,(double) mng_info->mng_height);
5375 Insert a background layer behind the upcoming image if
5376 framing_mode is 3, and we haven't already inserted one.
5378 if (insert_layers && (mng_info->framing_mode == 3) &&
5379 (subframe_width) && (subframe_height) && (simplicity == 0 ||
5380 (simplicity & 0x08)))
5382 if (GetAuthenticPixelQueue(image) != (PixelPacket *) NULL)
5385 Allocate next image structure.
5387 AcquireNextImage(image_info,image);
5389 if (GetNextImageInList(image) == (Image *) NULL)
5391 image=DestroyImageList(image);
5392 MngInfoFreeStruct(mng_info,&have_mng_structure);
5393 return((Image *) NULL);
5396 image=SyncNextImageInList(image);
5399 mng_info->image=image;
5401 if (term_chunk_found)
5403 image->start_loop=MagickTrue;
5404 image->iterations=mng_iterations;
5405 term_chunk_found=MagickFalse;
5409 image->start_loop=MagickFalse;
5412 image->columns=subframe_width;
5413 image->rows=subframe_height;
5414 image->page.width=subframe_width;
5415 image->page.height=subframe_height;
5416 image->page.x=mng_info->clip.left;
5417 image->page.y=mng_info->clip.top;
5418 image->background_color=mng_background_color;
5419 image->matte=MagickFalse;
5420 (void) SetImageBackgroundColor(image);
5422 if (logging != MagickFalse)
5423 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5424 " Insert background layer, L=%.20g, R=%.20g T=%.20g, B=%.20g",
5425 (double) mng_info->clip.left,(double) mng_info->clip.right,
5426 (double) mng_info->clip.top,(double) mng_info->clip.bottom);
5428 #endif /* MNG_INSERT_LAYERS */
5429 first_mng_object=MagickFalse;
5431 if (GetAuthenticPixelQueue(image) != (PixelPacket *) NULL)
5434 Allocate next image structure.
5436 AcquireNextImage(image_info,image);
5438 if (GetNextImageInList(image) == (Image *) NULL)
5440 image=DestroyImageList(image);
5441 MngInfoFreeStruct(mng_info,&have_mng_structure);
5442 return((Image *) NULL);
5445 image=SyncNextImageInList(image);
5447 mng_info->image=image;
5448 status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
5449 GetBlobSize(image));
5451 if (status == MagickFalse)
5454 if (term_chunk_found)
5456 image->start_loop=MagickTrue;
5457 term_chunk_found=MagickFalse;
5461 image->start_loop=MagickFalse;
5463 if (mng_info->framing_mode == 1 || mng_info->framing_mode == 3)
5465 image->delay=frame_delay;
5466 frame_delay=default_frame_delay;
5472 image->page.width=mng_info->mng_width;
5473 image->page.height=mng_info->mng_height;
5474 image->page.x=mng_info->x_off[object_id];
5475 image->page.y=mng_info->y_off[object_id];
5476 image->iterations=mng_iterations;
5479 Seek back to the beginning of the IHDR or JHDR chunk's length field.
5482 if (logging != MagickFalse)
5483 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5484 " Seeking back to beginning of %c%c%c%c chunk",type[0],type[1],
5487 offset=SeekBlob(image,-((ssize_t) length+12),SEEK_CUR);
5490 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
5494 mng_info->image=image;
5495 mng_info->mng_type=mng_type;
5496 mng_info->object_id=object_id;
5498 if (memcmp(type,mng_IHDR,4) == 0)
5499 image=ReadOnePNGImage(mng_info,image_info,exception);
5501 #if defined(JNG_SUPPORTED)
5503 image=ReadOneJNGImage(mng_info,image_info,exception);
5506 if (image == (Image *) NULL)
5508 if (IsImageObject(previous) != MagickFalse)
5510 (void) DestroyImageList(previous);
5511 (void) CloseBlob(previous);
5514 MngInfoFreeStruct(mng_info,&have_mng_structure);
5515 return((Image *) NULL);
5518 if (image->columns == 0 || image->rows == 0)
5520 (void) CloseBlob(image);
5521 image=DestroyImageList(image);
5522 MngInfoFreeStruct(mng_info,&have_mng_structure);
5523 return((Image *) NULL);
5526 mng_info->image=image;
5533 if (mng_info->magn_methx || mng_info->magn_methy)
5539 if (logging != MagickFalse)
5540 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5541 " Processing MNG MAGN chunk");
5543 if (mng_info->magn_methx == 1)
5545 magnified_width=mng_info->magn_ml;
5547 if (image->columns > 1)
5548 magnified_width += mng_info->magn_mr;
5550 if (image->columns > 2)
5551 magnified_width += (png_uint_32)
5552 ((image->columns-2)*(mng_info->magn_mx));
5557 magnified_width=(png_uint_32) image->columns;
5559 if (image->columns > 1)
5560 magnified_width += mng_info->magn_ml-1;
5562 if (image->columns > 2)
5563 magnified_width += mng_info->magn_mr-1;
5565 if (image->columns > 3)
5566 magnified_width += (png_uint_32)
5567 ((image->columns-3)*(mng_info->magn_mx-1));
5570 if (mng_info->magn_methy == 1)
5572 magnified_height=mng_info->magn_mt;
5574 if (image->rows > 1)
5575 magnified_height += mng_info->magn_mb;
5577 if (image->rows > 2)
5578 magnified_height += (png_uint_32)
5579 ((image->rows-2)*(mng_info->magn_my));
5584 magnified_height=(png_uint_32) image->rows;
5586 if (image->rows > 1)
5587 magnified_height += mng_info->magn_mt-1;
5589 if (image->rows > 2)
5590 magnified_height += mng_info->magn_mb-1;
5592 if (image->rows > 3)
5593 magnified_height += (png_uint_32)
5594 ((image->rows-3)*(mng_info->magn_my-1));
5597 if (magnified_height > image->rows ||
5598 magnified_width > image->columns)
5613 register PixelPacket
5625 /* Allocate next image structure. */
5627 if (logging != MagickFalse)
5628 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5629 " Allocate magnified image");
5631 AcquireNextImage(image_info,image);
5633 if (GetNextImageInList(image) == (Image *) NULL)
5635 image=DestroyImageList(image);
5636 MngInfoFreeStruct(mng_info,&have_mng_structure);
5637 return((Image *) NULL);
5640 large_image=SyncNextImageInList(image);
5642 large_image->columns=magnified_width;
5643 large_image->rows=magnified_height;
5645 magn_methx=mng_info->magn_methx;
5646 magn_methy=mng_info->magn_methy;
5648 #if (MAGICKCORE_QUANTUM_DEPTH == 32)
5649 #define QM unsigned short
5650 if (magn_methx != 1 || magn_methy != 1)
5653 Scale pixels to unsigned shorts to prevent
5654 overflow of intermediate values of interpolations
5656 for (y=0; y < (ssize_t) image->rows; y++)
5658 q=GetAuthenticPixels(image,0,y,image->columns,1,
5661 for (x=(ssize_t) image->columns-1; x >= 0; x--)
5663 q->red=ScaleQuantumToShort(q->red);
5664 q->green=ScaleQuantumToShort(q->green);
5665 q->blue=ScaleQuantumToShort(q->blue);
5666 q->opacity=ScaleQuantumToShort(q->opacity);
5670 if (SyncAuthenticPixels(image,exception) == MagickFalse)
5678 if (image->matte != MagickFalse)
5679 (void) SetImageBackgroundColor(large_image);
5683 large_image->background_color.opacity=OpaqueOpacity;
5684 (void) SetImageBackgroundColor(large_image);
5686 if (magn_methx == 4)
5689 if (magn_methx == 5)
5692 if (magn_methy == 4)
5695 if (magn_methy == 5)
5699 /* magnify the rows into the right side of the large image */
5701 if (logging != MagickFalse)
5702 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5703 " Magnify the rows to %.20g",(double) large_image->rows);
5704 m=(ssize_t) mng_info->magn_mt;
5706 length=(size_t) image->columns;
5707 next=(PixelPacket *) AcquireQuantumMemory(length,sizeof(*next));
5708 prev=(PixelPacket *) AcquireQuantumMemory(length,sizeof(*prev));
5710 if ((prev == (PixelPacket *) NULL) ||
5711 (next == (PixelPacket *) NULL))
5713 image=DestroyImageList(image);
5714 MngInfoFreeStruct(mng_info,&have_mng_structure);
5715 ThrowReaderException(ResourceLimitError,
5716 "MemoryAllocationFailed");
5719 n=GetAuthenticPixels(image,0,0,image->columns,1,exception);
5720 (void) CopyMagickMemory(next,n,length);
5722 for (y=0; y < (ssize_t) image->rows; y++)
5725 m=(ssize_t) mng_info->magn_mt;
5727 else if (magn_methy > 1 && y == (ssize_t) image->rows-2)
5728 m=(ssize_t) mng_info->magn_mb;
5730 else if (magn_methy <= 1 && y == (ssize_t) image->rows-1)
5731 m=(ssize_t) mng_info->magn_mb;
5733 else if (magn_methy > 1 && y == (ssize_t) image->rows-1)
5737 m=(ssize_t) mng_info->magn_my;
5743 if (y < (ssize_t) image->rows-1)
5745 n=GetAuthenticPixels(image,0,y+1,image->columns,1,
5747 (void) CopyMagickMemory(next,n,length);
5750 for (i=0; i < m; i++, yy++)
5752 register PixelPacket
5755 assert(yy < (ssize_t) large_image->rows);
5758 q=GetAuthenticPixels(large_image,0,yy,large_image->columns,
5760 q+=(large_image->columns-image->columns);
5762 for (x=(ssize_t) image->columns-1; x >= 0; x--)
5764 /* TO DO: get color as function of indexes[x] */
5766 if (image->storage_class == PseudoClass)
5771 if (magn_methy <= 1)
5773 *q=(*pixels); /* replicate previous */
5776 else if (magn_methy == 2 || magn_methy == 4)
5784 (*q).red=(QM) (((ssize_t) (2*i*((*n).red
5785 -(*pixels).red)+m))/((ssize_t) (m*2))
5787 (*q).green=(QM) (((ssize_t) (2*i*((*n).green
5788 -(*pixels).green)+m))/((ssize_t) (m*2))
5790 (*q).blue=(QM) (((ssize_t) (2*i*((*n).blue
5791 -(*pixels).blue)+m))/((ssize_t) (m*2))
5794 if (image->matte != MagickFalse)
5795 (*q).opacity=(QM) (((ssize_t)
5797 -(*pixels).opacity)+m))
5798 /((ssize_t) (m*2))+(*pixels).opacity);
5801 if (magn_methy == 4)
5803 /* Replicate nearest */
5804 if (i <= ((m+1) << 1))
5805 (*q).opacity=(*pixels).opacity+0;
5807 (*q).opacity=(*n).opacity+0;
5811 else /* if (magn_methy == 3 || magn_methy == 5) */
5813 /* Replicate nearest */
5814 if (i <= ((m+1) << 1))
5820 if (magn_methy == 5)
5822 (*q).opacity=(QM) (((ssize_t) (2*i*((*n).opacity
5823 -(*pixels).opacity)+m))/((ssize_t) (m*2))
5824 +(*pixels).opacity);
5832 if (SyncAuthenticPixels(large_image,exception) == 0)
5838 prev=(PixelPacket *) RelinquishMagickMemory(prev);
5839 next=(PixelPacket *) RelinquishMagickMemory(next);
5841 length=image->columns;
5843 if (logging != MagickFalse)
5844 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5845 " Delete original image");
5847 DeleteImageFromList(&image);
5851 mng_info->image=image;
5853 /* magnify the columns */
5854 if (logging != MagickFalse)
5855 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5856 " Magnify the columns to %.20g",(double) image->columns);
5858 for (y=0; y < (ssize_t) image->rows; y++)
5860 register PixelPacket
5863 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
5864 pixels=q+(image->columns-length);
5867 for (x=(ssize_t) (image->columns-length);
5868 x < (ssize_t) image->columns; x++)
5870 if (x == (ssize_t) (image->columns-length))
5871 m=(ssize_t) mng_info->magn_ml;
5873 else if (magn_methx > 1 && x == (ssize_t) image->columns-2)
5874 m=(ssize_t) mng_info->magn_mr;
5876 else if (magn_methx <= 1 && x == (ssize_t) image->columns-1)
5877 m=(ssize_t) mng_info->magn_mr;
5879 else if (magn_methx > 1 && x == (ssize_t) image->columns-1)
5883 m=(ssize_t) mng_info->magn_mx;
5885 for (i=0; i < m; i++)
5887 if (magn_methx <= 1)
5889 /* replicate previous */
5893 else if (magn_methx == 2 || magn_methx == 4)
5901 (*q).red=(QM) ((2*i*((*n).red
5903 /((ssize_t) (m*2))+(*pixels).red);
5904 (*q).green=(QM) ((2*i*((*n).green
5906 +m)/((ssize_t) (m*2))+(*pixels).green);
5907 (*q).blue=(QM) ((2*i*((*n).blue
5909 /((ssize_t) (m*2))+(*pixels).blue);
5910 if (image->matte != MagickFalse)
5911 (*q).opacity=(QM) ((2*i*((*n).opacity
5912 -(*pixels).opacity)+m)/((ssize_t) (m*2))
5913 +(*pixels).opacity);
5916 if (magn_methx == 4)
5918 /* Replicate nearest */
5919 if (i <= ((m+1) << 1))
5920 (*q).opacity=(*pixels).opacity+0;
5922 (*q).opacity=(*n).opacity+0;
5926 else /* if (magn_methx == 3 || magn_methx == 5) */
5928 /* Replicate nearest */
5929 if (i <= ((m+1) << 1))
5935 if (magn_methx == 5)
5938 (*q).opacity=(QM) ((2*i*((*n).opacity
5939 -(*pixels).opacity)+m) /((ssize_t) (m*2))
5940 +(*pixels).opacity);
5949 if (SyncAuthenticPixels(image,exception) == MagickFalse)
5952 #if (MAGICKCORE_QUANTUM_DEPTH == 32)
5953 if (magn_methx != 1 || magn_methy != 1)
5956 Rescale pixels to Quantum
5958 for (y=0; y < (ssize_t) image->rows; y++)
5960 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
5962 for (x=(ssize_t) image->columns-1; x >= 0; x--)
5964 q->red=ScaleShortToQuantum(q->red);
5965 q->green=ScaleShortToQuantum(q->green);
5966 q->blue=ScaleShortToQuantum(q->blue);
5967 q->opacity=ScaleShortToQuantum(q->opacity);
5971 if (SyncAuthenticPixels(image,exception) == MagickFalse)
5976 if (logging != MagickFalse)
5977 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
5978 " Finished MAGN processing");
5983 Crop_box is with respect to the upper left corner of the MNG.
5985 crop_box.left=mng_info->image_box.left+mng_info->x_off[object_id];
5986 crop_box.right=mng_info->image_box.right+mng_info->x_off[object_id];
5987 crop_box.top=mng_info->image_box.top+mng_info->y_off[object_id];
5988 crop_box.bottom=mng_info->image_box.bottom+mng_info->y_off[object_id];
5989 crop_box=mng_minimum_box(crop_box,mng_info->clip);
5990 crop_box=mng_minimum_box(crop_box,mng_info->frame);
5991 crop_box=mng_minimum_box(crop_box,mng_info->object_clip[object_id]);
5992 if ((crop_box.left != (mng_info->image_box.left
5993 +mng_info->x_off[object_id])) ||
5994 (crop_box.right != (mng_info->image_box.right
5995 +mng_info->x_off[object_id])) ||
5996 (crop_box.top != (mng_info->image_box.top
5997 +mng_info->y_off[object_id])) ||
5998 (crop_box.bottom != (mng_info->image_box.bottom
5999 +mng_info->y_off[object_id])))
6001 if (logging != MagickFalse)
6002 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6003 " Crop the PNG image");
6005 if ((crop_box.left < crop_box.right) &&
6006 (crop_box.top < crop_box.bottom))
6015 Crop_info is with respect to the upper left corner of
6018 crop_info.x=(crop_box.left-mng_info->x_off[object_id]);
6019 crop_info.y=(crop_box.top-mng_info->y_off[object_id]);
6020 crop_info.width=(size_t) (crop_box.right-crop_box.left);
6021 crop_info.height=(size_t) (crop_box.bottom-crop_box.top);
6022 image->page.width=image->columns;
6023 image->page.height=image->rows;
6026 im=CropImage(image,&crop_info,exception);
6028 if (im != (Image *) NULL)
6030 image->columns=im->columns;
6031 image->rows=im->rows;
6032 im=DestroyImage(im);
6033 image->page.width=image->columns;
6034 image->page.height=image->rows;
6035 image->page.x=crop_box.left;
6036 image->page.y=crop_box.top;
6043 No pixels in crop area. The MNG spec still requires
6044 a layer, though, so make a single transparent pixel in
6045 the top left corner.
6050 (void) SetImageBackgroundColor(image);
6051 image->page.width=1;
6052 image->page.height=1;
6057 #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
6058 image=mng_info->image;
6062 #if (MAGICKCORE_QUANTUM_DEPTH > 16)
6063 /* PNG does not handle depths greater than 16 so reduce it even
6066 if (image->depth > 16)
6070 #if (MAGICKCORE_QUANTUM_DEPTH >= 16)
6071 if (LosslessReduceDepthOK(image) != MagickFalse)
6075 GetImageException(image,exception);
6077 if (image_info->number_scenes != 0)
6079 if (mng_info->scenes_found >
6080 (ssize_t) (image_info->first_scene+image_info->number_scenes))
6084 if (logging != MagickFalse)
6085 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6086 " Finished reading image datastream.");
6088 } while (LocaleCompare(image_info->magick,"MNG") == 0);
6090 (void) CloseBlob(image);
6092 if (logging != MagickFalse)
6093 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6094 " Finished reading all image datastreams.");
6096 #if defined(MNG_INSERT_LAYERS)
6097 if (insert_layers && !mng_info->image_found && (mng_info->mng_width) &&
6098 (mng_info->mng_height))
6101 Insert a background layer if nothing else was found.
6103 if (logging != MagickFalse)
6104 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6105 " No images found. Inserting a background layer.");
6107 if (GetAuthenticPixelQueue(image) != (PixelPacket *) NULL)
6110 Allocate next image structure.
6112 AcquireNextImage(image_info,image);
6113 if (GetNextImageInList(image) == (Image *) NULL)
6115 image=DestroyImageList(image);
6116 MngInfoFreeStruct(mng_info,&have_mng_structure);
6118 if (logging != MagickFalse)
6119 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6120 " Allocation failed, returning NULL.");
6122 return((Image *) NULL);
6124 image=SyncNextImageInList(image);
6126 image->columns=mng_info->mng_width;
6127 image->rows=mng_info->mng_height;
6128 image->page.width=mng_info->mng_width;
6129 image->page.height=mng_info->mng_height;
6132 image->background_color=mng_background_color;
6133 image->matte=MagickFalse;
6135 if (image_info->ping == MagickFalse)
6136 (void) SetImageBackgroundColor(image);
6138 mng_info->image_found++;
6141 image->iterations=mng_iterations;
6143 if (mng_iterations == 1)
6144 image->start_loop=MagickTrue;
6146 while (GetPreviousImageInList(image) != (Image *) NULL)
6149 if (image_count > 10*mng_info->image_found)
6151 if (logging != MagickFalse)
6152 (void) LogMagickEvent(CoderEvent,GetMagickModule()," No beginning");
6154 (void) ThrowMagickException(&image->exception,GetMagickModule(),
6155 CoderError,"Linked list is corrupted, beginning of list not found",
6156 "`%s'",image_info->filename);
6158 return((Image *) NULL);
6161 image=GetPreviousImageInList(image);
6163 if (GetNextImageInList(image) == (Image *) NULL)
6165 if (logging != MagickFalse)
6166 (void) LogMagickEvent(CoderEvent,GetMagickModule()," Corrupt list");
6168 (void) ThrowMagickException(&image->exception,GetMagickModule(),
6169 CoderError,"Linked list is corrupted; next_image is NULL","`%s'",
6170 image_info->filename);
6174 if (mng_info->ticks_per_second && mng_info->image_found > 1 &&
6175 GetNextImageInList(image) ==
6178 if (logging != MagickFalse)
6179 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6180 " First image null");
6182 (void) ThrowMagickException(&image->exception,GetMagickModule(),
6183 CoderError,"image->next for first image is NULL but shouldn't be.",
6184 "`%s'",image_info->filename);
6187 if (mng_info->image_found == 0)
6189 if (logging != MagickFalse)
6190 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6191 " No visible images found.");
6193 (void) ThrowMagickException(&image->exception,GetMagickModule(),
6194 CoderError,"No visible images in file","`%s'",image_info->filename);
6196 if (image != (Image *) NULL)
6197 image=DestroyImageList(image);
6199 MngInfoFreeStruct(mng_info,&have_mng_structure);
6200 return((Image *) NULL);
6203 if (mng_info->ticks_per_second)
6204 final_delay=1UL*MagickMax(image->ticks_per_second,1L)*
6205 final_delay/mng_info->ticks_per_second;
6208 image->start_loop=MagickTrue;
6210 /* Find final nonzero image delay */
6211 final_image_delay=0;
6213 while (GetNextImageInList(image) != (Image *) NULL)
6216 final_image_delay=image->delay;
6218 image=GetNextImageInList(image);
6221 if (final_delay < final_image_delay)
6222 final_delay=final_image_delay;
6224 image->delay=final_delay;
6226 if (logging != MagickFalse)
6227 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6228 " image->delay=%.20g, final_delay=%.20g",(double) image->delay,
6229 (double) final_delay);
6231 if (logging != MagickFalse)
6237 image=GetFirstImageInList(image);
6239 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6240 " Before coalesce:");
6242 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6243 " scene 0 delay=%.20g",(double) image->delay);
6245 while (GetNextImageInList(image) != (Image *) NULL)
6247 image=GetNextImageInList(image);
6248 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6249 " scene %.20g delay=%.20g",(double) scene++,(double) image->delay);
6253 image=GetFirstImageInList(image);
6254 #ifdef MNG_COALESCE_LAYERS
6264 if (logging != MagickFalse)
6265 (void) LogMagickEvent(CoderEvent,GetMagickModule()," Coalesce Images");
6268 next_image=CoalesceImages(image,&image->exception);
6270 if (next_image == (Image *) NULL)
6271 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
6273 image=DestroyImageList(image);
6276 for (next=image; next != (Image *) NULL; next=next_image)
6278 next->page.width=mng_info->mng_width;
6279 next->page.height=mng_info->mng_height;
6282 next->scene=scene++;
6283 next_image=GetNextImageInList(next);
6285 if (next_image == (Image *) NULL)
6288 if (next->delay == 0)
6291 next_image->previous=GetPreviousImageInList(next);
6292 if (GetPreviousImageInList(next) == (Image *) NULL)
6295 next->previous->next=next_image;
6296 next=DestroyImage(next);
6302 while (GetNextImageInList(image) != (Image *) NULL)
6303 image=GetNextImageInList(image);
6305 image->dispose=BackgroundDispose;
6307 if (logging != MagickFalse)
6313 image=GetFirstImageInList(image);
6315 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6316 " After coalesce:");
6318 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6319 " scene 0 delay=%.20g dispose=%.20g",(double) image->delay,
6320 (double) image->dispose);
6322 while (GetNextImageInList(image) != (Image *) NULL)
6324 image=GetNextImageInList(image);
6326 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6327 " scene %.20g delay=%.20g dispose=%.20g",(double) scene++,
6328 (double) image->delay,(double) image->dispose);
6332 image=GetFirstImageInList(image);
6333 MngInfoFreeStruct(mng_info,&have_mng_structure);
6334 have_mng_structure=MagickFalse;
6336 if (logging != MagickFalse)
6337 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit ReadMNGImage()");
6339 return(GetFirstImageInList(image));
6341 #else /* PNG_LIBPNG_VER > 10011 */
6342 static Image *ReadPNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
6344 printf("Your PNG library is too old: You have libpng-%s\n",
6345 PNG_LIBPNG_VER_STRING);
6347 (void) ThrowMagickException(exception,GetMagickModule(),CoderError,
6348 "PNG library is too old","`%s'",image_info->filename);
6350 return(Image *) NULL;
6353 static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception)
6355 return(ReadPNGImage(image_info,exception));
6357 #endif /* PNG_LIBPNG_VER > 10011 */
6361 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6365 % R e g i s t e r P N G I m a g e %
6369 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6371 % RegisterPNGImage() adds properties for the PNG image format to
6372 % the list of supported formats. The properties include the image format
6373 % tag, a method to read and/or write the format, whether the format
6374 % supports the saving of more than one frame to the same file or blob,
6375 % whether the format supports native in-memory I/O, and a brief
6376 % description of the format.
6378 % The format of the RegisterPNGImage method is:
6380 % size_t RegisterPNGImage(void)
6383 ModuleExport size_t RegisterPNGImage(void)
6386 version[MaxTextExtent];
6394 "See http://www.libpng.org/ for details about the PNG format."
6399 "See http://www.libpng.org/pub/mng/ for details about the JNG\n"
6405 "See http://www.libpng.org/pub/mng/ for details about the MNG\n"
6411 #if defined(PNG_LIBPNG_VER_STRING)
6412 (void) ConcatenateMagickString(version,"libpng ",MaxTextExtent);
6413 (void) ConcatenateMagickString(version,PNG_LIBPNG_VER_STRING,MaxTextExtent);
6415 if (LocaleCompare(PNG_LIBPNG_VER_STRING,png_get_header_ver(NULL)) != 0)
6417 (void) ConcatenateMagickString(version,",",MaxTextExtent);
6418 (void) ConcatenateMagickString(version,png_get_libpng_ver(NULL),
6423 entry=SetMagickInfo("MNG");
6424 entry->seekable_stream=MagickTrue; /* To do: eliminate this. */
6426 #if defined(MAGICKCORE_PNG_DELEGATE)
6427 entry->decoder=(DecodeImageHandler *) ReadMNGImage;
6428 entry->encoder=(EncodeImageHandler *) WriteMNGImage;
6431 entry->magick=(IsImageFormatHandler *) IsMNG;
6432 entry->description=ConstantString("Multiple-image Network Graphics");
6434 if (*version != '\0')
6435 entry->version=ConstantString(version);
6437 entry->module=ConstantString("PNG");
6438 entry->note=ConstantString(MNGNote);
6439 (void) RegisterMagickInfo(entry);
6441 entry=SetMagickInfo("PNG");
6443 #if defined(MAGICKCORE_PNG_DELEGATE)
6444 entry->decoder=(DecodeImageHandler *) ReadPNGImage;
6445 entry->encoder=(EncodeImageHandler *) WritePNGImage;
6448 entry->magick=(IsImageFormatHandler *) IsPNG;
6449 entry->adjoin=MagickFalse;
6450 entry->description=ConstantString("Portable Network Graphics");
6451 entry->module=ConstantString("PNG");
6453 if (*version != '\0')
6454 entry->version=ConstantString(version);
6456 entry->note=ConstantString(PNGNote);
6457 (void) RegisterMagickInfo(entry);
6459 entry=SetMagickInfo("PNG8");
6461 #if defined(MAGICKCORE_PNG_DELEGATE)
6462 entry->decoder=(DecodeImageHandler *) ReadPNGImage;
6463 entry->encoder=(EncodeImageHandler *) WritePNGImage;
6466 entry->magick=(IsImageFormatHandler *) IsPNG;
6467 entry->adjoin=MagickFalse;
6468 entry->description=ConstantString(
6469 "8-bit indexed with optional binary transparency");
6470 entry->module=ConstantString("PNG");
6471 (void) RegisterMagickInfo(entry);
6473 entry=SetMagickInfo("PNG24");
6476 #if defined(ZLIB_VERSION)
6477 (void) ConcatenateMagickString(version,"zlib ",MaxTextExtent);
6478 (void) ConcatenateMagickString(version,ZLIB_VERSION,MaxTextExtent);
6480 if (LocaleCompare(ZLIB_VERSION,zlib_version) != 0)
6482 (void) ConcatenateMagickString(version,",",MaxTextExtent);
6483 (void) ConcatenateMagickString(version,zlib_version,MaxTextExtent);
6487 if (*version != '\0')
6488 entry->version=ConstantString(version);
6490 #if defined(MAGICKCORE_PNG_DELEGATE)
6491 entry->decoder=(DecodeImageHandler *) ReadPNGImage;
6492 entry->encoder=(EncodeImageHandler *) WritePNGImage;
6495 entry->magick=(IsImageFormatHandler *) IsPNG;
6496 entry->adjoin=MagickFalse;
6497 entry->description=ConstantString("opaque 24-bit RGB");
6498 entry->module=ConstantString("PNG");
6499 (void) RegisterMagickInfo(entry);
6501 entry=SetMagickInfo("PNG32");
6503 #if defined(MAGICKCORE_PNG_DELEGATE)
6504 entry->decoder=(DecodeImageHandler *) ReadPNGImage;
6505 entry->encoder=(EncodeImageHandler *) WritePNGImage;
6508 entry->magick=(IsImageFormatHandler *) IsPNG;
6509 entry->adjoin=MagickFalse;
6510 entry->description=ConstantString("opaque or transparent 32-bit RGBA");
6511 entry->module=ConstantString("PNG");
6512 (void) RegisterMagickInfo(entry);
6514 entry=SetMagickInfo("JNG");
6516 #if defined(JNG_SUPPORTED)
6517 #if defined(MAGICKCORE_PNG_DELEGATE)
6518 entry->decoder=(DecodeImageHandler *) ReadJNGImage;
6519 entry->encoder=(EncodeImageHandler *) WriteJNGImage;
6523 entry->magick=(IsImageFormatHandler *) IsJNG;
6524 entry->adjoin=MagickFalse;
6525 entry->description=ConstantString("JPEG Network Graphics");
6526 entry->module=ConstantString("PNG");
6527 entry->note=ConstantString(JNGNote);
6528 (void) RegisterMagickInfo(entry);
6530 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
6531 png_semaphore=AllocateSemaphoreInfo();
6534 return(MagickImageCoderSignature);
6538 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6542 % U n r e g i s t e r P N G I m a g e %
6546 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6548 % UnregisterPNGImage() removes format registrations made by the
6549 % PNG module from the list of supported formats.
6551 % The format of the UnregisterPNGImage method is:
6553 % UnregisterPNGImage(void)
6556 ModuleExport void UnregisterPNGImage(void)
6558 (void) UnregisterMagickInfo("MNG");
6559 (void) UnregisterMagickInfo("PNG");
6560 (void) UnregisterMagickInfo("PNG8");
6561 (void) UnregisterMagickInfo("PNG24");
6562 (void) UnregisterMagickInfo("PNG32");
6563 (void) UnregisterMagickInfo("JNG");
6565 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
6566 if (png_semaphore != (SemaphoreInfo *) NULL)
6567 DestroySemaphoreInfo(&png_semaphore);
6571 #if defined(MAGICKCORE_PNG_DELEGATE)
6572 #if PNG_LIBPNG_VER > 10011
6574 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6578 % W r i t e M N G I m a g e %
6582 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6584 % WriteMNGImage() writes an image in the Portable Network Graphics
6585 % Group's "Multiple-image Network Graphics" encoded image format.
6587 % MNG support written by Glenn Randers-Pehrson, glennrp@image...
6589 % The format of the WriteMNGImage method is:
6591 % MagickBooleanType WriteMNGImage(const ImageInfo *image_info,Image *image)
6593 % A description of each parameter follows.
6595 % o image_info: the image info.
6597 % o image: The image.
6600 % To do (as of version 5.5.2, November 26, 2002 -- glennrp -- see also
6601 % "To do" under ReadPNGImage):
6603 % Fix problem with palette sorting (when PNG_SORT_PALETTE is enabled,
6604 % some GIF animations don't convert properly)
6606 % Preserve all unknown and not-yet-handled known chunks found in input
6607 % PNG file and copy them into output PNG files according to the PNG
6610 % Write the iCCP chunk at MNG level when (icc profile length > 0)
6612 % Improve selection of color type (use indexed-colour or indexed-colour
6613 % with tRNS when 256 or fewer unique RGBA values are present).
6615 % Figure out what to do with "dispose=<restore-to-previous>" (dispose == 3)
6616 % This will be complicated if we limit ourselves to generating MNG-LC
6617 % files. For now we ignore disposal method 3 and simply overlay the next
6620 % Check for identical PLTE's or PLTE/tRNS combinations and use a
6621 % global MNG PLTE or PLTE/tRNS combination when appropriate.
6622 % [mostly done 15 June 1999 but still need to take care of tRNS]
6624 % Check for identical sRGB and replace with a global sRGB (and remove
6625 % gAMA/cHRM if sRGB is found; check for identical gAMA/cHRM and
6626 % replace with global gAMA/cHRM (or with sRGB if appropriate; replace
6627 % local gAMA/cHRM with local sRGB if appropriate).
6629 % Check for identical sBIT chunks and write global ones.
6631 % Provide option to skip writing the signature tEXt chunks.
6633 % Use signatures to detect identical objects and reuse the first
6634 % instance of such objects instead of writing duplicate objects.
6636 % Use a smaller-than-32k value of compression window size when
6639 % Encode JNG datastreams. Mostly done as of 5.5.2; need to write
6640 % ancillary text chunks and save profiles.
6642 % Provide an option to force LC files (to ensure exact framing rate)
6645 % Provide an option to force VLC files instead of LC, even when offsets
6646 % are present. This will involve expanding the embedded images with a
6647 % transparent region at the top and/or left.
6651 png_write_raw_profile(const ImageInfo *image_info,png_struct *ping,
6652 png_info *ping_info, unsigned char *profile_type, unsigned char
6653 *profile_description, unsigned char *profile_data, png_uint_32 length)
6672 hex[16]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
6674 if (LocaleNCompare((char *) profile_type+1, "ng-chunk-",9) == 0)
6677 if (image_info->verbose)
6679 (void) printf("writing raw profile: type=%s, length=%.20g\n",
6680 (char *) profile_type, (double) length);
6683 text=(png_textp) png_malloc(ping,(png_uint_32) sizeof(png_text));
6684 description_length=(png_uint_32) strlen((const char *) profile_description);
6685 allocated_length=(png_uint_32) (length*2 + (length >> 5) + 20
6686 + description_length);
6687 text[0].text=(png_charp) png_malloc(ping,allocated_length);
6688 text[0].key=(png_charp) png_malloc(ping, (png_uint_32) 80);
6689 text[0].key[0]='\0';
6690 (void) ConcatenateMagickString(text[0].key,
6691 "Raw profile type ",MaxTextExtent);
6692 (void) ConcatenateMagickString(text[0].key,(const char *) profile_type,62);
6696 (void) CopyMagickString(dp,(const char *) profile_description,
6698 dp+=description_length;
6700 (void) FormatMagickString(dp,allocated_length-
6701 (png_size_t) (dp-text[0].text),"%8lu ",(unsigned long) length);
6704 for (i=0; i < (ssize_t) length; i++)
6708 *(dp++)=(char) hex[((*sp >> 4) & 0x0f)];
6709 *(dp++)=(char) hex[((*sp++ ) & 0x0f)];
6714 text[0].text_length=(png_size_t) (dp-text[0].text);
6715 text[0].compression=image_info->compression == NoCompression ||
6716 (image_info->compression == UndefinedCompression &&
6717 text[0].text_length < 128) ? -1 : 0;
6719 if (text[0].text_length <= allocated_length)
6720 png_set_text(ping,ping_info,text,1);
6722 png_free(ping,text[0].text);
6723 png_free(ping,text[0].key);
6724 png_free(ping,text);
6727 static MagickBooleanType png_write_chunk_from_profile(Image *image,
6728 const char *string, MagickBooleanType logging)
6741 ResetImageProfileIterator(image);
6743 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
6745 profile=GetImageProfile(image,name);
6747 if (profile != (const StringInfo *) NULL)
6752 if (LocaleNCompare(name,string,11) == 0)
6754 if (logging != MagickFalse)
6755 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6756 " Found %s profile",name);
6758 png_profile=CloneStringInfo(profile);
6759 data=GetStringInfoDatum(png_profile),
6760 length=(png_uint_32) GetStringInfoLength(png_profile);
6765 (void) WriteBlobMSBULong(image,length-5); /* data length */
6766 (void) WriteBlob(image,length-1,data+1);
6767 (void) WriteBlobMSBULong(image,crc32(0,data+1,(uInt) length-1));
6768 png_profile=DestroyStringInfo(png_profile);
6772 name=GetNextImageProfile(image);
6779 /* Write one PNG image */
6780 static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
6781 const ImageInfo *IMimage_info,Image *IMimage)
6805 ping_trans_alpha[256];
6843 /* ping_exclude_iTXt, */
6850 ping_exclude_zCCP, /* hex-encoded iCCP */
6853 ping_need_colortype_warning,
6871 ping_interlace_method,
6872 ping_compression_method,
6888 number_semitransparent,
6890 ping_pHYs_unit_type;
6893 ping_pHYs_x_resolution,
6894 ping_pHYs_y_resolution;
6896 logging=LogMagickEvent(CoderEvent,GetMagickModule(),
6897 " enter WriteOnePNGImage()");
6899 image = CloneImage(IMimage,0,0,MagickFalse,&IMimage->exception);
6900 image_info=(ImageInfo *) CloneImageInfo(IMimage_info);
6902 if (mng_info->need_blob != MagickFalse)
6904 if (OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception) ==
6907 image_info=DestroyImageInfo(image_info);
6908 image=DestroyImage(image);
6909 return(MagickFalse);
6913 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
6914 LockSemaphoreInfo(png_semaphore);
6917 /* Initialize some stuff */
6920 ping_interlace_method=0,
6921 ping_compression_method=0,
6922 ping_filter_method=0,
6925 ping_background.red = 0;
6926 ping_background.green = 0;
6927 ping_background.blue = 0;
6928 ping_background.gray = 0;
6929 ping_background.index = 0;
6931 ping_trans_color.red=0;
6932 ping_trans_color.green=0;
6933 ping_trans_color.blue=0;
6934 ping_trans_color.gray=0;
6936 ping_pHYs_unit_type = 0;
6937 ping_pHYs_x_resolution = 0;
6938 ping_pHYs_y_resolution = 0;
6940 ping_have_color=MagickTrue;
6941 ping_have_PLTE=MagickFalse;
6942 ping_have_bKGD=MagickFalse;
6943 ping_have_pHYs=MagickFalse;
6944 ping_have_tRNS=MagickFalse;
6946 ping_exclude_bKGD=mng_info->ping_exclude_bKGD;
6947 ping_exclude_cHRM=mng_info->ping_exclude_cHRM;
6948 ping_exclude_EXIF=mng_info->ping_exclude_EXIF; /* hex-encoded EXIF in zTXt */
6949 ping_exclude_gAMA=mng_info->ping_exclude_gAMA;
6950 ping_exclude_cHRM=mng_info->ping_exclude_cHRM;
6951 ping_exclude_iCCP=mng_info->ping_exclude_iCCP;
6952 /* ping_exclude_iTXt=mng_info->ping_exclude_iTXt; */
6953 ping_exclude_oFFs=mng_info->ping_exclude_oFFs;
6954 ping_exclude_pHYs=mng_info->ping_exclude_pHYs;
6955 ping_exclude_sRGB=mng_info->ping_exclude_sRGB;
6956 ping_exclude_tEXt=mng_info->ping_exclude_tEXt;
6957 ping_exclude_tRNS=mng_info->ping_exclude_tRNS;
6958 ping_exclude_vpAg=mng_info->ping_exclude_vpAg;
6959 ping_exclude_zCCP=mng_info->ping_exclude_zCCP; /* hex-encoded iCCP in zTXt */
6960 ping_exclude_zTXt=mng_info->ping_exclude_zTXt;
6962 ping_need_colortype_warning = MagickFalse;
6965 number_semitransparent = 0;
6966 number_transparent = 0;
6968 if (image->colorspace != RGBColorspace)
6969 (void) TransformImageColorspace(image,RGBColorspace);
6972 Sometimes we get PseudoClass images whose RGB values don't match
6973 the colors in the colormap. This code syncs the RGB values.
6975 if (image->depth <= 8 && image->taint && image->storage_class == PseudoClass)
6976 (void) SyncImage(image);
6978 #if (MAGICKCORE_QUANTUM_DEPTH == 8)
6979 if (image->depth > 8)
6981 if (logging != MagickFalse)
6982 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
6983 " Reducing PNG bit depth to 8 since this is a Q8 build.");
6990 #if (MAGICKCORE_QUANTUM_DEPTH > 16)
6991 /* PNG does not handle depths greater than 16 so reduce it even
6994 if (image->depth > 16)
6998 #if (MAGICKCORE_QUANTUM_DEPTH >= 16)
6999 if (image->depth == 16 && mng_info->write_png_colortype != 16)
7000 if (mng_info->write_png8 || LosslessReduceDepthOK(image) != MagickFalse)
7004 #ifdef PNG_BUILD_PALETTE
7005 if (mng_info->write_png_colortype < 8 /* all */)
7008 * Sometimes we get DirectClass images that have 256 colors or fewer.
7009 * This code will build a colormap.
7011 * Also, sometimes we get PseudoClass images with an out-of-date
7012 * colormap. This code will replace the colormap with a new one.
7013 * Sometimes we get PseudoClass images that have more than 256 colors.
7014 * This code will delete the colormap and change the image to
7017 * Also we gather some information (number of opaque, transparent,
7018 * and semitransparent pixels, and whether the image has any non-gray
7019 * pixels) that we might need later. If the user wants to force
7020 * GrayAlpha or RGBA (colortype 4 or 6) we probably don't need any
7032 semitransparent[260],
7035 register IndexPacket
7038 register const PixelPacket
7041 if (logging != MagickFalse)
7042 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7043 " Enter BUILD_PALETTE:");
7045 if (logging != MagickFalse)
7047 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7048 " image->columns=%.20g",(double) image->columns);
7049 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7050 " image->rows=%.20g",(double) image->rows);
7051 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7052 " image->matte=%.20g",(double) image->matte);
7053 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7054 " image->depth=%.20g",(double) image->depth);
7056 if (image->colormap != NULL)
7058 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7059 " Original colormap:");
7060 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7061 " i (red,green,blue,opacity)");
7063 for (i=0; i < 256; i++)
7065 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7066 " %d (%d,%d,%d,%d)",
7068 (int) image->colormap[i].red,
7069 (int) image->colormap[i].green,
7070 (int) image->colormap[i].blue,
7071 (int) image->colormap[i].opacity);
7074 for (i=image->colors - 10; i < (ssize_t) image->colors; i++)
7078 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7079 " %d (%d,%d,%d,%d)",
7081 (int) image->colormap[i].red,
7082 (int) image->colormap[i].green,
7083 (int) image->colormap[i].blue,
7084 (int) image->colormap[i].opacity);
7089 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7090 " image->colors=%d",(int) image->colors);
7092 if (image->colors == 0)
7093 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7094 " (zero means unknown)");
7096 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7097 " Regenerate the colormap");
7100 exception=(&image->exception);
7102 ping_have_color=MagickFalse;
7105 for (y=0; y < (ssize_t) image->rows; y++)
7107 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
7109 if (q == (PixelPacket *) NULL)
7112 for (x=0; x < (ssize_t) image->columns; x++)
7114 if (q->red != q->green || q->red != q->blue)
7115 ping_have_color=MagickTrue;
7117 if (q->opacity == OpaqueOpacity)
7119 if (number_opaque < 259)
7121 if (number_opaque == 0)
7124 opaque[0].opacity=OpaqueOpacity;
7128 for (i=0; i< (ssize_t) number_opaque; i++)
7130 if (IsColorEqual(opaque+i, (PixelPacket *) q))
7134 if (i == (ssize_t) number_opaque &&
7135 number_opaque < 259)
7139 opaque[i].opacity = OpaqueOpacity;
7143 else if (q->opacity == TransparentOpacity)
7145 if (number_transparent < 259)
7147 if (number_transparent == 0)
7150 ping_trans_color.red=(unsigned short)(q->red);
7151 ping_trans_color.green=(unsigned short) (q->green);
7152 ping_trans_color.blue=(unsigned short) (q->blue);
7153 ping_trans_color.gray=(unsigned short) (q->blue);
7154 number_transparent = 1;
7157 for (i=0; i< (ssize_t) number_transparent; i++)
7159 if (IsColorEqual(transparent+i, (PixelPacket *) q))
7163 if (i == (ssize_t) number_transparent &&
7164 number_transparent < 259)
7166 number_transparent++;
7167 transparent[i] = *q;
7173 if (number_semitransparent < 259)
7175 if (number_semitransparent == 0)
7177 semitransparent[0]=*q;
7178 number_semitransparent = 1;
7181 for (i=0; i< (ssize_t) number_semitransparent; i++)
7183 if (IsColorEqual(semitransparent+i,
7184 (PixelPacket *) q) &&
7185 q->opacity == semitransparent[i].opacity)
7189 if (i == (ssize_t) number_semitransparent &&
7190 number_semitransparent < 259)
7192 number_semitransparent++;
7193 semitransparent[i] = *q;
7201 image_colors=number_opaque+number_transparent+number_semitransparent;
7203 if (logging != MagickFalse)
7205 if (image_colors >= 256)
7206 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7207 " image has more than 256 colors");
7210 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7211 " image has %d colors",image_colors);
7214 if (image_colors < 257)
7220 Initialize image colormap.
7223 if (logging != MagickFalse)
7224 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7225 " Sort the new colormap");
7227 /* Sort palette, transparent first */;
7231 for (i=0; i<number_transparent; i++)
7232 colormap[n++] = transparent[i];
7234 for (i=0; i<number_semitransparent; i++)
7235 colormap[n++] = semitransparent[i];
7237 for (i=0; i<number_opaque; i++)
7238 colormap[n++] = opaque[i];
7240 if (ping_exclude_bKGD == MagickFalse)
7242 /* Add the background color to the palette, if it
7243 * isn't already there.
7245 for (i=0; i<number_opaque; i++)
7247 if (IsColorEqual(opaque+i,
7248 &image->background_color))
7252 if (number_opaque < 257 && i == number_opaque)
7254 opaque[i]=image->background_color;
7255 opaque[i].opacity = OpaqueOpacity;
7260 if ((mng_info->ping_exclude_tRNS == MagickFalse ||
7261 (number_transparent == 0 && number_semitransparent == 0)) &&
7262 (((mng_info->write_png_colortype-1) ==
7263 PNG_COLOR_TYPE_PALETTE) ||
7264 (mng_info->write_png_colortype == 0)))
7266 if (logging != MagickFalse)
7268 if (n != (ssize_t) image_colors)
7269 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7270 " image_colors (%d) and n (%d) don't match",
7273 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7274 " AcquireImageColormap");
7277 image->colors = image_colors;
7279 if (AcquireImageColormap(image,image_colors) ==
7281 ThrowWriterException(ResourceLimitError,
7282 "MemoryAllocationFailed");
7284 for (i=0; i< (ssize_t) image_colors; i++)
7285 image->colormap[i] = colormap[i];
7287 if (logging != MagickFalse)
7289 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7290 " image->colors=%d (%d)",
7291 (int) image->colors, image_colors);
7293 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7294 " Update the pixel indexes");
7297 for (y=0; y < (ssize_t) image->rows; y++)
7299 q=GetAuthenticPixels(image,0,y,image->columns,1,
7302 if (q == (PixelPacket *) NULL)
7305 indexes=GetAuthenticIndexQueue(image);
7307 for (x=0; x < (ssize_t) image->columns; x++)
7309 for (i=0; i< (ssize_t) image_colors; i++)
7311 if ((image->matte == MagickFalse ||
7312 image->colormap[i].opacity == q->opacity) &&
7313 (IsColorEqual(&image->colormap[i],(PixelPacket *) q)))
7315 indexes[x]=(IndexPacket) i;
7322 if (SyncAuthenticPixels(image,exception) == MagickFalse)
7328 if (logging != MagickFalse)
7330 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7331 " image->colors=%d", (int) image->colors);
7333 if (image->colormap != NULL)
7335 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7336 " i (red,green,blue,opacity)");
7338 for (i=0; i < (ssize_t) image->colors; i++)
7340 if (i < 300 || i >= image->colors - 10)
7342 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7343 " %d (%d,%d,%d,%d)",
7345 (int) image->colormap[i].red,
7346 (int) image->colormap[i].green,
7347 (int) image->colormap[i].blue,
7348 (int) image->colormap[i].opacity);
7353 if (logging != MagickFalse)
7355 if (number_transparent < 257)
7356 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7357 " number_transparent = %d",
7358 number_transparent);
7361 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7362 " number_transparent > 256");
7364 if (number_opaque < 257)
7365 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7366 " number_opaque = %d",
7369 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7370 " number_opaque > 256");
7372 if (number_semitransparent < 257)
7373 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7374 " number_semitransparent = %d",
7375 number_semitransparent);
7378 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7379 " number_semitransparent > 256");
7382 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7383 " Exit BUILD_PALETTE:");
7386 #endif /* PNG_BUILD_PALETTE */
7388 if (mng_info->ping_exclude_tRNS != MagickFalse &&
7389 (number_transparent != 0 || number_semitransparent != 0))
7391 int colortype=mng_info->write_png_colortype;
7393 if (ping_have_color == MagickFalse)
7394 mng_info->write_png_colortype = 5;
7397 mng_info->write_png_colortype = 7;
7399 if (colortype != 0 && mng_info->write_png_colortype != (ssize_t) colortype)
7400 ping_need_colortype_warning=MagickTrue;
7404 image_depth=image->depth;
7406 quantum_info = (QuantumInfo *) NULL;
7408 image_colors=(int) image->colors;
7409 image_matte=image->matte;
7411 mng_info->IsPalette=image->storage_class == PseudoClass &&
7412 image_colors <= 256;
7415 Allocate the PNG structures
7417 #ifdef PNG_USER_MEM_SUPPORTED
7418 ping=png_create_write_struct_2(PNG_LIBPNG_VER_STRING,image,
7419 PNGErrorHandler,PNGWarningHandler,(void *) NULL,
7420 (png_malloc_ptr) png_IM_malloc,(png_free_ptr) png_IM_free);
7423 ping=png_create_write_struct(PNG_LIBPNG_VER_STRING,image,
7424 PNGErrorHandler,PNGWarningHandler);
7427 if (ping == (png_struct *) NULL)
7428 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
7430 ping_info=png_create_info_struct(ping);
7432 if (ping_info == (png_info *) NULL)
7434 png_destroy_write_struct(&ping,(png_info **) NULL);
7435 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
7438 png_set_write_fn(ping,image,png_put_data,png_flush_data);
7439 png_pixels=(unsigned char *) NULL;
7441 if (setjmp(png_jmpbuf(ping)))
7447 if (image_info->verbose)
7448 (void) printf("PNG write has failed.\n");
7450 png_destroy_write_struct(&ping,&ping_info);
7451 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
7452 UnlockSemaphoreInfo(png_semaphore);
7454 if (mng_info->need_blob != MagickFalse)
7455 (void) CloseBlob(image);
7456 image_info=DestroyImageInfo(image_info);
7457 image=DestroyImage(image);
7458 return(MagickFalse);
7461 Prepare PNG for writing.
7463 #if defined(PNG_MNG_FEATURES_SUPPORTED)
7464 if (mng_info->write_mng)
7465 (void) png_permit_mng_features(ping,PNG_ALL_MNG_FEATURES);
7468 # ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
7469 if (mng_info->write_mng)
7470 png_permit_empty_plte(ping,MagickTrue);
7477 ping_width=(png_uint_32) image->columns;
7478 ping_height=(png_uint_32) image->rows;
7480 if (mng_info->write_png8 || mng_info->write_png24 || mng_info->write_png32)
7483 if (mng_info->write_png_depth != 0)
7484 image_depth=mng_info->write_png_depth;
7486 /* Adjust requested depth to next higher valid depth if necessary */
7487 if (image_depth > 8)
7490 if ((image_depth > 4) && (image_depth < 8))
7493 if (image_depth == 3)
7496 if (logging != MagickFalse)
7498 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7499 " width=%.20g",(double) ping_width);
7500 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7501 " height=%.20g",(double) ping_height);
7502 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7503 " image_matte=%.20g",(double) image->matte);
7504 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7505 " image->depth=%.20g",(double) image->depth);
7506 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7507 " Tentative ping_bit_depth=%.20g",(double) image_depth);
7510 save_image_depth=image_depth;
7511 ping_bit_depth=(png_byte) save_image_depth;
7514 #if defined(PNG_pHYs_SUPPORTED)
7515 if (ping_exclude_pHYs == MagickFalse)
7517 if ((image->x_resolution != 0) && (image->y_resolution != 0) &&
7518 (!mng_info->write_mng || !mng_info->equal_physs))
7520 if (logging != MagickFalse)
7521 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7522 " Setting up pHYs chunk");
7524 if (image->units == PixelsPerInchResolution)
7526 ping_pHYs_unit_type=PNG_RESOLUTION_METER;
7527 ping_pHYs_x_resolution=(png_uint_32) (100.0*image->x_resolution/2.54);
7528 ping_pHYs_y_resolution=(png_uint_32) (100.0*image->y_resolution/2.54);
7531 else if (image->units == PixelsPerCentimeterResolution)
7533 ping_pHYs_unit_type=PNG_RESOLUTION_METER;
7534 ping_pHYs_x_resolution=(png_uint_32) (100.0*image->x_resolution);
7535 ping_pHYs_y_resolution=(png_uint_32) (100.0*image->y_resolution);
7540 ping_pHYs_unit_type=PNG_RESOLUTION_UNKNOWN;
7541 ping_pHYs_x_resolution=(png_uint_32) image->x_resolution;
7542 ping_pHYs_y_resolution=(png_uint_32) image->y_resolution;
7545 ping_have_pHYs = MagickTrue;
7550 if (ping_exclude_bKGD == MagickFalse)
7552 if ((!mng_info->adjoin || !mng_info->equal_backgrounds))
7558 if (ping_bit_depth == 8)
7561 if (ping_bit_depth == 4)
7564 if (ping_bit_depth == 2)
7567 if (ping_bit_depth == 1)
7570 ping_background.red=(png_uint_16)
7571 (ScaleQuantumToShort(image->background_color.red) & mask);
7573 ping_background.green=(png_uint_16)
7574 (ScaleQuantumToShort(image->background_color.green) & mask);
7576 ping_background.blue=(png_uint_16)
7577 (ScaleQuantumToShort(image->background_color.blue) & mask);
7580 if (logging != MagickFalse)
7582 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7583 " Setting up bKGD chunk (1)");
7585 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7586 " ping_bit_depth=%d",ping_bit_depth);
7589 ping_have_bKGD = MagickTrue;
7593 Select the color type.
7598 if (mng_info->write_png8)
7601 /* TO DO: make this a function cause it's used twice, except
7602 for reducing the sample depth from 8. */
7604 number_colors=image_colors;
7606 ping_have_tRNS=MagickFalse;
7611 ping_color_type=(png_byte) PNG_COLOR_TYPE_PALETTE;
7613 if (logging != MagickFalse)
7614 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7615 " Setting up PLTE chunk with %d colors (%d)",
7616 number_colors, image_colors);
7618 for (i=0; i < (ssize_t) number_colors; i++)
7620 palette[i].red=ScaleQuantumToChar(image->colormap[i].red);
7621 palette[i].green=ScaleQuantumToChar(image->colormap[i].green);
7622 palette[i].blue=ScaleQuantumToChar(image->colormap[i].blue);
7623 if (logging != MagickFalse)
7624 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7625 #if MAGICKCORE_QUANTUM_DEPTH == 8
7626 " %3ld (%3d,%3d,%3d)",
7628 " %5ld (%5d,%5d,%5d)",
7630 (long) i,palette[i].red,palette[i].green,palette[i].blue);
7634 ping_have_PLTE=MagickTrue;
7635 image_depth=ping_bit_depth;
7638 if (matte != MagickFalse)
7641 Identify which colormap entry is transparent.
7643 assert(number_colors <= 256);
7644 assert(image->colormap != NULL);
7646 for (i=0; i < (ssize_t) number_transparent; i++)
7647 ping_trans_alpha[i]=0;
7649 /* PNG8 can't have semitransparent colors so we threshold them
7652 for (; i < (ssize_t) number_semitransparent; i++)
7653 ping_trans_alpha[i]=image->colormap[i].opacity >
7654 OpaqueOpacity/2 ? 0 : 255;
7656 ping_num_trans=(unsigned short) (number_transparent +
7657 number_semitransparent);
7659 if (ping_num_trans == 0)
7660 ping_have_tRNS=MagickFalse;
7663 ping_have_tRNS=MagickTrue;
7666 if (ping_exclude_bKGD == MagickFalse)
7669 * Identify which colormap entry is the background color.
7671 for (i=0; i < (ssize_t) MagickMax(1L*number_colors-1L,1L); i++)
7672 if (IsPNGColorEqual(ping_background,image->colormap[i]))
7675 ping_background.index=(png_byte) i;
7677 } /* end of write_png8 */
7679 else if (mng_info->write_png24)
7681 image_matte=MagickFalse;
7682 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB;
7685 else if (mng_info->write_png32)
7687 image_matte=MagickTrue;
7688 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB_ALPHA;
7691 else /* mng_info->write_pngNN not specified */
7693 image_depth=ping_bit_depth;
7695 if (mng_info->write_png_colortype != 0)
7697 ping_color_type=(png_byte) mng_info->write_png_colortype-1;
7699 if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA ||
7700 ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA)
7701 image_matte=MagickTrue;
7704 image_matte=MagickFalse;
7707 else /* write_ping_colortype not specified */
7709 if (logging != MagickFalse)
7710 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7711 " Selecting PNG colortype:");
7713 ping_color_type=(png_byte) ((matte != MagickFalse)?
7714 PNG_COLOR_TYPE_RGB_ALPHA:PNG_COLOR_TYPE_RGB);
7716 if (image_info->type == TrueColorType)
7718 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB;
7719 image_matte=MagickFalse;
7722 if (image_info->type == TrueColorMatteType)
7724 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB_ALPHA;
7725 image_matte=MagickTrue;
7728 if (image_info->type == PaletteType ||
7729 image_info->type == PaletteMatteType)
7730 ping_color_type=(png_byte) PNG_COLOR_TYPE_PALETTE;
7732 if (image_info->type == UndefinedType ||
7733 image_info->type == OptimizeType)
7735 if (ping_have_color == MagickFalse)
7737 if (image_matte == MagickFalse)
7739 ping_color_type=(png_byte) PNG_COLOR_TYPE_GRAY;
7740 image_matte=MagickFalse;
7745 ping_color_type=(png_byte) PNG_COLOR_TYPE_GRAY_ALPHA;
7746 image_matte=MagickTrue;
7751 if (image_matte == MagickFalse)
7753 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB;
7754 image_matte=MagickFalse;
7759 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGBA;
7760 image_matte=MagickTrue;
7767 if (logging != MagickFalse)
7768 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7769 " Selected PNG colortype=%d",ping_color_type);
7771 if (ping_bit_depth < 8)
7773 if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA ||
7774 ping_color_type == PNG_COLOR_TYPE_RGB ||
7775 ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA)
7779 old_bit_depth=ping_bit_depth;
7781 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
7783 if (image->matte == MagickFalse && image->colors < 256)
7785 if (ImageIsMonochrome(image))
7792 if (ping_color_type == PNG_COLOR_TYPE_PALETTE)
7797 if (image->colors == 0)
7800 (void) ThrowMagickException(&image->exception,
7801 GetMagickModule(),CoderError,
7802 "image has 0 colors", "`%s'","");
7805 while ((int) (one << ping_bit_depth) < (ssize_t) image_colors)
7806 ping_bit_depth <<= 1;
7809 if (logging != MagickFalse)
7811 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7812 " Number of colors: %.20g",(double) image_colors);
7814 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7815 " Tentative PNG bit depth: %d",ping_bit_depth);
7818 if (ping_bit_depth < (int) mng_info->write_png_depth)
7819 ping_bit_depth = mng_info->write_png_depth;
7822 image_depth=ping_bit_depth;
7824 if (logging != MagickFalse)
7826 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7827 " Tentative PNG color type: %.20g",(double) ping_color_type);
7829 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7830 " image_info->type: %.20g",(double) image_info->type);
7832 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7833 " image_depth: %.20g",(double) image_depth);
7835 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7837 " image->depth: %.20g",(double) image->depth);
7839 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7840 " ping_bit_depth: %.20g",(double) ping_bit_depth);
7843 if (matte != MagickFalse)
7845 if (mng_info->IsPalette)
7848 ping_color_type=PNG_COLOR_TYPE_GRAY_ALPHA;
7850 if (ping_have_color != MagickFalse)
7851 ping_color_type=PNG_COLOR_TYPE_RGBA;
7854 * Determine if there is any transparent color.
7856 if (number_transparent + number_semitransparent == 0)
7859 No transparent pixels are present. Change 4 or 6 to 0 or 2.
7862 image_matte=MagickFalse;
7863 ping_color_type&=0x03;
7873 if (ping_bit_depth == 8)
7876 if (ping_bit_depth == 4)
7879 if (ping_bit_depth == 2)
7882 if (ping_bit_depth == 1)
7885 ping_trans_color.red=(png_uint_16)
7886 (ScaleQuantumToShort(image->colormap[0].red) & mask);
7888 ping_trans_color.green=(png_uint_16)
7889 (ScaleQuantumToShort(image->colormap[0].green) & mask);
7891 ping_trans_color.blue=(png_uint_16)
7892 (ScaleQuantumToShort(image->colormap[0].blue) & mask);
7894 ping_trans_color.gray=(png_uint_16)
7895 (ScaleQuantumToShort(PixelIntensityToQuantum(
7896 image->colormap)) & mask);
7898 ping_trans_color.index=(png_byte) 0;
7900 ping_have_tRNS=MagickTrue;
7903 if (ping_have_tRNS != MagickFalse)
7906 Determine if there is one and only one transparent color
7907 and if so if it is fully transparent.
7909 if (logging != MagickFalse)
7910 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7911 " Is there a single fully transparent color?");
7913 if (number_transparent > 1 || number_semitransparent > 0)
7915 ping_have_tRNS = MagickFalse;
7916 if (logging != MagickFalse)
7917 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7922 if (logging != MagickFalse)
7923 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7924 " ... Yes: (%d,%d,%d), (gray: %d)",
7925 (int) ping_trans_color.red,
7926 (int) ping_trans_color.green,
7927 (int) ping_trans_color.blue,
7928 (int) ping_trans_color.gray);
7932 if (ping_have_tRNS != MagickFalse)
7934 ping_color_type &= 0x03; /* changes 4 or 6 to 0 or 2 */
7936 if (image_depth == 8)
7938 ping_trans_color.red&=0xff;
7939 ping_trans_color.green&=0xff;
7940 ping_trans_color.blue&=0xff;
7941 ping_trans_color.gray&=0xff;
7947 if (image_depth == 8)
7949 ping_trans_color.red&=0xff;
7950 ping_trans_color.green&=0xff;
7951 ping_trans_color.blue&=0xff;
7952 ping_trans_color.gray&=0xff;
7959 if (ping_have_tRNS != MagickFalse)
7960 image_matte=MagickFalse;
7962 if ((mng_info->IsPalette) &&
7963 mng_info->write_png_colortype-1 != PNG_COLOR_TYPE_PALETTE &&
7964 ImageIsGray(image) && (image_matte == MagickFalse || image_depth >= 8))
7968 if (image_matte != MagickFalse)
7969 ping_color_type=PNG_COLOR_TYPE_GRAY_ALPHA;
7973 ping_color_type=PNG_COLOR_TYPE_GRAY;
7975 if (save_image_depth == 16 && image_depth == 8)
7977 if (logging != MagickFalse)
7979 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7980 " Scaling ping_trans_color (0)");
7982 ping_trans_color.gray*=0x0101;
7986 if (image_depth > MAGICKCORE_QUANTUM_DEPTH)
7987 image_depth=MAGICKCORE_QUANTUM_DEPTH;
7989 if (image_colors == 0 || image_colors-1 > MaxColormapSize)
7990 image_colors=(int) (one << image_depth);
7992 if (image_depth > 8)
7998 if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
8000 if(!mng_info->write_png_depth)
8004 while ((int) (one << ping_bit_depth)
8005 < (ssize_t) image_colors)
8006 ping_bit_depth <<= 1;
8010 else if (ping_color_type ==
8011 PNG_COLOR_TYPE_GRAY && image_colors < 17 &&
8012 mng_info->IsPalette)
8015 /* Check if grayscale is reducible */
8017 depth_4_ok=MagickTrue,
8018 depth_2_ok=MagickTrue,
8019 depth_1_ok=MagickTrue;
8021 for (i=0; i < (ssize_t) image_colors; i++)
8026 intensity=ScaleQuantumToChar(image->colormap[i].red);
8028 if ((intensity & 0x0f) != ((intensity & 0xf0) >> 4))
8029 depth_4_ok=depth_2_ok=depth_1_ok=MagickFalse;
8031 else if ((intensity & 0x03) != ((intensity & 0x0c) >> 2))
8032 depth_2_ok=depth_1_ok=MagickFalse;
8034 else if ((intensity & 0x01) != ((intensity & 0x02) >> 1))
8035 depth_1_ok=MagickFalse;
8038 if (depth_1_ok && mng_info->write_png_depth <= 1)
8041 else if (depth_2_ok && mng_info->write_png_depth <= 2)
8044 else if (depth_4_ok && mng_info->write_png_depth <= 4)
8049 image_depth=ping_bit_depth;
8054 if (mng_info->IsPalette)
8056 number_colors=image_colors;
8058 if (image_depth <= 8)
8063 ping_color_type=(png_byte) PNG_COLOR_TYPE_PALETTE;
8065 if (mng_info->have_write_global_plte && matte == MagickFalse)
8067 png_set_PLTE(ping,ping_info,NULL,0);
8069 if (logging != MagickFalse)
8070 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8071 " Setting up empty PLTE chunk");
8076 for (i=0; i < (ssize_t) number_colors; i++)
8078 palette[i].red=ScaleQuantumToChar(image->colormap[i].red);
8079 palette[i].green=ScaleQuantumToChar(image->colormap[i].green);
8080 palette[i].blue=ScaleQuantumToChar(image->colormap[i].blue);
8083 if (logging != MagickFalse)
8084 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8085 " Setting up PLTE chunk with %d colors",
8088 ping_have_PLTE=MagickTrue;
8091 /* color_type is PNG_COLOR_TYPE_PALETTE */
8092 if (mng_info->write_png_depth == 0)
8100 while ((one << ping_bit_depth) < number_colors)
8101 ping_bit_depth <<= 1;
8106 if (matte != MagickFalse)
8109 * Set up trans_colors array.
8111 assert(number_colors <= 256);
8113 ping_num_trans=(unsigned short) (number_transparent +
8114 number_semitransparent);
8116 if (ping_num_trans == 0)
8117 ping_have_tRNS=MagickFalse;
8121 if (logging != MagickFalse)
8123 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8124 " Scaling ping_trans_color (1)");
8126 ping_have_tRNS=MagickTrue;
8128 for (i=0; i < ping_num_trans; i++)
8130 ping_trans_alpha[i]= (png_byte) (255-
8131 ScaleQuantumToChar(image->colormap[i].opacity));
8141 if (image_depth < 8)
8144 if ((save_image_depth == 16) && (image_depth == 8))
8146 if (logging != MagickFalse)
8148 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8149 " Scaling ping_trans_color from (%d,%d,%d)",
8150 (int) ping_trans_color.red,
8151 (int) ping_trans_color.green,
8152 (int) ping_trans_color.blue);
8155 ping_trans_color.red*=0x0101;
8156 ping_trans_color.green*=0x0101;
8157 ping_trans_color.blue*=0x0101;
8158 ping_trans_color.gray*=0x0101;
8160 if (logging != MagickFalse)
8162 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8164 (int) ping_trans_color.red,
8165 (int) ping_trans_color.green,
8166 (int) ping_trans_color.blue);
8171 if (ping_bit_depth < (ssize_t) mng_info->write_png_depth)
8172 ping_bit_depth = (ssize_t) mng_info->write_png_depth;
8175 Adjust background and transparency samples in sub-8-bit grayscale files.
8177 if (ping_bit_depth < 8 && ping_color_type ==
8178 PNG_COLOR_TYPE_GRAY)
8186 maxval=(png_uint_16) ((one << ping_bit_depth)-1);
8188 if (ping_exclude_bKGD == MagickFalse)
8191 ping_background.gray=(png_uint_16)
8192 (QuantumScale*(maxval*(PixelIntensity(&image->background_color))));
8194 if (logging != MagickFalse)
8195 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8196 " Setting up bKGD chunk (2)");
8198 ping_have_bKGD = MagickTrue;
8201 ping_trans_color.gray=(png_uint_16) (QuantumScale*(maxval*
8202 ping_trans_color.gray));
8205 if (ping_exclude_bKGD == MagickFalse)
8207 if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
8210 Identify which colormap entry is the background color.
8213 number_colors=image_colors;
8215 for (i=0; i < (ssize_t) MagickMax(1L*number_colors,1L); i++)
8216 if (IsPNGColorEqual(image->background_color,image->colormap[i]))
8219 ping_background.index=(png_byte) i;
8221 if (logging != MagickFalse)
8223 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8224 " Setting up bKGD chunk with index=%d",(int) i);
8227 if (i < (ssize_t) number_colors)
8229 ping_have_bKGD = MagickTrue;
8231 if (logging != MagickFalse)
8233 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8234 " background =(%d,%d,%d)",
8235 (int) ping_background.red,
8236 (int) ping_background.green,
8237 (int) ping_background.blue);
8241 else /* Can't happen */
8243 if (logging != MagickFalse)
8244 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8245 " No room in PLTE to add bKGD color");
8246 ping_have_bKGD = MagickFalse;
8251 if (logging != MagickFalse)
8252 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8253 " PNG color type: %d",ping_color_type);
8255 Initialize compression level and filtering.
8257 if (logging != MagickFalse)
8259 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8260 " Setting up deflate compression");
8262 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8263 " Compression buffer size: 32768");
8266 png_set_compression_buffer_size(ping,32768L);
8268 if (logging != MagickFalse)
8269 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8270 " Compression mem level: 9");
8272 png_set_compression_mem_level(ping, 9);
8274 quality=image->quality == UndefinedCompressionQuality ? 75UL :
8282 level=(int) MagickMin((ssize_t) quality/10,9);
8284 if (logging != MagickFalse)
8285 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8286 " Compression level: %d",level);
8288 png_set_compression_level(ping,level);
8293 if (logging != MagickFalse)
8294 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8295 " Compression strategy: Z_HUFFMAN_ONLY");
8297 png_set_compression_strategy(ping, Z_HUFFMAN_ONLY);
8300 if (logging != MagickFalse)
8301 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8302 " Setting up filtering");
8304 #if defined(PNG_MNG_FEATURES_SUPPORTED) && defined(PNG_INTRAPIXEL_DIFFERENCING)
8305 /* This became available in libpng-1.0.9. Output must be a MNG. */
8306 if (mng_info->write_mng && ((quality % 10) == 7))
8308 if (logging != MagickFalse)
8309 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8310 " Filter_type: PNG_INTRAPIXEL_DIFFERENCING");
8312 ping_filter_method=PNG_INTRAPIXEL_DIFFERENCING;
8316 if (logging != MagickFalse)
8317 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8325 if ((quality % 10) > 5)
8326 base_filter=PNG_ALL_FILTERS;
8329 if ((quality % 10) != 5)
8330 base_filter=(int) quality % 10;
8333 if (((int) ping_color_type == PNG_COLOR_TYPE_GRAY) ||
8334 ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE) ||
8336 base_filter=PNG_NO_FILTERS;
8339 base_filter=PNG_ALL_FILTERS;
8341 if (logging != MagickFalse)
8343 if (base_filter == PNG_ALL_FILTERS)
8344 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8345 " Base filter method: ADAPTIVE");
8347 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8348 " Base filter method: NONE");
8351 png_set_filter(ping,PNG_FILTER_TYPE_BASE,base_filter);
8354 if (ping_exclude_iCCP == MagickFalse || ping_exclude_zCCP == MagickFalse)
8356 ResetImageProfileIterator(image);
8357 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
8359 profile=GetImageProfile(image,name);
8361 if (profile != (StringInfo *) NULL)
8363 #ifdef PNG_WRITE_iCCP_SUPPORTED
8364 if ((LocaleCompare(name,"ICC") == 0) ||
8365 (LocaleCompare(name,"ICM") == 0))
8368 if (ping_exclude_iCCP == MagickFalse)
8370 png_set_iCCP(ping,ping_info,(const png_charp) name,0,
8371 #if (PNG_LIBPNG_VER < 10500)
8372 (png_charp) GetStringInfoDatum(profile),
8374 (png_const_bytep) GetStringInfoDatum(profile),
8376 (png_uint_32) GetStringInfoLength(profile));
8382 if (ping_exclude_zCCP == MagickFalse)
8384 png_write_raw_profile(image_info,ping,ping_info,
8385 (unsigned char *) name,(unsigned char *) name,
8386 GetStringInfoDatum(profile),
8387 (png_uint_32) GetStringInfoLength(profile));
8391 if (logging != MagickFalse)
8392 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8393 " Setting up text chunk with %s profile",name);
8395 name=GetNextImageProfile(image);
8399 #if defined(PNG_WRITE_sRGB_SUPPORTED)
8400 if ((mng_info->have_write_global_srgb == 0) &&
8401 ((image->rendering_intent != UndefinedIntent) ||
8402 (image->colorspace == sRGBColorspace)))
8404 if (ping_exclude_sRGB == MagickFalse)
8407 Note image rendering intent.
8409 if (logging != MagickFalse)
8410 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8411 " Setting up sRGB chunk");
8413 (void) png_set_sRGB(ping,ping_info,(
8414 PNG_RenderingIntent_from_Magick_RenderingIntent(
8415 image->rendering_intent)));
8417 if (ping_exclude_gAMA == MagickFalse)
8418 png_set_gAMA(ping,ping_info,0.45455);
8422 if ((!mng_info->write_mng) || (!png_get_valid(ping,ping_info,PNG_INFO_sRGB)))
8425 if (ping_exclude_gAMA == MagickFalse &&
8426 (ping_exclude_sRGB == MagickFalse ||
8427 (image->gamma < .45 || image->gamma > .46)))
8429 if ((mng_info->have_write_global_gama == 0) && (image->gamma != 0.0))
8433 To do: check for cHRM+gAMA == sRGB, and write sRGB instead.
8435 if (logging != MagickFalse)
8436 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8437 " Setting up gAMA chunk");
8439 png_set_gAMA(ping,ping_info,image->gamma);
8443 if (ping_exclude_cHRM == MagickFalse)
8445 if ((mng_info->have_write_global_chrm == 0) &&
8446 (image->chromaticity.red_primary.x != 0.0))
8449 Note image chromaticity.
8450 To do: check for cHRM+gAMA == sRGB, and write sRGB instead.
8458 wp=image->chromaticity.white_point;
8459 rp=image->chromaticity.red_primary;
8460 gp=image->chromaticity.green_primary;
8461 bp=image->chromaticity.blue_primary;
8463 if (logging != MagickFalse)
8464 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8465 " Setting up cHRM chunk");
8467 png_set_cHRM(ping,ping_info,wp.x,wp.y,rp.x,rp.y,gp.x,gp.y,
8473 ping_interlace_method=image_info->interlace != NoInterlace;
8475 if (mng_info->write_mng)
8476 png_set_sig_bytes(ping,8);
8478 /* Bail out if cannot meet defined PNG:bit-depth or PNG:color-type */
8480 if (mng_info->write_png_colortype != 0)
8482 if (mng_info->write_png_colortype-1 == PNG_COLOR_TYPE_GRAY)
8483 if (ImageIsGray(image) == MagickFalse)
8485 ping_color_type = PNG_COLOR_TYPE_RGB;
8487 if (ping_bit_depth < 8)
8491 if (mng_info->write_png_colortype-1 == PNG_COLOR_TYPE_GRAY_ALPHA)
8492 if (ImageIsGray(image) == MagickFalse)
8493 ping_color_type = PNG_COLOR_TYPE_RGB_ALPHA;
8496 if (ping_need_colortype_warning != MagickFalse ||
8497 ((mng_info->write_png_depth &&
8498 (int) mng_info->write_png_depth != ping_bit_depth) ||
8499 (mng_info->write_png_colortype &&
8500 ((int) mng_info->write_png_colortype-1 != ping_color_type &&
8501 mng_info->write_png_colortype != 7 &&
8502 !(mng_info->write_png_colortype == 5 && ping_color_type == 0)))))
8504 if (logging != MagickFalse)
8506 if (ping_need_colortype_warning != MagickFalse)
8508 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8509 " Image has transparency but tRNS chunk was excluded");
8512 if (mng_info->write_png_depth)
8514 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8515 " Defined PNG:bit-depth=%u, Computed depth=%u",
8516 mng_info->write_png_depth,
8520 if (mng_info->write_png_colortype)
8522 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8523 " Defined PNG:color-type=%u, Computed color type=%u",
8524 mng_info->write_png_colortype-1,
8530 "Cannot write image with defined PNG:bit-depth or PNG:color-type.");
8533 if (image_matte != MagickFalse && image->matte == MagickFalse)
8535 /* Add an opaque matte channel */
8536 image->matte = MagickTrue;
8537 (void) SetImageOpacity(image,0);
8539 if (logging != MagickFalse)
8540 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8541 " Added an opaque matte channel");
8544 if (number_transparent != 0 || number_semitransparent != 0)
8546 if (ping_color_type < 4)
8548 ping_have_tRNS=MagickTrue;
8549 if (logging != MagickFalse)
8550 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8551 " Setting ping_have_tRNS=MagickTrue.");
8555 if (logging != MagickFalse)
8556 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8557 " Writing PNG header chunks");
8559 png_set_IHDR(ping,ping_info,ping_width,ping_height,
8560 ping_bit_depth,ping_color_type,
8561 ping_interlace_method,ping_compression_method,
8562 ping_filter_method);
8564 if (ping_color_type == 3 && ping_have_PLTE != MagickFalse)
8566 png_set_PLTE(ping,ping_info,palette,number_colors);
8568 if (logging != MagickFalse)
8570 for (i=0; i< (ssize_t) number_colors; i++)
8572 if (i < ping_num_trans)
8573 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8574 " PLTE[%d] = (%d,%d,%d), tRNS[%d] = (%d)",
8576 (int) palette[i].red,
8577 (int) palette[i].green,
8578 (int) palette[i].blue,
8580 (int) ping_trans_alpha[i]);
8582 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8583 " PLTE[%d] = (%d,%d,%d)",
8585 (int) palette[i].red,
8586 (int) palette[i].green,
8587 (int) palette[i].blue);
8592 if (ping_exclude_bKGD == MagickFalse)
8594 if (ping_have_bKGD != MagickFalse)
8595 png_set_bKGD(ping,ping_info,&ping_background);
8598 if (ping_exclude_pHYs == MagickFalse)
8600 if (ping_have_pHYs != MagickFalse)
8602 png_set_pHYs(ping,ping_info,
8603 ping_pHYs_x_resolution,
8604 ping_pHYs_y_resolution,
8605 ping_pHYs_unit_type);
8609 #if defined(PNG_oFFs_SUPPORTED)
8610 if (ping_exclude_oFFs == MagickFalse)
8612 if (image->page.x || image->page.y)
8614 png_set_oFFs(ping,ping_info,(png_int_32) image->page.x,
8615 (png_int_32) image->page.y, 0);
8617 if (logging != MagickFalse)
8618 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8619 " Setting up oFFs chunk with x=%d, y=%d, units=0",
8620 (int) image->page.x, (int) image->page.y);
8625 png_write_info_before_PLTE(ping, ping_info);
8627 if (ping_have_tRNS != MagickFalse && ping_color_type < 4)
8629 if (logging != MagickFalse)
8631 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8632 " Calling png_set_tRNS with num_trans=%d",ping_num_trans);
8635 if (ping_color_type == 3)
8636 (void) png_set_tRNS(ping, ping_info,
8643 (void) png_set_tRNS(ping, ping_info,
8648 if (logging != MagickFalse)
8650 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8651 " tRNS color =(%d,%d,%d)",
8652 (int) ping_trans_color.red,
8653 (int) ping_trans_color.green,
8654 (int) ping_trans_color.blue);
8659 /* write any png-chunk-b profiles */
8660 (void) png_write_chunk_from_profile(image,"PNG-chunk-b",logging);
8661 png_write_info(ping,ping_info);
8663 /* write any PNG-chunk-m profiles */
8664 (void) png_write_chunk_from_profile(image,"PNG-chunk-m",logging);
8666 if (ping_exclude_vpAg == MagickFalse)
8668 if ((image->page.width != 0 && image->page.width != image->columns) ||
8669 (image->page.height != 0 && image->page.height != image->rows))
8674 (void) WriteBlobMSBULong(image,9L); /* data length=8 */
8675 PNGType(chunk,mng_vpAg);
8676 LogPNGChunk(logging,mng_vpAg,9L);
8677 PNGLong(chunk+4,(png_uint_32) image->page.width);
8678 PNGLong(chunk+8,(png_uint_32) image->page.height);
8679 chunk[12]=0; /* unit = pixels */
8680 (void) WriteBlob(image,13,chunk);
8681 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
8685 #if (PNG_LIBPNG_VER == 10206)
8686 /* avoid libpng-1.2.6 bug by setting PNG_HAVE_IDAT flag */
8687 #define PNG_HAVE_IDAT 0x04
8688 ping->mode |= PNG_HAVE_IDAT;
8689 #undef PNG_HAVE_IDAT
8692 png_set_packing(ping);
8696 rowbytes=image->columns;
8697 if (image_depth > 8)
8699 switch (ping_color_type)
8701 case PNG_COLOR_TYPE_RGB:
8705 case PNG_COLOR_TYPE_GRAY_ALPHA:
8709 case PNG_COLOR_TYPE_RGBA:
8717 if (logging != MagickFalse)
8719 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8720 " Writing PNG image data");
8722 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8723 " Allocating %.20g bytes of memory for pixels",(double) rowbytes);
8725 png_pixels=(unsigned char *) AcquireQuantumMemory(rowbytes,
8726 sizeof(*png_pixels));
8728 if (png_pixels == (unsigned char *) NULL)
8729 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
8732 Initialize image scanlines.
8734 if (setjmp(png_jmpbuf(ping)))
8740 if (image_info->verbose)
8741 (void) printf("PNG write has failed.\n");
8743 png_destroy_write_struct(&ping,&ping_info);
8744 if (quantum_info != (QuantumInfo *) NULL)
8745 quantum_info=DestroyQuantumInfo(quantum_info);
8746 if (png_pixels != (unsigned char *) NULL)
8747 png_pixels=(unsigned char *) RelinquishMagickMemory(png_pixels);
8748 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
8749 UnlockSemaphoreInfo(png_semaphore);
8751 if (mng_info->need_blob != MagickFalse)
8752 (void) CloseBlob(image);
8753 image_info=DestroyImageInfo(image_info);
8754 image=DestroyImage(image);
8755 return(MagickFalse);
8757 quantum_info=AcquireQuantumInfo(image_info,image);
8758 if (quantum_info == (QuantumInfo *) NULL)
8759 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
8760 quantum_info->format=UndefinedQuantumFormat;
8761 quantum_info->depth=image_depth;
8762 num_passes=png_set_interlace_handling(ping);
8764 if ((!mng_info->write_png8 && !mng_info->write_png24 &&
8765 !mng_info->write_png32) &&
8766 (mng_info->IsPalette ||
8767 (image_info->type == BilevelType)) &&
8768 image_matte == MagickFalse && ImageIsMonochrome(image))
8770 /* Palette, Bilevel, or Opaque Monochrome */
8771 register const PixelPacket
8774 quantum_info->depth=8;
8775 for (pass=0; pass < num_passes; pass++)
8778 Convert PseudoClass image to a PNG monochrome image.
8780 for (y=0; y < (ssize_t) image->rows; y++)
8783 if (logging != MagickFalse)
8784 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8785 " Writing row of pixels (0)");
8787 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
8789 if (p == (const PixelPacket *) NULL)
8792 if (mng_info->IsPalette)
8794 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8795 quantum_info,GrayQuantum,png_pixels,&image->exception);
8796 if (mng_info->write_png_colortype-1 == PNG_COLOR_TYPE_PALETTE &&
8797 mng_info->write_png_depth &&
8798 mng_info->write_png_depth != old_bit_depth)
8800 /* Undo pixel scaling */
8801 for (i=0; i < (ssize_t) image->columns; i++)
8802 *(png_pixels+i)=(unsigned char) (*(png_pixels+i)
8803 >> (8-old_bit_depth));
8809 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8810 quantum_info,RedQuantum,png_pixels,&image->exception);
8813 if (mng_info->write_png_colortype-1 != PNG_COLOR_TYPE_PALETTE)
8814 for (i=0; i < (ssize_t) image->columns; i++)
8815 *(png_pixels+i)=(unsigned char) ((*(png_pixels+i) > 127) ?
8818 if (logging != MagickFalse && y == 0)
8819 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8820 " Writing row of pixels (1)");
8822 png_write_row(ping,png_pixels);
8824 if (image->previous == (Image *) NULL)
8826 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
8827 if (status == MagickFalse)
8833 else /* Not Palette, Bilevel, or Opaque Monochrome */
8835 if ((!mng_info->write_png8 && !mng_info->write_png24 &&
8836 !mng_info->write_png32) &&
8837 (image_matte != MagickFalse ||
8838 (ping_bit_depth >= MAGICKCORE_QUANTUM_DEPTH)) &&
8839 (mng_info->IsPalette) && ImageIsGray(image))
8841 register const PixelPacket
8844 for (pass=0; pass < num_passes; pass++)
8847 for (y=0; y < (ssize_t) image->rows; y++)
8849 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
8851 if (p == (const PixelPacket *) NULL)
8854 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
8856 if (mng_info->IsPalette)
8857 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8858 quantum_info,GrayQuantum,png_pixels,&image->exception);
8861 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8862 quantum_info,RedQuantum,png_pixels,&image->exception);
8864 if (logging != MagickFalse && y == 0)
8865 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8866 " Writing GRAY PNG pixels (2)");
8869 else /* PNG_COLOR_TYPE_GRAY_ALPHA */
8871 if (logging != MagickFalse && y == 0)
8872 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8873 " Writing GRAY_ALPHA PNG pixels (2)");
8875 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8876 quantum_info,GrayAlphaQuantum,png_pixels,&image->exception);
8879 if (logging != MagickFalse && y == 0)
8880 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8881 " Writing row of pixels (2)");
8883 png_write_row(ping,png_pixels);
8886 if (image->previous == (Image *) NULL)
8888 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
8889 if (status == MagickFalse)
8897 register const PixelPacket
8900 for (pass=0; pass < num_passes; pass++)
8902 if ((image_depth > 8) || (mng_info->write_png24 ||
8903 mng_info->write_png32 ||
8904 (!mng_info->write_png8 && !mng_info->IsPalette)))
8906 for (y=0; y < (ssize_t) image->rows; y++)
8908 p=GetVirtualPixels(image,0,y,image->columns,1,
8911 if (p == (const PixelPacket *) NULL)
8914 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
8916 if (image->storage_class == DirectClass)
8917 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8918 quantum_info,RedQuantum,png_pixels,&image->exception);
8921 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8922 quantum_info,GrayQuantum,png_pixels,&image->exception);
8925 else if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
8927 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8928 quantum_info,GrayAlphaQuantum,png_pixels,
8931 if (logging != MagickFalse && y == 0)
8932 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8933 " Writing GRAY_ALPHA PNG pixels (3)");
8936 else if (image_matte != MagickFalse)
8937 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8938 quantum_info,RGBAQuantum,png_pixels,&image->exception);
8941 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8942 quantum_info,RGBQuantum,png_pixels,&image->exception);
8944 if (logging != MagickFalse && y == 0)
8945 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8946 " Writing row of pixels (3)");
8948 png_write_row(ping,png_pixels);
8953 /* not ((image_depth > 8) || (mng_info->write_png24 ||
8954 mng_info->write_png32 ||
8955 (!mng_info->write_png8 && !mng_info->IsPalette))) */
8957 if ((ping_color_type != PNG_COLOR_TYPE_GRAY) &&
8958 (ping_color_type != PNG_COLOR_TYPE_GRAY_ALPHA))
8960 if (logging != MagickFalse)
8961 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8962 " pass %d, Image Is not GRAY or GRAY_ALPHA",pass);
8964 quantum_info->depth=8;
8968 for (y=0; y < (ssize_t) image->rows; y++)
8970 if (logging != MagickFalse && y == 0)
8971 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8972 " pass %d, Image Is RGB, 16-bit GRAY, or GRAY_ALPHA",pass);
8974 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
8976 if (p == (const PixelPacket *) NULL)
8979 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
8980 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8981 quantum_info,GrayQuantum,png_pixels,&image->exception);
8983 else if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
8985 if (logging != MagickFalse && y == 0)
8986 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8987 " Writing GRAY_ALPHA PNG pixels (4)");
8989 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8990 quantum_info,GrayAlphaQuantum,png_pixels,
8995 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8996 quantum_info,IndexQuantum,png_pixels,&image->exception);
8998 if (logging != MagickFalse && y <= 2)
9000 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9001 " Writing row of pixels (4)");
9003 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9004 " png_pixels[0]=%d,png_pixels[1]=%d",
9005 (int)png_pixels[0],(int)png_pixels[1]);
9007 png_write_row(ping,png_pixels);
9011 if (image->previous == (Image *) NULL)
9013 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
9014 if (status == MagickFalse)
9021 if (quantum_info != (QuantumInfo *) NULL)
9022 quantum_info=DestroyQuantumInfo(quantum_info);
9024 if (logging != MagickFalse)
9026 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9027 " Wrote PNG image data");
9029 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9030 " Width: %.20g",(double) ping_width);
9032 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9033 " Height: %.20g",(double) ping_height);
9035 if (mng_info->write_png_depth)
9037 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9038 " Defined PNG:bit-depth: %d",mng_info->write_png_depth);
9041 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9042 " PNG bit-depth written: %d",ping_bit_depth);
9044 if (mng_info->write_png_colortype)
9046 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9047 " Defined PNG:color-type: %d",mng_info->write_png_colortype-1);
9050 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9051 " PNG color-type written: %d",ping_color_type);
9053 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9054 " PNG Interlace method: %d",ping_interlace_method);
9057 Generate text chunks.
9059 if (ping_exclude_tEXt == MagickFalse && ping_exclude_zTXt == MagickFalse)
9061 ResetImagePropertyIterator(image);
9062 property=GetNextImageProperty(image);
9063 while (property != (const char *) NULL)
9068 value=GetImageProperty(image,property);
9069 if (value != (const char *) NULL)
9071 text=(png_textp) png_malloc(ping,(png_uint_32) sizeof(png_text));
9072 text[0].key=(char *) property;
9073 text[0].text=(char *) value;
9074 text[0].text_length=strlen(value);
9076 if (ping_exclude_tEXt != MagickFalse)
9077 text[0].compression=PNG_TEXT_COMPRESSION_zTXt;
9079 else if (ping_exclude_zTXt != MagickFalse)
9080 text[0].compression=PNG_TEXT_COMPRESSION_NONE;
9084 text[0].compression=image_info->compression == NoCompression ||
9085 (image_info->compression == UndefinedCompression &&
9086 text[0].text_length < 128) ? PNG_TEXT_COMPRESSION_NONE :
9087 PNG_TEXT_COMPRESSION_zTXt ;
9090 if (logging != MagickFalse)
9092 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9093 " Setting up text chunk");
9095 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9096 " keyword: %s",text[0].key);
9099 png_set_text(ping,ping_info,text,1);
9100 png_free(ping,text);
9102 property=GetNextImageProperty(image);
9106 /* write any PNG-chunk-e profiles */
9107 (void) png_write_chunk_from_profile(image,"PNG-chunk-e",logging);
9109 if (logging != MagickFalse)
9110 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9111 " Writing PNG end info");
9113 png_write_end(ping,ping_info);
9115 if (mng_info->need_fram && (int) image->dispose == BackgroundDispose)
9117 if (mng_info->page.x || mng_info->page.y ||
9118 (ping_width != mng_info->page.width) ||
9119 (ping_height != mng_info->page.height))
9125 Write FRAM 4 with clipping boundaries followed by FRAM 1.
9127 (void) WriteBlobMSBULong(image,27L); /* data length=27 */
9128 PNGType(chunk,mng_FRAM);
9129 LogPNGChunk(logging,mng_FRAM,27L);
9131 chunk[5]=0; /* frame name separator (no name) */
9132 chunk[6]=1; /* flag for changing delay, for next frame only */
9133 chunk[7]=0; /* flag for changing frame timeout */
9134 chunk[8]=1; /* flag for changing frame clipping for next frame */
9135 chunk[9]=0; /* flag for changing frame sync_id */
9136 PNGLong(chunk+10,(png_uint_32) (0L)); /* temporary 0 delay */
9137 chunk[14]=0; /* clipping boundaries delta type */
9138 PNGLong(chunk+15,(png_uint_32) (mng_info->page.x)); /* left cb */
9140 (png_uint_32) (mng_info->page.x + ping_width));
9141 PNGLong(chunk+23,(png_uint_32) (mng_info->page.y)); /* top cb */
9143 (png_uint_32) (mng_info->page.y + ping_height));
9144 (void) WriteBlob(image,31,chunk);
9145 (void) WriteBlobMSBULong(image,crc32(0,chunk,31));
9146 mng_info->old_framing_mode=4;
9147 mng_info->framing_mode=1;
9151 mng_info->framing_mode=3;
9153 if (mng_info->write_mng && !mng_info->need_fram &&
9154 ((int) image->dispose == 3))
9155 (void) ThrowMagickException(&image->exception,GetMagickModule(),
9156 CoderError,"Cannot convert GIF with disposal method 3 to MNG-LC",
9157 "`%s'",image->filename);
9163 png_destroy_write_struct(&ping,&ping_info);
9165 png_pixels=(unsigned char *) RelinquishMagickMemory(png_pixels);
9167 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
9168 UnlockSemaphoreInfo(png_semaphore);
9171 if (mng_info->need_blob != MagickFalse)
9172 (void) CloseBlob(image);
9174 image_info=DestroyImageInfo(image_info);
9175 image=DestroyImage(image);
9177 /* Store bit depth actually written */
9178 s[0]=(char) ping_bit_depth;
9181 (void) SetImageProperty(IMimage,"png:bit-depth-written",s);
9183 if (logging != MagickFalse)
9184 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9185 " exit WriteOnePNGImage()");
9188 /* End write one PNG image */
9192 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9196 % W r i t e P N G I m a g e %
9200 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9202 % WritePNGImage() writes a Portable Network Graphics (PNG) or
9203 % Multiple-image Network Graphics (MNG) image file.
9205 % MNG support written by Glenn Randers-Pehrson, glennrp@image...
9207 % The format of the WritePNGImage method is:
9209 % MagickBooleanType WritePNGImage(const ImageInfo *image_info,Image *image)
9211 % A description of each parameter follows:
9213 % o image_info: the image info.
9215 % o image: The image.
9217 % Returns MagickTrue on success, MagickFalse on failure.
9219 % Communicating with the PNG encoder:
9221 % While the datastream written is always in PNG format and normally would
9222 % be given the "png" file extension, this method also writes the following
9223 % pseudo-formats which are subsets of PNG:
9225 % o PNG8: An 8-bit indexed PNG datastream is written. If transparency
9226 % is present, the tRNS chunk must only have values 0 and 255
9227 % (i.e., transparency is binary: fully opaque or fully
9228 % transparent). The pixels contain 8-bit indices even if
9229 % they could be represented with 1, 2, or 4 bits. Note: grayscale
9230 % images will be written as indexed PNG files even though the
9231 % PNG grayscale type might be slightly more efficient.
9233 % o PNG24: An 8-bit per sample RGB PNG datastream is written. The tRNS
9234 % chunk can be present to convey binary transparency by naming
9235 % one of the colors as transparent.
9237 % o PNG32: An 8-bit per sample RGBA PNG is written. Partial
9238 % transparency is permitted, i.e., the alpha sample for
9239 % each pixel can have any value from 0 to 255. The alpha
9240 % channel is present even if the image is fully opaque.
9242 % o -define: For more precise control of the PNG output, you can use the
9243 % Image options "png:bit-depth" and "png:color-type". These
9244 % can be set from the commandline with "-define" and also
9245 % from the application programming interfaces. The options
9246 % are case-independent and are converted to lowercase before
9247 % being passed to this encoder.
9249 % png:color-type can be 0, 2, 3, 4, or 6.
9251 % When png:color-type is 0 (Grayscale), png:bit-depth can
9252 % be 1, 2, 4, 8, or 16.
9254 % When png:color-type is 2 (RGB), png:bit-depth can
9257 % When png:color-type is 3 (Indexed), png:bit-depth can
9258 % be 1, 2, 4, or 8. This refers to the number of bits
9259 % used to store the index. The color samples always have
9260 % bit-depth 8 in indexed PNG files.
9262 % When png:color-type is 4 (Gray-Matte) or 6 (RGB-Matte),
9263 % png:bit-depth can be 8 or 16.
9265 % If the image cannot be written without loss in the requested PNG8, PNG24,
9266 % or PNG32 format or with the requested bit-depth and color-type without loss,
9267 % a PNG file will not be written, and the encoder will return MagickFalse.
9268 % Since image encoders should not be responsible for the "heavy lifting",
9269 % the user should make sure that ImageMagick has already reduced the
9270 % image depth and number of colors and limit transparency to binary
9271 % transparency prior to attempting to write the image in a format that
9272 % is subject to depth, color, or transparency limitations.
9274 % TODO: Enforce the previous paragraph.
9276 % Note that another definition, "png:bit-depth-written" exists, but it
9277 % is not intended for external use. It is only used internally by the
9278 % PNG encoder to inform the JNG encoder of the depth of the alpha channel.
9280 % It is possible to request that the PNG encoder write previously-formatted
9281 % ancillary chunks in the output PNG file, using the "-profile" commandline
9282 % option as shown below or by setting the profile via a programming
9285 % -profile PNG-chunk-x:<file>
9287 % where x is a location flag and <file> is a file containing the chunk
9288 % name in the first 4 bytes, then a colon (":"), followed by the chunk data.
9289 % This encoder will compute the chunk length and CRC, so those must not
9290 % be included in the file.
9292 % "x" can be "b" (before PLTE), "m" (middle, i.e., between PLTE and IDAT),
9293 % or "e" (end, i.e., after IDAT). If you want to write multiple chunks
9294 % of the same type, then add a short unique string after the "x" to prevent
9295 % subsequent profiles from overwriting the preceding ones, e.g.,
9297 % -profile PNG-chunk-b01:file01 -profile PNG-chunk-b02:file02
9299 % As of version 6.6.6 the following optimizations are always done:
9301 % o 32-bit depth is reduced to 16.
9302 % o 16-bit depth is reduced to 8 if all pixels contain samples whose
9303 % high byte and low byte are identical.
9304 % o Palette is sorted to remove unused entries and to put a
9305 % transparent color first, if PNG_BUILD_PALETTE is defined.
9306 % o Opaque matte channel is removed when writing an indexed PNG.
9307 % o Grayscale images are reduced to 1, 2, or 4 bit depth if
9308 % this can be done without loss and a larger bit depth N was not
9309 % requested via the "-define PNG:bit-depth=N" option.
9310 % o If matte channel is present but only one transparent color is
9311 % present, RGB+tRNS is written instead of RGBA
9312 % o Opaque matte channel is removed (or added, if color-type 4 or 6
9313 % was requested when converting an opaque image).
9315 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9317 static MagickBooleanType WritePNGImage(const ImageInfo *image_info,
9339 assert(image_info != (const ImageInfo *) NULL);
9340 assert(image_info->signature == MagickSignature);
9341 assert(image != (Image *) NULL);
9342 assert(image->signature == MagickSignature);
9343 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
9344 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"enter WritePNGImage()");
9346 Allocate a MngInfo structure.
9348 have_mng_structure=MagickFalse;
9349 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
9351 if (mng_info == (MngInfo *) NULL)
9352 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
9355 Initialize members of the MngInfo structure.
9357 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
9358 mng_info->image=image;
9359 mng_info->equal_backgrounds=MagickTrue;
9360 have_mng_structure=MagickTrue;
9362 /* See if user has requested a specific PNG subformat */
9364 mng_info->write_png8=LocaleCompare(image_info->magick,"PNG8") == 0;
9365 mng_info->write_png24=LocaleCompare(image_info->magick,"PNG24") == 0;
9366 mng_info->write_png32=LocaleCompare(image_info->magick,"PNG32") == 0;
9368 if (mng_info->write_png8)
9370 mng_info->write_png_colortype = /* 3 */ 4;
9371 mng_info->write_png_depth = 8;
9375 if (mng_info->write_png24)
9377 mng_info->write_png_colortype = /* 2 */ 3;
9378 mng_info->write_png_depth = 8;
9381 if (image->matte == MagickTrue)
9382 (void) SetImageType(image,TrueColorMatteType);
9385 (void) SetImageType(image,TrueColorType);
9387 (void) SyncImage(image);
9390 if (mng_info->write_png32)
9392 mng_info->write_png_colortype = /* 6 */ 7;
9393 mng_info->write_png_depth = 8;
9396 if (image->matte == MagickTrue)
9397 (void) SetImageType(image,TrueColorMatteType);
9400 (void) SetImageType(image,TrueColorType);
9402 (void) SyncImage(image);
9405 value=GetImageOption(image_info,"png:bit-depth");
9407 if (value != (char *) NULL)
9409 if (LocaleCompare(value,"1") == 0)
9410 mng_info->write_png_depth = 1;
9412 else if (LocaleCompare(value,"2") == 0)
9413 mng_info->write_png_depth = 2;
9415 else if (LocaleCompare(value,"4") == 0)
9416 mng_info->write_png_depth = 4;
9418 else if (LocaleCompare(value,"8") == 0)
9419 mng_info->write_png_depth = 8;
9421 else if (LocaleCompare(value,"16") == 0)
9422 mng_info->write_png_depth = 16;
9425 (void) ThrowMagickException(&image->exception,
9426 GetMagickModule(),CoderWarning,
9427 "ignoring invalid defined png:bit-depth",
9430 if (logging != MagickFalse)
9431 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9432 " png:bit-depth=%d was defined.\n",mng_info->write_png_depth);
9435 value=GetImageOption(image_info,"png:color-type");
9437 if (value != (char *) NULL)
9439 /* We must store colortype+1 because 0 is a valid colortype */
9440 if (LocaleCompare(value,"0") == 0)
9441 mng_info->write_png_colortype = 1;
9443 else if (LocaleCompare(value,"2") == 0)
9444 mng_info->write_png_colortype = 3;
9446 else if (LocaleCompare(value,"3") == 0)
9447 mng_info->write_png_colortype = 4;
9449 else if (LocaleCompare(value,"4") == 0)
9450 mng_info->write_png_colortype = 5;
9452 else if (LocaleCompare(value,"6") == 0)
9453 mng_info->write_png_colortype = 7;
9456 (void) ThrowMagickException(&image->exception,
9457 GetMagickModule(),CoderWarning,
9458 "ignoring invalid defined png:color-type",
9461 if (logging != MagickFalse)
9462 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9463 " png:color-type=%d was defined.\n",mng_info->write_png_colortype-1);
9466 /* Check for chunks to be excluded:
9468 * The default is to not exclude any known chunks except for any
9469 * listed in the "unused_chunks" array, above.
9471 * Chunks can be listed for exclusion via a "PNG:exclude-chunk"
9472 * define (in the image properties or in the image artifacts)
9473 * or via a mng_info member. For convenience, in addition
9474 * to or instead of a comma-separated list of chunks, the
9475 * "exclude-chunk" string can be simply "all" or "none".
9477 * The exclude-chunk define takes priority over the mng_info.
9479 * A "PNG:include-chunk" define takes priority over both the
9480 * mng_info and the "PNG:exclude-chunk" define. Like the
9481 * "exclude-chunk" string, it can define "all" or "none" as
9482 * well as a comma-separated list. Chunks that are unknown to
9483 * ImageMagick are always excluded, regardless of their "copy-safe"
9484 * status according to the PNG specification, and even if they
9485 * appear in the "include-chunk" list.
9487 * Finally, all chunks listed in the "unused_chunks" array are
9488 * automatically excluded, regardless of the other instructions
9491 * if you exclude sRGB but not gAMA (recommended), then sRGB chunk
9492 * will not be written and the gAMA chunk will only be written if it
9493 * is not between .45 and .46, or approximately (1.0/2.2).
9495 * If you exclude tRNS and the image has transparency, the colortype
9496 * is forced to be 4 or 6 (GRAY_ALPHA or RGB_ALPHA).
9498 * The -strip option causes StripImage() to set the png:include-chunk
9499 * artifact to "none,gama".
9502 mng_info->ping_exclude_bKGD=MagickFalse;
9503 mng_info->ping_exclude_cHRM=MagickFalse;
9504 mng_info->ping_exclude_EXIF=MagickFalse; /* hex-encoded EXIF in zTXt */
9505 mng_info->ping_exclude_gAMA=MagickFalse;
9506 mng_info->ping_exclude_cHRM=MagickFalse;
9507 mng_info->ping_exclude_iCCP=MagickFalse;
9508 /* mng_info->ping_exclude_iTXt=MagickFalse; */
9509 mng_info->ping_exclude_oFFs=MagickFalse;
9510 mng_info->ping_exclude_pHYs=MagickFalse;
9511 mng_info->ping_exclude_sRGB=MagickFalse;
9512 mng_info->ping_exclude_tEXt=MagickFalse;
9513 mng_info->ping_exclude_tRNS=MagickFalse;
9514 mng_info->ping_exclude_vpAg=MagickFalse;
9515 mng_info->ping_exclude_zCCP=MagickFalse; /* hex-encoded iCCP in zTXt */
9516 mng_info->ping_exclude_zTXt=MagickFalse;
9518 excluding=MagickFalse;
9520 for (source=0; source<1; source++)
9524 value=GetImageArtifact(image,"png:exclude-chunk");
9527 value=GetImageArtifact(image,"png:exclude-chunks");
9531 value=GetImageOption(image_info,"png:exclude-chunk");
9534 value=GetImageOption(image_info,"png:exclude-chunks");
9543 excluding=MagickTrue;
9545 if (logging != MagickFalse)
9548 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9549 " png:exclude-chunk=%s found in image artifacts.\n", value);
9551 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9552 " png:exclude-chunk=%s found in image properties.\n", value);
9557 for (i=0; i<(int) last; i+=5)
9560 if (LocaleNCompare(value+i,"all",3) == 0)
9562 mng_info->ping_exclude_bKGD=MagickTrue;
9563 mng_info->ping_exclude_cHRM=MagickTrue;
9564 mng_info->ping_exclude_EXIF=MagickTrue;
9565 mng_info->ping_exclude_gAMA=MagickTrue;
9566 mng_info->ping_exclude_iCCP=MagickTrue;
9567 /* mng_info->ping_exclude_iTXt=MagickTrue; */
9568 mng_info->ping_exclude_oFFs=MagickTrue;
9569 mng_info->ping_exclude_pHYs=MagickTrue;
9570 mng_info->ping_exclude_sRGB=MagickTrue;
9571 mng_info->ping_exclude_tEXt=MagickTrue;
9572 mng_info->ping_exclude_tRNS=MagickTrue;
9573 mng_info->ping_exclude_vpAg=MagickTrue;
9574 mng_info->ping_exclude_zCCP=MagickTrue;
9575 mng_info->ping_exclude_zTXt=MagickTrue;
9579 if (LocaleNCompare(value+i,"none",4) == 0)
9581 mng_info->ping_exclude_bKGD=MagickFalse;
9582 mng_info->ping_exclude_cHRM=MagickFalse;
9583 mng_info->ping_exclude_EXIF=MagickFalse;
9584 mng_info->ping_exclude_gAMA=MagickFalse;
9585 mng_info->ping_exclude_iCCP=MagickFalse;
9586 /* mng_info->ping_exclude_iTXt=MagickFalse; */
9587 mng_info->ping_exclude_oFFs=MagickFalse;
9588 mng_info->ping_exclude_pHYs=MagickFalse;
9589 mng_info->ping_exclude_sRGB=MagickFalse;
9590 mng_info->ping_exclude_tEXt=MagickFalse;
9591 mng_info->ping_exclude_tRNS=MagickFalse;
9592 mng_info->ping_exclude_vpAg=MagickFalse;
9593 mng_info->ping_exclude_zCCP=MagickFalse;
9594 mng_info->ping_exclude_zTXt=MagickFalse;
9597 if (LocaleNCompare(value+i,"bkgd",4) == 0)
9598 mng_info->ping_exclude_bKGD=MagickTrue;
9600 if (LocaleNCompare(value+i,"chrm",4) == 0)
9601 mng_info->ping_exclude_cHRM=MagickTrue;
9603 if (LocaleNCompare(value+i,"exif",4) == 0)
9604 mng_info->ping_exclude_EXIF=MagickTrue;
9606 if (LocaleNCompare(value+i,"gama",4) == 0)
9607 mng_info->ping_exclude_gAMA=MagickTrue;
9609 if (LocaleNCompare(value+i,"iccp",4) == 0)
9610 mng_info->ping_exclude_iCCP=MagickTrue;
9613 if (LocaleNCompare(value+i,"itxt",4) == 0)
9614 mng_info->ping_exclude_iTXt=MagickTrue;
9617 if (LocaleNCompare(value+i,"gama",4) == 0)
9618 mng_info->ping_exclude_gAMA=MagickTrue;
9620 if (LocaleNCompare(value+i,"offs",4) == 0)
9621 mng_info->ping_exclude_oFFs=MagickTrue;
9623 if (LocaleNCompare(value+i,"phys",4) == 0)
9624 mng_info->ping_exclude_pHYs=MagickTrue;
9626 if (LocaleNCompare(value+i,"srgb",4) == 0)
9627 mng_info->ping_exclude_sRGB=MagickTrue;
9629 if (LocaleNCompare(value+i,"text",4) == 0)
9630 mng_info->ping_exclude_tEXt=MagickTrue;
9632 if (LocaleNCompare(value+i,"trns",4) == 0)
9633 mng_info->ping_exclude_tRNS=MagickTrue;
9635 if (LocaleNCompare(value+i,"vpag",4) == 0)
9636 mng_info->ping_exclude_vpAg=MagickTrue;
9638 if (LocaleNCompare(value+i,"zccp",4) == 0)
9639 mng_info->ping_exclude_zCCP=MagickTrue;
9641 if (LocaleNCompare(value+i,"ztxt",4) == 0)
9642 mng_info->ping_exclude_zTXt=MagickTrue;
9648 for (source=0; source<1; source++)
9652 value=GetImageArtifact(image,"png:include-chunk");
9655 value=GetImageArtifact(image,"png:include-chunks");
9659 value=GetImageOption(image_info,"png:include-chunk");
9662 value=GetImageOption(image_info,"png:include-chunks");
9670 excluding=MagickTrue;
9672 if (logging != MagickFalse)
9675 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9676 " png:include-chunk=%s found in image artifacts.\n", value);
9678 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9679 " png:include-chunk=%s found in image properties.\n", value);
9684 for (i=0; i<(int) last; i+=5)
9686 if (LocaleNCompare(value+i,"all",3) == 0)
9688 mng_info->ping_exclude_bKGD=MagickFalse;
9689 mng_info->ping_exclude_cHRM=MagickFalse;
9690 mng_info->ping_exclude_EXIF=MagickFalse;
9691 mng_info->ping_exclude_gAMA=MagickFalse;
9692 mng_info->ping_exclude_iCCP=MagickFalse;
9693 /* mng_info->ping_exclude_iTXt=MagickFalse; */
9694 mng_info->ping_exclude_oFFs=MagickFalse;
9695 mng_info->ping_exclude_pHYs=MagickFalse;
9696 mng_info->ping_exclude_sRGB=MagickFalse;
9697 mng_info->ping_exclude_tEXt=MagickFalse;
9698 mng_info->ping_exclude_tRNS=MagickFalse;
9699 mng_info->ping_exclude_vpAg=MagickFalse;
9700 mng_info->ping_exclude_zCCP=MagickFalse;
9701 mng_info->ping_exclude_zTXt=MagickFalse;
9705 if (LocaleNCompare(value+i,"none",4) == 0)
9707 mng_info->ping_exclude_bKGD=MagickTrue;
9708 mng_info->ping_exclude_cHRM=MagickTrue;
9709 mng_info->ping_exclude_EXIF=MagickTrue;
9710 mng_info->ping_exclude_gAMA=MagickTrue;
9711 mng_info->ping_exclude_iCCP=MagickTrue;
9712 /* mng_info->ping_exclude_iTXt=MagickTrue; */
9713 mng_info->ping_exclude_oFFs=MagickTrue;
9714 mng_info->ping_exclude_pHYs=MagickTrue;
9715 mng_info->ping_exclude_sRGB=MagickTrue;
9716 mng_info->ping_exclude_tEXt=MagickTrue;
9717 mng_info->ping_exclude_tRNS=MagickTrue;
9718 mng_info->ping_exclude_vpAg=MagickTrue;
9719 mng_info->ping_exclude_zCCP=MagickTrue;
9720 mng_info->ping_exclude_zTXt=MagickTrue;
9723 if (LocaleNCompare(value+i,"bkgd",4) == 0)
9724 mng_info->ping_exclude_bKGD=MagickFalse;
9726 if (LocaleNCompare(value+i,"chrm",4) == 0)
9727 mng_info->ping_exclude_cHRM=MagickFalse;
9729 if (LocaleNCompare(value+i,"exif",4) == 0)
9730 mng_info->ping_exclude_EXIF=MagickFalse;
9732 if (LocaleNCompare(value+i,"gama",4) == 0)
9733 mng_info->ping_exclude_gAMA=MagickFalse;
9735 if (LocaleNCompare(value+i,"iccp",4) == 0)
9736 mng_info->ping_exclude_iCCP=MagickFalse;
9739 if (LocaleNCompare(value+i,"itxt",4) == 0)
9740 mng_info->ping_exclude_iTXt=MagickFalse;
9743 if (LocaleNCompare(value+i,"gama",4) == 0)
9744 mng_info->ping_exclude_gAMA=MagickFalse;
9746 if (LocaleNCompare(value+i,"offs",4) == 0)
9747 mng_info->ping_exclude_oFFs=MagickFalse;
9749 if (LocaleNCompare(value+i,"phys",4) == 0)
9750 mng_info->ping_exclude_pHYs=MagickFalse;
9752 if (LocaleNCompare(value+i,"srgb",4) == 0)
9753 mng_info->ping_exclude_sRGB=MagickFalse;
9755 if (LocaleNCompare(value+i,"text",4) == 0)
9756 mng_info->ping_exclude_tEXt=MagickFalse;
9758 if (LocaleNCompare(value+i,"trns",4) == 0)
9759 mng_info->ping_exclude_tRNS=MagickFalse;
9761 if (LocaleNCompare(value+i,"vpag",4) == 0)
9762 mng_info->ping_exclude_vpAg=MagickFalse;
9764 if (LocaleNCompare(value+i,"zccp",4) == 0)
9765 mng_info->ping_exclude_zCCP=MagickFalse;
9767 if (LocaleNCompare(value+i,"ztxt",4) == 0)
9768 mng_info->ping_exclude_zTXt=MagickFalse;
9774 if (excluding != MagickFalse && logging != MagickFalse)
9776 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9777 " Chunks to be excluded from the output PNG:");
9778 if (mng_info->ping_exclude_bKGD != MagickFalse)
9779 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9781 if (mng_info->ping_exclude_cHRM != MagickFalse)
9782 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9784 if (mng_info->ping_exclude_EXIF != MagickFalse)
9785 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9787 if (mng_info->ping_exclude_gAMA != MagickFalse)
9788 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9790 if (mng_info->ping_exclude_iCCP != MagickFalse)
9791 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9794 if (mng_info->ping_exclude_iTXt != MagickFalse)
9795 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9798 if (mng_info->ping_exclude_oFFs != MagickFalse)
9799 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9801 if (mng_info->ping_exclude_pHYs != MagickFalse)
9802 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9804 if (mng_info->ping_exclude_sRGB != MagickFalse)
9805 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9807 if (mng_info->ping_exclude_tEXt != MagickFalse)
9808 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9810 if (mng_info->ping_exclude_tRNS != MagickFalse)
9811 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9813 if (mng_info->ping_exclude_vpAg != MagickFalse)
9814 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9816 if (mng_info->ping_exclude_zCCP != MagickFalse)
9817 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9819 if (mng_info->ping_exclude_zTXt != MagickFalse)
9820 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9824 mng_info->need_blob = MagickTrue;
9826 status=WriteOnePNGImage(mng_info,image_info,image);
9828 MngInfoFreeStruct(mng_info,&have_mng_structure);
9830 if (logging != MagickFalse)
9831 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit WritePNGImage()");
9836 #if defined(JNG_SUPPORTED)
9838 /* Write one JNG image */
9839 static MagickBooleanType WriteOneJNGImage(MngInfo *mng_info,
9840 const ImageInfo *image_info,Image *image)
9861 jng_alpha_compression_method,
9862 jng_alpha_sample_depth,
9869 logging=LogMagickEvent(CoderEvent,GetMagickModule(),
9870 " enter WriteOneJNGImage()");
9872 blob=(unsigned char *) NULL;
9873 jpeg_image=(Image *) NULL;
9874 jpeg_image_info=(ImageInfo *) NULL;
9877 transparent=image_info->type==GrayscaleMatteType ||
9878 image_info->type==TrueColorMatteType;
9880 jng_alpha_sample_depth=0;
9881 jng_quality=image_info->quality == 0UL ? 75UL : image_info->quality;
9882 jng_alpha_compression_method=0;
9884 if (image->matte != MagickFalse)
9886 /* if any pixels are transparent */
9887 transparent=MagickTrue;
9888 if (image_info->compression==JPEGCompression)
9889 jng_alpha_compression_method=8;
9896 /* Create JPEG blob, image, and image_info */
9897 if (logging != MagickFalse)
9898 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9899 " Creating jpeg_image_info for opacity.");
9901 jpeg_image_info=(ImageInfo *) CloneImageInfo(image_info);
9903 if (jpeg_image_info == (ImageInfo *) NULL)
9904 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
9906 if (logging != MagickFalse)
9907 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9908 " Creating jpeg_image.");
9910 jpeg_image=CloneImage(image,0,0,MagickTrue,&image->exception);
9912 if (jpeg_image == (Image *) NULL)
9913 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
9915 (void) CopyMagickString(jpeg_image->magick,"JPEG",MaxTextExtent);
9916 status=SeparateImageChannel(jpeg_image,OpacityChannel);
9917 status=NegateImage(jpeg_image,MagickFalse);
9918 jpeg_image->matte=MagickFalse;
9920 if (jng_quality >= 1000)
9921 jpeg_image_info->quality=jng_quality/1000;
9924 jpeg_image_info->quality=jng_quality;
9926 jpeg_image_info->type=GrayscaleType;
9927 (void) SetImageType(jpeg_image,GrayscaleType);
9928 (void) AcquireUniqueFilename(jpeg_image->filename);
9929 (void) FormatMagickString(jpeg_image_info->filename,MaxTextExtent,
9930 "%s",jpeg_image->filename);
9933 /* To do: check bit depth of PNG alpha channel */
9935 /* Check if image is grayscale. */
9936 if (image_info->type != TrueColorMatteType && image_info->type !=
9937 TrueColorType && ImageIsGray(image))
9942 if (jng_alpha_compression_method==0)
9947 /* Encode opacity as a grayscale PNG blob */
9948 status=OpenBlob(jpeg_image_info,jpeg_image,WriteBinaryBlobMode,
9950 if (logging != MagickFalse)
9951 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9952 " Creating PNG blob.");
9955 (void) CopyMagickString(jpeg_image_info->magick,"PNG",MaxTextExtent);
9956 (void) CopyMagickString(jpeg_image->magick,"PNG",MaxTextExtent);
9957 jpeg_image_info->interlace=NoInterlace;
9959 blob=ImageToBlob(jpeg_image_info,jpeg_image,&length,
9962 /* Retrieve sample depth used */
9963 value=GetImageProperty(jpeg_image,"png:bit-depth-written");
9964 if (value != (char *) NULL)
9965 jng_alpha_sample_depth= (unsigned int) value[0];
9969 /* Encode opacity as a grayscale JPEG blob */
9971 status=OpenBlob(jpeg_image_info,jpeg_image,WriteBinaryBlobMode,
9974 (void) CopyMagickString(jpeg_image_info->magick,"JPEG",MaxTextExtent);
9975 (void) CopyMagickString(jpeg_image->magick,"JPEG",MaxTextExtent);
9976 jpeg_image_info->interlace=NoInterlace;
9977 if (logging != MagickFalse)
9978 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9980 blob=ImageToBlob(jpeg_image_info,jpeg_image,&length,
9982 jng_alpha_sample_depth=8;
9984 if (logging != MagickFalse)
9985 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9986 " Successfully read jpeg_image into a blob, length=%.20g.",
9990 /* Destroy JPEG image and image_info */
9991 jpeg_image=DestroyImage(jpeg_image);
9992 (void) RelinquishUniqueFileResource(jpeg_image_info->filename);
9993 jpeg_image_info=DestroyImageInfo(jpeg_image_info);
9996 /* Write JHDR chunk */
9997 (void) WriteBlobMSBULong(image,16L); /* chunk data length=16 */
9998 PNGType(chunk,mng_JHDR);
9999 LogPNGChunk(logging,mng_JHDR,16L);
10000 PNGLong(chunk+4,(png_uint_32) image->columns);
10001 PNGLong(chunk+8,(png_uint_32) image->rows);
10002 chunk[12]=jng_color_type;
10003 chunk[13]=8; /* sample depth */
10004 chunk[14]=8; /*jng_image_compression_method */
10005 chunk[15]=(unsigned char) (image_info->interlace == NoInterlace ? 0 : 8);
10006 chunk[16]=jng_alpha_sample_depth;
10007 chunk[17]=jng_alpha_compression_method;
10008 chunk[18]=0; /*jng_alpha_filter_method */
10009 chunk[19]=0; /*jng_alpha_interlace_method */
10010 (void) WriteBlob(image,20,chunk);
10011 (void) WriteBlobMSBULong(image,crc32(0,chunk,20));
10012 if (logging != MagickFalse)
10014 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10015 " JNG width:%15lu",(unsigned long) image->columns);
10017 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10018 " JNG height:%14lu",(unsigned long) image->rows);
10020 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10021 " JNG color type:%10d",jng_color_type);
10023 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10024 " JNG sample depth:%8d",8);
10026 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10027 " JNG compression:%9d",8);
10029 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10030 " JNG interlace:%11d",0);
10032 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10033 " JNG alpha depth:%9d",jng_alpha_sample_depth);
10035 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10036 " JNG alpha compression:%3d",jng_alpha_compression_method);
10038 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10039 " JNG alpha filter:%8d",0);
10041 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10042 " JNG alpha interlace:%5d",0);
10045 /* Write any JNG-chunk-b profiles */
10046 (void) png_write_chunk_from_profile(image,"JNG-chunk-b",logging);
10049 Write leading ancillary chunks
10055 Write JNG bKGD chunk
10066 if (jng_color_type == 8 || jng_color_type == 12)
10070 (void) WriteBlobMSBULong(image,(size_t) (num_bytes-4L));
10071 PNGType(chunk,mng_bKGD);
10072 LogPNGChunk(logging,mng_bKGD,(size_t) (num_bytes-4L));
10073 red=ScaleQuantumToChar(image->background_color.red);
10074 green=ScaleQuantumToChar(image->background_color.green);
10075 blue=ScaleQuantumToChar(image->background_color.blue);
10082 (void) WriteBlob(image,(size_t) num_bytes,chunk);
10083 (void) WriteBlobMSBULong(image,crc32(0,chunk,(uInt) num_bytes));
10086 if ((image->colorspace == sRGBColorspace || image->rendering_intent))
10089 Write JNG sRGB chunk
10091 (void) WriteBlobMSBULong(image,1L);
10092 PNGType(chunk,mng_sRGB);
10093 LogPNGChunk(logging,mng_sRGB,1L);
10095 if (image->rendering_intent != UndefinedIntent)
10096 chunk[4]=(unsigned char)
10097 PNG_RenderingIntent_from_Magick_RenderingIntent(
10098 (image->rendering_intent));
10101 chunk[4]=(unsigned char)
10102 PNG_RenderingIntent_from_Magick_RenderingIntent(
10103 (PerceptualIntent));
10105 (void) WriteBlob(image,5,chunk);
10106 (void) WriteBlobMSBULong(image,crc32(0,chunk,5));
10110 if (image->gamma != 0.0)
10113 Write JNG gAMA chunk
10115 (void) WriteBlobMSBULong(image,4L);
10116 PNGType(chunk,mng_gAMA);
10117 LogPNGChunk(logging,mng_gAMA,4L);
10118 PNGLong(chunk+4,(png_uint_32) (100000*image->gamma+0.5));
10119 (void) WriteBlob(image,8,chunk);
10120 (void) WriteBlobMSBULong(image,crc32(0,chunk,8));
10123 if ((mng_info->equal_chrms == MagickFalse) &&
10124 (image->chromaticity.red_primary.x != 0.0))
10130 Write JNG cHRM chunk
10132 (void) WriteBlobMSBULong(image,32L);
10133 PNGType(chunk,mng_cHRM);
10134 LogPNGChunk(logging,mng_cHRM,32L);
10135 primary=image->chromaticity.white_point;
10136 PNGLong(chunk+4,(png_uint_32) (100000*primary.x+0.5));
10137 PNGLong(chunk+8,(png_uint_32) (100000*primary.y+0.5));
10138 primary=image->chromaticity.red_primary;
10139 PNGLong(chunk+12,(png_uint_32) (100000*primary.x+0.5));
10140 PNGLong(chunk+16,(png_uint_32) (100000*primary.y+0.5));
10141 primary=image->chromaticity.green_primary;
10142 PNGLong(chunk+20,(png_uint_32) (100000*primary.x+0.5));
10143 PNGLong(chunk+24,(png_uint_32) (100000*primary.y+0.5));
10144 primary=image->chromaticity.blue_primary;
10145 PNGLong(chunk+28,(png_uint_32) (100000*primary.x+0.5));
10146 PNGLong(chunk+32,(png_uint_32) (100000*primary.y+0.5));
10147 (void) WriteBlob(image,36,chunk);
10148 (void) WriteBlobMSBULong(image,crc32(0,chunk,36));
10152 if (image->x_resolution && image->y_resolution && !mng_info->equal_physs)
10155 Write JNG pHYs chunk
10157 (void) WriteBlobMSBULong(image,9L);
10158 PNGType(chunk,mng_pHYs);
10159 LogPNGChunk(logging,mng_pHYs,9L);
10160 if (image->units == PixelsPerInchResolution)
10162 PNGLong(chunk+4,(png_uint_32)
10163 (image->x_resolution*100.0/2.54+0.5));
10165 PNGLong(chunk+8,(png_uint_32)
10166 (image->y_resolution*100.0/2.54+0.5));
10173 if (image->units == PixelsPerCentimeterResolution)
10175 PNGLong(chunk+4,(png_uint_32)
10176 (image->x_resolution*100.0+0.5));
10178 PNGLong(chunk+8,(png_uint_32)
10179 (image->y_resolution*100.0+0.5));
10186 PNGLong(chunk+4,(png_uint_32) (image->x_resolution+0.5));
10187 PNGLong(chunk+8,(png_uint_32) (image->y_resolution+0.5));
10191 (void) WriteBlob(image,13,chunk);
10192 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
10195 if (mng_info->write_mng == 0 && (image->page.x || image->page.y))
10198 Write JNG oFFs chunk
10200 (void) WriteBlobMSBULong(image,9L);
10201 PNGType(chunk,mng_oFFs);
10202 LogPNGChunk(logging,mng_oFFs,9L);
10203 PNGsLong(chunk+4,(ssize_t) (image->page.x));
10204 PNGsLong(chunk+8,(ssize_t) (image->page.y));
10206 (void) WriteBlob(image,13,chunk);
10207 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
10209 if (mng_info->write_mng == 0 && (image->page.width || image->page.height))
10211 (void) WriteBlobMSBULong(image,9L); /* data length=8 */
10212 PNGType(chunk,mng_vpAg);
10213 LogPNGChunk(logging,mng_vpAg,9L);
10214 PNGLong(chunk+4,(png_uint_32) image->page.width);
10215 PNGLong(chunk+8,(png_uint_32) image->page.height);
10216 chunk[12]=0; /* unit = pixels */
10217 (void) WriteBlob(image,13,chunk);
10218 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
10224 if (jng_alpha_compression_method==0)
10232 /* Write IDAT chunk header */
10233 if (logging != MagickFalse)
10234 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10235 " Write IDAT chunks from blob, length=%.20g.",(double)
10238 /* Copy IDAT chunks */
10241 for (i=8; i<(ssize_t) length; i+=len+12)
10243 len=(*p<<24)|((*(p+1))<<16)|((*(p+2))<<8)|(*(p+3));
10246 if (*(p)==73 && *(p+1)==68 && *(p+2)==65 && *(p+3)==84) /* IDAT */
10248 /* Found an IDAT chunk. */
10249 (void) WriteBlobMSBULong(image,(size_t) len);
10250 LogPNGChunk(logging,mng_IDAT,(size_t) len);
10251 (void) WriteBlob(image,(size_t) len+4,p);
10252 (void) WriteBlobMSBULong(image,
10253 crc32(0,p,(uInt) len+4));
10258 if (logging != MagickFalse)
10259 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10260 " Skipping %c%c%c%c chunk, length=%.20g.",
10261 *(p),*(p+1),*(p+2),*(p+3),(double) len);
10268 /* Write JDAA chunk header */
10269 if (logging != MagickFalse)
10270 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10271 " Write JDAA chunk, length=%.20g.",(double) length);
10272 (void) WriteBlobMSBULong(image,(size_t) length);
10273 PNGType(chunk,mng_JDAA);
10274 LogPNGChunk(logging,mng_JDAA,length);
10275 /* Write JDAT chunk(s) data */
10276 (void) WriteBlob(image,4,chunk);
10277 (void) WriteBlob(image,length,blob);
10278 (void) WriteBlobMSBULong(image,crc32(crc32(0,chunk,4),blob,
10281 blob=(unsigned char *) RelinquishMagickMemory(blob);
10284 /* Encode image as a JPEG blob */
10285 if (logging != MagickFalse)
10286 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10287 " Creating jpeg_image_info.");
10288 jpeg_image_info=(ImageInfo *) CloneImageInfo(image_info);
10289 if (jpeg_image_info == (ImageInfo *) NULL)
10290 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
10292 if (logging != MagickFalse)
10293 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10294 " Creating jpeg_image.");
10296 jpeg_image=CloneImage(image,0,0,MagickTrue,&image->exception);
10297 if (jpeg_image == (Image *) NULL)
10298 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
10299 (void) CopyMagickString(jpeg_image->magick,"JPEG",MaxTextExtent);
10301 (void) AcquireUniqueFilename(jpeg_image->filename);
10302 (void) FormatMagickString(jpeg_image_info->filename,MaxTextExtent,"%s",
10303 jpeg_image->filename);
10305 status=OpenBlob(jpeg_image_info,jpeg_image,WriteBinaryBlobMode,
10306 &image->exception);
10308 if (logging != MagickFalse)
10309 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10310 " Created jpeg_image, %.20g x %.20g.",(double) jpeg_image->columns,
10311 (double) jpeg_image->rows);
10313 if (jng_color_type == 8 || jng_color_type == 12)
10314 jpeg_image_info->type=GrayscaleType;
10316 jpeg_image_info->quality=jng_quality % 1000;
10317 (void) CopyMagickString(jpeg_image_info->magick,"JPEG",MaxTextExtent);
10318 (void) CopyMagickString(jpeg_image->magick,"JPEG",MaxTextExtent);
10320 if (logging != MagickFalse)
10321 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10322 " Creating blob.");
10324 blob=ImageToBlob(jpeg_image_info,jpeg_image,&length,&image->exception);
10326 if (logging != MagickFalse)
10328 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10329 " Successfully read jpeg_image into a blob, length=%.20g.",
10332 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10333 " Write JDAT chunk, length=%.20g.",(double) length);
10336 /* Write JDAT chunk(s) */
10337 (void) WriteBlobMSBULong(image,(size_t) length);
10338 PNGType(chunk,mng_JDAT);
10339 LogPNGChunk(logging,mng_JDAT,length);
10340 (void) WriteBlob(image,4,chunk);
10341 (void) WriteBlob(image,length,blob);
10342 (void) WriteBlobMSBULong(image,crc32(crc32(0,chunk,4),blob,(uInt) length));
10344 jpeg_image=DestroyImage(jpeg_image);
10345 (void) RelinquishUniqueFileResource(jpeg_image_info->filename);
10346 jpeg_image_info=DestroyImageInfo(jpeg_image_info);
10347 blob=(unsigned char *) RelinquishMagickMemory(blob);
10349 /* Write any JNG-chunk-e profiles */
10350 (void) png_write_chunk_from_profile(image,"JNG-chunk-e",logging);
10352 /* Write IEND chunk */
10353 (void) WriteBlobMSBULong(image,0L);
10354 PNGType(chunk,mng_IEND);
10355 LogPNGChunk(logging,mng_IEND,0);
10356 (void) WriteBlob(image,4,chunk);
10357 (void) WriteBlobMSBULong(image,crc32(0,chunk,4));
10359 if (logging != MagickFalse)
10360 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10361 " exit WriteOneJNGImage()");
10368 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10372 % W r i t e J N G I m a g e %
10376 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10378 % WriteJNGImage() writes a JPEG Network Graphics (JNG) image file.
10380 % JNG support written by Glenn Randers-Pehrson, glennrp@image...
10382 % The format of the WriteJNGImage method is:
10384 % MagickBooleanType WriteJNGImage(const ImageInfo *image_info,Image *image)
10386 % A description of each parameter follows:
10388 % o image_info: the image info.
10390 % o image: The image.
10392 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10394 static MagickBooleanType WriteJNGImage(const ImageInfo *image_info,Image *image)
10397 have_mng_structure,
10407 assert(image_info != (const ImageInfo *) NULL);
10408 assert(image_info->signature == MagickSignature);
10409 assert(image != (Image *) NULL);
10410 assert(image->signature == MagickSignature);
10411 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
10412 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"enter WriteJNGImage()");
10413 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
10414 if (status == MagickFalse)
10418 Allocate a MngInfo structure.
10420 have_mng_structure=MagickFalse;
10421 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
10422 if (mng_info == (MngInfo *) NULL)
10423 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
10425 Initialize members of the MngInfo structure.
10427 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
10428 mng_info->image=image;
10429 have_mng_structure=MagickTrue;
10431 (void) WriteBlob(image,8,(const unsigned char *) "\213JNG\r\n\032\n");
10433 status=WriteOneJNGImage(mng_info,image_info,image);
10434 (void) CloseBlob(image);
10436 (void) CatchImageException(image);
10437 MngInfoFreeStruct(mng_info,&have_mng_structure);
10438 if (logging != MagickFalse)
10439 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit WriteJNGImage()");
10446 static MagickBooleanType WriteMNGImage(const ImageInfo *image_info,Image *image)
10455 have_mng_structure,
10458 volatile MagickBooleanType
10470 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
10471 defined(PNG_MNG_FEATURES_SUPPORTED)
10474 all_images_are_gray,
10484 volatile unsigned int
10495 #if (PNG_LIBPNG_VER < 10200)
10496 if (image_info->verbose)
10497 printf("Your PNG library (libpng-%s) is rather old.\n",
10498 PNG_LIBPNG_VER_STRING);
10504 assert(image_info != (const ImageInfo *) NULL);
10505 assert(image_info->signature == MagickSignature);
10506 assert(image != (Image *) NULL);
10507 assert(image->signature == MagickSignature);
10508 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
10509 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"enter WriteMNGImage()");
10510 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
10511 if (status == MagickFalse)
10515 Allocate a MngInfo structure.
10517 have_mng_structure=MagickFalse;
10518 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
10519 if (mng_info == (MngInfo *) NULL)
10520 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
10522 Initialize members of the MngInfo structure.
10524 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
10525 mng_info->image=image;
10526 have_mng_structure=MagickTrue;
10527 write_mng=LocaleCompare(image_info->magick,"MNG") == 0;
10530 * See if user has requested a specific PNG subformat to be used
10531 * for all of the PNGs in the MNG being written, e.g.,
10533 * convert *.png png8:animation.mng
10535 * To do: check -define png:bit_depth and png:color_type as well,
10536 * or perhaps use mng:bit_depth and mng:color_type instead for
10540 mng_info->write_png8=LocaleCompare(image_info->magick,"PNG8") == 0;
10541 mng_info->write_png24=LocaleCompare(image_info->magick,"PNG24") == 0;
10542 mng_info->write_png32=LocaleCompare(image_info->magick,"PNG32") == 0;
10544 write_jng=MagickFalse;
10545 if (image_info->compression == JPEGCompression)
10546 write_jng=MagickTrue;
10548 mng_info->adjoin=image_info->adjoin &&
10549 (GetNextImageInList(image) != (Image *) NULL) && write_mng;
10551 if (logging != MagickFalse)
10553 /* Log some info about the input */
10557 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10558 " Checking input image(s)");
10560 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10561 " Image_info depth: %.20g",(double) image_info->depth);
10563 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10564 " Type: %d",image_info->type);
10567 for (p=image; p != (Image *) NULL; p=GetNextImageInList(p))
10569 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10570 " Scene: %.20g",(double) scene++);
10572 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10573 " Image depth: %.20g",(double) p->depth);
10576 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10580 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10583 if (p->storage_class == PseudoClass)
10584 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10585 " Storage class: PseudoClass");
10588 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10589 " Storage class: DirectClass");
10592 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10593 " Number of colors: %.20g",(double) p->colors);
10596 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10597 " Number of colors: unspecified");
10599 if (mng_info->adjoin == MagickFalse)
10604 use_global_plte=MagickFalse;
10605 all_images_are_gray=MagickFalse;
10606 #ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
10607 need_local_plte=MagickTrue;
10609 need_defi=MagickFalse;
10610 need_matte=MagickFalse;
10611 mng_info->framing_mode=1;
10612 mng_info->old_framing_mode=1;
10615 if (image_info->page != (char *) NULL)
10618 Determine image bounding box.
10620 SetGeometry(image,&mng_info->page);
10621 (void) ParseMetaGeometry(image_info->page,&mng_info->page.x,
10622 &mng_info->page.y,&mng_info->page.width,&mng_info->page.height);
10634 mng_info->page=image->page;
10635 need_geom=MagickTrue;
10636 if (mng_info->page.width || mng_info->page.height)
10637 need_geom=MagickFalse;
10639 Check all the scenes.
10641 initial_delay=image->delay;
10642 need_iterations=MagickFalse;
10643 mng_info->equal_chrms=image->chromaticity.red_primary.x != 0.0;
10644 mng_info->equal_physs=MagickTrue,
10645 mng_info->equal_gammas=MagickTrue;
10646 mng_info->equal_srgbs=MagickTrue;
10647 mng_info->equal_backgrounds=MagickTrue;
10649 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
10650 defined(PNG_MNG_FEATURES_SUPPORTED)
10651 all_images_are_gray=MagickTrue;
10652 mng_info->equal_palettes=MagickFalse;
10653 need_local_plte=MagickFalse;
10655 for (next_image=image; next_image != (Image *) NULL; )
10659 if ((next_image->columns+next_image->page.x) > mng_info->page.width)
10660 mng_info->page.width=next_image->columns+next_image->page.x;
10662 if ((next_image->rows+next_image->page.y) > mng_info->page.height)
10663 mng_info->page.height=next_image->rows+next_image->page.y;
10666 if (next_image->page.x || next_image->page.y)
10667 need_defi=MagickTrue;
10669 if (next_image->matte)
10670 need_matte=MagickTrue;
10672 if ((int) next_image->dispose >= BackgroundDispose)
10673 if (next_image->matte || next_image->page.x || next_image->page.y ||
10674 ((next_image->columns < mng_info->page.width) &&
10675 (next_image->rows < mng_info->page.height)))
10676 mng_info->need_fram=MagickTrue;
10678 if (next_image->iterations)
10679 need_iterations=MagickTrue;
10681 final_delay=next_image->delay;
10683 if (final_delay != initial_delay || final_delay > 1UL*
10684 next_image->ticks_per_second)
10685 mng_info->need_fram=1;
10687 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
10688 defined(PNG_MNG_FEATURES_SUPPORTED)
10690 check for global palette possibility.
10692 if (image->matte != MagickFalse)
10693 need_local_plte=MagickTrue;
10695 if (need_local_plte == 0)
10697 if (ImageIsGray(image) == MagickFalse)
10698 all_images_are_gray=MagickFalse;
10699 mng_info->equal_palettes=PalettesAreEqual(image,next_image);
10700 if (use_global_plte == 0)
10701 use_global_plte=mng_info->equal_palettes;
10702 need_local_plte=!mng_info->equal_palettes;
10705 if (GetNextImageInList(next_image) != (Image *) NULL)
10707 if (next_image->background_color.red !=
10708 next_image->next->background_color.red ||
10709 next_image->background_color.green !=
10710 next_image->next->background_color.green ||
10711 next_image->background_color.blue !=
10712 next_image->next->background_color.blue)
10713 mng_info->equal_backgrounds=MagickFalse;
10715 if (next_image->gamma != next_image->next->gamma)
10716 mng_info->equal_gammas=MagickFalse;
10718 if (next_image->rendering_intent !=
10719 next_image->next->rendering_intent)
10720 mng_info->equal_srgbs=MagickFalse;
10722 if ((next_image->units != next_image->next->units) ||
10723 (next_image->x_resolution != next_image->next->x_resolution) ||
10724 (next_image->y_resolution != next_image->next->y_resolution))
10725 mng_info->equal_physs=MagickFalse;
10727 if (mng_info->equal_chrms)
10729 if (next_image->chromaticity.red_primary.x !=
10730 next_image->next->chromaticity.red_primary.x ||
10731 next_image->chromaticity.red_primary.y !=
10732 next_image->next->chromaticity.red_primary.y ||
10733 next_image->chromaticity.green_primary.x !=
10734 next_image->next->chromaticity.green_primary.x ||
10735 next_image->chromaticity.green_primary.y !=
10736 next_image->next->chromaticity.green_primary.y ||
10737 next_image->chromaticity.blue_primary.x !=
10738 next_image->next->chromaticity.blue_primary.x ||
10739 next_image->chromaticity.blue_primary.y !=
10740 next_image->next->chromaticity.blue_primary.y ||
10741 next_image->chromaticity.white_point.x !=
10742 next_image->next->chromaticity.white_point.x ||
10743 next_image->chromaticity.white_point.y !=
10744 next_image->next->chromaticity.white_point.y)
10745 mng_info->equal_chrms=MagickFalse;
10749 next_image=GetNextImageInList(next_image);
10751 if (image_count < 2)
10753 mng_info->equal_backgrounds=MagickFalse;
10754 mng_info->equal_chrms=MagickFalse;
10755 mng_info->equal_gammas=MagickFalse;
10756 mng_info->equal_srgbs=MagickFalse;
10757 mng_info->equal_physs=MagickFalse;
10758 use_global_plte=MagickFalse;
10759 #ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
10760 need_local_plte=MagickTrue;
10762 need_iterations=MagickFalse;
10765 if (mng_info->need_fram == MagickFalse)
10768 Only certain framing rates 100/n are exactly representable without
10769 the FRAM chunk but we'll allow some slop in VLC files
10771 if (final_delay == 0)
10773 if (need_iterations != MagickFalse)
10776 It's probably a GIF with loop; don't run it *too* fast.
10778 if (mng_info->adjoin)
10781 (void) ThrowMagickException(&image->exception,
10782 GetMagickModule(),CoderWarning,
10783 "input has zero delay between all frames; assuming",
10788 mng_info->ticks_per_second=0;
10790 if (final_delay != 0)
10791 mng_info->ticks_per_second=(png_uint_32) (image->ticks_per_second/final_delay);
10792 if (final_delay > 50)
10793 mng_info->ticks_per_second=2;
10795 if (final_delay > 75)
10796 mng_info->ticks_per_second=1;
10798 if (final_delay > 125)
10799 mng_info->need_fram=MagickTrue;
10801 if (need_defi && final_delay > 2 && (final_delay != 4) &&
10802 (final_delay != 5) && (final_delay != 10) && (final_delay != 20) &&
10803 (final_delay != 25) && (final_delay != 50) && (final_delay !=
10804 1UL*image->ticks_per_second))
10805 mng_info->need_fram=MagickTrue; /* make it exact; cannot be VLC */
10808 if (mng_info->need_fram != MagickFalse)
10809 mng_info->ticks_per_second=1UL*image->ticks_per_second;
10811 If pseudocolor, we should also check to see if all the
10812 palettes are identical and write a global PLTE if they are.
10816 Write the MNG version 1.0 signature and MHDR chunk.
10818 (void) WriteBlob(image,8,(const unsigned char *) "\212MNG\r\n\032\n");
10819 (void) WriteBlobMSBULong(image,28L); /* chunk data length=28 */
10820 PNGType(chunk,mng_MHDR);
10821 LogPNGChunk(logging,mng_MHDR,28L);
10822 PNGLong(chunk+4,(png_uint_32) mng_info->page.width);
10823 PNGLong(chunk+8,(png_uint_32) mng_info->page.height);
10824 PNGLong(chunk+12,mng_info->ticks_per_second);
10825 PNGLong(chunk+16,0L); /* layer count=unknown */
10826 PNGLong(chunk+20,0L); /* frame count=unknown */
10827 PNGLong(chunk+24,0L); /* play time=unknown */
10832 if (need_defi || mng_info->need_fram || use_global_plte)
10833 PNGLong(chunk+28,27L); /* simplicity=LC+JNG */
10836 PNGLong(chunk+28,25L); /* simplicity=VLC+JNG */
10841 if (need_defi || mng_info->need_fram || use_global_plte)
10842 PNGLong(chunk+28,19L); /* simplicity=LC+JNG, no transparency */
10845 PNGLong(chunk+28,17L); /* simplicity=VLC+JNG, no transparency */
10853 if (need_defi || mng_info->need_fram || use_global_plte)
10854 PNGLong(chunk+28,11L); /* simplicity=LC */
10857 PNGLong(chunk+28,9L); /* simplicity=VLC */
10862 if (need_defi || mng_info->need_fram || use_global_plte)
10863 PNGLong(chunk+28,3L); /* simplicity=LC, no transparency */
10866 PNGLong(chunk+28,1L); /* simplicity=VLC, no transparency */
10869 (void) WriteBlob(image,32,chunk);
10870 (void) WriteBlobMSBULong(image,crc32(0,chunk,32));
10871 option=GetImageOption(image_info,"mng:need-cacheoff");
10872 if (option != (const char *) NULL)
10878 Write "nEED CACHEOFF" to turn playback caching off for streaming MNG.
10880 PNGType(chunk,mng_nEED);
10881 length=CopyMagickString((char *) chunk+4,"CACHEOFF",20);
10882 (void) WriteBlobMSBULong(image,(size_t) length);
10883 LogPNGChunk(logging,mng_nEED,(size_t) length);
10885 (void) WriteBlob(image,length,chunk);
10886 (void) WriteBlobMSBULong(image,crc32(0,chunk,(uInt) length));
10888 if ((GetPreviousImageInList(image) == (Image *) NULL) &&
10889 (GetNextImageInList(image) != (Image *) NULL) &&
10890 (image->iterations != 1))
10893 Write MNG TERM chunk
10895 (void) WriteBlobMSBULong(image,10L); /* data length=10 */
10896 PNGType(chunk,mng_TERM);
10897 LogPNGChunk(logging,mng_TERM,10L);
10898 chunk[4]=3; /* repeat animation */
10899 chunk[5]=0; /* show last frame when done */
10900 PNGLong(chunk+6,(png_uint_32) (mng_info->ticks_per_second*
10901 final_delay/MagickMax(image->ticks_per_second,1)));
10903 if (image->iterations == 0)
10904 PNGLong(chunk+10,PNG_UINT_31_MAX);
10907 PNGLong(chunk+10,(png_uint_32) image->iterations);
10909 if (logging != MagickFalse)
10911 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10912 " TERM delay: %.20g",(double) (mng_info->ticks_per_second*
10913 final_delay/MagickMax(image->ticks_per_second,1)));
10915 if (image->iterations == 0)
10916 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10917 " TERM iterations: %.20g",(double) PNG_UINT_31_MAX);
10920 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10921 " Image iterations: %.20g",(double) image->iterations);
10923 (void) WriteBlob(image,14,chunk);
10924 (void) WriteBlobMSBULong(image,crc32(0,chunk,14));
10927 To do: check for cHRM+gAMA == sRGB, and write sRGB instead.
10929 if ((image->colorspace == sRGBColorspace || image->rendering_intent) &&
10930 mng_info->equal_srgbs)
10933 Write MNG sRGB chunk
10935 (void) WriteBlobMSBULong(image,1L);
10936 PNGType(chunk,mng_sRGB);
10937 LogPNGChunk(logging,mng_sRGB,1L);
10939 if (image->rendering_intent != UndefinedIntent)
10940 chunk[4]=(unsigned char)
10941 PNG_RenderingIntent_from_Magick_RenderingIntent(
10942 (image->rendering_intent));
10945 chunk[4]=(unsigned char)
10946 PNG_RenderingIntent_from_Magick_RenderingIntent(
10947 (PerceptualIntent));
10949 (void) WriteBlob(image,5,chunk);
10950 (void) WriteBlobMSBULong(image,crc32(0,chunk,5));
10951 mng_info->have_write_global_srgb=MagickTrue;
10956 if (image->gamma && mng_info->equal_gammas)
10959 Write MNG gAMA chunk
10961 (void) WriteBlobMSBULong(image,4L);
10962 PNGType(chunk,mng_gAMA);
10963 LogPNGChunk(logging,mng_gAMA,4L);
10964 PNGLong(chunk+4,(png_uint_32) (100000*image->gamma+0.5));
10965 (void) WriteBlob(image,8,chunk);
10966 (void) WriteBlobMSBULong(image,crc32(0,chunk,8));
10967 mng_info->have_write_global_gama=MagickTrue;
10969 if (mng_info->equal_chrms)
10975 Write MNG cHRM chunk
10977 (void) WriteBlobMSBULong(image,32L);
10978 PNGType(chunk,mng_cHRM);
10979 LogPNGChunk(logging,mng_cHRM,32L);
10980 primary=image->chromaticity.white_point;
10981 PNGLong(chunk+4,(png_uint_32) (100000*primary.x+0.5));
10982 PNGLong(chunk+8,(png_uint_32) (100000*primary.y+0.5));
10983 primary=image->chromaticity.red_primary;
10984 PNGLong(chunk+12,(png_uint_32) (100000*primary.x+0.5));
10985 PNGLong(chunk+16,(png_uint_32) (100000*primary.y+0.5));
10986 primary=image->chromaticity.green_primary;
10987 PNGLong(chunk+20,(png_uint_32) (100000*primary.x+0.5));
10988 PNGLong(chunk+24,(png_uint_32) (100000*primary.y+0.5));
10989 primary=image->chromaticity.blue_primary;
10990 PNGLong(chunk+28,(png_uint_32) (100000*primary.x+0.5));
10991 PNGLong(chunk+32,(png_uint_32) (100000*primary.y+0.5));
10992 (void) WriteBlob(image,36,chunk);
10993 (void) WriteBlobMSBULong(image,crc32(0,chunk,36));
10994 mng_info->have_write_global_chrm=MagickTrue;
10997 if (image->x_resolution && image->y_resolution && mng_info->equal_physs)
11000 Write MNG pHYs chunk
11002 (void) WriteBlobMSBULong(image,9L);
11003 PNGType(chunk,mng_pHYs);
11004 LogPNGChunk(logging,mng_pHYs,9L);
11006 if (image->units == PixelsPerInchResolution)
11008 PNGLong(chunk+4,(png_uint_32)
11009 (image->x_resolution*100.0/2.54+0.5));
11011 PNGLong(chunk+8,(png_uint_32)
11012 (image->y_resolution*100.0/2.54+0.5));
11019 if (image->units == PixelsPerCentimeterResolution)
11021 PNGLong(chunk+4,(png_uint_32)
11022 (image->x_resolution*100.0+0.5));
11024 PNGLong(chunk+8,(png_uint_32)
11025 (image->y_resolution*100.0+0.5));
11032 PNGLong(chunk+4,(png_uint_32) (image->x_resolution+0.5));
11033 PNGLong(chunk+8,(png_uint_32) (image->y_resolution+0.5));
11037 (void) WriteBlob(image,13,chunk);
11038 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
11041 Write MNG BACK chunk and global bKGD chunk, if the image is transparent
11042 or does not cover the entire frame.
11044 if (write_mng && (image->matte || image->page.x > 0 ||
11045 image->page.y > 0 || (image->page.width &&
11046 (image->page.width+image->page.x < mng_info->page.width))
11047 || (image->page.height && (image->page.height+image->page.y
11048 < mng_info->page.height))))
11050 (void) WriteBlobMSBULong(image,6L);
11051 PNGType(chunk,mng_BACK);
11052 LogPNGChunk(logging,mng_BACK,6L);
11053 red=ScaleQuantumToShort(image->background_color.red);
11054 green=ScaleQuantumToShort(image->background_color.green);
11055 blue=ScaleQuantumToShort(image->background_color.blue);
11056 PNGShort(chunk+4,red);
11057 PNGShort(chunk+6,green);
11058 PNGShort(chunk+8,blue);
11059 (void) WriteBlob(image,10,chunk);
11060 (void) WriteBlobMSBULong(image,crc32(0,chunk,10));
11061 if (mng_info->equal_backgrounds)
11063 (void) WriteBlobMSBULong(image,6L);
11064 PNGType(chunk,mng_bKGD);
11065 LogPNGChunk(logging,mng_bKGD,6L);
11066 (void) WriteBlob(image,10,chunk);
11067 (void) WriteBlobMSBULong(image,crc32(0,chunk,10));
11071 #ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
11072 if ((need_local_plte == MagickFalse) &&
11073 (image->storage_class == PseudoClass) &&
11074 (all_images_are_gray == MagickFalse))
11080 Write MNG PLTE chunk
11082 data_length=3*image->colors;
11083 (void) WriteBlobMSBULong(image,data_length);
11084 PNGType(chunk,mng_PLTE);
11085 LogPNGChunk(logging,mng_PLTE,data_length);
11087 for (i=0; i < (ssize_t) image->colors; i++)
11089 chunk[4+i*3]=ScaleQuantumToChar(image->colormap[i].red) & 0xff;
11090 chunk[5+i*3]=ScaleQuantumToChar(image->colormap[i].green) & 0xff;
11091 chunk[6+i*3]=ScaleQuantumToChar(image->colormap[i].blue) & 0xff;
11094 (void) WriteBlob(image,data_length+4,chunk);
11095 (void) WriteBlobMSBULong(image,crc32(0,chunk,(uInt) (data_length+4)));
11096 mng_info->have_write_global_plte=MagickTrue;
11102 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
11103 defined(PNG_MNG_FEATURES_SUPPORTED)
11104 mng_info->equal_palettes=MagickFalse;
11108 if (mng_info->adjoin)
11110 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
11111 defined(PNG_MNG_FEATURES_SUPPORTED)
11113 If we aren't using a global palette for the entire MNG, check to
11114 see if we can use one for two or more consecutive images.
11116 if (need_local_plte && use_global_plte && !all_images_are_gray)
11118 if (mng_info->IsPalette)
11121 When equal_palettes is true, this image has the same palette
11122 as the previous PseudoClass image
11124 mng_info->have_write_global_plte=mng_info->equal_palettes;
11125 mng_info->equal_palettes=PalettesAreEqual(image,image->next);
11126 if (mng_info->equal_palettes && !mng_info->have_write_global_plte)
11129 Write MNG PLTE chunk
11134 data_length=3*image->colors;
11135 (void) WriteBlobMSBULong(image,data_length);
11136 PNGType(chunk,mng_PLTE);
11137 LogPNGChunk(logging,mng_PLTE,data_length);
11139 for (i=0; i < (ssize_t) image->colors; i++)
11141 chunk[4+i*3]=ScaleQuantumToChar(image->colormap[i].red);
11142 chunk[5+i*3]=ScaleQuantumToChar(image->colormap[i].green);
11143 chunk[6+i*3]=ScaleQuantumToChar(image->colormap[i].blue);
11146 (void) WriteBlob(image,data_length+4,chunk);
11147 (void) WriteBlobMSBULong(image,crc32(0,chunk,
11148 (uInt) (data_length+4)));
11149 mng_info->have_write_global_plte=MagickTrue;
11153 mng_info->have_write_global_plte=MagickFalse;
11164 previous_x=mng_info->page.x;
11165 previous_y=mng_info->page.y;
11172 mng_info->page=image->page;
11173 if ((mng_info->page.x != previous_x) ||
11174 (mng_info->page.y != previous_y))
11176 (void) WriteBlobMSBULong(image,12L); /* data length=12 */
11177 PNGType(chunk,mng_DEFI);
11178 LogPNGChunk(logging,mng_DEFI,12L);
11179 chunk[4]=0; /* object 0 MSB */
11180 chunk[5]=0; /* object 0 LSB */
11181 chunk[6]=0; /* visible */
11182 chunk[7]=0; /* abstract */
11183 PNGLong(chunk+8,(png_uint_32) mng_info->page.x);
11184 PNGLong(chunk+12,(png_uint_32) mng_info->page.y);
11185 (void) WriteBlob(image,16,chunk);
11186 (void) WriteBlobMSBULong(image,crc32(0,chunk,16));
11191 mng_info->write_mng=write_mng;
11193 if ((int) image->dispose >= 3)
11194 mng_info->framing_mode=3;
11196 if (mng_info->need_fram && mng_info->adjoin &&
11197 ((image->delay != mng_info->delay) ||
11198 (mng_info->framing_mode != mng_info->old_framing_mode)))
11200 if (image->delay == mng_info->delay)
11203 Write a MNG FRAM chunk with the new framing mode.
11205 (void) WriteBlobMSBULong(image,1L); /* data length=1 */
11206 PNGType(chunk,mng_FRAM);
11207 LogPNGChunk(logging,mng_FRAM,1L);
11208 chunk[4]=(unsigned char) mng_info->framing_mode;
11209 (void) WriteBlob(image,5,chunk);
11210 (void) WriteBlobMSBULong(image,crc32(0,chunk,5));
11215 Write a MNG FRAM chunk with the delay.
11217 (void) WriteBlobMSBULong(image,10L); /* data length=10 */
11218 PNGType(chunk,mng_FRAM);
11219 LogPNGChunk(logging,mng_FRAM,10L);
11220 chunk[4]=(unsigned char) mng_info->framing_mode;
11221 chunk[5]=0; /* frame name separator (no name) */
11222 chunk[6]=2; /* flag for changing default delay */
11223 chunk[7]=0; /* flag for changing frame timeout */
11224 chunk[8]=0; /* flag for changing frame clipping */
11225 chunk[9]=0; /* flag for changing frame sync_id */
11226 PNGLong(chunk+10,(png_uint_32)
11227 ((mng_info->ticks_per_second*
11228 image->delay)/MagickMax(image->ticks_per_second,1)));
11229 (void) WriteBlob(image,14,chunk);
11230 (void) WriteBlobMSBULong(image,crc32(0,chunk,14));
11231 mng_info->delay=(png_uint_32) image->delay;
11233 mng_info->old_framing_mode=mng_info->framing_mode;
11236 #if defined(JNG_SUPPORTED)
11237 if (image_info->compression == JPEGCompression)
11242 if (logging != MagickFalse)
11243 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11244 " Writing JNG object.");
11245 /* To do: specify the desired alpha compression method. */
11246 write_info=CloneImageInfo(image_info);
11247 write_info->compression=UndefinedCompression;
11248 status=WriteOneJNGImage(mng_info,write_info,image);
11249 write_info=DestroyImageInfo(write_info);
11254 if (logging != MagickFalse)
11255 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11256 " Writing PNG object.");
11258 mng_info->need_blob = MagickFalse;
11260 /* We don't want any ancillary chunks written */
11261 mng_info->ping_exclude_bKGD=MagickTrue;
11262 mng_info->ping_exclude_cHRM=MagickTrue;
11263 mng_info->ping_exclude_EXIF=MagickTrue;
11264 mng_info->ping_exclude_gAMA=MagickTrue;
11265 mng_info->ping_exclude_cHRM=MagickTrue;
11266 mng_info->ping_exclude_iCCP=MagickTrue;
11267 /* mng_info->ping_exclude_iTXt=MagickTrue; */
11268 mng_info->ping_exclude_oFFs=MagickTrue;
11269 mng_info->ping_exclude_pHYs=MagickTrue;
11270 mng_info->ping_exclude_sRGB=MagickTrue;
11271 mng_info->ping_exclude_tEXt=MagickTrue;
11272 mng_info->ping_exclude_tRNS=MagickTrue;
11273 mng_info->ping_exclude_vpAg=MagickTrue;
11274 mng_info->ping_exclude_zCCP=MagickTrue;
11275 mng_info->ping_exclude_zTXt=MagickTrue;
11277 status=WriteOnePNGImage(mng_info,image_info,image);
11280 if (status == MagickFalse)
11282 MngInfoFreeStruct(mng_info,&have_mng_structure);
11283 (void) CloseBlob(image);
11284 return(MagickFalse);
11286 (void) CatchImageException(image);
11287 if (GetNextImageInList(image) == (Image *) NULL)
11289 image=SyncNextImageInList(image);
11290 status=SetImageProgress(image,SaveImagesTag,scene++,
11291 GetImageListLength(image));
11293 if (status == MagickFalse)
11296 } while (mng_info->adjoin);
11300 while (GetPreviousImageInList(image) != (Image *) NULL)
11301 image=GetPreviousImageInList(image);
11303 Write the MEND chunk.
11305 (void) WriteBlobMSBULong(image,0x00000000L);
11306 PNGType(chunk,mng_MEND);
11307 LogPNGChunk(logging,mng_MEND,0L);
11308 (void) WriteBlob(image,4,chunk);
11309 (void) WriteBlobMSBULong(image,crc32(0,chunk,4));
11312 Relinquish resources.
11314 (void) CloseBlob(image);
11315 MngInfoFreeStruct(mng_info,&have_mng_structure);
11317 if (logging != MagickFalse)
11318 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit WriteMNGImage()");
11320 return(MagickTrue);
11322 #else /* PNG_LIBPNG_VER > 10011 */
11324 static MagickBooleanType WritePNGImage(const ImageInfo *image_info,Image *image)
11327 printf("Your PNG library is too old: You have libpng-%s\n",
11328 PNG_LIBPNG_VER_STRING);
11330 ThrowBinaryException(CoderError,"PNG library is too old",
11331 image_info->filename);
11334 static MagickBooleanType WriteMNGImage(const ImageInfo *image_info,Image *image)
11336 return(WritePNGImage(image_info,image));
11338 #endif /* PNG_LIBPNG_VER > 10011 */