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);
1696 Allocate the PNG structures
1698 #ifdef PNG_USER_MEM_SUPPORTED
1699 ping=png_create_read_struct_2(PNG_LIBPNG_VER_STRING, image,
1700 PNGErrorHandler,PNGWarningHandler, NULL,
1701 (png_malloc_ptr) png_IM_malloc,(png_free_ptr) png_IM_free);
1703 ping=png_create_read_struct(PNG_LIBPNG_VER_STRING,image,
1704 PNGErrorHandler,PNGWarningHandler);
1706 if (ping == (png_struct *) NULL)
1707 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1709 ping_info=png_create_info_struct(ping);
1711 if (ping_info == (png_info *) NULL)
1713 png_destroy_read_struct(&ping,(png_info **) NULL,(png_info **) NULL);
1714 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1717 end_info=png_create_info_struct(ping);
1719 if (end_info == (png_info *) NULL)
1721 png_destroy_read_struct(&ping,&ping_info,(png_info **) NULL);
1722 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1725 png_pixels=(unsigned char *) NULL;
1727 if (setjmp(png_jmpbuf(ping)))
1730 PNG image is corrupt.
1732 png_destroy_read_struct(&ping,&ping_info,&end_info);
1733 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
1734 UnlockSemaphoreInfo(png_semaphore);
1736 if (logging != MagickFalse)
1737 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1738 " exit ReadOnePNGImage() with error.");
1740 if (image != (Image *) NULL)
1742 InheritException(exception,&image->exception);
1746 return(GetFirstImageInList(image));
1749 Prepare PNG for reading.
1752 mng_info->image_found++;
1753 png_set_sig_bytes(ping,8);
1755 if (LocaleCompare(image_info->magick,"MNG") == 0)
1757 #if defined(PNG_MNG_FEATURES_SUPPORTED)
1758 (void) png_permit_mng_features(ping,PNG_ALL_MNG_FEATURES);
1759 png_set_read_fn(ping,image,png_get_data);
1761 #if defined(PNG_READ_EMPTY_PLTE_SUPPORTED)
1762 png_permit_empty_plte(ping,MagickTrue);
1763 png_set_read_fn(ping,image,png_get_data);
1765 mng_info->image=image;
1766 mng_info->bytes_in_read_buffer=0;
1767 mng_info->found_empty_plte=MagickFalse;
1768 mng_info->have_saved_bkgd_index=MagickFalse;
1769 png_set_read_fn(ping,mng_info,mng_get_data);
1775 png_set_read_fn(ping,image,png_get_data);
1777 #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
1778 /* Ignore unused chunks and all unknown chunks except for vpAg */
1779 png_set_keep_unknown_chunks(ping, 1, NULL, 0);
1780 png_set_keep_unknown_chunks(ping, 2, mng_vpAg, 1);
1781 png_set_keep_unknown_chunks(ping, 1, unused_chunks,
1782 (int)sizeof(unused_chunks)/5);
1783 /* Callback for other unknown chunks */
1784 png_set_read_user_chunk_fn(ping, image, read_vpag_chunk_callback);
1787 #if (PNG_LIBPNG_VER < 10400)
1788 # if defined(PNG_USE_PNGGCCRD) && defined(PNG_ASSEMBLER_CODE_SUPPORTED) && \
1789 (PNG_LIBPNG_VER >= 10200) && (PNG_LIBPNG_VER < 10220) && defined(__i386__)
1790 /* Disable thread-unsafe features of pnggccrd */
1791 if (png_access_version_number() >= 10200)
1793 png_uint_32 mmx_disable_mask=0;
1794 png_uint_32 asm_flags;
1796 mmx_disable_mask |= ( PNG_ASM_FLAG_MMX_READ_COMBINE_ROW \
1797 | PNG_ASM_FLAG_MMX_READ_FILTER_SUB \
1798 | PNG_ASM_FLAG_MMX_READ_FILTER_AVG \
1799 | PNG_ASM_FLAG_MMX_READ_FILTER_PAETH );
1800 asm_flags=png_get_asm_flags(ping);
1801 png_set_asm_flags(ping, asm_flags & ~mmx_disable_mask);
1806 png_read_info(ping,ping_info);
1808 png_get_IHDR(ping,ping_info,&ping_width,&ping_height,
1809 &ping_bit_depth,&ping_color_type,
1810 &ping_interlace_method,&ping_compression_method,
1811 &ping_filter_method);
1813 (void) png_get_tRNS(ping, ping_info, &ping_trans_alpha, &ping_num_trans,
1816 (void) png_get_bKGD(ping, ping_info, &ping_background);
1818 if (ping_bit_depth < 8)
1820 if (((int) ping_color_type == PNG_COLOR_TYPE_PALETTE))
1822 png_set_packing(ping);
1827 image->depth=ping_bit_depth;
1828 image->depth=GetImageQuantumDepth(image,MagickFalse);
1829 image->interlace=ping_interlace_method != 0 ? PNGInterlace : NoInterlace;
1830 if (logging != MagickFalse)
1832 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1833 " PNG width: %.20g, height: %.20g",
1834 (double) ping_width, (double) ping_height);
1836 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1837 " PNG color_type: %d, bit_depth: %d",
1838 ping_color_type, ping_bit_depth);
1840 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1841 " PNG compression_method: %d",
1842 ping_compression_method);
1844 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1845 " PNG interlace_method: %d, filter_method: %d",
1846 ping_interlace_method,ping_filter_method);
1849 #ifdef PNG_READ_iCCP_SUPPORTED
1850 if (png_get_valid(ping,ping_info,PNG_INFO_iCCP))
1855 #if (PNG_LIBPNG_VER < 10500)
1869 (void) png_get_iCCP(ping,ping_info,&name,(int *) &compression,&info,
1872 if (profile_length != 0)
1877 if (logging != MagickFalse)
1878 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1879 " Reading PNG iCCP chunk.");
1880 profile=AcquireStringInfo(profile_length);
1881 SetStringInfoDatum(profile,(const unsigned char *) info);
1882 (void) SetImageProfile(image,"icc",profile);
1883 profile=DestroyStringInfo(profile);
1887 #if defined(PNG_READ_sRGB_SUPPORTED)
1892 if (mng_info->have_global_srgb)
1893 image->rendering_intent=PNG_RenderingIntent_to_Magick_RenderingIntent(
1894 mng_info->global_srgb_intent);
1896 if (png_get_sRGB(ping,ping_info,&intent))
1898 image->rendering_intent=PNG_RenderingIntent_to_Magick_RenderingIntent(
1901 if (logging != MagickFalse)
1902 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1903 " Reading PNG sRGB chunk: rendering_intent: %d",intent);
1911 if (!png_get_gAMA(ping,ping_info,&file_gamma))
1912 if (mng_info->have_global_gama)
1913 png_set_gAMA(ping,ping_info,mng_info->global_gamma);
1915 if (png_get_gAMA(ping,ping_info,&file_gamma))
1917 image->gamma=(float) file_gamma;
1918 if (logging != MagickFalse)
1919 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1920 " Reading PNG gAMA chunk: gamma: %f",file_gamma);
1923 if (!png_get_valid(ping,ping_info,PNG_INFO_cHRM))
1925 if (mng_info->have_global_chrm != MagickFalse)
1927 (void) png_set_cHRM(ping,ping_info,
1928 mng_info->global_chrm.white_point.x,
1929 mng_info->global_chrm.white_point.y,
1930 mng_info->global_chrm.red_primary.x,
1931 mng_info->global_chrm.red_primary.y,
1932 mng_info->global_chrm.green_primary.x,
1933 mng_info->global_chrm.green_primary.y,
1934 mng_info->global_chrm.blue_primary.x,
1935 mng_info->global_chrm.blue_primary.y);
1939 if (png_get_valid(ping,ping_info,PNG_INFO_cHRM))
1941 (void) png_get_cHRM(ping,ping_info,
1942 &image->chromaticity.white_point.x,
1943 &image->chromaticity.white_point.y,
1944 &image->chromaticity.red_primary.x,
1945 &image->chromaticity.red_primary.y,
1946 &image->chromaticity.green_primary.x,
1947 &image->chromaticity.green_primary.y,
1948 &image->chromaticity.blue_primary.x,
1949 &image->chromaticity.blue_primary.y);
1951 if (logging != MagickFalse)
1952 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1953 " Reading PNG cHRM chunk.");
1956 if (image->rendering_intent != UndefinedIntent)
1958 png_set_sRGB(ping,ping_info,
1959 PNG_RenderingIntent_from_Magick_RenderingIntent(
1960 image->rendering_intent));
1961 png_set_gAMA(ping,ping_info,0.45455f);
1962 png_set_cHRM(ping,ping_info,
1963 0.6400f, 0.3300f, 0.3000f, 0.6000f,
1964 0.1500f, 0.0600f, 0.3127f, 0.3290f);
1966 #if defined(PNG_oFFs_SUPPORTED)
1967 if (png_get_valid(ping,ping_info,PNG_INFO_oFFs))
1969 image->page.x=png_get_x_offset_pixels(ping, ping_info);
1970 image->page.y=png_get_y_offset_pixels(ping, ping_info);
1972 if (logging != MagickFalse)
1973 if (image->page.x || image->page.y)
1974 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1975 " Reading PNG oFFs chunk: x: %.20g, y: %.20g.",(double)
1976 image->page.x,(double) image->page.y);
1979 #if defined(PNG_pHYs_SUPPORTED)
1980 if (!png_get_valid(ping,ping_info,PNG_INFO_pHYs))
1982 if (mng_info->have_global_phys)
1984 png_set_pHYs(ping,ping_info,
1985 mng_info->global_x_pixels_per_unit,
1986 mng_info->global_y_pixels_per_unit,
1987 mng_info->global_phys_unit_type);
1991 if (png_get_valid(ping,ping_info,PNG_INFO_pHYs))
2001 Set image resolution.
2003 (void) png_get_pHYs(ping,ping_info,&x_resolution,&y_resolution,
2005 image->x_resolution=(double) x_resolution;
2006 image->y_resolution=(double) y_resolution;
2008 if (unit_type == PNG_RESOLUTION_METER)
2010 image->units=PixelsPerCentimeterResolution;
2011 image->x_resolution=(double) x_resolution/100.0;
2012 image->y_resolution=(double) y_resolution/100.0;
2015 if (logging != MagickFalse)
2016 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2017 " Reading PNG pHYs chunk: xres: %.20g, yres: %.20g, units: %d.",
2018 (double) x_resolution,(double) y_resolution,unit_type);
2021 if (png_get_valid(ping,ping_info,PNG_INFO_PLTE))
2029 (void) png_get_PLTE(ping,ping_info,&palette,&number_colors);
2031 if ((number_colors == 0) &&
2032 ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE))
2034 if (mng_info->global_plte_length)
2036 png_set_PLTE(ping,ping_info,mng_info->global_plte,
2037 (int) mng_info->global_plte_length);
2039 if (!png_get_valid(ping,ping_info,PNG_INFO_tRNS))
2040 if (mng_info->global_trns_length)
2042 if (mng_info->global_trns_length >
2043 mng_info->global_plte_length)
2044 (void) ThrowMagickException(&image->exception,
2045 GetMagickModule(),CoderError,
2046 "global tRNS has more entries than global PLTE",
2047 "`%s'",image_info->filename);
2048 png_set_tRNS(ping,ping_info,mng_info->global_trns,
2049 (int) mng_info->global_trns_length,NULL);
2051 #if defined(PNG_READ_bKGD_SUPPORTED)
2053 #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
2054 mng_info->have_saved_bkgd_index ||
2056 png_get_valid(ping,ping_info,PNG_INFO_bKGD))
2061 #ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
2062 if (mng_info->have_saved_bkgd_index)
2063 background.index=mng_info->saved_bkgd_index;
2065 if (png_get_valid(ping, ping_info, PNG_INFO_bKGD))
2066 background.index=ping_background->index;
2068 background.red=(png_uint_16)
2069 mng_info->global_plte[background.index].red;
2071 background.green=(png_uint_16)
2072 mng_info->global_plte[background.index].green;
2074 background.blue=(png_uint_16)
2075 mng_info->global_plte[background.index].blue;
2077 png_set_bKGD(ping,ping_info,&background);
2082 (void) ThrowMagickException(&image->exception,GetMagickModule(),
2083 CoderError,"No global PLTE in file","`%s'",
2084 image_info->filename);
2088 #if defined(PNG_READ_bKGD_SUPPORTED)
2089 if (mng_info->have_global_bkgd &&
2090 (!png_get_valid(ping,ping_info,PNG_INFO_bKGD)))
2091 image->background_color=mng_info->mng_global_bkgd;
2093 if (png_get_valid(ping,ping_info,PNG_INFO_bKGD))
2096 Set image background color.
2098 if (logging != MagickFalse)
2099 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2100 " Reading PNG bKGD chunk.");
2102 if (ping_bit_depth == MAGICKCORE_QUANTUM_DEPTH)
2104 image->background_color.red=ping_background->red;
2105 image->background_color.green=ping_background->green;
2106 image->background_color.blue=ping_background->blue;
2109 else /* Scale background components to 16-bit */
2114 if (logging != MagickFalse)
2115 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2116 " raw ping_background=(%d,%d,%d).",ping_background->red,
2117 ping_background->green,ping_background->blue);
2121 if (ping_bit_depth == 1)
2124 else if (ping_bit_depth == 2)
2127 else if (ping_bit_depth == 4)
2130 if (ping_bit_depth <= 8)
2133 ping_background->red *= bkgd_scale;
2134 ping_background->green *= bkgd_scale;
2135 ping_background->blue *= bkgd_scale;
2137 if (logging != MagickFalse)
2139 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2140 " bkgd_scale=%d.",bkgd_scale);
2142 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2143 " ping_background=(%d,%d,%d).",ping_background->red,
2144 ping_background->green,ping_background->blue);
2147 image->background_color.red=
2148 ScaleShortToQuantum(ping_background->red);
2150 image->background_color.green=
2151 ScaleShortToQuantum(ping_background->green);
2153 image->background_color.blue=
2154 ScaleShortToQuantum(ping_background->blue);
2156 image->background_color.opacity=OpaqueOpacity;
2158 if (logging != MagickFalse)
2159 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2160 " image->background_color=(%.20g,%.20g,%.20g).",
2161 (double) image->background_color.red,
2162 (double) image->background_color.green,
2163 (double) image->background_color.blue);
2168 /* Set to an out-of-range color unless tRNS chunk is present */
2169 transparent_color.red=65537;
2170 transparent_color.green=65537;
2171 transparent_color.blue=65537;
2172 transparent_color.opacity=65537;
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 image->colors=GetNumberColors(image,(FILE *) NULL,&image->exception);
7046 image_colors=(int) image->colors;
7048 if (logging != MagickFalse)
7050 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7051 " image->columns=%.20g",(double) image->columns);
7052 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7053 " image->rows=%.20g",(double) image->rows);
7054 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7055 " image->matte=%.20g",(double) image->matte);
7056 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7057 " image->depth=%.20g",(double) image->depth);
7059 if (image->colormap != NULL)
7061 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7062 " Original colormap:");
7063 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7064 " i (red,green,blue,opacity)");
7066 for (i=0; i < (ssize_t) image->colors; i++)
7068 if (i < 300 || i >= image->colors - 10)
7070 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7071 " %d (%d,%d,%d,%d)",
7073 (int) image->colormap[i].red,
7074 (int) image->colormap[i].green,
7075 (int) image->colormap[i].blue,
7076 (int) image->colormap[i].opacity);
7081 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7082 " image->colors=%d",(int) image->colors);
7084 if (image->colors == 0)
7085 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7086 " (zero means unknown)");
7088 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7089 " Regenerate the colormap");
7092 exception=(&image->exception);
7094 ping_have_color=MagickFalse;
7097 for (y=0; y < (ssize_t) image->rows; y++)
7099 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
7101 if (q == (PixelPacket *) NULL)
7104 for (x=0; x < (ssize_t) image->columns; x++)
7106 if (q->red != q->green || q->red != q->blue)
7107 ping_have_color=MagickTrue;
7109 if (q->opacity == OpaqueOpacity)
7111 if (number_opaque == 0)
7114 opaque[0].opacity=OpaqueOpacity;
7118 for (i=0; i< (ssize_t) number_opaque; i++)
7120 if (IsColorEqual(opaque+i, (PixelPacket *) q))
7124 if (i == (ssize_t) number_opaque && number_opaque < 259)
7128 opaque[i].opacity = OpaqueOpacity;
7131 else if (q->opacity == TransparentOpacity)
7133 if (number_transparent == 0)
7136 ping_trans_color.red=(unsigned short)(q->red);
7137 ping_trans_color.green=(unsigned short) (q->green);
7138 ping_trans_color.blue=(unsigned short) (q->blue);
7139 ping_trans_color.gray=(unsigned short) (q->blue);
7140 number_transparent = 1;
7143 for (i=0; i< (ssize_t) number_transparent; i++)
7145 if (IsColorEqual(transparent+i, (PixelPacket *) q))
7149 if (i == (ssize_t) number_transparent &&
7150 number_transparent < 259)
7152 number_transparent++;
7153 transparent[i] = *q;
7158 if (number_semitransparent == 0)
7160 semitransparent[0]=*q;
7161 number_semitransparent = 1;
7164 for (i=0; i< (ssize_t) number_semitransparent; i++)
7166 if (IsColorEqual(semitransparent+i,
7167 (PixelPacket *) q) &&
7168 q->opacity == semitransparent[i].opacity)
7172 if (i == (ssize_t) number_semitransparent &&
7173 number_semitransparent < 259)
7175 number_semitransparent++;
7176 semitransparent[i] = *q;
7183 image_colors=number_opaque+number_transparent+number_semitransparent;
7185 if (logging != MagickFalse)
7187 if (image_colors >= 256)
7188 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7189 " image has more than 256 colors");
7192 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7193 " image has %d colors",image_colors);
7196 if (image_colors < 257)
7202 Initialize image colormap.
7205 if (logging != MagickFalse)
7206 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7207 " Sort the new colormap");
7209 /* Sort palette, transparent first */;
7213 for (i=0; i<number_transparent; i++)
7214 colormap[n++] = transparent[i];
7216 for (i=0; i<number_semitransparent; i++)
7217 colormap[n++] = semitransparent[i];
7219 for (i=0; i<number_opaque; i++)
7220 colormap[n++] = opaque[i];
7222 if (ping_exclude_bKGD == MagickFalse)
7224 /* Add the background color to the palette, if it
7225 * isn't already there.
7227 for (i=0; i<number_opaque; i++)
7229 if (IsColorEqual(opaque+i,
7230 &image->background_color))
7234 if (number_opaque < 257 && i == number_opaque)
7236 opaque[i]=image->background_color;
7237 opaque[i].opacity = OpaqueOpacity;
7242 if ((mng_info->ping_exclude_tRNS == MagickFalse ||
7243 (number_transparent == 0 && number_semitransparent == 0)) &&
7244 (((mng_info->write_png_colortype-1) ==
7245 PNG_COLOR_TYPE_PALETTE) ||
7246 (mng_info->write_png_colortype == 0)))
7248 if (logging != MagickFalse)
7250 if (n != (ssize_t) image_colors)
7251 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7252 " image_colors (%d) and n (%d) don't match",
7255 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7256 " AcquireImageColormap");
7259 image->colors = image_colors;
7261 if (AcquireImageColormap(image,image_colors) ==
7263 ThrowWriterException(ResourceLimitError,
7264 "MemoryAllocationFailed");
7266 for (i=0; i< (ssize_t) image_colors; i++)
7267 image->colormap[i] = colormap[i];
7269 if (logging != MagickFalse)
7271 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7272 " image->colors=%d (%d)",
7273 (int) image->colors, image_colors);
7275 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7276 " Update the pixel indexes");
7279 for (y=0; y < (ssize_t) image->rows; y++)
7281 q=GetAuthenticPixels(image,0,y,image->columns,1,
7284 if (q == (PixelPacket *) NULL)
7287 indexes=GetAuthenticIndexQueue(image);
7289 for (x=0; x < (ssize_t) image->columns; x++)
7291 for (i=0; i< (ssize_t) image_colors; i++)
7293 if ((image->matte == MagickFalse ||
7294 image->colormap[i].opacity == q->opacity) &&
7295 (IsColorEqual(&image->colormap[i],(PixelPacket *) q)))
7297 indexes[x]=(IndexPacket) i;
7304 if (SyncAuthenticPixels(image,exception) == MagickFalse)
7310 if (logging != MagickFalse)
7312 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7313 " image->colors=%d", (int) image->colors);
7315 if (image->colormap != NULL)
7317 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7318 " i (red,green,blue,opacity)");
7320 for (i=0; i < (ssize_t) image->colors; i++)
7322 if (i < 300 || i >= image->colors - 10)
7324 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7325 " %d (%d,%d,%d,%d)",
7327 (int) image->colormap[i].red,
7328 (int) image->colormap[i].green,
7329 (int) image->colormap[i].blue,
7330 (int) image->colormap[i].opacity);
7335 if (logging != MagickFalse)
7337 if (number_transparent < 257)
7338 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7339 " number_transparent = %d",
7340 number_transparent);
7343 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7344 " number_transparent > 256");
7346 if (number_opaque < 257)
7347 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7348 " number_opaque = %d",
7351 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7352 " number_opaque > 256");
7354 if (number_semitransparent < 257)
7355 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7356 " number_semitransparent = %d",
7357 number_semitransparent);
7360 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7361 " number_semitransparent > 256");
7364 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7365 " Exit BUILD_PALETTE:");
7368 #endif /* PNG_BUILD_PALETTE */
7370 if (mng_info->ping_exclude_tRNS != MagickFalse &&
7371 (number_transparent != 0 || number_semitransparent != 0))
7373 int colortype=mng_info->write_png_colortype;
7375 if (ping_have_color == MagickFalse)
7376 mng_info->write_png_colortype = 5;
7379 mng_info->write_png_colortype = 7;
7381 if (colortype != 0 && mng_info->write_png_colortype != (ssize_t) colortype)
7382 ping_need_colortype_warning=MagickTrue;
7386 image_depth=image->depth;
7388 quantum_info = (QuantumInfo *) NULL;
7390 image_colors=(int) image->colors;
7391 image_matte=image->matte;
7393 mng_info->IsPalette=image->storage_class == PseudoClass &&
7394 image_colors <= 256;
7397 Allocate the PNG structures
7399 #ifdef PNG_USER_MEM_SUPPORTED
7400 ping=png_create_write_struct_2(PNG_LIBPNG_VER_STRING,image,
7401 PNGErrorHandler,PNGWarningHandler,(void *) NULL,
7402 (png_malloc_ptr) png_IM_malloc,(png_free_ptr) png_IM_free);
7405 ping=png_create_write_struct(PNG_LIBPNG_VER_STRING,image,
7406 PNGErrorHandler,PNGWarningHandler);
7409 if (ping == (png_struct *) NULL)
7410 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
7412 ping_info=png_create_info_struct(ping);
7414 if (ping_info == (png_info *) NULL)
7416 png_destroy_write_struct(&ping,(png_info **) NULL);
7417 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
7420 png_set_write_fn(ping,image,png_put_data,png_flush_data);
7421 png_pixels=(unsigned char *) NULL;
7423 if (setjmp(png_jmpbuf(ping)))
7429 if (image_info->verbose)
7430 (void) printf("PNG write has failed.\n");
7432 png_destroy_write_struct(&ping,&ping_info);
7433 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
7434 UnlockSemaphoreInfo(png_semaphore);
7436 if (mng_info->need_blob != MagickFalse)
7437 (void) CloseBlob(image);
7438 image_info=DestroyImageInfo(image_info);
7439 image=DestroyImage(image);
7440 return(MagickFalse);
7443 Prepare PNG for writing.
7445 #if defined(PNG_MNG_FEATURES_SUPPORTED)
7446 if (mng_info->write_mng)
7447 (void) png_permit_mng_features(ping,PNG_ALL_MNG_FEATURES);
7450 # ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
7451 if (mng_info->write_mng)
7452 png_permit_empty_plte(ping,MagickTrue);
7459 ping_width=(png_uint_32) image->columns;
7460 ping_height=(png_uint_32) image->rows;
7462 if (mng_info->write_png8 || mng_info->write_png24 || mng_info->write_png32)
7465 if (mng_info->write_png_depth != 0)
7466 image_depth=mng_info->write_png_depth;
7468 /* Adjust requested depth to next higher valid depth if necessary */
7469 if (image_depth > 8)
7472 if ((image_depth > 4) && (image_depth < 8))
7475 if (image_depth == 3)
7478 if (logging != MagickFalse)
7480 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7481 " width=%.20g",(double) ping_width);
7482 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7483 " height=%.20g",(double) ping_height);
7484 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7485 " image_matte=%.20g",(double) image->matte);
7486 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7487 " image->depth=%.20g",(double) image->depth);
7488 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7489 " Tentative ping_bit_depth=%.20g",(double) image_depth);
7492 save_image_depth=image_depth;
7493 ping_bit_depth=(png_byte) save_image_depth;
7496 #if defined(PNG_pHYs_SUPPORTED)
7497 if (ping_exclude_pHYs == MagickFalse)
7499 if ((image->x_resolution != 0) && (image->y_resolution != 0) &&
7500 (!mng_info->write_mng || !mng_info->equal_physs))
7502 if (logging != MagickFalse)
7503 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7504 " Setting up pHYs chunk");
7506 if (image->units == PixelsPerInchResolution)
7508 ping_pHYs_unit_type=PNG_RESOLUTION_METER;
7509 ping_pHYs_x_resolution=(png_uint_32) (100.0*image->x_resolution/2.54);
7510 ping_pHYs_y_resolution=(png_uint_32) (100.0*image->y_resolution/2.54);
7513 else if (image->units == PixelsPerCentimeterResolution)
7515 ping_pHYs_unit_type=PNG_RESOLUTION_METER;
7516 ping_pHYs_x_resolution=(png_uint_32) (100.0*image->x_resolution);
7517 ping_pHYs_y_resolution=(png_uint_32) (100.0*image->y_resolution);
7522 ping_pHYs_unit_type=PNG_RESOLUTION_UNKNOWN;
7523 ping_pHYs_x_resolution=(png_uint_32) image->x_resolution;
7524 ping_pHYs_y_resolution=(png_uint_32) image->y_resolution;
7527 ping_have_pHYs = MagickTrue;
7532 if (ping_exclude_bKGD == MagickFalse)
7534 if ((!mng_info->adjoin || !mng_info->equal_backgrounds))
7540 if (ping_bit_depth == 8)
7543 if (ping_bit_depth == 4)
7546 if (ping_bit_depth == 2)
7549 if (ping_bit_depth == 1)
7552 ping_background.red=(png_uint_16)
7553 (ScaleQuantumToShort(image->background_color.red) & mask);
7555 ping_background.green=(png_uint_16)
7556 (ScaleQuantumToShort(image->background_color.green) & mask);
7558 ping_background.blue=(png_uint_16)
7559 (ScaleQuantumToShort(image->background_color.blue) & mask);
7562 if (logging != MagickFalse)
7564 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7565 " Setting up bKGD chunk (1)");
7567 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7568 " ping_bit_depth=%d",ping_bit_depth);
7571 ping_have_bKGD = MagickTrue;
7575 Select the color type.
7580 if (mng_info->write_png8)
7583 /* TO DO: make this a function cause it's used twice, except
7584 for reducing the sample depth from 8. */
7586 number_colors=image_colors;
7588 ping_have_tRNS=MagickFalse;
7593 ping_color_type=(png_byte) PNG_COLOR_TYPE_PALETTE;
7595 if (logging != MagickFalse)
7596 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7597 " Setting up PLTE chunk with %d colors (%d)",
7598 number_colors, image_colors);
7600 for (i=0; i < (ssize_t) number_colors; i++)
7602 palette[i].red=ScaleQuantumToChar(image->colormap[i].red);
7603 palette[i].green=ScaleQuantumToChar(image->colormap[i].green);
7604 palette[i].blue=ScaleQuantumToChar(image->colormap[i].blue);
7605 if (logging != MagickFalse)
7606 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7607 #if MAGICKCORE_QUANTUM_DEPTH == 8
7608 " %3ld (%3d,%3d,%3d)",
7610 " %5ld (%5d,%5d,%5d)",
7612 (long) i,palette[i].red,palette[i].green,palette[i].blue);
7616 ping_have_PLTE=MagickTrue;
7617 image_depth=ping_bit_depth;
7620 if (matte != MagickFalse)
7623 Identify which colormap entry is transparent.
7625 assert(number_colors <= 256);
7626 assert(image->colormap != NULL);
7628 for (i=0; i < (ssize_t) number_transparent; i++)
7629 ping_trans_alpha[i]=0;
7631 /* PNG8 can't have semitransparent colors so we threshold them
7634 for (; i < (ssize_t) number_semitransparent; i++)
7635 ping_trans_alpha[i]=image->colormap[i].opacity >
7636 OpaqueOpacity/2 ? 0 : 255;
7638 ping_num_trans=(unsigned short) (number_transparent +
7639 number_semitransparent);
7641 if (ping_num_trans == 0)
7642 ping_have_tRNS=MagickFalse;
7645 ping_have_tRNS=MagickTrue;
7648 if (ping_exclude_bKGD == MagickFalse)
7651 * Identify which colormap entry is the background color.
7653 for (i=0; i < (ssize_t) MagickMax(1L*number_colors-1L,1L); i++)
7654 if (IsPNGColorEqual(ping_background,image->colormap[i]))
7657 ping_background.index=(png_byte) i;
7659 } /* end of write_png8 */
7661 else if (mng_info->write_png24)
7663 image_matte=MagickFalse;
7664 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB;
7667 else if (mng_info->write_png32)
7669 image_matte=MagickTrue;
7670 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB_ALPHA;
7673 else /* mng_info->write_pngNN not specified */
7675 image_depth=ping_bit_depth;
7677 if (mng_info->write_png_colortype != 0)
7679 ping_color_type=(png_byte) mng_info->write_png_colortype-1;
7681 if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA ||
7682 ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA)
7683 image_matte=MagickTrue;
7686 image_matte=MagickFalse;
7689 else /* write_ping_colortype not specified */
7691 if (logging != MagickFalse)
7692 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7693 " Selecting PNG colortype:");
7695 ping_color_type=(png_byte) ((matte != MagickFalse)?
7696 PNG_COLOR_TYPE_RGB_ALPHA:PNG_COLOR_TYPE_RGB);
7698 if (image_info->type == TrueColorType)
7700 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB;
7701 image_matte=MagickFalse;
7704 if (image_info->type == TrueColorMatteType)
7706 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB_ALPHA;
7707 image_matte=MagickTrue;
7710 if (image_info->type == PaletteType ||
7711 image_info->type == PaletteMatteType)
7712 ping_color_type=(png_byte) PNG_COLOR_TYPE_PALETTE;
7714 if (image_info->type == UndefinedType ||
7715 image_info->type == OptimizeType)
7717 if (ping_have_color == MagickFalse)
7719 if (image_matte == MagickFalse)
7721 ping_color_type=(png_byte) PNG_COLOR_TYPE_GRAY;
7722 image_matte=MagickFalse;
7727 ping_color_type=(png_byte) PNG_COLOR_TYPE_GRAY_ALPHA;
7728 image_matte=MagickTrue;
7733 if (image_matte == MagickFalse)
7735 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB;
7736 image_matte=MagickFalse;
7741 ping_color_type=(png_byte) PNG_COLOR_TYPE_RGBA;
7742 image_matte=MagickTrue;
7749 if (logging != MagickFalse)
7750 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7751 " Selected PNG colortype=%d",ping_color_type);
7753 if (ping_bit_depth < 8)
7755 if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA ||
7756 ping_color_type == PNG_COLOR_TYPE_RGB ||
7757 ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA)
7761 old_bit_depth=ping_bit_depth;
7763 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
7765 if (image->matte == MagickFalse && image->colors < 256)
7767 if (ImageIsMonochrome(image))
7774 if (ping_color_type == PNG_COLOR_TYPE_PALETTE)
7779 if (image->colors == 0)
7782 (void) ThrowMagickException(&image->exception,
7783 GetMagickModule(),CoderError,
7784 "image has 0 colors", "`%s'","");
7787 while ((int) (one << ping_bit_depth) < (ssize_t) image_colors)
7788 ping_bit_depth <<= 1;
7791 if (logging != MagickFalse)
7793 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7794 " Number of colors: %.20g",(double) image_colors);
7796 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7797 " Tentative PNG bit depth: %d",ping_bit_depth);
7800 if (ping_bit_depth < (int) mng_info->write_png_depth)
7801 ping_bit_depth = mng_info->write_png_depth;
7804 image_depth=ping_bit_depth;
7806 if (logging != MagickFalse)
7808 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7809 " Tentative PNG color type: %.20g",(double) ping_color_type);
7811 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7812 " image_info->type: %.20g",(double) image_info->type);
7814 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7815 " image_depth: %.20g",(double) image_depth);
7817 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7819 " image->depth: %.20g",(double) image->depth);
7821 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7822 " ping_bit_depth: %.20g",(double) ping_bit_depth);
7825 if (matte != MagickFalse)
7827 if (mng_info->IsPalette)
7830 ping_color_type=PNG_COLOR_TYPE_GRAY_ALPHA;
7832 if (ping_have_color != MagickFalse)
7833 ping_color_type=PNG_COLOR_TYPE_RGBA;
7836 * Determine if there is any transparent color.
7838 if (number_transparent + number_semitransparent == 0)
7841 No transparent pixels are present. Change 4 or 6 to 0 or 2.
7844 image_matte=MagickFalse;
7845 ping_color_type&=0x03;
7855 if (ping_bit_depth == 8)
7858 if (ping_bit_depth == 4)
7861 if (ping_bit_depth == 2)
7864 if (ping_bit_depth == 1)
7867 ping_trans_color.red=(png_uint_16)
7868 (ScaleQuantumToShort(image->colormap[0].red) & mask);
7870 ping_trans_color.green=(png_uint_16)
7871 (ScaleQuantumToShort(image->colormap[0].green) & mask);
7873 ping_trans_color.blue=(png_uint_16)
7874 (ScaleQuantumToShort(image->colormap[0].blue) & mask);
7876 ping_trans_color.gray=(png_uint_16)
7877 (ScaleQuantumToShort(PixelIntensityToQuantum(
7878 image->colormap)) & mask);
7880 ping_trans_color.index=(png_byte) 0;
7882 ping_have_tRNS=MagickTrue;
7885 if (ping_have_tRNS != MagickFalse)
7888 Determine if there is one and only one transparent color
7889 and if so if it is fully transparent.
7891 if (logging != MagickFalse)
7892 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7893 " Is there a single fully transparent color?");
7895 if (number_transparent > 1 || number_semitransparent > 0)
7897 ping_have_tRNS = MagickFalse;
7898 if (logging != MagickFalse)
7899 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7904 if (logging != MagickFalse)
7905 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7906 " ... Yes: (%d,%d,%d), (gray: %d)",
7907 (int) ping_trans_color.red,
7908 (int) ping_trans_color.green,
7909 (int) ping_trans_color.blue,
7910 (int) ping_trans_color.gray);
7914 if (ping_have_tRNS != MagickFalse)
7916 ping_color_type &= 0x03; /* changes 4 or 6 to 0 or 2 */
7918 if (image_depth == 8)
7920 ping_trans_color.red&=0xff;
7921 ping_trans_color.green&=0xff;
7922 ping_trans_color.blue&=0xff;
7923 ping_trans_color.gray&=0xff;
7929 if (image_depth == 8)
7931 ping_trans_color.red&=0xff;
7932 ping_trans_color.green&=0xff;
7933 ping_trans_color.blue&=0xff;
7934 ping_trans_color.gray&=0xff;
7941 if (ping_have_tRNS != MagickFalse)
7942 image_matte=MagickFalse;
7944 if ((mng_info->IsPalette) &&
7945 mng_info->write_png_colortype-1 != PNG_COLOR_TYPE_PALETTE &&
7946 ImageIsGray(image) && (image_matte == MagickFalse || image_depth >= 8))
7950 if (image_matte != MagickFalse)
7951 ping_color_type=PNG_COLOR_TYPE_GRAY_ALPHA;
7955 ping_color_type=PNG_COLOR_TYPE_GRAY;
7957 if (save_image_depth == 16 && image_depth == 8)
7959 if (logging != MagickFalse)
7961 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
7962 " Scaling ping_trans_color (0)");
7964 ping_trans_color.gray*=0x0101;
7968 if (image_depth > MAGICKCORE_QUANTUM_DEPTH)
7969 image_depth=MAGICKCORE_QUANTUM_DEPTH;
7971 if (image_colors == 0 || image_colors-1 > MaxColormapSize)
7972 image_colors=(int) (one << image_depth);
7974 if (image_depth > 8)
7980 if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
7982 if(!mng_info->write_png_depth)
7986 while ((int) (one << ping_bit_depth)
7987 < (ssize_t) image_colors)
7988 ping_bit_depth <<= 1;
7992 else if (ping_color_type ==
7993 PNG_COLOR_TYPE_GRAY && image_colors < 17 &&
7994 mng_info->IsPalette)
7997 /* Check if grayscale is reducible */
7999 depth_4_ok=MagickTrue,
8000 depth_2_ok=MagickTrue,
8001 depth_1_ok=MagickTrue;
8003 for (i=0; i < (ssize_t) image_colors; i++)
8008 intensity=ScaleQuantumToChar(image->colormap[i].red);
8010 if ((intensity & 0x0f) != ((intensity & 0xf0) >> 4))
8011 depth_4_ok=depth_2_ok=depth_1_ok=MagickFalse;
8013 else if ((intensity & 0x03) != ((intensity & 0x0c) >> 2))
8014 depth_2_ok=depth_1_ok=MagickFalse;
8016 else if ((intensity & 0x01) != ((intensity & 0x02) >> 1))
8017 depth_1_ok=MagickFalse;
8020 if (depth_1_ok && mng_info->write_png_depth <= 1)
8023 else if (depth_2_ok && mng_info->write_png_depth <= 2)
8026 else if (depth_4_ok && mng_info->write_png_depth <= 4)
8031 image_depth=ping_bit_depth;
8036 if (mng_info->IsPalette)
8038 number_colors=image_colors;
8040 if (image_depth <= 8)
8045 ping_color_type=(png_byte) PNG_COLOR_TYPE_PALETTE;
8047 if (mng_info->have_write_global_plte && matte == MagickFalse)
8049 png_set_PLTE(ping,ping_info,NULL,0);
8051 if (logging != MagickFalse)
8052 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8053 " Setting up empty PLTE chunk");
8058 for (i=0; i < (ssize_t) number_colors; i++)
8060 palette[i].red=ScaleQuantumToChar(image->colormap[i].red);
8061 palette[i].green=ScaleQuantumToChar(image->colormap[i].green);
8062 palette[i].blue=ScaleQuantumToChar(image->colormap[i].blue);
8065 if (logging != MagickFalse)
8066 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8067 " Setting up PLTE chunk with %d colors",
8070 ping_have_PLTE=MagickTrue;
8073 /* color_type is PNG_COLOR_TYPE_PALETTE */
8074 if (mng_info->write_png_depth == 0)
8082 while ((one << ping_bit_depth) < number_colors)
8083 ping_bit_depth <<= 1;
8088 if (matte != MagickFalse)
8091 * Set up trans_colors array.
8093 assert(number_colors <= 256);
8095 ping_num_trans=(unsigned short) (number_transparent +
8096 number_semitransparent);
8098 if (ping_num_trans == 0)
8099 ping_have_tRNS=MagickFalse;
8103 if (logging != MagickFalse)
8105 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8106 " Scaling ping_trans_color (1)");
8108 ping_have_tRNS=MagickTrue;
8110 for (i=0; i < ping_num_trans; i++)
8112 ping_trans_alpha[i]= (png_byte) (255-
8113 ScaleQuantumToChar(image->colormap[i].opacity));
8123 if (image_depth < 8)
8126 if ((save_image_depth == 16) && (image_depth == 8))
8128 if (logging != MagickFalse)
8130 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8131 " Scaling ping_trans_color from (%d,%d,%d)",
8132 (int) ping_trans_color.red,
8133 (int) ping_trans_color.green,
8134 (int) ping_trans_color.blue);
8137 ping_trans_color.red*=0x0101;
8138 ping_trans_color.green*=0x0101;
8139 ping_trans_color.blue*=0x0101;
8140 ping_trans_color.gray*=0x0101;
8142 if (logging != MagickFalse)
8144 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8146 (int) ping_trans_color.red,
8147 (int) ping_trans_color.green,
8148 (int) ping_trans_color.blue);
8153 if (ping_bit_depth < (ssize_t) mng_info->write_png_depth)
8154 ping_bit_depth = (ssize_t) mng_info->write_png_depth;
8157 Adjust background and transparency samples in sub-8-bit grayscale files.
8159 if (ping_bit_depth < 8 && ping_color_type ==
8160 PNG_COLOR_TYPE_GRAY)
8168 maxval=(png_uint_16) ((one << ping_bit_depth)-1);
8170 if (ping_exclude_bKGD == MagickFalse)
8173 ping_background.gray=(png_uint_16)
8174 (QuantumScale*(maxval*(PixelIntensity(&image->background_color))));
8176 if (logging != MagickFalse)
8177 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8178 " Setting up bKGD chunk (2)");
8180 ping_have_bKGD = MagickTrue;
8183 ping_trans_color.gray=(png_uint_16) (QuantumScale*(maxval*
8184 ping_trans_color.gray));
8187 if (ping_exclude_bKGD == MagickFalse)
8189 if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
8192 Identify which colormap entry is the background color.
8195 number_colors=image_colors;
8197 for (i=0; i < (ssize_t) MagickMax(1L*number_colors,1L); i++)
8198 if (IsPNGColorEqual(image->background_color,image->colormap[i]))
8201 ping_background.index=(png_byte) i;
8203 if (logging != MagickFalse)
8205 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8206 " Setting up bKGD chunk with index=%d",(int) i);
8209 if (i < (ssize_t) number_colors)
8211 ping_have_bKGD = MagickTrue;
8213 if (logging != MagickFalse)
8215 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8216 " background =(%d,%d,%d)",
8217 (int) ping_background.red,
8218 (int) ping_background.green,
8219 (int) ping_background.blue);
8223 else /* Can't happen */
8225 if (logging != MagickFalse)
8226 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8227 " No room in PLTE to add bKGD color");
8228 ping_have_bKGD = MagickFalse;
8233 if (logging != MagickFalse)
8234 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8235 " PNG color type: %d",ping_color_type);
8237 Initialize compression level and filtering.
8239 if (logging != MagickFalse)
8241 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8242 " Setting up deflate compression");
8244 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8245 " Compression buffer size: 32768");
8248 png_set_compression_buffer_size(ping,32768L);
8250 if (logging != MagickFalse)
8251 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8252 " Compression mem level: 9");
8254 png_set_compression_mem_level(ping, 9);
8256 quality=image->quality == UndefinedCompressionQuality ? 75UL :
8264 level=(int) MagickMin((ssize_t) quality/10,9);
8266 if (logging != MagickFalse)
8267 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8268 " Compression level: %d",level);
8270 png_set_compression_level(ping,level);
8275 if (logging != MagickFalse)
8276 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8277 " Compression strategy: Z_HUFFMAN_ONLY");
8279 png_set_compression_strategy(ping, Z_HUFFMAN_ONLY);
8282 if (logging != MagickFalse)
8283 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8284 " Setting up filtering");
8286 #if defined(PNG_MNG_FEATURES_SUPPORTED) && defined(PNG_INTRAPIXEL_DIFFERENCING)
8287 /* This became available in libpng-1.0.9. Output must be a MNG. */
8288 if (mng_info->write_mng && ((quality % 10) == 7))
8290 if (logging != MagickFalse)
8291 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8292 " Filter_type: PNG_INTRAPIXEL_DIFFERENCING");
8294 ping_filter_method=PNG_INTRAPIXEL_DIFFERENCING;
8298 if (logging != MagickFalse)
8299 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8307 if ((quality % 10) > 5)
8308 base_filter=PNG_ALL_FILTERS;
8311 if ((quality % 10) != 5)
8312 base_filter=(int) quality % 10;
8315 if (((int) ping_color_type == PNG_COLOR_TYPE_GRAY) ||
8316 ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE) ||
8318 base_filter=PNG_NO_FILTERS;
8321 base_filter=PNG_ALL_FILTERS;
8323 if (logging != MagickFalse)
8325 if (base_filter == PNG_ALL_FILTERS)
8326 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8327 " Base filter method: ADAPTIVE");
8329 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8330 " Base filter method: NONE");
8333 png_set_filter(ping,PNG_FILTER_TYPE_BASE,base_filter);
8336 if (ping_exclude_iCCP == MagickFalse || ping_exclude_zCCP == MagickFalse)
8338 ResetImageProfileIterator(image);
8339 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
8341 profile=GetImageProfile(image,name);
8343 if (profile != (StringInfo *) NULL)
8345 #ifdef PNG_WRITE_iCCP_SUPPORTED
8346 if ((LocaleCompare(name,"ICC") == 0) ||
8347 (LocaleCompare(name,"ICM") == 0))
8350 if (ping_exclude_iCCP == MagickFalse)
8352 png_set_iCCP(ping,ping_info,(const png_charp) name,0,
8353 #if (PNG_LIBPNG_VER < 10500)
8354 (png_charp) GetStringInfoDatum(profile),
8356 (png_const_bytep) GetStringInfoDatum(profile),
8358 (png_uint_32) GetStringInfoLength(profile));
8364 if (ping_exclude_zCCP == MagickFalse)
8366 png_write_raw_profile(image_info,ping,ping_info,
8367 (unsigned char *) name,(unsigned char *) name,
8368 GetStringInfoDatum(profile),
8369 (png_uint_32) GetStringInfoLength(profile));
8373 if (logging != MagickFalse)
8374 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8375 " Setting up text chunk with %s profile",name);
8377 name=GetNextImageProfile(image);
8381 #if defined(PNG_WRITE_sRGB_SUPPORTED)
8382 if ((mng_info->have_write_global_srgb == 0) &&
8383 ((image->rendering_intent != UndefinedIntent) ||
8384 (image->colorspace == sRGBColorspace)))
8386 if (ping_exclude_sRGB == MagickFalse)
8389 Note image rendering intent.
8391 if (logging != MagickFalse)
8392 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8393 " Setting up sRGB chunk");
8395 (void) png_set_sRGB(ping,ping_info,(
8396 PNG_RenderingIntent_from_Magick_RenderingIntent(
8397 image->rendering_intent)));
8399 if (ping_exclude_gAMA == MagickFalse)
8400 png_set_gAMA(ping,ping_info,0.45455);
8404 if ((!mng_info->write_mng) || (!png_get_valid(ping,ping_info,PNG_INFO_sRGB)))
8407 if (ping_exclude_gAMA == MagickFalse &&
8408 (ping_exclude_sRGB == MagickFalse ||
8409 (image->gamma < .45 || image->gamma > .46)))
8411 if ((mng_info->have_write_global_gama == 0) && (image->gamma != 0.0))
8415 To do: check for cHRM+gAMA == sRGB, and write sRGB instead.
8417 if (logging != MagickFalse)
8418 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8419 " Setting up gAMA chunk");
8421 png_set_gAMA(ping,ping_info,image->gamma);
8425 if (ping_exclude_cHRM == MagickFalse)
8427 if ((mng_info->have_write_global_chrm == 0) &&
8428 (image->chromaticity.red_primary.x != 0.0))
8431 Note image chromaticity.
8432 To do: check for cHRM+gAMA == sRGB, and write sRGB instead.
8440 wp=image->chromaticity.white_point;
8441 rp=image->chromaticity.red_primary;
8442 gp=image->chromaticity.green_primary;
8443 bp=image->chromaticity.blue_primary;
8445 if (logging != MagickFalse)
8446 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8447 " Setting up cHRM chunk");
8449 png_set_cHRM(ping,ping_info,wp.x,wp.y,rp.x,rp.y,gp.x,gp.y,
8455 ping_interlace_method=image_info->interlace != NoInterlace;
8457 if (mng_info->write_mng)
8458 png_set_sig_bytes(ping,8);
8460 /* Bail out if cannot meet defined PNG:bit-depth or PNG:color-type */
8462 if (mng_info->write_png_colortype != 0)
8464 if (mng_info->write_png_colortype-1 == PNG_COLOR_TYPE_GRAY)
8465 if (ImageIsGray(image) == MagickFalse)
8467 ping_color_type = PNG_COLOR_TYPE_RGB;
8469 if (ping_bit_depth < 8)
8473 if (mng_info->write_png_colortype-1 == PNG_COLOR_TYPE_GRAY_ALPHA)
8474 if (ImageIsGray(image) == MagickFalse)
8475 ping_color_type = PNG_COLOR_TYPE_RGB_ALPHA;
8478 if (ping_need_colortype_warning != MagickFalse ||
8479 ((mng_info->write_png_depth &&
8480 (int) mng_info->write_png_depth != ping_bit_depth) ||
8481 (mng_info->write_png_colortype &&
8482 ((int) mng_info->write_png_colortype-1 != ping_color_type &&
8483 mng_info->write_png_colortype != 7 &&
8484 !(mng_info->write_png_colortype == 5 && ping_color_type == 0)))))
8486 if (logging != MagickFalse)
8488 if (ping_need_colortype_warning != MagickFalse)
8490 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8491 " Image has transparency but tRNS chunk was excluded");
8494 if (mng_info->write_png_depth)
8496 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8497 " Defined PNG:bit-depth=%u, Computed depth=%u",
8498 mng_info->write_png_depth,
8502 if (mng_info->write_png_colortype)
8504 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8505 " Defined PNG:color-type=%u, Computed color type=%u",
8506 mng_info->write_png_colortype-1,
8512 "Cannot write image with defined PNG:bit-depth or PNG:color-type.");
8515 if (image_matte != MagickFalse && image->matte == MagickFalse)
8517 /* Add an opaque matte channel */
8518 image->matte = MagickTrue;
8519 (void) SetImageOpacity(image,0);
8521 if (logging != MagickFalse)
8522 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8523 " Added an opaque matte channel");
8526 if (image->matte == MagickTrue)
8528 if (ping_color_type < 4)
8529 if (ping_color_type != 3 || ping_num_trans > 0)
8531 ping_have_tRNS=MagickTrue;
8532 if (logging != MagickFalse)
8533 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8534 " Setting ping_have_tRNS=MagickTrue.");
8538 if (logging != MagickFalse)
8539 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8540 " Writing PNG header chunks");
8542 png_set_IHDR(ping,ping_info,ping_width,ping_height,
8543 ping_bit_depth,ping_color_type,
8544 ping_interlace_method,ping_compression_method,
8545 ping_filter_method);
8547 if (ping_color_type == 3 && ping_have_PLTE != MagickFalse)
8549 png_set_PLTE(ping,ping_info,palette,number_colors);
8551 if (logging != MagickFalse)
8553 for (i=0; i< (ssize_t) number_colors; i++)
8555 if (i < ping_num_trans)
8556 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8557 " PLTE[%d] = (%d,%d,%d), tRNS[%d] = (%d)",
8559 (int) palette[i].red,
8560 (int) palette[i].green,
8561 (int) palette[i].blue,
8563 (int) ping_trans_alpha[i]);
8565 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8566 " PLTE[%d] = (%d,%d,%d)",
8568 (int) palette[i].red,
8569 (int) palette[i].green,
8570 (int) palette[i].blue);
8575 if (ping_exclude_bKGD == MagickFalse)
8577 if (ping_have_bKGD != MagickFalse)
8578 png_set_bKGD(ping,ping_info,&ping_background);
8581 if (ping_exclude_pHYs == MagickFalse)
8583 if (ping_have_pHYs != MagickFalse)
8585 png_set_pHYs(ping,ping_info,
8586 ping_pHYs_x_resolution,
8587 ping_pHYs_y_resolution,
8588 ping_pHYs_unit_type);
8592 #if defined(PNG_oFFs_SUPPORTED)
8593 if (ping_exclude_oFFs == MagickFalse)
8595 if (image->page.x || image->page.y)
8597 png_set_oFFs(ping,ping_info,(png_int_32) image->page.x,
8598 (png_int_32) image->page.y, 0);
8600 if (logging != MagickFalse)
8601 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8602 " Setting up oFFs chunk with x=%d, y=%d, units=0",
8603 (int) image->page.x, (int) image->page.y);
8608 png_write_info_before_PLTE(ping, ping_info);
8610 if (ping_have_tRNS != MagickFalse && ping_color_type < 4)
8612 if (logging != MagickFalse)
8614 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8615 " Calling png_set_tRNS with num_trans=%d",ping_num_trans);
8618 if (ping_color_type == 3)
8619 (void) png_set_tRNS(ping, ping_info,
8626 (void) png_set_tRNS(ping, ping_info,
8631 if (logging != MagickFalse)
8633 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8634 " tRNS color =(%d,%d,%d)",
8635 (int) ping_trans_color.red,
8636 (int) ping_trans_color.green,
8637 (int) ping_trans_color.blue);
8642 /* write any png-chunk-b profiles */
8643 (void) png_write_chunk_from_profile(image,"PNG-chunk-b",logging);
8644 png_write_info(ping,ping_info);
8646 /* write any PNG-chunk-m profiles */
8647 (void) png_write_chunk_from_profile(image,"PNG-chunk-m",logging);
8649 if (ping_exclude_vpAg == MagickFalse)
8651 if ((image->page.width != 0 && image->page.width != image->columns) ||
8652 (image->page.height != 0 && image->page.height != image->rows))
8657 (void) WriteBlobMSBULong(image,9L); /* data length=8 */
8658 PNGType(chunk,mng_vpAg);
8659 LogPNGChunk(logging,mng_vpAg,9L);
8660 PNGLong(chunk+4,(png_uint_32) image->page.width);
8661 PNGLong(chunk+8,(png_uint_32) image->page.height);
8662 chunk[12]=0; /* unit = pixels */
8663 (void) WriteBlob(image,13,chunk);
8664 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
8668 #if (PNG_LIBPNG_VER == 10206)
8669 /* avoid libpng-1.2.6 bug by setting PNG_HAVE_IDAT flag */
8670 #define PNG_HAVE_IDAT 0x04
8671 ping->mode |= PNG_HAVE_IDAT;
8672 #undef PNG_HAVE_IDAT
8675 png_set_packing(ping);
8679 rowbytes=image->columns;
8680 if (image_depth > 8)
8682 switch (ping_color_type)
8684 case PNG_COLOR_TYPE_RGB:
8688 case PNG_COLOR_TYPE_GRAY_ALPHA:
8692 case PNG_COLOR_TYPE_RGBA:
8700 if (logging != MagickFalse)
8702 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8703 " Writing PNG image data");
8705 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8706 " Allocating %.20g bytes of memory for pixels",(double) rowbytes);
8708 png_pixels=(unsigned char *) AcquireQuantumMemory(rowbytes,
8709 sizeof(*png_pixels));
8711 if (png_pixels == (unsigned char *) NULL)
8712 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
8715 Initialize image scanlines.
8717 if (setjmp(png_jmpbuf(ping)))
8723 if (image_info->verbose)
8724 (void) printf("PNG write has failed.\n");
8726 png_destroy_write_struct(&ping,&ping_info);
8727 if (quantum_info != (QuantumInfo *) NULL)
8728 quantum_info=DestroyQuantumInfo(quantum_info);
8729 if (png_pixels != (unsigned char *) NULL)
8730 png_pixels=(unsigned char *) RelinquishMagickMemory(png_pixels);
8731 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
8732 UnlockSemaphoreInfo(png_semaphore);
8734 if (mng_info->need_blob != MagickFalse)
8735 (void) CloseBlob(image);
8736 image_info=DestroyImageInfo(image_info);
8737 image=DestroyImage(image);
8738 return(MagickFalse);
8740 quantum_info=AcquireQuantumInfo(image_info,image);
8741 if (quantum_info == (QuantumInfo *) NULL)
8742 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
8743 quantum_info->format=UndefinedQuantumFormat;
8744 quantum_info->depth=image_depth;
8745 num_passes=png_set_interlace_handling(ping);
8747 if ((!mng_info->write_png8 && !mng_info->write_png24 &&
8748 !mng_info->write_png32) &&
8749 (mng_info->IsPalette ||
8750 (image_info->type == BilevelType)) &&
8751 image_matte == MagickFalse && ImageIsMonochrome(image))
8753 /* Palette, Bilevel, or Opaque Monochrome */
8754 register const PixelPacket
8757 quantum_info->depth=8;
8758 for (pass=0; pass < num_passes; pass++)
8761 Convert PseudoClass image to a PNG monochrome image.
8763 for (y=0; y < (ssize_t) image->rows; y++)
8766 if (logging != MagickFalse)
8767 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8768 " Writing row of pixels (0)");
8770 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
8772 if (p == (const PixelPacket *) NULL)
8775 if (mng_info->IsPalette)
8777 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8778 quantum_info,GrayQuantum,png_pixels,&image->exception);
8779 if (mng_info->write_png_colortype-1 == PNG_COLOR_TYPE_PALETTE &&
8780 mng_info->write_png_depth &&
8781 mng_info->write_png_depth != old_bit_depth)
8783 /* Undo pixel scaling */
8784 for (i=0; i < (ssize_t) image->columns; i++)
8785 *(png_pixels+i)=(unsigned char) (*(png_pixels+i)
8786 >> (8-old_bit_depth));
8792 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8793 quantum_info,RedQuantum,png_pixels,&image->exception);
8796 if (mng_info->write_png_colortype-1 != PNG_COLOR_TYPE_PALETTE)
8797 for (i=0; i < (ssize_t) image->columns; i++)
8798 *(png_pixels+i)=(unsigned char) ((*(png_pixels+i) > 127) ?
8801 if (logging != MagickFalse && y == 0)
8802 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8803 " Writing row of pixels (1)");
8805 png_write_row(ping,png_pixels);
8807 if (image->previous == (Image *) NULL)
8809 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
8810 if (status == MagickFalse)
8816 else /* Not Palette, Bilevel, or Opaque Monochrome */
8818 if ((!mng_info->write_png8 && !mng_info->write_png24 &&
8819 !mng_info->write_png32) &&
8820 (image_matte != MagickFalse ||
8821 (ping_bit_depth >= MAGICKCORE_QUANTUM_DEPTH)) &&
8822 (mng_info->IsPalette) && ImageIsGray(image))
8824 register const PixelPacket
8827 for (pass=0; pass < num_passes; pass++)
8830 for (y=0; y < (ssize_t) image->rows; y++)
8832 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
8834 if (p == (const PixelPacket *) NULL)
8837 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
8839 if (mng_info->IsPalette)
8840 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8841 quantum_info,GrayQuantum,png_pixels,&image->exception);
8844 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8845 quantum_info,RedQuantum,png_pixels,&image->exception);
8847 if (logging != MagickFalse && y == 0)
8848 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8849 " Writing GRAY PNG pixels (2)");
8852 else /* PNG_COLOR_TYPE_GRAY_ALPHA */
8854 if (logging != MagickFalse && y == 0)
8855 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8856 " Writing GRAY_ALPHA PNG pixels (2)");
8858 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8859 quantum_info,GrayAlphaQuantum,png_pixels,&image->exception);
8862 if (logging != MagickFalse && y == 0)
8863 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8864 " Writing row of pixels (2)");
8866 png_write_row(ping,png_pixels);
8869 if (image->previous == (Image *) NULL)
8871 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
8872 if (status == MagickFalse)
8880 register const PixelPacket
8883 for (pass=0; pass < num_passes; pass++)
8885 if ((image_depth > 8) || (mng_info->write_png24 ||
8886 mng_info->write_png32 ||
8887 (!mng_info->write_png8 && !mng_info->IsPalette)))
8889 for (y=0; y < (ssize_t) image->rows; y++)
8891 p=GetVirtualPixels(image,0,y,image->columns,1,
8894 if (p == (const PixelPacket *) NULL)
8897 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
8899 if (image->storage_class == DirectClass)
8900 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8901 quantum_info,RedQuantum,png_pixels,&image->exception);
8904 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8905 quantum_info,GrayQuantum,png_pixels,&image->exception);
8908 else if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
8910 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8911 quantum_info,GrayAlphaQuantum,png_pixels,
8914 if (logging != MagickFalse && y == 0)
8915 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8916 " Writing GRAY_ALPHA PNG pixels (3)");
8919 else if (image_matte != MagickFalse)
8920 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8921 quantum_info,RGBAQuantum,png_pixels,&image->exception);
8924 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8925 quantum_info,RGBQuantum,png_pixels,&image->exception);
8927 if (logging != MagickFalse && y == 0)
8928 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8929 " Writing row of pixels (3)");
8931 png_write_row(ping,png_pixels);
8936 /* not ((image_depth > 8) || (mng_info->write_png24 ||
8937 mng_info->write_png32 ||
8938 (!mng_info->write_png8 && !mng_info->IsPalette))) */
8940 if ((ping_color_type != PNG_COLOR_TYPE_GRAY) &&
8941 (ping_color_type != PNG_COLOR_TYPE_GRAY_ALPHA))
8943 if (logging != MagickFalse)
8944 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8945 " pass %d, Image Is not GRAY or GRAY_ALPHA",pass);
8947 quantum_info->depth=8;
8951 for (y=0; y < (ssize_t) image->rows; y++)
8953 if (logging != MagickFalse && y == 0)
8954 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8955 " pass %d, Image Is RGB, 16-bit GRAY, or GRAY_ALPHA",pass);
8957 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
8959 if (p == (const PixelPacket *) NULL)
8962 if (ping_color_type == PNG_COLOR_TYPE_GRAY)
8963 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8964 quantum_info,GrayQuantum,png_pixels,&image->exception);
8966 else if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
8968 if (logging != MagickFalse && y == 0)
8969 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8970 " Writing GRAY_ALPHA PNG pixels (4)");
8972 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8973 quantum_info,GrayAlphaQuantum,png_pixels,
8978 (void) ExportQuantumPixels(image,(const CacheView *) NULL,
8979 quantum_info,IndexQuantum,png_pixels,&image->exception);
8981 if (logging != MagickFalse && y <= 2)
8983 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8984 " Writing row of pixels (4)");
8986 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
8987 " png_pixels[0]=%d,png_pixels[1]=%d",
8988 (int)png_pixels[0],(int)png_pixels[1]);
8990 png_write_row(ping,png_pixels);
8994 if (image->previous == (Image *) NULL)
8996 status=SetImageProgress(image,LoadImageTag,pass,num_passes);
8997 if (status == MagickFalse)
9004 if (quantum_info != (QuantumInfo *) NULL)
9005 quantum_info=DestroyQuantumInfo(quantum_info);
9007 if (logging != MagickFalse)
9009 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9010 " Wrote PNG image data");
9012 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9013 " Width: %.20g",(double) ping_width);
9015 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9016 " Height: %.20g",(double) ping_height);
9018 if (mng_info->write_png_depth)
9020 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9021 " Defined PNG:bit-depth: %d",mng_info->write_png_depth);
9024 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9025 " PNG bit-depth written: %d",ping_bit_depth);
9027 if (mng_info->write_png_colortype)
9029 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9030 " Defined PNG:color-type: %d",mng_info->write_png_colortype-1);
9033 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9034 " PNG color-type written: %d",ping_color_type);
9036 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9037 " PNG Interlace method: %d",ping_interlace_method);
9040 Generate text chunks.
9042 if (ping_exclude_tEXt == MagickFalse && ping_exclude_zTXt == MagickFalse)
9044 ResetImagePropertyIterator(image);
9045 property=GetNextImageProperty(image);
9046 while (property != (const char *) NULL)
9051 value=GetImageProperty(image,property);
9052 if (value != (const char *) NULL)
9054 text=(png_textp) png_malloc(ping,(png_uint_32) sizeof(png_text));
9055 text[0].key=(char *) property;
9056 text[0].text=(char *) value;
9057 text[0].text_length=strlen(value);
9059 if (ping_exclude_tEXt != MagickFalse)
9060 text[0].compression=PNG_TEXT_COMPRESSION_zTXt;
9062 else if (ping_exclude_zTXt != MagickFalse)
9063 text[0].compression=PNG_TEXT_COMPRESSION_NONE;
9067 text[0].compression=image_info->compression == NoCompression ||
9068 (image_info->compression == UndefinedCompression &&
9069 text[0].text_length < 128) ? PNG_TEXT_COMPRESSION_NONE :
9070 PNG_TEXT_COMPRESSION_zTXt ;
9073 if (logging != MagickFalse)
9075 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9076 " Setting up text chunk");
9078 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9079 " keyword: %s",text[0].key);
9082 png_set_text(ping,ping_info,text,1);
9083 png_free(ping,text);
9085 property=GetNextImageProperty(image);
9089 /* write any PNG-chunk-e profiles */
9090 (void) png_write_chunk_from_profile(image,"PNG-chunk-e",logging);
9092 if (logging != MagickFalse)
9093 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9094 " Writing PNG end info");
9096 png_write_end(ping,ping_info);
9098 if (mng_info->need_fram && (int) image->dispose == BackgroundDispose)
9100 if (mng_info->page.x || mng_info->page.y ||
9101 (ping_width != mng_info->page.width) ||
9102 (ping_height != mng_info->page.height))
9108 Write FRAM 4 with clipping boundaries followed by FRAM 1.
9110 (void) WriteBlobMSBULong(image,27L); /* data length=27 */
9111 PNGType(chunk,mng_FRAM);
9112 LogPNGChunk(logging,mng_FRAM,27L);
9114 chunk[5]=0; /* frame name separator (no name) */
9115 chunk[6]=1; /* flag for changing delay, for next frame only */
9116 chunk[7]=0; /* flag for changing frame timeout */
9117 chunk[8]=1; /* flag for changing frame clipping for next frame */
9118 chunk[9]=0; /* flag for changing frame sync_id */
9119 PNGLong(chunk+10,(png_uint_32) (0L)); /* temporary 0 delay */
9120 chunk[14]=0; /* clipping boundaries delta type */
9121 PNGLong(chunk+15,(png_uint_32) (mng_info->page.x)); /* left cb */
9123 (png_uint_32) (mng_info->page.x + ping_width));
9124 PNGLong(chunk+23,(png_uint_32) (mng_info->page.y)); /* top cb */
9126 (png_uint_32) (mng_info->page.y + ping_height));
9127 (void) WriteBlob(image,31,chunk);
9128 (void) WriteBlobMSBULong(image,crc32(0,chunk,31));
9129 mng_info->old_framing_mode=4;
9130 mng_info->framing_mode=1;
9134 mng_info->framing_mode=3;
9136 if (mng_info->write_mng && !mng_info->need_fram &&
9137 ((int) image->dispose == 3))
9138 (void) ThrowMagickException(&image->exception,GetMagickModule(),
9139 CoderError,"Cannot convert GIF with disposal method 3 to MNG-LC",
9140 "`%s'",image->filename);
9146 png_destroy_write_struct(&ping,&ping_info);
9148 png_pixels=(unsigned char *) RelinquishMagickMemory(png_pixels);
9150 #if defined(PNG_SETJMP_NOT_THREAD_SAFE)
9151 UnlockSemaphoreInfo(png_semaphore);
9154 if (mng_info->need_blob != MagickFalse)
9155 (void) CloseBlob(image);
9157 image_info=DestroyImageInfo(image_info);
9158 image=DestroyImage(image);
9160 /* Store bit depth actually written */
9161 s[0]=(char) ping_bit_depth;
9164 (void) SetImageProperty(IMimage,"png:bit-depth-written",s);
9166 if (logging != MagickFalse)
9167 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9168 " exit WriteOnePNGImage()");
9171 /* End write one PNG image */
9175 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9179 % W r i t e P N G I m a g e %
9183 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9185 % WritePNGImage() writes a Portable Network Graphics (PNG) or
9186 % Multiple-image Network Graphics (MNG) image file.
9188 % MNG support written by Glenn Randers-Pehrson, glennrp@image...
9190 % The format of the WritePNGImage method is:
9192 % MagickBooleanType WritePNGImage(const ImageInfo *image_info,Image *image)
9194 % A description of each parameter follows:
9196 % o image_info: the image info.
9198 % o image: The image.
9200 % Returns MagickTrue on success, MagickFalse on failure.
9202 % Communicating with the PNG encoder:
9204 % While the datastream written is always in PNG format and normally would
9205 % be given the "png" file extension, this method also writes the following
9206 % pseudo-formats which are subsets of PNG:
9208 % o PNG8: An 8-bit indexed PNG datastream is written. If transparency
9209 % is present, the tRNS chunk must only have values 0 and 255
9210 % (i.e., transparency is binary: fully opaque or fully
9211 % transparent). The pixels contain 8-bit indices even if
9212 % they could be represented with 1, 2, or 4 bits. Note: grayscale
9213 % images will be written as indexed PNG files even though the
9214 % PNG grayscale type might be slightly more efficient.
9216 % o PNG24: An 8-bit per sample RGB PNG datastream is written. The tRNS
9217 % chunk can be present to convey binary transparency by naming
9218 % one of the colors as transparent.
9220 % o PNG32: An 8-bit per sample RGBA PNG is written. Partial
9221 % transparency is permitted, i.e., the alpha sample for
9222 % each pixel can have any value from 0 to 255. The alpha
9223 % channel is present even if the image is fully opaque.
9225 % o -define: For more precise control of the PNG output, you can use the
9226 % Image options "png:bit-depth" and "png:color-type". These
9227 % can be set from the commandline with "-define" and also
9228 % from the application programming interfaces. The options
9229 % are case-independent and are converted to lowercase before
9230 % being passed to this encoder.
9232 % png:color-type can be 0, 2, 3, 4, or 6.
9234 % When png:color-type is 0 (Grayscale), png:bit-depth can
9235 % be 1, 2, 4, 8, or 16.
9237 % When png:color-type is 2 (RGB), png:bit-depth can
9240 % When png:color-type is 3 (Indexed), png:bit-depth can
9241 % be 1, 2, 4, or 8. This refers to the number of bits
9242 % used to store the index. The color samples always have
9243 % bit-depth 8 in indexed PNG files.
9245 % When png:color-type is 4 (Gray-Matte) or 6 (RGB-Matte),
9246 % png:bit-depth can be 8 or 16.
9248 % If the image cannot be written without loss in the requested PNG8, PNG24,
9249 % or PNG32 format or with the requested bit-depth and color-type without loss,
9250 % a PNG file will not be written, and the encoder will return MagickFalse.
9251 % Since image encoders should not be responsible for the "heavy lifting",
9252 % the user should make sure that ImageMagick has already reduced the
9253 % image depth and number of colors and limit transparency to binary
9254 % transparency prior to attempting to write the image in a format that
9255 % is subject to depth, color, or transparency limitations.
9257 % TODO: Enforce the previous paragraph.
9259 % Note that another definition, "png:bit-depth-written" exists, but it
9260 % is not intended for external use. It is only used internally by the
9261 % PNG encoder to inform the JNG encoder of the depth of the alpha channel.
9263 % It is possible to request that the PNG encoder write previously-formatted
9264 % ancillary chunks in the output PNG file, using the "-profile" commandline
9265 % option as shown below or by setting the profile via a programming
9268 % -profile PNG-chunk-x:<file>
9270 % where x is a location flag and <file> is a file containing the chunk
9271 % name in the first 4 bytes, then a colon (":"), followed by the chunk data.
9272 % This encoder will compute the chunk length and CRC, so those must not
9273 % be included in the file.
9275 % "x" can be "b" (before PLTE), "m" (middle, i.e., between PLTE and IDAT),
9276 % or "e" (end, i.e., after IDAT). If you want to write multiple chunks
9277 % of the same type, then add a short unique string after the "x" to prevent
9278 % subsequent profiles from overwriting the preceding ones, e.g.,
9280 % -profile PNG-chunk-b01:file01 -profile PNG-chunk-b02:file02
9282 % As of version 6.6.6 the following optimizations are always done:
9284 % o 32-bit depth is reduced to 16.
9285 % o 16-bit depth is reduced to 8 if all pixels contain samples whose
9286 % high byte and low byte are identical.
9287 % o Palette is sorted to remove unused entries and to put a
9288 % transparent color first, if PNG_BUILD_PALETTE is defined.
9289 % o Opaque matte channel is removed when writing an indexed PNG.
9290 % o Grayscale images are reduced to 1, 2, or 4 bit depth if
9291 % this can be done without loss and a larger bit depth N was not
9292 % requested via the "-define PNG:bit-depth=N" option.
9293 % o If matte channel is present but only one transparent color is
9294 % present, RGB+tRNS is written instead of RGBA
9295 % o Opaque matte channel is removed (or added, if color-type 4 or 6
9296 % was requested when converting an opaque image).
9298 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9300 static MagickBooleanType WritePNGImage(const ImageInfo *image_info,
9322 assert(image_info != (const ImageInfo *) NULL);
9323 assert(image_info->signature == MagickSignature);
9324 assert(image != (Image *) NULL);
9325 assert(image->signature == MagickSignature);
9326 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
9327 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"enter WritePNGImage()");
9329 Allocate a MngInfo structure.
9331 have_mng_structure=MagickFalse;
9332 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
9334 if (mng_info == (MngInfo *) NULL)
9335 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
9338 Initialize members of the MngInfo structure.
9340 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
9341 mng_info->image=image;
9342 mng_info->equal_backgrounds=MagickTrue;
9343 have_mng_structure=MagickTrue;
9345 /* See if user has requested a specific PNG subformat */
9347 mng_info->write_png8=LocaleCompare(image_info->magick,"PNG8") == 0;
9348 mng_info->write_png24=LocaleCompare(image_info->magick,"PNG24") == 0;
9349 mng_info->write_png32=LocaleCompare(image_info->magick,"PNG32") == 0;
9351 if (mng_info->write_png8)
9353 mng_info->write_png_colortype = /* 3 */ 4;
9354 mng_info->write_png_depth = 8;
9358 if (mng_info->write_png24)
9360 mng_info->write_png_colortype = /* 2 */ 3;
9361 mng_info->write_png_depth = 8;
9364 if (image->matte == MagickTrue)
9365 (void) SetImageType(image,TrueColorMatteType);
9368 (void) SetImageType(image,TrueColorType);
9370 (void) SyncImage(image);
9373 if (mng_info->write_png32)
9375 mng_info->write_png_colortype = /* 6 */ 7;
9376 mng_info->write_png_depth = 8;
9379 if (image->matte == MagickTrue)
9380 (void) SetImageType(image,TrueColorMatteType);
9383 (void) SetImageType(image,TrueColorType);
9385 (void) SyncImage(image);
9388 value=GetImageOption(image_info,"png:bit-depth");
9390 if (value != (char *) NULL)
9392 if (LocaleCompare(value,"1") == 0)
9393 mng_info->write_png_depth = 1;
9395 else if (LocaleCompare(value,"2") == 0)
9396 mng_info->write_png_depth = 2;
9398 else if (LocaleCompare(value,"4") == 0)
9399 mng_info->write_png_depth = 4;
9401 else if (LocaleCompare(value,"8") == 0)
9402 mng_info->write_png_depth = 8;
9404 else if (LocaleCompare(value,"16") == 0)
9405 mng_info->write_png_depth = 16;
9408 (void) ThrowMagickException(&image->exception,
9409 GetMagickModule(),CoderWarning,
9410 "ignoring invalid defined png:bit-depth",
9413 if (logging != MagickFalse)
9414 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9415 " png:bit-depth=%d was defined.\n",mng_info->write_png_depth);
9418 value=GetImageOption(image_info,"png:color-type");
9420 if (value != (char *) NULL)
9422 /* We must store colortype+1 because 0 is a valid colortype */
9423 if (LocaleCompare(value,"0") == 0)
9424 mng_info->write_png_colortype = 1;
9426 else if (LocaleCompare(value,"2") == 0)
9427 mng_info->write_png_colortype = 3;
9429 else if (LocaleCompare(value,"3") == 0)
9430 mng_info->write_png_colortype = 4;
9432 else if (LocaleCompare(value,"4") == 0)
9433 mng_info->write_png_colortype = 5;
9435 else if (LocaleCompare(value,"6") == 0)
9436 mng_info->write_png_colortype = 7;
9439 (void) ThrowMagickException(&image->exception,
9440 GetMagickModule(),CoderWarning,
9441 "ignoring invalid defined png:color-type",
9444 if (logging != MagickFalse)
9445 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9446 " png:color-type=%d was defined.\n",mng_info->write_png_colortype-1);
9449 /* Check for chunks to be excluded:
9451 * The default is to not exclude any chunks except for any
9452 * listed in the "unused_chunks" array, above.
9454 * Chunks can be listed for exclusion via a "PNG:exclude-chunk"
9455 * define (in the image properties or in the image artifacts)
9456 * or via a mng_info member. For convenience, in addition
9457 * to or instead of a comma-separated list of chunks, the
9458 * "exclude-chunk" string can be simply "all" or "none".
9460 * The exclude-chunk define takes priority over the mng_info.
9462 * A "PNG:include-chunk" define takes priority over both the
9463 * mng_info and the "PNG:exclude-chunk" define. Like the
9464 * "exclude-chunk" string, it can define "all" or "none" as
9465 * well as a comma-separated list.
9467 * Finally, all chunks listed in the "unused_chunks" array are
9468 * automatically excluded, regardless of the other instructions
9471 * if you exclude sRGB but not gAMA (recommended), then sRGB chunk
9472 * will not be written and the gAMA chunk will only be written if it
9473 * is not between .45 and .46, or approximately (1.0/2.2).
9475 * If you exclude tRNS and the image has transparency, the colortype
9476 * is forced to be 4 or 6 (GRAY_ALPHA or RGB_ALPHA).
9478 * The -strip option causes StripImage() to set the png:include-chunk
9479 * artifact to "none,gama".
9482 mng_info->ping_exclude_bKGD=MagickFalse;
9483 mng_info->ping_exclude_cHRM=MagickFalse;
9484 mng_info->ping_exclude_EXIF=MagickFalse; /* hex-encoded EXIF in zTXt */
9485 mng_info->ping_exclude_gAMA=MagickFalse;
9486 mng_info->ping_exclude_cHRM=MagickFalse;
9487 mng_info->ping_exclude_iCCP=MagickFalse;
9488 /* mng_info->ping_exclude_iTXt=MagickFalse; */
9489 mng_info->ping_exclude_oFFs=MagickFalse;
9490 mng_info->ping_exclude_pHYs=MagickFalse;
9491 mng_info->ping_exclude_sRGB=MagickFalse;
9492 mng_info->ping_exclude_tEXt=MagickFalse;
9493 mng_info->ping_exclude_tRNS=MagickFalse;
9494 mng_info->ping_exclude_vpAg=MagickFalse;
9495 mng_info->ping_exclude_zCCP=MagickFalse; /* hex-encoded iCCP in zTXt */
9496 mng_info->ping_exclude_zTXt=MagickFalse;
9498 excluding=MagickFalse;
9500 for (source=0; source<1; source++)
9504 value=GetImageArtifact(image,"png:exclude-chunk");
9507 value=GetImageArtifact(image,"png:exclude-chunks");
9511 value=GetImageOption(image_info,"png:exclude-chunk");
9514 value=GetImageOption(image_info,"png:exclude-chunks");
9523 excluding=MagickTrue;
9525 if (logging != MagickFalse)
9528 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9529 " png:exclude-chunk=%s found in image artifacts.\n", value);
9531 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9532 " png:exclude-chunk=%s found in image properties.\n", value);
9537 for (i=0; i<(int) last; i+=5)
9540 if (LocaleNCompare(value+i,"all",3) == 0)
9542 mng_info->ping_exclude_bKGD=MagickTrue;
9543 mng_info->ping_exclude_cHRM=MagickTrue;
9544 mng_info->ping_exclude_EXIF=MagickTrue;
9545 mng_info->ping_exclude_gAMA=MagickTrue;
9546 mng_info->ping_exclude_iCCP=MagickTrue;
9547 /* mng_info->ping_exclude_iTXt=MagickTrue; */
9548 mng_info->ping_exclude_oFFs=MagickTrue;
9549 mng_info->ping_exclude_pHYs=MagickTrue;
9550 mng_info->ping_exclude_sRGB=MagickTrue;
9551 mng_info->ping_exclude_tEXt=MagickTrue;
9552 mng_info->ping_exclude_tRNS=MagickTrue;
9553 mng_info->ping_exclude_vpAg=MagickTrue;
9554 mng_info->ping_exclude_zCCP=MagickTrue;
9555 mng_info->ping_exclude_zTXt=MagickTrue;
9559 if (LocaleNCompare(value+i,"none",4) == 0)
9561 mng_info->ping_exclude_bKGD=MagickFalse;
9562 mng_info->ping_exclude_cHRM=MagickFalse;
9563 mng_info->ping_exclude_EXIF=MagickFalse;
9564 mng_info->ping_exclude_gAMA=MagickFalse;
9565 mng_info->ping_exclude_iCCP=MagickFalse;
9566 /* mng_info->ping_exclude_iTXt=MagickFalse; */
9567 mng_info->ping_exclude_oFFs=MagickFalse;
9568 mng_info->ping_exclude_pHYs=MagickFalse;
9569 mng_info->ping_exclude_sRGB=MagickFalse;
9570 mng_info->ping_exclude_tEXt=MagickFalse;
9571 mng_info->ping_exclude_tRNS=MagickFalse;
9572 mng_info->ping_exclude_vpAg=MagickFalse;
9573 mng_info->ping_exclude_zCCP=MagickFalse;
9574 mng_info->ping_exclude_zTXt=MagickFalse;
9577 if (LocaleNCompare(value+i,"bkgd",4) == 0)
9578 mng_info->ping_exclude_bKGD=MagickTrue;
9580 if (LocaleNCompare(value+i,"chrm",4) == 0)
9581 mng_info->ping_exclude_cHRM=MagickTrue;
9583 if (LocaleNCompare(value+i,"exif",4) == 0)
9584 mng_info->ping_exclude_EXIF=MagickTrue;
9586 if (LocaleNCompare(value+i,"gama",4) == 0)
9587 mng_info->ping_exclude_gAMA=MagickTrue;
9589 if (LocaleNCompare(value+i,"iccp",4) == 0)
9590 mng_info->ping_exclude_iCCP=MagickTrue;
9593 if (LocaleNCompare(value+i,"itxt",4) == 0)
9594 mng_info->ping_exclude_iTXt=MagickTrue;
9597 if (LocaleNCompare(value+i,"gama",4) == 0)
9598 mng_info->ping_exclude_gAMA=MagickTrue;
9600 if (LocaleNCompare(value+i,"offs",4) == 0)
9601 mng_info->ping_exclude_oFFs=MagickTrue;
9603 if (LocaleNCompare(value+i,"phys",4) == 0)
9604 mng_info->ping_exclude_pHYs=MagickTrue;
9606 if (LocaleNCompare(value+i,"srgb",4) == 0)
9607 mng_info->ping_exclude_sRGB=MagickTrue;
9609 if (LocaleNCompare(value+i,"text",4) == 0)
9610 mng_info->ping_exclude_tEXt=MagickTrue;
9612 if (LocaleNCompare(value+i,"trns",4) == 0)
9613 mng_info->ping_exclude_tRNS=MagickTrue;
9615 if (LocaleNCompare(value+i,"vpag",4) == 0)
9616 mng_info->ping_exclude_vpAg=MagickTrue;
9618 if (LocaleNCompare(value+i,"zccp",4) == 0)
9619 mng_info->ping_exclude_zCCP=MagickTrue;
9621 if (LocaleNCompare(value+i,"ztxt",4) == 0)
9622 mng_info->ping_exclude_zTXt=MagickTrue;
9628 for (source=0; source<1; source++)
9632 value=GetImageArtifact(image,"png:include-chunk");
9635 value=GetImageArtifact(image,"png:include-chunks");
9639 value=GetImageOption(image_info,"png:include-chunk");
9642 value=GetImageOption(image_info,"png:include-chunks");
9650 excluding=MagickTrue;
9652 if (logging != MagickFalse)
9655 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9656 " png:include-chunk=%s found in image artifacts.\n", value);
9658 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9659 " png:include-chunk=%s found in image properties.\n", value);
9664 for (i=0; i<(int) last; i+=5)
9666 if (LocaleNCompare(value+i,"all",3) == 0)
9668 mng_info->ping_exclude_bKGD=MagickFalse;
9669 mng_info->ping_exclude_cHRM=MagickFalse;
9670 mng_info->ping_exclude_EXIF=MagickFalse;
9671 mng_info->ping_exclude_gAMA=MagickFalse;
9672 mng_info->ping_exclude_iCCP=MagickFalse;
9673 /* mng_info->ping_exclude_iTXt=MagickFalse; */
9674 mng_info->ping_exclude_oFFs=MagickFalse;
9675 mng_info->ping_exclude_pHYs=MagickFalse;
9676 mng_info->ping_exclude_sRGB=MagickFalse;
9677 mng_info->ping_exclude_tEXt=MagickFalse;
9678 mng_info->ping_exclude_tRNS=MagickFalse;
9679 mng_info->ping_exclude_vpAg=MagickFalse;
9680 mng_info->ping_exclude_zCCP=MagickFalse;
9681 mng_info->ping_exclude_zTXt=MagickFalse;
9685 if (LocaleNCompare(value+i,"none",4) == 0)
9687 mng_info->ping_exclude_bKGD=MagickTrue;
9688 mng_info->ping_exclude_cHRM=MagickTrue;
9689 mng_info->ping_exclude_EXIF=MagickTrue;
9690 mng_info->ping_exclude_gAMA=MagickTrue;
9691 mng_info->ping_exclude_iCCP=MagickTrue;
9692 /* mng_info->ping_exclude_iTXt=MagickTrue; */
9693 mng_info->ping_exclude_oFFs=MagickTrue;
9694 mng_info->ping_exclude_pHYs=MagickTrue;
9695 mng_info->ping_exclude_sRGB=MagickTrue;
9696 mng_info->ping_exclude_tEXt=MagickTrue;
9697 mng_info->ping_exclude_tRNS=MagickTrue;
9698 mng_info->ping_exclude_vpAg=MagickTrue;
9699 mng_info->ping_exclude_zCCP=MagickTrue;
9700 mng_info->ping_exclude_zTXt=MagickTrue;
9703 if (LocaleNCompare(value+i,"bkgd",4) == 0)
9704 mng_info->ping_exclude_bKGD=MagickFalse;
9706 if (LocaleNCompare(value+i,"chrm",4) == 0)
9707 mng_info->ping_exclude_cHRM=MagickFalse;
9709 if (LocaleNCompare(value+i,"exif",4) == 0)
9710 mng_info->ping_exclude_EXIF=MagickFalse;
9712 if (LocaleNCompare(value+i,"gama",4) == 0)
9713 mng_info->ping_exclude_gAMA=MagickFalse;
9715 if (LocaleNCompare(value+i,"iccp",4) == 0)
9716 mng_info->ping_exclude_iCCP=MagickFalse;
9719 if (LocaleNCompare(value+i,"itxt",4) == 0)
9720 mng_info->ping_exclude_iTXt=MagickFalse;
9723 if (LocaleNCompare(value+i,"gama",4) == 0)
9724 mng_info->ping_exclude_gAMA=MagickFalse;
9726 if (LocaleNCompare(value+i,"offs",4) == 0)
9727 mng_info->ping_exclude_oFFs=MagickFalse;
9729 if (LocaleNCompare(value+i,"phys",4) == 0)
9730 mng_info->ping_exclude_pHYs=MagickFalse;
9732 if (LocaleNCompare(value+i,"srgb",4) == 0)
9733 mng_info->ping_exclude_sRGB=MagickFalse;
9735 if (LocaleNCompare(value+i,"text",4) == 0)
9736 mng_info->ping_exclude_tEXt=MagickFalse;
9738 if (LocaleNCompare(value+i,"trns",4) == 0)
9739 mng_info->ping_exclude_tRNS=MagickFalse;
9741 if (LocaleNCompare(value+i,"vpag",4) == 0)
9742 mng_info->ping_exclude_vpAg=MagickFalse;
9744 if (LocaleNCompare(value+i,"zccp",4) == 0)
9745 mng_info->ping_exclude_zCCP=MagickFalse;
9747 if (LocaleNCompare(value+i,"ztxt",4) == 0)
9748 mng_info->ping_exclude_zTXt=MagickFalse;
9754 if (excluding != MagickFalse && logging != MagickFalse)
9756 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9757 " Chunks to be excluded from the output PNG:");
9758 if (mng_info->ping_exclude_bKGD != MagickFalse)
9759 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9761 if (mng_info->ping_exclude_cHRM != MagickFalse)
9762 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9764 if (mng_info->ping_exclude_EXIF != MagickFalse)
9765 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9767 if (mng_info->ping_exclude_gAMA != MagickFalse)
9768 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9770 if (mng_info->ping_exclude_iCCP != MagickFalse)
9771 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9774 if (mng_info->ping_exclude_iTXt != MagickFalse)
9775 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9778 if (mng_info->ping_exclude_oFFs != MagickFalse)
9779 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9781 if (mng_info->ping_exclude_pHYs != MagickFalse)
9782 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9784 if (mng_info->ping_exclude_sRGB != MagickFalse)
9785 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9787 if (mng_info->ping_exclude_tEXt != MagickFalse)
9788 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9790 if (mng_info->ping_exclude_tRNS != MagickFalse)
9791 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9793 if (mng_info->ping_exclude_vpAg != MagickFalse)
9794 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9796 if (mng_info->ping_exclude_zCCP != MagickFalse)
9797 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9799 if (mng_info->ping_exclude_zTXt != MagickFalse)
9800 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9804 mng_info->need_blob = MagickTrue;
9806 status=WriteOnePNGImage(mng_info,image_info,image);
9808 MngInfoFreeStruct(mng_info,&have_mng_structure);
9810 if (logging != MagickFalse)
9811 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit WritePNGImage()");
9816 #if defined(JNG_SUPPORTED)
9818 /* Write one JNG image */
9819 static MagickBooleanType WriteOneJNGImage(MngInfo *mng_info,
9820 const ImageInfo *image_info,Image *image)
9841 jng_alpha_compression_method,
9842 jng_alpha_sample_depth,
9849 logging=LogMagickEvent(CoderEvent,GetMagickModule(),
9850 " enter WriteOneJNGImage()");
9852 blob=(unsigned char *) NULL;
9853 jpeg_image=(Image *) NULL;
9854 jpeg_image_info=(ImageInfo *) NULL;
9857 transparent=image_info->type==GrayscaleMatteType ||
9858 image_info->type==TrueColorMatteType;
9860 jng_alpha_sample_depth=0;
9861 jng_quality=image_info->quality == 0UL ? 75UL : image_info->quality;
9862 jng_alpha_compression_method=0;
9864 if (image->matte != MagickFalse)
9866 /* if any pixels are transparent */
9867 transparent=MagickTrue;
9868 if (image_info->compression==JPEGCompression)
9869 jng_alpha_compression_method=8;
9876 /* Create JPEG blob, image, and image_info */
9877 if (logging != MagickFalse)
9878 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9879 " Creating jpeg_image_info for opacity.");
9881 jpeg_image_info=(ImageInfo *) CloneImageInfo(image_info);
9883 if (jpeg_image_info == (ImageInfo *) NULL)
9884 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
9886 if (logging != MagickFalse)
9887 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9888 " Creating jpeg_image.");
9890 jpeg_image=CloneImage(image,0,0,MagickTrue,&image->exception);
9892 if (jpeg_image == (Image *) NULL)
9893 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
9895 (void) CopyMagickString(jpeg_image->magick,"JPEG",MaxTextExtent);
9896 status=SeparateImageChannel(jpeg_image,OpacityChannel);
9897 status=NegateImage(jpeg_image,MagickFalse);
9898 jpeg_image->matte=MagickFalse;
9900 if (jng_quality >= 1000)
9901 jpeg_image_info->quality=jng_quality/1000;
9904 jpeg_image_info->quality=jng_quality;
9906 jpeg_image_info->type=GrayscaleType;
9907 (void) SetImageType(jpeg_image,GrayscaleType);
9908 (void) AcquireUniqueFilename(jpeg_image->filename);
9909 (void) FormatMagickString(jpeg_image_info->filename,MaxTextExtent,
9910 "%s",jpeg_image->filename);
9913 /* To do: check bit depth of PNG alpha channel */
9915 /* Check if image is grayscale. */
9916 if (image_info->type != TrueColorMatteType && image_info->type !=
9917 TrueColorType && ImageIsGray(image))
9922 if (jng_alpha_compression_method==0)
9927 /* Encode opacity as a grayscale PNG blob */
9928 status=OpenBlob(jpeg_image_info,jpeg_image,WriteBinaryBlobMode,
9930 if (logging != MagickFalse)
9931 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9932 " Creating PNG blob.");
9935 (void) CopyMagickString(jpeg_image_info->magick,"PNG",MaxTextExtent);
9936 (void) CopyMagickString(jpeg_image->magick,"PNG",MaxTextExtent);
9937 jpeg_image_info->interlace=NoInterlace;
9939 blob=ImageToBlob(jpeg_image_info,jpeg_image,&length,
9942 /* Retrieve sample depth used */
9943 value=GetImageProperty(jpeg_image,"png:bit-depth-written");
9944 if (value != (char *) NULL)
9945 jng_alpha_sample_depth= (unsigned int) value[0];
9949 /* Encode opacity as a grayscale JPEG blob */
9951 status=OpenBlob(jpeg_image_info,jpeg_image,WriteBinaryBlobMode,
9954 (void) CopyMagickString(jpeg_image_info->magick,"JPEG",MaxTextExtent);
9955 (void) CopyMagickString(jpeg_image->magick,"JPEG",MaxTextExtent);
9956 jpeg_image_info->interlace=NoInterlace;
9957 if (logging != MagickFalse)
9958 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9960 blob=ImageToBlob(jpeg_image_info,jpeg_image,&length,
9962 jng_alpha_sample_depth=8;
9964 if (logging != MagickFalse)
9965 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9966 " Successfully read jpeg_image into a blob, length=%.20g.",
9970 /* Destroy JPEG image and image_info */
9971 jpeg_image=DestroyImage(jpeg_image);
9972 (void) RelinquishUniqueFileResource(jpeg_image_info->filename);
9973 jpeg_image_info=DestroyImageInfo(jpeg_image_info);
9976 /* Write JHDR chunk */
9977 (void) WriteBlobMSBULong(image,16L); /* chunk data length=16 */
9978 PNGType(chunk,mng_JHDR);
9979 LogPNGChunk(logging,mng_JHDR,16L);
9980 PNGLong(chunk+4,(png_uint_32) image->columns);
9981 PNGLong(chunk+8,(png_uint_32) image->rows);
9982 chunk[12]=jng_color_type;
9983 chunk[13]=8; /* sample depth */
9984 chunk[14]=8; /*jng_image_compression_method */
9985 chunk[15]=(unsigned char) (image_info->interlace == NoInterlace ? 0 : 8);
9986 chunk[16]=jng_alpha_sample_depth;
9987 chunk[17]=jng_alpha_compression_method;
9988 chunk[18]=0; /*jng_alpha_filter_method */
9989 chunk[19]=0; /*jng_alpha_interlace_method */
9990 (void) WriteBlob(image,20,chunk);
9991 (void) WriteBlobMSBULong(image,crc32(0,chunk,20));
9992 if (logging != MagickFalse)
9994 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9995 " JNG width:%15lu",(unsigned long) image->columns);
9997 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
9998 " JNG height:%14lu",(unsigned long) image->rows);
10000 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10001 " JNG color type:%10d",jng_color_type);
10003 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10004 " JNG sample depth:%8d",8);
10006 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10007 " JNG compression:%9d",8);
10009 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10010 " JNG interlace:%11d",0);
10012 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10013 " JNG alpha depth:%9d",jng_alpha_sample_depth);
10015 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10016 " JNG alpha compression:%3d",jng_alpha_compression_method);
10018 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10019 " JNG alpha filter:%8d",0);
10021 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10022 " JNG alpha interlace:%5d",0);
10025 /* Write any JNG-chunk-b profiles */
10026 (void) png_write_chunk_from_profile(image,"JNG-chunk-b",logging);
10029 Write leading ancillary chunks
10035 Write JNG bKGD chunk
10046 if (jng_color_type == 8 || jng_color_type == 12)
10050 (void) WriteBlobMSBULong(image,(size_t) (num_bytes-4L));
10051 PNGType(chunk,mng_bKGD);
10052 LogPNGChunk(logging,mng_bKGD,(size_t) (num_bytes-4L));
10053 red=ScaleQuantumToChar(image->background_color.red);
10054 green=ScaleQuantumToChar(image->background_color.green);
10055 blue=ScaleQuantumToChar(image->background_color.blue);
10062 (void) WriteBlob(image,(size_t) num_bytes,chunk);
10063 (void) WriteBlobMSBULong(image,crc32(0,chunk,(uInt) num_bytes));
10066 if ((image->colorspace == sRGBColorspace || image->rendering_intent))
10069 Write JNG sRGB chunk
10071 (void) WriteBlobMSBULong(image,1L);
10072 PNGType(chunk,mng_sRGB);
10073 LogPNGChunk(logging,mng_sRGB,1L);
10075 if (image->rendering_intent != UndefinedIntent)
10076 chunk[4]=(unsigned char)
10077 PNG_RenderingIntent_from_Magick_RenderingIntent(
10078 (image->rendering_intent));
10081 chunk[4]=(unsigned char)
10082 PNG_RenderingIntent_from_Magick_RenderingIntent(
10083 (PerceptualIntent));
10085 (void) WriteBlob(image,5,chunk);
10086 (void) WriteBlobMSBULong(image,crc32(0,chunk,5));
10090 if (image->gamma != 0.0)
10093 Write JNG gAMA chunk
10095 (void) WriteBlobMSBULong(image,4L);
10096 PNGType(chunk,mng_gAMA);
10097 LogPNGChunk(logging,mng_gAMA,4L);
10098 PNGLong(chunk+4,(png_uint_32) (100000*image->gamma+0.5));
10099 (void) WriteBlob(image,8,chunk);
10100 (void) WriteBlobMSBULong(image,crc32(0,chunk,8));
10103 if ((mng_info->equal_chrms == MagickFalse) &&
10104 (image->chromaticity.red_primary.x != 0.0))
10110 Write JNG cHRM chunk
10112 (void) WriteBlobMSBULong(image,32L);
10113 PNGType(chunk,mng_cHRM);
10114 LogPNGChunk(logging,mng_cHRM,32L);
10115 primary=image->chromaticity.white_point;
10116 PNGLong(chunk+4,(png_uint_32) (100000*primary.x+0.5));
10117 PNGLong(chunk+8,(png_uint_32) (100000*primary.y+0.5));
10118 primary=image->chromaticity.red_primary;
10119 PNGLong(chunk+12,(png_uint_32) (100000*primary.x+0.5));
10120 PNGLong(chunk+16,(png_uint_32) (100000*primary.y+0.5));
10121 primary=image->chromaticity.green_primary;
10122 PNGLong(chunk+20,(png_uint_32) (100000*primary.x+0.5));
10123 PNGLong(chunk+24,(png_uint_32) (100000*primary.y+0.5));
10124 primary=image->chromaticity.blue_primary;
10125 PNGLong(chunk+28,(png_uint_32) (100000*primary.x+0.5));
10126 PNGLong(chunk+32,(png_uint_32) (100000*primary.y+0.5));
10127 (void) WriteBlob(image,36,chunk);
10128 (void) WriteBlobMSBULong(image,crc32(0,chunk,36));
10132 if (image->x_resolution && image->y_resolution && !mng_info->equal_physs)
10135 Write JNG pHYs chunk
10137 (void) WriteBlobMSBULong(image,9L);
10138 PNGType(chunk,mng_pHYs);
10139 LogPNGChunk(logging,mng_pHYs,9L);
10140 if (image->units == PixelsPerInchResolution)
10142 PNGLong(chunk+4,(png_uint_32)
10143 (image->x_resolution*100.0/2.54+0.5));
10145 PNGLong(chunk+8,(png_uint_32)
10146 (image->y_resolution*100.0/2.54+0.5));
10153 if (image->units == PixelsPerCentimeterResolution)
10155 PNGLong(chunk+4,(png_uint_32)
10156 (image->x_resolution*100.0+0.5));
10158 PNGLong(chunk+8,(png_uint_32)
10159 (image->y_resolution*100.0+0.5));
10166 PNGLong(chunk+4,(png_uint_32) (image->x_resolution+0.5));
10167 PNGLong(chunk+8,(png_uint_32) (image->y_resolution+0.5));
10171 (void) WriteBlob(image,13,chunk);
10172 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
10175 if (mng_info->write_mng == 0 && (image->page.x || image->page.y))
10178 Write JNG oFFs chunk
10180 (void) WriteBlobMSBULong(image,9L);
10181 PNGType(chunk,mng_oFFs);
10182 LogPNGChunk(logging,mng_oFFs,9L);
10183 PNGsLong(chunk+4,(ssize_t) (image->page.x));
10184 PNGsLong(chunk+8,(ssize_t) (image->page.y));
10186 (void) WriteBlob(image,13,chunk);
10187 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
10189 if (mng_info->write_mng == 0 && (image->page.width || image->page.height))
10191 (void) WriteBlobMSBULong(image,9L); /* data length=8 */
10192 PNGType(chunk,mng_vpAg);
10193 LogPNGChunk(logging,mng_vpAg,9L);
10194 PNGLong(chunk+4,(png_uint_32) image->page.width);
10195 PNGLong(chunk+8,(png_uint_32) image->page.height);
10196 chunk[12]=0; /* unit = pixels */
10197 (void) WriteBlob(image,13,chunk);
10198 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
10204 if (jng_alpha_compression_method==0)
10212 /* Write IDAT chunk header */
10213 if (logging != MagickFalse)
10214 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10215 " Write IDAT chunks from blob, length=%.20g.",(double)
10218 /* Copy IDAT chunks */
10221 for (i=8; i<(ssize_t) length; i+=len+12)
10223 len=(*p<<24)|((*(p+1))<<16)|((*(p+2))<<8)|(*(p+3));
10226 if (*(p)==73 && *(p+1)==68 && *(p+2)==65 && *(p+3)==84) /* IDAT */
10228 /* Found an IDAT chunk. */
10229 (void) WriteBlobMSBULong(image,(size_t) len);
10230 LogPNGChunk(logging,mng_IDAT,(size_t) len);
10231 (void) WriteBlob(image,(size_t) len+4,p);
10232 (void) WriteBlobMSBULong(image,
10233 crc32(0,p,(uInt) len+4));
10238 if (logging != MagickFalse)
10239 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10240 " Skipping %c%c%c%c chunk, length=%.20g.",
10241 *(p),*(p+1),*(p+2),*(p+3),(double) len);
10248 /* Write JDAA chunk header */
10249 if (logging != MagickFalse)
10250 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10251 " Write JDAA chunk, length=%.20g.",(double) length);
10252 (void) WriteBlobMSBULong(image,(size_t) length);
10253 PNGType(chunk,mng_JDAA);
10254 LogPNGChunk(logging,mng_JDAA,length);
10255 /* Write JDAT chunk(s) data */
10256 (void) WriteBlob(image,4,chunk);
10257 (void) WriteBlob(image,length,blob);
10258 (void) WriteBlobMSBULong(image,crc32(crc32(0,chunk,4),blob,
10261 blob=(unsigned char *) RelinquishMagickMemory(blob);
10264 /* Encode image as a JPEG blob */
10265 if (logging != MagickFalse)
10266 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10267 " Creating jpeg_image_info.");
10268 jpeg_image_info=(ImageInfo *) CloneImageInfo(image_info);
10269 if (jpeg_image_info == (ImageInfo *) NULL)
10270 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
10272 if (logging != MagickFalse)
10273 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10274 " Creating jpeg_image.");
10276 jpeg_image=CloneImage(image,0,0,MagickTrue,&image->exception);
10277 if (jpeg_image == (Image *) NULL)
10278 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
10279 (void) CopyMagickString(jpeg_image->magick,"JPEG",MaxTextExtent);
10281 (void) AcquireUniqueFilename(jpeg_image->filename);
10282 (void) FormatMagickString(jpeg_image_info->filename,MaxTextExtent,"%s",
10283 jpeg_image->filename);
10285 status=OpenBlob(jpeg_image_info,jpeg_image,WriteBinaryBlobMode,
10286 &image->exception);
10288 if (logging != MagickFalse)
10289 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10290 " Created jpeg_image, %.20g x %.20g.",(double) jpeg_image->columns,
10291 (double) jpeg_image->rows);
10293 if (jng_color_type == 8 || jng_color_type == 12)
10294 jpeg_image_info->type=GrayscaleType;
10296 jpeg_image_info->quality=jng_quality % 1000;
10297 (void) CopyMagickString(jpeg_image_info->magick,"JPEG",MaxTextExtent);
10298 (void) CopyMagickString(jpeg_image->magick,"JPEG",MaxTextExtent);
10300 if (logging != MagickFalse)
10301 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10302 " Creating blob.");
10304 blob=ImageToBlob(jpeg_image_info,jpeg_image,&length,&image->exception);
10306 if (logging != MagickFalse)
10308 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10309 " Successfully read jpeg_image into a blob, length=%.20g.",
10312 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10313 " Write JDAT chunk, length=%.20g.",(double) length);
10316 /* Write JDAT chunk(s) */
10317 (void) WriteBlobMSBULong(image,(size_t) length);
10318 PNGType(chunk,mng_JDAT);
10319 LogPNGChunk(logging,mng_JDAT,length);
10320 (void) WriteBlob(image,4,chunk);
10321 (void) WriteBlob(image,length,blob);
10322 (void) WriteBlobMSBULong(image,crc32(crc32(0,chunk,4),blob,(uInt) length));
10324 jpeg_image=DestroyImage(jpeg_image);
10325 (void) RelinquishUniqueFileResource(jpeg_image_info->filename);
10326 jpeg_image_info=DestroyImageInfo(jpeg_image_info);
10327 blob=(unsigned char *) RelinquishMagickMemory(blob);
10329 /* Write any JNG-chunk-e profiles */
10330 (void) png_write_chunk_from_profile(image,"JNG-chunk-e",logging);
10332 /* Write IEND chunk */
10333 (void) WriteBlobMSBULong(image,0L);
10334 PNGType(chunk,mng_IEND);
10335 LogPNGChunk(logging,mng_IEND,0);
10336 (void) WriteBlob(image,4,chunk);
10337 (void) WriteBlobMSBULong(image,crc32(0,chunk,4));
10339 if (logging != MagickFalse)
10340 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10341 " exit WriteOneJNGImage()");
10348 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10352 % W r i t e J N G I m a g e %
10356 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10358 % WriteJNGImage() writes a JPEG Network Graphics (JNG) image file.
10360 % JNG support written by Glenn Randers-Pehrson, glennrp@image...
10362 % The format of the WriteJNGImage method is:
10364 % MagickBooleanType WriteJNGImage(const ImageInfo *image_info,Image *image)
10366 % A description of each parameter follows:
10368 % o image_info: the image info.
10370 % o image: The image.
10372 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10374 static MagickBooleanType WriteJNGImage(const ImageInfo *image_info,Image *image)
10377 have_mng_structure,
10387 assert(image_info != (const ImageInfo *) NULL);
10388 assert(image_info->signature == MagickSignature);
10389 assert(image != (Image *) NULL);
10390 assert(image->signature == MagickSignature);
10391 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
10392 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"enter WriteJNGImage()");
10393 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
10394 if (status == MagickFalse)
10398 Allocate a MngInfo structure.
10400 have_mng_structure=MagickFalse;
10401 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
10402 if (mng_info == (MngInfo *) NULL)
10403 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
10405 Initialize members of the MngInfo structure.
10407 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
10408 mng_info->image=image;
10409 have_mng_structure=MagickTrue;
10411 (void) WriteBlob(image,8,(const unsigned char *) "\213JNG\r\n\032\n");
10413 status=WriteOneJNGImage(mng_info,image_info,image);
10414 (void) CloseBlob(image);
10416 (void) CatchImageException(image);
10417 MngInfoFreeStruct(mng_info,&have_mng_structure);
10418 if (logging != MagickFalse)
10419 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit WriteJNGImage()");
10426 static MagickBooleanType WriteMNGImage(const ImageInfo *image_info,Image *image)
10435 have_mng_structure,
10438 volatile MagickBooleanType
10450 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
10451 defined(PNG_MNG_FEATURES_SUPPORTED)
10454 all_images_are_gray,
10464 volatile unsigned int
10475 #if (PNG_LIBPNG_VER < 10200)
10476 if (image_info->verbose)
10477 printf("Your PNG library (libpng-%s) is rather old.\n",
10478 PNG_LIBPNG_VER_STRING);
10484 assert(image_info != (const ImageInfo *) NULL);
10485 assert(image_info->signature == MagickSignature);
10486 assert(image != (Image *) NULL);
10487 assert(image->signature == MagickSignature);
10488 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
10489 logging=LogMagickEvent(CoderEvent,GetMagickModule(),"enter WriteMNGImage()");
10490 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
10491 if (status == MagickFalse)
10495 Allocate a MngInfo structure.
10497 have_mng_structure=MagickFalse;
10498 mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo));
10499 if (mng_info == (MngInfo *) NULL)
10500 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
10502 Initialize members of the MngInfo structure.
10504 (void) ResetMagickMemory(mng_info,0,sizeof(MngInfo));
10505 mng_info->image=image;
10506 have_mng_structure=MagickTrue;
10507 write_mng=LocaleCompare(image_info->magick,"MNG") == 0;
10510 * See if user has requested a specific PNG subformat to be used
10511 * for all of the PNGs in the MNG being written, e.g.,
10513 * convert *.png png8:animation.mng
10515 * To do: check -define png:bit_depth and png:color_type as well,
10516 * or perhaps use mng:bit_depth and mng:color_type instead for
10520 mng_info->write_png8=LocaleCompare(image_info->magick,"PNG8") == 0;
10521 mng_info->write_png24=LocaleCompare(image_info->magick,"PNG24") == 0;
10522 mng_info->write_png32=LocaleCompare(image_info->magick,"PNG32") == 0;
10524 write_jng=MagickFalse;
10525 if (image_info->compression == JPEGCompression)
10526 write_jng=MagickTrue;
10528 mng_info->adjoin=image_info->adjoin &&
10529 (GetNextImageInList(image) != (Image *) NULL) && write_mng;
10531 if (logging != MagickFalse)
10533 /* Log some info about the input */
10537 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10538 " Checking input image(s)");
10540 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10541 " Image_info depth: %.20g",(double) image_info->depth);
10543 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10544 " Type: %d",image_info->type);
10547 for (p=image; p != (Image *) NULL; p=GetNextImageInList(p))
10549 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10550 " Scene: %.20g",(double) scene++);
10552 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10553 " Image depth: %.20g",(double) p->depth);
10556 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10560 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10563 if (p->storage_class == PseudoClass)
10564 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10565 " Storage class: PseudoClass");
10568 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10569 " Storage class: DirectClass");
10572 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10573 " Number of colors: %.20g",(double) p->colors);
10576 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10577 " Number of colors: unspecified");
10579 if (mng_info->adjoin == MagickFalse)
10584 use_global_plte=MagickFalse;
10585 all_images_are_gray=MagickFalse;
10586 #ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
10587 need_local_plte=MagickTrue;
10589 need_defi=MagickFalse;
10590 need_matte=MagickFalse;
10591 mng_info->framing_mode=1;
10592 mng_info->old_framing_mode=1;
10595 if (image_info->page != (char *) NULL)
10598 Determine image bounding box.
10600 SetGeometry(image,&mng_info->page);
10601 (void) ParseMetaGeometry(image_info->page,&mng_info->page.x,
10602 &mng_info->page.y,&mng_info->page.width,&mng_info->page.height);
10614 mng_info->page=image->page;
10615 need_geom=MagickTrue;
10616 if (mng_info->page.width || mng_info->page.height)
10617 need_geom=MagickFalse;
10619 Check all the scenes.
10621 initial_delay=image->delay;
10622 need_iterations=MagickFalse;
10623 mng_info->equal_chrms=image->chromaticity.red_primary.x != 0.0;
10624 mng_info->equal_physs=MagickTrue,
10625 mng_info->equal_gammas=MagickTrue;
10626 mng_info->equal_srgbs=MagickTrue;
10627 mng_info->equal_backgrounds=MagickTrue;
10629 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
10630 defined(PNG_MNG_FEATURES_SUPPORTED)
10631 all_images_are_gray=MagickTrue;
10632 mng_info->equal_palettes=MagickFalse;
10633 need_local_plte=MagickFalse;
10635 for (next_image=image; next_image != (Image *) NULL; )
10639 if ((next_image->columns+next_image->page.x) > mng_info->page.width)
10640 mng_info->page.width=next_image->columns+next_image->page.x;
10642 if ((next_image->rows+next_image->page.y) > mng_info->page.height)
10643 mng_info->page.height=next_image->rows+next_image->page.y;
10646 if (next_image->page.x || next_image->page.y)
10647 need_defi=MagickTrue;
10649 if (next_image->matte)
10650 need_matte=MagickTrue;
10652 if ((int) next_image->dispose >= BackgroundDispose)
10653 if (next_image->matte || next_image->page.x || next_image->page.y ||
10654 ((next_image->columns < mng_info->page.width) &&
10655 (next_image->rows < mng_info->page.height)))
10656 mng_info->need_fram=MagickTrue;
10658 if (next_image->iterations)
10659 need_iterations=MagickTrue;
10661 final_delay=next_image->delay;
10663 if (final_delay != initial_delay || final_delay > 1UL*
10664 next_image->ticks_per_second)
10665 mng_info->need_fram=1;
10667 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
10668 defined(PNG_MNG_FEATURES_SUPPORTED)
10670 check for global palette possibility.
10672 if (image->matte != MagickFalse)
10673 need_local_plte=MagickTrue;
10675 if (need_local_plte == 0)
10677 if (ImageIsGray(image) == MagickFalse)
10678 all_images_are_gray=MagickFalse;
10679 mng_info->equal_palettes=PalettesAreEqual(image,next_image);
10680 if (use_global_plte == 0)
10681 use_global_plte=mng_info->equal_palettes;
10682 need_local_plte=!mng_info->equal_palettes;
10685 if (GetNextImageInList(next_image) != (Image *) NULL)
10687 if (next_image->background_color.red !=
10688 next_image->next->background_color.red ||
10689 next_image->background_color.green !=
10690 next_image->next->background_color.green ||
10691 next_image->background_color.blue !=
10692 next_image->next->background_color.blue)
10693 mng_info->equal_backgrounds=MagickFalse;
10695 if (next_image->gamma != next_image->next->gamma)
10696 mng_info->equal_gammas=MagickFalse;
10698 if (next_image->rendering_intent !=
10699 next_image->next->rendering_intent)
10700 mng_info->equal_srgbs=MagickFalse;
10702 if ((next_image->units != next_image->next->units) ||
10703 (next_image->x_resolution != next_image->next->x_resolution) ||
10704 (next_image->y_resolution != next_image->next->y_resolution))
10705 mng_info->equal_physs=MagickFalse;
10707 if (mng_info->equal_chrms)
10709 if (next_image->chromaticity.red_primary.x !=
10710 next_image->next->chromaticity.red_primary.x ||
10711 next_image->chromaticity.red_primary.y !=
10712 next_image->next->chromaticity.red_primary.y ||
10713 next_image->chromaticity.green_primary.x !=
10714 next_image->next->chromaticity.green_primary.x ||
10715 next_image->chromaticity.green_primary.y !=
10716 next_image->next->chromaticity.green_primary.y ||
10717 next_image->chromaticity.blue_primary.x !=
10718 next_image->next->chromaticity.blue_primary.x ||
10719 next_image->chromaticity.blue_primary.y !=
10720 next_image->next->chromaticity.blue_primary.y ||
10721 next_image->chromaticity.white_point.x !=
10722 next_image->next->chromaticity.white_point.x ||
10723 next_image->chromaticity.white_point.y !=
10724 next_image->next->chromaticity.white_point.y)
10725 mng_info->equal_chrms=MagickFalse;
10729 next_image=GetNextImageInList(next_image);
10731 if (image_count < 2)
10733 mng_info->equal_backgrounds=MagickFalse;
10734 mng_info->equal_chrms=MagickFalse;
10735 mng_info->equal_gammas=MagickFalse;
10736 mng_info->equal_srgbs=MagickFalse;
10737 mng_info->equal_physs=MagickFalse;
10738 use_global_plte=MagickFalse;
10739 #ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
10740 need_local_plte=MagickTrue;
10742 need_iterations=MagickFalse;
10745 if (mng_info->need_fram == MagickFalse)
10748 Only certain framing rates 100/n are exactly representable without
10749 the FRAM chunk but we'll allow some slop in VLC files
10751 if (final_delay == 0)
10753 if (need_iterations != MagickFalse)
10756 It's probably a GIF with loop; don't run it *too* fast.
10758 if (mng_info->adjoin)
10761 (void) ThrowMagickException(&image->exception,
10762 GetMagickModule(),CoderWarning,
10763 "input has zero delay between all frames; assuming",
10768 mng_info->ticks_per_second=0;
10770 if (final_delay != 0)
10771 mng_info->ticks_per_second=(png_uint_32) (image->ticks_per_second/final_delay);
10772 if (final_delay > 50)
10773 mng_info->ticks_per_second=2;
10775 if (final_delay > 75)
10776 mng_info->ticks_per_second=1;
10778 if (final_delay > 125)
10779 mng_info->need_fram=MagickTrue;
10781 if (need_defi && final_delay > 2 && (final_delay != 4) &&
10782 (final_delay != 5) && (final_delay != 10) && (final_delay != 20) &&
10783 (final_delay != 25) && (final_delay != 50) && (final_delay !=
10784 1UL*image->ticks_per_second))
10785 mng_info->need_fram=MagickTrue; /* make it exact; cannot be VLC */
10788 if (mng_info->need_fram != MagickFalse)
10789 mng_info->ticks_per_second=1UL*image->ticks_per_second;
10791 If pseudocolor, we should also check to see if all the
10792 palettes are identical and write a global PLTE if they are.
10796 Write the MNG version 1.0 signature and MHDR chunk.
10798 (void) WriteBlob(image,8,(const unsigned char *) "\212MNG\r\n\032\n");
10799 (void) WriteBlobMSBULong(image,28L); /* chunk data length=28 */
10800 PNGType(chunk,mng_MHDR);
10801 LogPNGChunk(logging,mng_MHDR,28L);
10802 PNGLong(chunk+4,(png_uint_32) mng_info->page.width);
10803 PNGLong(chunk+8,(png_uint_32) mng_info->page.height);
10804 PNGLong(chunk+12,mng_info->ticks_per_second);
10805 PNGLong(chunk+16,0L); /* layer count=unknown */
10806 PNGLong(chunk+20,0L); /* frame count=unknown */
10807 PNGLong(chunk+24,0L); /* play time=unknown */
10812 if (need_defi || mng_info->need_fram || use_global_plte)
10813 PNGLong(chunk+28,27L); /* simplicity=LC+JNG */
10816 PNGLong(chunk+28,25L); /* simplicity=VLC+JNG */
10821 if (need_defi || mng_info->need_fram || use_global_plte)
10822 PNGLong(chunk+28,19L); /* simplicity=LC+JNG, no transparency */
10825 PNGLong(chunk+28,17L); /* simplicity=VLC+JNG, no transparency */
10833 if (need_defi || mng_info->need_fram || use_global_plte)
10834 PNGLong(chunk+28,11L); /* simplicity=LC */
10837 PNGLong(chunk+28,9L); /* simplicity=VLC */
10842 if (need_defi || mng_info->need_fram || use_global_plte)
10843 PNGLong(chunk+28,3L); /* simplicity=LC, no transparency */
10846 PNGLong(chunk+28,1L); /* simplicity=VLC, no transparency */
10849 (void) WriteBlob(image,32,chunk);
10850 (void) WriteBlobMSBULong(image,crc32(0,chunk,32));
10851 option=GetImageOption(image_info,"mng:need-cacheoff");
10852 if (option != (const char *) NULL)
10858 Write "nEED CACHEOFF" to turn playback caching off for streaming MNG.
10860 PNGType(chunk,mng_nEED);
10861 length=CopyMagickString((char *) chunk+4,"CACHEOFF",20);
10862 (void) WriteBlobMSBULong(image,(size_t) length);
10863 LogPNGChunk(logging,mng_nEED,(size_t) length);
10865 (void) WriteBlob(image,length,chunk);
10866 (void) WriteBlobMSBULong(image,crc32(0,chunk,(uInt) length));
10868 if ((GetPreviousImageInList(image) == (Image *) NULL) &&
10869 (GetNextImageInList(image) != (Image *) NULL) &&
10870 (image->iterations != 1))
10873 Write MNG TERM chunk
10875 (void) WriteBlobMSBULong(image,10L); /* data length=10 */
10876 PNGType(chunk,mng_TERM);
10877 LogPNGChunk(logging,mng_TERM,10L);
10878 chunk[4]=3; /* repeat animation */
10879 chunk[5]=0; /* show last frame when done */
10880 PNGLong(chunk+6,(png_uint_32) (mng_info->ticks_per_second*
10881 final_delay/MagickMax(image->ticks_per_second,1)));
10883 if (image->iterations == 0)
10884 PNGLong(chunk+10,PNG_UINT_31_MAX);
10887 PNGLong(chunk+10,(png_uint_32) image->iterations);
10889 if (logging != MagickFalse)
10891 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10892 " TERM delay: %.20g",(double) (mng_info->ticks_per_second*
10893 final_delay/MagickMax(image->ticks_per_second,1)));
10895 if (image->iterations == 0)
10896 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10897 " TERM iterations: %.20g",(double) PNG_UINT_31_MAX);
10900 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
10901 " Image iterations: %.20g",(double) image->iterations);
10903 (void) WriteBlob(image,14,chunk);
10904 (void) WriteBlobMSBULong(image,crc32(0,chunk,14));
10907 To do: check for cHRM+gAMA == sRGB, and write sRGB instead.
10909 if ((image->colorspace == sRGBColorspace || image->rendering_intent) &&
10910 mng_info->equal_srgbs)
10913 Write MNG sRGB chunk
10915 (void) WriteBlobMSBULong(image,1L);
10916 PNGType(chunk,mng_sRGB);
10917 LogPNGChunk(logging,mng_sRGB,1L);
10919 if (image->rendering_intent != UndefinedIntent)
10920 chunk[4]=(unsigned char)
10921 PNG_RenderingIntent_from_Magick_RenderingIntent(
10922 (image->rendering_intent));
10925 chunk[4]=(unsigned char)
10926 PNG_RenderingIntent_from_Magick_RenderingIntent(
10927 (PerceptualIntent));
10929 (void) WriteBlob(image,5,chunk);
10930 (void) WriteBlobMSBULong(image,crc32(0,chunk,5));
10931 mng_info->have_write_global_srgb=MagickTrue;
10936 if (image->gamma && mng_info->equal_gammas)
10939 Write MNG gAMA chunk
10941 (void) WriteBlobMSBULong(image,4L);
10942 PNGType(chunk,mng_gAMA);
10943 LogPNGChunk(logging,mng_gAMA,4L);
10944 PNGLong(chunk+4,(png_uint_32) (100000*image->gamma+0.5));
10945 (void) WriteBlob(image,8,chunk);
10946 (void) WriteBlobMSBULong(image,crc32(0,chunk,8));
10947 mng_info->have_write_global_gama=MagickTrue;
10949 if (mng_info->equal_chrms)
10955 Write MNG cHRM chunk
10957 (void) WriteBlobMSBULong(image,32L);
10958 PNGType(chunk,mng_cHRM);
10959 LogPNGChunk(logging,mng_cHRM,32L);
10960 primary=image->chromaticity.white_point;
10961 PNGLong(chunk+4,(png_uint_32) (100000*primary.x+0.5));
10962 PNGLong(chunk+8,(png_uint_32) (100000*primary.y+0.5));
10963 primary=image->chromaticity.red_primary;
10964 PNGLong(chunk+12,(png_uint_32) (100000*primary.x+0.5));
10965 PNGLong(chunk+16,(png_uint_32) (100000*primary.y+0.5));
10966 primary=image->chromaticity.green_primary;
10967 PNGLong(chunk+20,(png_uint_32) (100000*primary.x+0.5));
10968 PNGLong(chunk+24,(png_uint_32) (100000*primary.y+0.5));
10969 primary=image->chromaticity.blue_primary;
10970 PNGLong(chunk+28,(png_uint_32) (100000*primary.x+0.5));
10971 PNGLong(chunk+32,(png_uint_32) (100000*primary.y+0.5));
10972 (void) WriteBlob(image,36,chunk);
10973 (void) WriteBlobMSBULong(image,crc32(0,chunk,36));
10974 mng_info->have_write_global_chrm=MagickTrue;
10977 if (image->x_resolution && image->y_resolution && mng_info->equal_physs)
10980 Write MNG pHYs chunk
10982 (void) WriteBlobMSBULong(image,9L);
10983 PNGType(chunk,mng_pHYs);
10984 LogPNGChunk(logging,mng_pHYs,9L);
10986 if (image->units == PixelsPerInchResolution)
10988 PNGLong(chunk+4,(png_uint_32)
10989 (image->x_resolution*100.0/2.54+0.5));
10991 PNGLong(chunk+8,(png_uint_32)
10992 (image->y_resolution*100.0/2.54+0.5));
10999 if (image->units == PixelsPerCentimeterResolution)
11001 PNGLong(chunk+4,(png_uint_32)
11002 (image->x_resolution*100.0+0.5));
11004 PNGLong(chunk+8,(png_uint_32)
11005 (image->y_resolution*100.0+0.5));
11012 PNGLong(chunk+4,(png_uint_32) (image->x_resolution+0.5));
11013 PNGLong(chunk+8,(png_uint_32) (image->y_resolution+0.5));
11017 (void) WriteBlob(image,13,chunk);
11018 (void) WriteBlobMSBULong(image,crc32(0,chunk,13));
11021 Write MNG BACK chunk and global bKGD chunk, if the image is transparent
11022 or does not cover the entire frame.
11024 if (write_mng && (image->matte || image->page.x > 0 ||
11025 image->page.y > 0 || (image->page.width &&
11026 (image->page.width+image->page.x < mng_info->page.width))
11027 || (image->page.height && (image->page.height+image->page.y
11028 < mng_info->page.height))))
11030 (void) WriteBlobMSBULong(image,6L);
11031 PNGType(chunk,mng_BACK);
11032 LogPNGChunk(logging,mng_BACK,6L);
11033 red=ScaleQuantumToShort(image->background_color.red);
11034 green=ScaleQuantumToShort(image->background_color.green);
11035 blue=ScaleQuantumToShort(image->background_color.blue);
11036 PNGShort(chunk+4,red);
11037 PNGShort(chunk+6,green);
11038 PNGShort(chunk+8,blue);
11039 (void) WriteBlob(image,10,chunk);
11040 (void) WriteBlobMSBULong(image,crc32(0,chunk,10));
11041 if (mng_info->equal_backgrounds)
11043 (void) WriteBlobMSBULong(image,6L);
11044 PNGType(chunk,mng_bKGD);
11045 LogPNGChunk(logging,mng_bKGD,6L);
11046 (void) WriteBlob(image,10,chunk);
11047 (void) WriteBlobMSBULong(image,crc32(0,chunk,10));
11051 #ifdef PNG_WRITE_EMPTY_PLTE_SUPPORTED
11052 if ((need_local_plte == MagickFalse) &&
11053 (image->storage_class == PseudoClass) &&
11054 (all_images_are_gray == MagickFalse))
11060 Write MNG PLTE chunk
11062 data_length=3*image->colors;
11063 (void) WriteBlobMSBULong(image,data_length);
11064 PNGType(chunk,mng_PLTE);
11065 LogPNGChunk(logging,mng_PLTE,data_length);
11067 for (i=0; i < (ssize_t) image->colors; i++)
11069 chunk[4+i*3]=ScaleQuantumToChar(image->colormap[i].red) & 0xff;
11070 chunk[5+i*3]=ScaleQuantumToChar(image->colormap[i].green) & 0xff;
11071 chunk[6+i*3]=ScaleQuantumToChar(image->colormap[i].blue) & 0xff;
11074 (void) WriteBlob(image,data_length+4,chunk);
11075 (void) WriteBlobMSBULong(image,crc32(0,chunk,(uInt) (data_length+4)));
11076 mng_info->have_write_global_plte=MagickTrue;
11082 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
11083 defined(PNG_MNG_FEATURES_SUPPORTED)
11084 mng_info->equal_palettes=MagickFalse;
11088 if (mng_info->adjoin)
11090 #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \
11091 defined(PNG_MNG_FEATURES_SUPPORTED)
11093 If we aren't using a global palette for the entire MNG, check to
11094 see if we can use one for two or more consecutive images.
11096 if (need_local_plte && use_global_plte && !all_images_are_gray)
11098 if (mng_info->IsPalette)
11101 When equal_palettes is true, this image has the same palette
11102 as the previous PseudoClass image
11104 mng_info->have_write_global_plte=mng_info->equal_palettes;
11105 mng_info->equal_palettes=PalettesAreEqual(image,image->next);
11106 if (mng_info->equal_palettes && !mng_info->have_write_global_plte)
11109 Write MNG PLTE chunk
11114 data_length=3*image->colors;
11115 (void) WriteBlobMSBULong(image,data_length);
11116 PNGType(chunk,mng_PLTE);
11117 LogPNGChunk(logging,mng_PLTE,data_length);
11119 for (i=0; i < (ssize_t) image->colors; i++)
11121 chunk[4+i*3]=ScaleQuantumToChar(image->colormap[i].red);
11122 chunk[5+i*3]=ScaleQuantumToChar(image->colormap[i].green);
11123 chunk[6+i*3]=ScaleQuantumToChar(image->colormap[i].blue);
11126 (void) WriteBlob(image,data_length+4,chunk);
11127 (void) WriteBlobMSBULong(image,crc32(0,chunk,
11128 (uInt) (data_length+4)));
11129 mng_info->have_write_global_plte=MagickTrue;
11133 mng_info->have_write_global_plte=MagickFalse;
11144 previous_x=mng_info->page.x;
11145 previous_y=mng_info->page.y;
11152 mng_info->page=image->page;
11153 if ((mng_info->page.x != previous_x) ||
11154 (mng_info->page.y != previous_y))
11156 (void) WriteBlobMSBULong(image,12L); /* data length=12 */
11157 PNGType(chunk,mng_DEFI);
11158 LogPNGChunk(logging,mng_DEFI,12L);
11159 chunk[4]=0; /* object 0 MSB */
11160 chunk[5]=0; /* object 0 LSB */
11161 chunk[6]=0; /* visible */
11162 chunk[7]=0; /* abstract */
11163 PNGLong(chunk+8,(png_uint_32) mng_info->page.x);
11164 PNGLong(chunk+12,(png_uint_32) mng_info->page.y);
11165 (void) WriteBlob(image,16,chunk);
11166 (void) WriteBlobMSBULong(image,crc32(0,chunk,16));
11171 mng_info->write_mng=write_mng;
11173 if ((int) image->dispose >= 3)
11174 mng_info->framing_mode=3;
11176 if (mng_info->need_fram && mng_info->adjoin &&
11177 ((image->delay != mng_info->delay) ||
11178 (mng_info->framing_mode != mng_info->old_framing_mode)))
11180 if (image->delay == mng_info->delay)
11183 Write a MNG FRAM chunk with the new framing mode.
11185 (void) WriteBlobMSBULong(image,1L); /* data length=1 */
11186 PNGType(chunk,mng_FRAM);
11187 LogPNGChunk(logging,mng_FRAM,1L);
11188 chunk[4]=(unsigned char) mng_info->framing_mode;
11189 (void) WriteBlob(image,5,chunk);
11190 (void) WriteBlobMSBULong(image,crc32(0,chunk,5));
11195 Write a MNG FRAM chunk with the delay.
11197 (void) WriteBlobMSBULong(image,10L); /* data length=10 */
11198 PNGType(chunk,mng_FRAM);
11199 LogPNGChunk(logging,mng_FRAM,10L);
11200 chunk[4]=(unsigned char) mng_info->framing_mode;
11201 chunk[5]=0; /* frame name separator (no name) */
11202 chunk[6]=2; /* flag for changing default delay */
11203 chunk[7]=0; /* flag for changing frame timeout */
11204 chunk[8]=0; /* flag for changing frame clipping */
11205 chunk[9]=0; /* flag for changing frame sync_id */
11206 PNGLong(chunk+10,(png_uint_32)
11207 ((mng_info->ticks_per_second*
11208 image->delay)/MagickMax(image->ticks_per_second,1)));
11209 (void) WriteBlob(image,14,chunk);
11210 (void) WriteBlobMSBULong(image,crc32(0,chunk,14));
11211 mng_info->delay=(png_uint_32) image->delay;
11213 mng_info->old_framing_mode=mng_info->framing_mode;
11216 #if defined(JNG_SUPPORTED)
11217 if (image_info->compression == JPEGCompression)
11222 if (logging != MagickFalse)
11223 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11224 " Writing JNG object.");
11225 /* To do: specify the desired alpha compression method. */
11226 write_info=CloneImageInfo(image_info);
11227 write_info->compression=UndefinedCompression;
11228 status=WriteOneJNGImage(mng_info,write_info,image);
11229 write_info=DestroyImageInfo(write_info);
11234 if (logging != MagickFalse)
11235 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
11236 " Writing PNG object.");
11238 mng_info->need_blob = MagickFalse;
11240 /* We don't want any ancillary chunks written */
11241 mng_info->ping_exclude_bKGD=MagickTrue;
11242 mng_info->ping_exclude_cHRM=MagickTrue;
11243 mng_info->ping_exclude_EXIF=MagickTrue;
11244 mng_info->ping_exclude_gAMA=MagickTrue;
11245 mng_info->ping_exclude_cHRM=MagickTrue;
11246 mng_info->ping_exclude_iCCP=MagickTrue;
11247 /* mng_info->ping_exclude_iTXt=MagickTrue; */
11248 mng_info->ping_exclude_oFFs=MagickTrue;
11249 mng_info->ping_exclude_pHYs=MagickTrue;
11250 mng_info->ping_exclude_sRGB=MagickTrue;
11251 mng_info->ping_exclude_tEXt=MagickTrue;
11252 mng_info->ping_exclude_tRNS=MagickTrue;
11253 mng_info->ping_exclude_vpAg=MagickTrue;
11254 mng_info->ping_exclude_zCCP=MagickTrue;
11255 mng_info->ping_exclude_zTXt=MagickTrue;
11257 status=WriteOnePNGImage(mng_info,image_info,image);
11260 if (status == MagickFalse)
11262 MngInfoFreeStruct(mng_info,&have_mng_structure);
11263 (void) CloseBlob(image);
11264 return(MagickFalse);
11266 (void) CatchImageException(image);
11267 if (GetNextImageInList(image) == (Image *) NULL)
11269 image=SyncNextImageInList(image);
11270 status=SetImageProgress(image,SaveImagesTag,scene++,
11271 GetImageListLength(image));
11273 if (status == MagickFalse)
11276 } while (mng_info->adjoin);
11280 while (GetPreviousImageInList(image) != (Image *) NULL)
11281 image=GetPreviousImageInList(image);
11283 Write the MEND chunk.
11285 (void) WriteBlobMSBULong(image,0x00000000L);
11286 PNGType(chunk,mng_MEND);
11287 LogPNGChunk(logging,mng_MEND,0L);
11288 (void) WriteBlob(image,4,chunk);
11289 (void) WriteBlobMSBULong(image,crc32(0,chunk,4));
11292 Relinquish resources.
11294 (void) CloseBlob(image);
11295 MngInfoFreeStruct(mng_info,&have_mng_structure);
11297 if (logging != MagickFalse)
11298 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit WriteMNGImage()");
11300 return(MagickTrue);
11302 #else /* PNG_LIBPNG_VER > 10011 */
11304 static MagickBooleanType WritePNGImage(const ImageInfo *image_info,Image *image)
11307 printf("Your PNG library is too old: You have libpng-%s\n",
11308 PNG_LIBPNG_VER_STRING);
11310 ThrowBinaryException(CoderError,"PNG library is too old",
11311 image_info->filename);
11314 static MagickBooleanType WriteMNGImage(const ImageInfo *image_info,Image *image)
11316 return(WritePNGImage(image_info,image));
11318 #endif /* PNG_LIBPNG_VER > 10011 */